CAY-2166 Auto-loading of Cayenne modules * auto-loading
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/ba59e95e Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/ba59e95e Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/ba59e95e Branch: refs/heads/master Commit: ba59e95eaf440b1c3cc7c01ecc32dc88f1c5d86d Parents: 3dc06bd Author: Andrus Adamchik <and...@objectstyle.com> Authored: Sun Dec 11 17:05:33 2016 +0300 Committer: Andrus Adamchik <and...@objectstyle.com> Committed: Sun Dec 11 19:19:51 2016 +0300 ---------------------------------------------------------------------- .../server/ServerModuleProvider.java | 45 ++++++++++++++ .../configuration/server/ServerRuntime.java | 8 +-- .../server/ServerRuntimeBuilder.java | 37 +++++++++--- .../org.apache.cayenne.di.spi.ModuleProvider | 1 + .../server/ServerModuleProviderTest.java | 30 ++++++++++ .../server/ServerRuntimeBuilderTest.java | 13 +--- .../unit/util/ModuleProviderChecker.java | 62 ++++++++++++++++++++ docs/doc/src/main/resources/UPGRADE.txt | 6 ++ 8 files changed, 179 insertions(+), 23 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cayenne/blob/ba59e95e/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModuleProvider.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModuleProvider.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModuleProvider.java new file mode 100644 index 0000000..55d681d --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModuleProvider.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cayenne.configuration.server; + +import org.apache.cayenne.di.Module; +import org.apache.cayenne.di.spi.ModuleProvider; + +/** + * ServerModule auto-loading facility. + * + * @since 4.0 + */ +public class ServerModuleProvider implements ModuleProvider { + + @Override + public Module module() { + return new ServerModule(); + } + + @Override + public Class<? extends Module> moduleType() { + return ServerModule.class; + } + + @Override + public Class<? extends Module>[] overrides() { + return new Class[0]; + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/ba59e95e/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntime.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntime.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntime.java index d6029a2..8425dca 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntime.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntime.java @@ -59,7 +59,7 @@ public class ServerRuntime extends CayenneRuntime { /** * Creates a builder of ServerRuntime. * - * @param name + * @param name optional symbolic name of the created runtime. * @return a named builder of ServerRuntime. */ public static ServerRuntimeBuilder builder(String name) { @@ -71,19 +71,19 @@ public class ServerRuntime extends CayenneRuntime { Collection<Module> modules = new ArrayList<>(); modules.add(new ServerModule()); - if(configurationLocations.length > 0) { + if (configurationLocations.length > 0) { modules.add(new Module() { @Override public void configure(Binder binder) { ListBuilder<String> locationsBinder = ServerModule.contributeProjectLocations(binder); - for(String c : configurationLocations) { + for (String c : configurationLocations) { locationsBinder.add(c); } } }); } - if(extraModules != null) { + if (extraModules != null) { modules.addAll(asList(extraModules)); } http://git-wip-us.apache.org/repos/asf/cayenne/blob/ba59e95e/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilder.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilder.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilder.java index e5e2ae2..19938b5 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilder.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilder.java @@ -25,6 +25,7 @@ import org.apache.cayenne.di.Binder; import org.apache.cayenne.di.ListBuilder; import org.apache.cayenne.di.MapBuilder; import org.apache.cayenne.di.Module; +import org.apache.cayenne.di.spi.ModuleLoader; import javax.sql.DataSource; import java.util.*; @@ -72,7 +73,11 @@ public class ServerRuntimeBuilder { /** * Creates an empty builder. + * + * @deprecated since 4.0.M5 in favor of {@link ServerRuntime#builder()} */ + @Deprecated + // TODO remove once we are comfortable with removal of the deprecated API public ServerRuntimeBuilder() { this(null); } @@ -81,7 +86,11 @@ public class ServerRuntimeBuilder { * Creates a builder with a fixed name of the DataDomain of the resulting * ServerRuntime. Specifying explicit name is often needed for consistency * in runtimes merged from multiple configs, each having its own name. + * + * @deprecated since 4.0.M5 in favor of {@link ServerRuntime#builder(String)} */ + @Deprecated + // TODO make private once we are comfortable with removal of the deprecated API public ServerRuntimeBuilder(String name) { this.configs = new LinkedHashSet<String>(); this.modules = new ArrayList<Module>(); @@ -211,28 +220,38 @@ public class ServerRuntimeBuilder { public ServerRuntime build() { - Collection<Module> configModules = buildConfigModules(); - Collection<Module> allModules = new ArrayList<>(); - // TODO: make ServerModule auto-loadable? - allModules.add(new ServerModule()); - allModules.addAll(configModules); - // custom modules override config modules... + + // first load default or auto-loaded modules... + allModules.addAll(autoLoadModules ? autoLoadedModules() : defaultModules()); + + // custom modules override default and auto-loaded modules... allModules.addAll(this.modules); + // builder modules override default, auto-loaded and custom modules... + allModules.addAll(builderModules()); + return new ServerRuntime(allModules); } - private Collection<Module> buildConfigModules() { + private Collection<? extends Module> autoLoadedModules() { + return new ModuleLoader().load(); + } + + private Collection<? extends Module> defaultModules() { + return Collections.singleton(new ServerModule()); + } + + private Collection<? extends Module> builderModules() { Collection<Module> modules = new ArrayList<>(); - if(!configs.isEmpty()) { + if (!configs.isEmpty()) { modules.add(new Module() { @Override public void configure(Binder binder) { ListBuilder<String> locationsBinder = ServerModule.contributeProjectLocations(binder); - for(String c : configs) { + for (String c : configs) { locationsBinder.add(c); } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/ba59e95e/cayenne-server/src/main/resources/META-INF/services/org.apache.cayenne.di.spi.ModuleProvider ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/resources/META-INF/services/org.apache.cayenne.di.spi.ModuleProvider b/cayenne-server/src/main/resources/META-INF/services/org.apache.cayenne.di.spi.ModuleProvider new file mode 100644 index 0000000..9e5f5bb --- /dev/null +++ b/cayenne-server/src/main/resources/META-INF/services/org.apache.cayenne.di.spi.ModuleProvider @@ -0,0 +1 @@ +org.apache.cayenne.configuration.server.ServerModuleProvider \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cayenne/blob/ba59e95e/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerModuleProviderTest.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerModuleProviderTest.java b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerModuleProviderTest.java new file mode 100644 index 0000000..6f30ec0 --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerModuleProviderTest.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cayenne.configuration.server; + +import org.apache.cayenne.unit.util.ModuleProviderChecker; +import org.junit.Test; + +public class ServerModuleProviderTest { + + @Test + public void testProviderPresent() { + ModuleProviderChecker.testProviderPresent(ServerModuleProvider.class); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/ba59e95e/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilderTest.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilderTest.java b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilderTest.java index 2617476..95e7a44 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilderTest.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilderTest.java @@ -26,7 +26,6 @@ import org.junit.Test; import java.util.Arrays; import java.util.Collection; -import java.util.Iterator; import java.util.List; import static org.hamcrest.CoreMatchers.instanceOf; @@ -104,15 +103,9 @@ public class ServerRuntimeBuilderTest { Collection<Module> modules = runtime.getModules(); assertEquals(3, modules.size()); - - Iterator<Module> it = modules.iterator(); - - assertThat(it.next(), instanceOf(ServerModule.class)); - - // rewind - this module is name fix module - it.next(); - - assertSame(m, it.next()); + Module[] array = modules.toArray(new Module[3]); + assertThat(array[0], instanceOf(ServerModule.class)); + assertSame(m, array[1]); } @Test http://git-wip-us.apache.org/repos/asf/cayenne/blob/ba59e95e/cayenne-server/src/test/java/org/apache/cayenne/unit/util/ModuleProviderChecker.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/util/ModuleProviderChecker.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/util/ModuleProviderChecker.java new file mode 100644 index 0000000..43770a5 --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/util/ModuleProviderChecker.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cayenne.unit.util; + +import org.apache.cayenne.di.spi.ModuleProvider; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.ServiceLoader; + +import static org.junit.Assert.fail; + +public class ModuleProviderChecker { + + private Class<? extends ModuleProvider> expectedProvider; + + public static void testProviderPresent(Class<? extends ModuleProvider> expectedProvider) { + new ModuleProviderChecker(expectedProvider).testProviderPresent(); + } + + protected ModuleProviderChecker(Class<? extends ModuleProvider> expectedProvider) { + this.expectedProvider = Objects.requireNonNull(expectedProvider); + } + + protected void testProviderPresent() { + + List<ModuleProvider> providers = new ArrayList<>(); + for (ModuleProvider p : ServiceLoader.load(ModuleProvider.class)) { + if (expectedProvider.equals(p.getClass())) { + providers.add(p); + } + } + + switch (providers.size()) { + case 0: + fail("Expected provider '" + expectedProvider.getName() + "' is not found"); + break; + case 1: + break; + default: + fail("Expected provider '" + expectedProvider.getName() + "' is found more then once: " + providers.size()); + break; + } + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/ba59e95e/docs/doc/src/main/resources/UPGRADE.txt ---------------------------------------------------------------------- diff --git a/docs/doc/src/main/resources/UPGRADE.txt b/docs/doc/src/main/resources/UPGRADE.txt index b352224..e0b9c39 100644 --- a/docs/doc/src/main/resources/UPGRADE.txt +++ b/docs/doc/src/main/resources/UPGRADE.txt @@ -6,6 +6,12 @@ IMPORTANT: be sure to read all notes for the intermediate releases between your ------------------------------------------------------------------------------- UPGRADING TO 4.0.M5 +* Per CAY-2166, Cayenne supports auto-loading of DI modules. The part of this is a tweak in DI service override policies. + In the previous 4.0 releases custom modules would override "builder" modules (i.e. implicit modules that wrap around + various customizations made in response to the builder method calls). It seemed logical to reverse this order, and + let builder modules override custom modules. As the builder is invoked explicitly when the stack assembly is performed, + while modules can be written without any knowledge of the final stack. + * Per CAY-2164, creating a ServerRuntimeBuilder is done via a static method on ServerRuntime ("ServerRuntime.builder()"). The previous style (ServerRuntimeBuilder.builder()) is deprecated and will soon be removed, so you should replace it with the new API.