This is an automated email from the ASF dual-hosted git repository.

udo pushed a commit to branch feature/GEODE-8294
in repository https://gitbox.apache.org/repos/asf/geode.git

commit 6a65bd359d7614e319f1e188a04b6f2d3c81aa5b
Author: Udo Kohlmeyer <ukohlme...@pivtotal.io>
AuthorDate: Tue May 19 09:20:46 2020 -0700

    GEODE-8043 - Create JBossModuleService and implement loadModule. (#5081)
---
 .../src/test/resources/expected-pom.xml            |  18 +
 .../gradle/plugins/DependencyConstraints.groovy    |   3 +
 geode-assembly/build.gradle                        |   2 +
 .../integrationTest/resources/assembly_content.txt |  22 ++
 .../resources/dependency_classpath.txt             |  27 +-
 .../integrationTest/resources/expected_jars.txt    |   1 +
 geode-common-services/build.gradle                 |  33 ++
 .../geode/services/module/ModuleDescriptor.java    | 100 +++++
 .../geode/services/module/ModuleService.java       |  36 ++
 .../src/test/resources/expected-pom.xml            |  60 +++
 geode-modules/build.gradle                         |  97 +++++
 .../services/module/impl/GeodeModuleLoader.java    |  53 +++
 .../services/module/impl/JBossModuleService.java   | 115 ++++++
 .../module/impl/JBossModuleServiceTest.java        | 402 +++++++++++++++++++++
 geode-modules/src/test/resources/expected-pom.xml  |  80 ++++
 .../module1/java/org/apache/geode/Module1.java     |  19 +
 .../module2/java/org.apache.geode/Module2.java     |  19 +
 .../module3/java/org/apache/geode/Module3.java     |  19 +
 .../module4/java/org/apache/geode/Module4.java     |  19 +
 settings.gradle                                    |   2 +
 20 files changed, 1115 insertions(+), 12 deletions(-)

diff --git a/boms/geode-all-bom/src/test/resources/expected-pom.xml 
b/boms/geode-all-bom/src/test/resources/expected-pom.xml
index 2885bd8..3807199 100644
--- a/boms/geode-all-bom/src/test/resources/expected-pom.xml
+++ b/boms/geode-all-bom/src/test/resources/expected-pom.xml
@@ -464,6 +464,12 @@
         <scope>compile</scope>
       </dependency>
       <dependency>
+        <groupId>org.jboss.modules</groupId>
+        <artifactId>jboss-modules</artifactId>
+        <version>1.10.1.Final</version>
+        <scope>compile</scope>
+      </dependency>
+      <dependency>
         <groupId>org.jgroups</groupId>
         <artifactId>jgroups</artifactId>
         <version>3.6.14.Final</version>
@@ -891,6 +897,12 @@
       </dependency>
       <dependency>
         <groupId>org.apache.geode</groupId>
+        <artifactId>geode-common-services</artifactId>
+        <version>${version}</version>
+        <scope>compile</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.geode</groupId>
         <artifactId>geode-concurrency-test</artifactId>
         <version>${version}</version>
         <scope>compile</scope>
@@ -981,6 +993,12 @@
       </dependency>
       <dependency>
         <groupId>org.apache.geode</groupId>
+        <artifactId>geode-modules</artifactId>
+        <version>${version}</version>
+        <scope>compile</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.geode</groupId>
         <artifactId>geode-old-client-support</artifactId>
         <version>${version}</version>
         <scope>compile</scope>
diff --git 
a/buildSrc/src/main/groovy/org/apache/geode/gradle/plugins/DependencyConstraints.groovy
 
b/buildSrc/src/main/groovy/org/apache/geode/gradle/plugins/DependencyConstraints.groovy
index 14d6b034..bb3ea96 100644
--- 
a/buildSrc/src/main/groovy/org/apache/geode/gradle/plugins/DependencyConstraints.groovy
+++ 
b/buildSrc/src/main/groovy/org/apache/geode/gradle/plugins/DependencyConstraints.groovy
@@ -31,6 +31,8 @@ class DependencyConstraints implements Plugin<Project> {
     Map<String,String> deps = new HashMap<>()
     // These versions are consumed beyond the scope of source set dependencies.
 
+    deps.put("jboss-modules.version", "1.10.1.Final")
+
     // These version numbers are consumed by 
:geode-modules-assembly:distAppServer filtering
     // Some of these are referenced below as well
     deps.put("antlr.version", "2.7.7")
@@ -155,6 +157,7 @@ class DependencyConstraints implements Plugin<Project> {
         api(group: 'org.eclipse.persistence', name: 'javax.persistence', 
version: '2.2.1')
         api(group: 'org.httpunit', name: 'httpunit', version: '1.7.3')
         api(group: 'org.iq80.snappy', name: 'snappy', version: '0.4')
+        api(group: 'org.jboss.modules', name: 'jboss-modules', version: 
get('jboss-modules.version'))
         api(group: 'org.jgroups', name: 'jgroups', version: 
get('jgroups.version'))
         api(group: 'org.mockito', name: 'mockito-core', version: '3.3.3')
         api(group: 'org.mortbay.jetty', name: 'servlet-api', version: 
'3.0.20100224')
diff --git a/geode-assembly/build.gradle b/geode-assembly/build.gradle
index 9f2e7f3..134cbe7 100755
--- a/geode-assembly/build.gradle
+++ b/geode-assembly/build.gradle
@@ -28,6 +28,7 @@ import java.nio.file.Paths
 // This list is used in a loop to defined the /lib copySpec
 def dependentProjectNames = [
   ':geode-common',
+  ':geode-common-services',
   ':geode-connectors',
   ':geode-core',
   ':geode-cq',
@@ -36,6 +37,7 @@ def dependentProjectNames = [
   ':geode-logging',
   ':geode-lucene',
   ':geode-memcached',
+  ':geode-modules',
   ':geode-old-client-support',
   ':geode-protobuf',
   ':geode-protobuf-messages',
diff --git a/geode-assembly/src/integrationTest/resources/assembly_content.txt 
b/geode-assembly/src/integrationTest/resources/assembly_content.txt
index bec9cce..60c602b 100644
--- a/geode-assembly/src/integrationTest/resources/assembly_content.txt
+++ b/geode-assembly/src/integrationTest/resources/assembly_content.txt
@@ -963,6 +963,25 @@ javadoc/org/apache/geode/security/SecurityManager.html
 javadoc/org/apache/geode/security/package-frame.html
 javadoc/org/apache/geode/security/package-summary.html
 javadoc/org/apache/geode/security/package-tree.html
+javadoc/org/apache/geode/services/bootstrapping/BootstrappingService.html
+javadoc/org/apache/geode/services/bootstrapping/package-frame.html
+javadoc/org/apache/geode/services/bootstrapping/package-summary.html
+javadoc/org/apache/geode/services/bootstrapping/package-tree.html
+javadoc/org/apache/geode/services/management/ManagementService.html
+javadoc/org/apache/geode/services/management/package-frame.html
+javadoc/org/apache/geode/services/management/package-summary.html
+javadoc/org/apache/geode/services/management/package-tree.html
+javadoc/org/apache/geode/services/module/ModuleDescriptor.Builder.html
+javadoc/org/apache/geode/services/module/ModuleDescriptor.html
+javadoc/org/apache/geode/services/module/ModuleService.html
+javadoc/org/apache/geode/services/module/impl/GeodeModuleLoader.html
+javadoc/org/apache/geode/services/module/impl/JBossModuleService.html
+javadoc/org/apache/geode/services/module/impl/package-frame.html
+javadoc/org/apache/geode/services/module/impl/package-summary.html
+javadoc/org/apache/geode/services/module/impl/package-tree.html
+javadoc/org/apache/geode/services/module/package-frame.html
+javadoc/org/apache/geode/services/module/package-summary.html
+javadoc/org/apache/geode/services/module/package-tree.html
 javadoc/overview-frame.html
 javadoc/overview-summary.html
 javadoc/overview-tree.html
@@ -988,6 +1007,7 @@ lib/fastutil-8.3.1.jar
 lib/findbugs-annotations-1.3.9-1.jar
 lib/geo-0.7.7.jar
 lib/geode-common-0.0.0.jar
+lib/geode-common-services-0.0.0.jar
 lib/geode-connectors-0.0.0.jar
 lib/geode-core-0.0.0.jar
 lib/geode-cq-0.0.0.jar
@@ -1001,6 +1021,7 @@ lib/geode-lucene-0.0.0.jar
 lib/geode-management-0.0.0.jar
 lib/geode-membership-0.0.0.jar
 lib/geode-memcached-0.0.0.jar
+lib/geode-modules-0.0.0.jar
 lib/geode-old-client-support-0.0.0.jar
 lib/geode-protobuf-0.0.0.jar
 lib/geode-protobuf-messages-0.0.0.jar
@@ -1025,6 +1046,7 @@ lib/javax.servlet-api-3.1.0.jar
 lib/javax.transaction-api-1.3.jar
 lib/jaxb-api-2.3.1.jar
 lib/jaxb-impl-2.3.2.jar
+lib/jboss-modules-1.10.1.Final.jar
 lib/jetty-http-9.4.21.v20190926.jar
 lib/jetty-io-9.4.21.v20190926.jar
 lib/jetty-security-9.4.21.v20190926.jar
diff --git 
a/geode-assembly/src/integrationTest/resources/dependency_classpath.txt 
b/geode-assembly/src/integrationTest/resources/dependency_classpath.txt
index df1bad5..078da56 100644
--- a/geode-assembly/src/integrationTest/resources/dependency_classpath.txt
+++ b/geode-assembly/src/integrationTest/resources/dependency_classpath.txt
@@ -1,4 +1,5 @@
 geode-common-0.0.0.jar
+geode-common-services-0.0.0.jar
 geode-connectors-0.0.0.jar
 geode-core-0.0.0.jar
 geode-cq-0.0.0.jar
@@ -6,8 +7,8 @@ geode-gfsh-0.0.0.jar
 geode-log4j-0.0.0.jar
 geode-logging-0.0.0.jar
 geode-lucene-0.0.0.jar
-geode-management-0.0.0.jar
 geode-memcached-0.0.0.jar
+geode-modules-0.0.0.jar
 geode-old-client-support-0.0.0.jar
 geode-protobuf-0.0.0.jar
 geode-protobuf-messages-0.0.0.jar
@@ -16,22 +17,15 @@ geode-redis-0.0.0.jar
 geode-serialization-0.0.0.jar
 geode-tcp-server-0.0.0.jar
 geode-wan-0.0.0.jar
+geode-management-0.0.0.jar
 jackson-databind-2.10.1.jar
 jackson-annotations-2.10.1.jar
 jackson-core-2.10.1.jar
 geode-membership-0.0.0.jar
 geode-http-service-0.0.0.jar
 geode-unsafe-0.0.0.jar
-httpclient-4.5.12.jar
-httpcore-4.4.13.jar
-HikariCP-3.4.2.jar
-commons-lang3-3.10.jar
-jaxb-api-2.3.1.jar
-log4j-jcl-2.13.1.jar
-log4j-api-2.13.1.jar
-spring-shell-1.2.0.RELEASE.jar
-rmiio-2.1.2.jar
 antlr-2.7.7.jar
+rmiio-2.1.2.jar
 javax.activation-1.2.0.jar
 istack-commons-runtime-3.0.11.jar
 jaxb-impl-2.3.2.jar
@@ -39,6 +33,7 @@ commons-validator-1.6.jar
 shiro-core-1.5.2.jar
 shiro-config-ogdl-1.5.2.jar
 commons-beanutils-1.9.4.jar
+httpclient-4.5.12.jar
 commons-codec-1.14.jar
 commons-collections-3.2.2.jar
 commons-io-2.6.jar
@@ -53,9 +48,12 @@ jetty-servlet-9.4.21.v20190926.jar
 jetty-security-9.4.21.v20190926.jar
 jetty-server-9.4.21.v20190926.jar
 javax.servlet-api-3.1.0.jar
+jaxb-api-2.3.1.jar
 jna-platform-5.5.0.jar
 jna-5.5.0.jar
 jopt-simple-5.0.4.jar
+commons-lang3-3.10.jar
+httpcore-4.4.13.jar
 snappy-0.4.jar
 jgroups-3.6.14.Final.jar
 shiro-cache-1.5.2.jar
@@ -66,17 +64,21 @@ shiro-event-1.5.2.jar
 shiro-crypto-core-1.5.2.jar
 shiro-lang-1.5.2.jar
 slf4j-api-1.7.30.jar
+log4j-api-2.13.1.jar
 spring-core-5.2.5.RELEASE.jar
-javax.activation-api-1.2.0.jar
-jline-2.12.jar
 HdrHistogram-2.1.12.jar
 LatencyUtils-2.0.3.jar
 javax.transaction-api-1.3.jar
+javax.activation-api-1.2.0.jar
 spring-jcl-5.2.5.RELEASE.jar
 jetty-http-9.4.21.v20190926.jar
 jetty-io-9.4.21.v20190926.jar
 jetty-xml-9.4.21.v20190926.jar
 jetty-util-9.4.21.v20190926.jar
+HikariCP-3.4.2.jar
+log4j-jcl-2.13.1.jar
+spring-shell-1.2.0.RELEASE.jar
+jline-2.12.jar
 log4j-slf4j-impl-2.13.1.jar
 log4j-core-2.13.1.jar
 log4j-jul-2.13.1.jar
@@ -85,6 +87,7 @@ lucene-analyzers-common-6.6.6.jar
 lucene-queryparser-6.6.6.jar
 lucene-core-6.6.6.jar
 lucene-queries-6.6.6.jar
+jboss-modules-1.10.1.Final.jar
 protobuf-java-3.11.4.jar
 geo-0.7.7.jar
 netty-all-4.1.48.Final.jar
diff --git a/geode-assembly/src/integrationTest/resources/expected_jars.txt 
b/geode-assembly/src/integrationTest/resources/expected_jars.txt
index c116f7c..131d9a1 100644
--- a/geode-assembly/src/integrationTest/resources/expected_jars.txt
+++ b/geode-assembly/src/integrationTest/resources/expected_jars.txt
@@ -44,6 +44,7 @@ javax.servlet-api
 javax.transaction-api
 jaxb-api
 jaxb-impl
+jboss-modules
 jcip-annotations
 jetty-http
 jetty-io
diff --git a/geode-common-services/build.gradle 
b/geode-common-services/build.gradle
new file mode 100644
index 0000000..da983cf
--- /dev/null
+++ b/geode-common-services/build.gradle
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
+apply from: "${project.projectDir}/../gradle/publish-java.gradle"
+apply from: "${project.projectDir}/../gradle/warnings.gradle"
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+    compile(platform(project(':boms:geode-all-bom')))
+
+    compile(project(':geode-common'))
+
+    compile(project(':geode-core'))
+}
diff --git 
a/geode-common-services/src/main/java/org/apache/geode/services/module/ModuleDescriptor.java
 
b/geode-common-services/src/main/java/org/apache/geode/services/module/ModuleDescriptor.java
new file mode 100644
index 0000000..3b84130
--- /dev/null
+++ 
b/geode-common-services/src/main/java/org/apache/geode/services/module/ModuleDescriptor.java
@@ -0,0 +1,100 @@
+/*
+ * 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.geode.services.module;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.geode.annotations.Experimental;
+
+/**
+ * Holds information to describe a classloader-isolated module including how 
to create it.
+ *
+ * @see Builder
+ * @see ModuleService
+ *
+ * @since Geode 1.13.0
+ */
+@Experimental
+public class ModuleDescriptor {
+
+  private String name;
+
+  private String version;
+
+  private List<String> sources;
+
+  private List<String> dependencies;
+
+  private ModuleDescriptor(String name, String version, List<String> sources,
+      List<String> dependencies) {
+    this.name = name;
+    this.version = version;
+    this.sources = sources;
+    this.dependencies = dependencies;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public String getVersion() {
+    return version;
+  }
+
+  public List<String> getSources() {
+    return sources;
+  }
+
+  public List<String> getDependedOnModules() {
+    return dependencies;
+  }
+
+  public String getVersionedName() {
+    return name + ":" + version;
+  }
+
+  /**
+   * A Builder used to construct a {@link ModuleDescriptor}
+   */
+  public static class Builder {
+
+    private final String name;
+    private final String version;
+    private List<String> dependencies = Collections.emptyList();
+    private List<String> sources = Collections.emptyList();
+
+    public Builder(String name, String version) {
+      this.name = name;
+      this.version = version;
+    }
+
+    public Builder fromSources(String... sources) {
+      this.sources = Arrays.asList(sources);
+      return this;
+    }
+
+    public Builder dependsOnModules(String... dependencies) {
+      this.dependencies = Arrays.asList(dependencies);
+      return this;
+    }
+
+    public ModuleDescriptor build() {
+      return new ModuleDescriptor(name, version, sources, dependencies);
+    }
+  }
+}
diff --git 
a/geode-common-services/src/main/java/org/apache/geode/services/module/ModuleService.java
 
b/geode-common-services/src/main/java/org/apache/geode/services/module/ModuleService.java
new file mode 100644
index 0000000..cd295c0
--- /dev/null
+++ 
b/geode-common-services/src/main/java/org/apache/geode/services/module/ModuleService.java
@@ -0,0 +1,36 @@
+/*
+ * 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.geode.services.module;
+
+import org.apache.geode.annotations.Experimental;
+
+/**
+ * Loads and unloads modules and services in a classloader-isolated manner.
+ *
+ * @since Geode 1.13.0
+ */
+@Experimental
+public interface ModuleService {
+
+  /**
+   * Loads a module from a resource.
+   *
+   * @param moduleDescriptor description of the module to be loaded and 
information necessary to
+   *        load it.
+   * @return true on success, false if the module could not be loaded.
+   */
+  boolean loadModule(ModuleDescriptor moduleDescriptor);
+}
diff --git a/geode-common-services/src/test/resources/expected-pom.xml 
b/geode-common-services/src/test/resources/expected-pom.xml
new file mode 100644
index 0000000..26f1cdd
--- /dev/null
+++ b/geode-common-services/src/test/resources/expected-pom.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+  <!--
+  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.
+  -->
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.geode</groupId>
+  <artifactId>geode-common-services</artifactId>
+  <version>1.13.0-SNAPSHOT</version>
+  <name>Apache Geode</name>
+  <description>Apache Geode provides a database-like consistency model, 
reliable transaction processing and a shared-nothing architecture to maintain 
very low latency performance with high concurrency processing</description>
+  <url>http://geode.apache.org</url>
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+    </license>
+  </licenses>
+  <scm>
+    <connection>scm:git:https://github.com:apache/geode.git</connection>
+    
<developerConnection>scm:git:https://github.com:apache/geode.git</developerConnection>
+    <url>https://github.com/apache/geode</url>
+  </scm>
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.apache.geode</groupId>
+        <artifactId>geode-all-bom</artifactId>
+        <version>1.13.0-SNAPSHOT</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.geode</groupId>
+      <artifactId>geode-common</artifactId>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geode</groupId>
+      <artifactId>geode-core</artifactId>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/geode-modules/build.gradle b/geode-modules/build.gradle
new file mode 100644
index 0000000..319c0bd
--- /dev/null
+++ b/geode-modules/build.gradle
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
+apply from: "${project.projectDir}/../gradle/publish-java.gradle"
+apply from: "${project.projectDir}/../gradle/warnings.gradle"
+
+sourceSets {
+    module1 {
+        java.srcDir "src/testModules/module1/java"
+        resources.srcDir "src/testModules/module1/resources"
+        compileClasspath += configurations.compileClasspath
+        runtimeClasspath += configurations.runtimeClasspath
+    }
+    module2 {
+        java.srcDir "src/testModules/module2/java"
+        resources.srcDir "src/testModules/module2/resources"
+        compileClasspath += configurations.compileClasspath
+        runtimeClasspath += configurations.runtimeClasspath
+    }
+    module3 {
+        java.srcDir "src/testModules/module3/java"
+        resources.srcDir "src/testModules/module3/resources"
+        compileClasspath += configurations.compileClasspath
+        runtimeClasspath += configurations.runtimeClasspath
+    }
+    module4 {
+        java.srcDir "src/testModules/module4/java"
+        resources.srcDir "src/testModules/module4/resources"
+        compileClasspath += configurations.compileClasspath
+        runtimeClasspath += configurations.runtimeClasspath
+    }
+}
+
+task module1Jar(type: Jar, dependsOn: classes) {
+    description 'Assembles the jar archive that contains the module1 classes'
+    from sourceSets.module1.output
+    archiveName 'module1.jar'
+}
+
+task module2Jar(type: Jar, dependsOn: classes) {
+    description 'Assembles the jar archive that contains the module2 classes'
+    from sourceSets.module2.output
+    archiveName 'module2.jar'
+}
+
+task module3Jar(type: Jar, dependsOn: classes) {
+    description 'Assembles the jar archive that contains the module3 classes'
+    from sourceSets.module3.output
+    archiveName 'module3.jar'
+}
+
+task module4Jar(type: Jar, dependsOn: classes) {
+    description 'Assembles the jar archive that contains the module4 classes'
+    from sourceSets.module4.output
+    archiveName 'module4.jar'
+}
+
+tasks.test.dependsOn("module1Jar")
+tasks.test.dependsOn("module2Jar")
+tasks.test.dependsOn("module3Jar")
+tasks.test.dependsOn("module4Jar")
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+    testCompile(group: 'junit', name: 'junit', version: '4.12')
+    testImplementation('org.assertj:assertj-core')
+
+    compile(platform(project(':boms:geode-all-bom')))
+
+    compile(project(':geode-common'))
+    implementation(project(':geode-logging'))
+    implementation(project(':geode-log4j'))
+
+    compile(project(':geode-common-services'))
+
+    implementation('org.apache.logging.log4j:log4j-core')
+    compile('org.jboss.modules:jboss-modules')
+}
diff --git 
a/geode-modules/src/main/java/org/apache/geode/services/module/impl/GeodeModuleLoader.java
 
b/geode-modules/src/main/java/org/apache/geode/services/module/impl/GeodeModuleLoader.java
new file mode 100644
index 0000000..913df0c
--- /dev/null
+++ 
b/geode-modules/src/main/java/org/apache/geode/services/module/impl/GeodeModuleLoader.java
@@ -0,0 +1,53 @@
+/*
+ * 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.geode.services.module.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jboss.modules.DelegatingModuleLoader;
+import org.jboss.modules.Module;
+import org.jboss.modules.ModuleLoadException;
+import org.jboss.modules.ModuleLoader;
+import org.jboss.modules.ModuleSpec;
+
+import org.apache.geode.annotations.Experimental;
+
+/**
+ * {@link ModuleLoader} for use by {@link JBossModuleService}.
+ */
+@Experimental
+public class GeodeModuleLoader extends DelegatingModuleLoader {
+  private Map<String, ModuleSpec> moduleSpecs = new HashMap<>();
+
+  public GeodeModuleLoader() {
+    super(Module.getSystemModuleLoader(), ModuleLoader.NO_FINDERS);
+  }
+
+  public void addModuleSpec(ModuleSpec moduleSpec) {
+    moduleSpecs.put(moduleSpec.getName(), moduleSpec);
+  }
+
+  @Override
+  protected ModuleSpec findModule(String name) throws ModuleLoadException {
+    ModuleSpec moduleSpec = moduleSpecs.get(name);
+    if (moduleSpec == null) {
+      throw new ModuleLoadException(
+          String.format("ModuleSpec for Module %s could not be found", name));
+    }
+    return moduleSpecs.get(name);
+  }
+}
diff --git 
a/geode-modules/src/main/java/org/apache/geode/services/module/impl/JBossModuleService.java
 
b/geode-modules/src/main/java/org/apache/geode/services/module/impl/JBossModuleService.java
new file mode 100644
index 0000000..9715709
--- /dev/null
+++ 
b/geode-modules/src/main/java/org/apache/geode/services/module/impl/JBossModuleService.java
@@ -0,0 +1,115 @@
+/*
+ * 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.geode.services.module.impl;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.jar.JarFile;
+
+import org.apache.logging.log4j.Logger;
+import org.jboss.modules.LocalDependencySpecBuilder;
+import org.jboss.modules.Module;
+import org.jboss.modules.ModuleDependencySpecBuilder;
+import org.jboss.modules.ModuleLoadException;
+import org.jboss.modules.ModuleSpec;
+import org.jboss.modules.ResourceLoader;
+import org.jboss.modules.ResourceLoaderSpec;
+import org.jboss.modules.ResourceLoaders;
+import org.jboss.modules.Version;
+
+import org.apache.geode.annotations.Experimental;
+import org.apache.geode.logging.internal.log4j.api.LogService;
+import org.apache.geode.services.module.ModuleDescriptor;
+import org.apache.geode.services.module.ModuleService;
+
+/**
+ * Implementation of {@link ModuleService} using JBoss-Modules.
+ */
+@Experimental
+public class JBossModuleService implements ModuleService {
+
+  private final Map<String, Module> modules = new HashMap<>();
+
+  private final GeodeModuleLoader moduleLoader = new GeodeModuleLoader();
+
+  private final Logger logger;
+
+  public JBossModuleService() {
+    this(LogService.getLogger());
+  }
+
+  public JBossModuleService(Logger logger) {
+    this.logger = logger;
+  }
+
+  public Module getModule(String name) {
+    return modules.get(name);
+  }
+
+  @Override
+  public boolean loadModule(ModuleDescriptor moduleDescriptor) {
+    logger.debug(String.format("Beginning to load module %s", 
moduleDescriptor.getVersionedName()));
+
+    if (modules.containsKey(moduleDescriptor.getVersionedName())) {
+      logger
+          .warn(String.format("Module %s is already loaded.", 
moduleDescriptor.getVersionedName()));
+      return false;
+    }
+
+    ModuleSpec.Builder builder = 
ModuleSpec.build(moduleDescriptor.getVersionedName());
+    builder.setVersion(Version.parse(moduleDescriptor.getVersion()));
+    builder.addDependency(new LocalDependencySpecBuilder()
+        .setImportServices(true)
+        .setExport(true)
+        .build());
+
+    moduleDescriptor.getDependedOnModules().forEach(dependency -> {
+      logger.debug(String.format("Adding dependency on module %s", 
dependency));
+      builder.addDependency(new ModuleDependencySpecBuilder()
+          .setName(dependency)
+          .build());
+    });
+
+    try {
+      for (String source : moduleDescriptor.getSources()) {
+        logger.debug(String.format("Adding resource %s to module", source));
+        ResourceLoader resourceLoader =
+            ResourceLoaders.createJarResourceLoader(new JarFile(source));
+        
builder.addResourceRoot(ResourceLoaderSpec.createResourceLoaderSpec(resourceLoader));
+      }
+    } catch (IOException e) {
+      logger.error(e);
+      return false;
+    }
+
+    ModuleSpec moduleSpec = builder.create();
+    moduleLoader.addModuleSpec(moduleSpec);
+
+    try {
+      modules.put(moduleDescriptor.getVersionedName(),
+          moduleLoader.loadModule(moduleSpec.getName()));
+    } catch (ModuleLoadException e) {
+      logger.error(e);
+      return false;
+    }
+
+    logger
+        .debug(String.format("Module %s successfully loaded", 
moduleDescriptor.getVersionedName()));
+
+    return true;
+  }
+}
diff --git 
a/geode-modules/src/test/java/org/apache/geode/services/module/impl/JBossModuleServiceTest.java
 
b/geode-modules/src/test/java/org/apache/geode/services/module/impl/JBossModuleServiceTest.java
new file mode 100644
index 0000000..bca62af
--- /dev/null
+++ 
b/geode-modules/src/test/java/org/apache/geode/services/module/impl/JBossModuleServiceTest.java
@@ -0,0 +1,402 @@
+/*
+ * 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.geode.services.module.impl;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.jboss.modules.Module;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.geode.services.module.ModuleDescriptor;
+
+public class JBossModuleServiceTest {
+
+  private static final String MODULE1_PATH =
+      System.getProperty("user.dir") + "/../libs/module1.jar";
+  private static final String MODULE2_PATH =
+      System.getProperty("user.dir") + "/../libs/module2.jar";
+  private static final String MODULE3_PATH =
+      System.getProperty("user.dir") + "/../libs/module3.jar";
+  private static final String MODULE4_PATH =
+      System.getProperty("user.dir") + "/../libs/module4.jar";
+
+  private JBossModuleService moduleService;
+
+  @Before
+  public void setup() {
+    moduleService = new JBossModuleService();
+  }
+
+  @After
+  public void teardown() {
+    moduleService = null;
+  }
+
+  @Test
+  public void modulesNotAccessibleFromSystemClassloaderNoModulesLoaded() {
+    assertThatThrownBy(() -> {
+      this.getClass().getClassLoader().loadClass("org.apache.geode.Module1");
+    }).isInstanceOf(ClassNotFoundException.class);
+
+    assertThatThrownBy(() -> {
+      this.getClass().getClassLoader().loadClass("org.apache.geode.Module2");
+    }).isInstanceOf(ClassNotFoundException.class);
+  }
+
+  @Test
+  public void modulesNotAccessibleFromSystemClassloaderWithModulesLoaded() {
+    ModuleDescriptor module1Descriptor = new 
ModuleDescriptor.Builder("module1", "1.0")
+        .fromSources(MODULE1_PATH)
+        .build();
+    ModuleDescriptor module2Descriptor = new 
ModuleDescriptor.Builder("module2", "1.0")
+        .fromSources(MODULE2_PATH)
+        .build();
+    moduleService.loadModule(module1Descriptor);
+    moduleService.loadModule(module2Descriptor);
+
+    assertThatThrownBy(() -> {
+      this.getClass().getClassLoader().loadClass("org.apache.geode.Module1");
+    }).isInstanceOf(ClassNotFoundException.class);
+
+    assertThatThrownBy(() -> {
+      this.getClass().getClassLoader().loadClass("org.apache.geode.Module2");
+    }).isInstanceOf(ClassNotFoundException.class);
+  }
+
+  @Test
+  public void loadSingleModuleFromSingleJarNoDependencies() throws 
ClassNotFoundException {
+    ModuleDescriptor module1Descriptor = new 
ModuleDescriptor.Builder("module1", "1.0")
+        .fromSources(MODULE1_PATH)
+        .build();
+    assertThat(moduleService.loadModule(module1Descriptor)).isTrue();
+
+    
moduleService.getModule(module1Descriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module1");
+  }
+
+  @Test
+  public void loadSingleModuleFromMultipleJarsNoDependencies() throws 
ClassNotFoundException {
+    ModuleDescriptor moduleDescriptor = new 
ModuleDescriptor.Builder("multiJarModule", "1.0")
+        .fromSources(MODULE1_PATH, MODULE2_PATH)
+        .build();
+    assertThat(moduleService.loadModule(moduleDescriptor)).isTrue();
+
+    
moduleService.getModule(moduleDescriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module1");
+    
moduleService.getModule(moduleDescriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module2");
+  }
+
+  @Test
+  public void loadMultipleModulesFromMultipleJarsNoDependencies() throws 
ClassNotFoundException {
+    ModuleDescriptor module1Descriptor = new 
ModuleDescriptor.Builder("module1", "1.0")
+        .fromSources(MODULE1_PATH, MODULE2_PATH)
+        .build();
+    ModuleDescriptor module2Descriptor = new 
ModuleDescriptor.Builder("module2", "1.0")
+        .fromSources(MODULE3_PATH, MODULE4_PATH)
+        .build();
+
+    assertThat(moduleService.loadModule(module1Descriptor)).isTrue();
+    assertThat(moduleService.loadModule(module2Descriptor)).isTrue();
+
+    
moduleService.getModule(module1Descriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module1");
+    
moduleService.getModule(module1Descriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module2");
+
+    
moduleService.getModule(module2Descriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module3");
+    
moduleService.getModule(module2Descriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module4");
+  }
+
+  @Test
+  public void 
modulesCannotAccessOtherModulesMultipleModulesFromMultipleJarsNoDependencies()
+      throws ClassNotFoundException {
+    ModuleDescriptor module1Descriptor = new 
ModuleDescriptor.Builder("module1", "1.0")
+        .fromSources(MODULE1_PATH, MODULE2_PATH)
+        .build();
+    ModuleDescriptor module2Descriptor = new 
ModuleDescriptor.Builder("module2", "1.0")
+        .fromSources(MODULE3_PATH, MODULE4_PATH)
+        .build();
+
+    moduleService.loadModule(module1Descriptor);
+    moduleService.loadModule(module2Descriptor);
+
+    assertThatThrownBy(() -> {
+      
moduleService.getModule(module1Descriptor.getVersionedName()).getClassLoader()
+          .loadClass("org.apache.geode.Module3");
+    }).isInstanceOf(ClassNotFoundException.class);
+    assertThatThrownBy(() -> {
+      
moduleService.getModule(module1Descriptor.getVersionedName()).getClassLoader()
+          .loadClass("org.apache.geode.Module4");
+    }).isInstanceOf(ClassNotFoundException.class);
+
+    assertThatThrownBy(() -> {
+      
moduleService.getModule(module2Descriptor.getVersionedName()).getClassLoader()
+          .loadClass("org.apache.geode.Module1");
+    }).isInstanceOf(ClassNotFoundException.class);
+    assertThatThrownBy(() -> {
+      
moduleService.getModule(module2Descriptor.getVersionedName()).getClassLoader()
+          .loadClass("org.apache.geode.Module2");
+    }).isInstanceOf(ClassNotFoundException.class);
+  }
+
+  @Test
+  public void loadMultipleModulesFromMultipleJarsWithDependencies() throws 
ClassNotFoundException {
+    ModuleDescriptor module1Descriptor = new 
ModuleDescriptor.Builder("module1", "1.0")
+        .fromSources(MODULE1_PATH, MODULE2_PATH)
+        .build();
+    ModuleDescriptor module2Descriptor = new 
ModuleDescriptor.Builder("module2", "1.0")
+        .fromSources(MODULE3_PATH, MODULE4_PATH)
+        .dependsOnModules(module1Descriptor.getVersionedName())
+        .build();
+
+    assertThat(moduleService.loadModule(module1Descriptor)).isTrue();
+    assertThat(moduleService.loadModule(module2Descriptor)).isTrue();
+
+    
moduleService.getModule(module2Descriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module1");
+    
moduleService.getModule(module2Descriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module2");
+    
moduleService.getModule(module2Descriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module3");
+    
moduleService.getModule(module2Descriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module4");
+  }
+
+  @Test
+  public void dependenciesDoNotGoBothWaysMultipleModulesFromMultipleJars()
+      throws ClassNotFoundException {
+    ModuleDescriptor module1Descriptor = new 
ModuleDescriptor.Builder("module1", "1.0")
+        .fromSources(MODULE1_PATH, MODULE2_PATH)
+        .build();
+    ModuleDescriptor module2Descriptor = new 
ModuleDescriptor.Builder("module2", "1.0")
+        .fromSources(MODULE3_PATH, MODULE4_PATH)
+        .dependsOnModules(module1Descriptor.getVersionedName())
+        .build();
+
+    moduleService.loadModule(module1Descriptor);
+    moduleService.loadModule(module2Descriptor);
+
+    assertThatThrownBy(() -> {
+      
moduleService.getModule(module1Descriptor.getVersionedName()).getClassLoader()
+          .loadClass("org.apache.geode.Module3");
+    }).isInstanceOf(ClassNotFoundException.class);
+    assertThatThrownBy(() -> {
+      
moduleService.getModule(module1Descriptor.getVersionedName()).getClassLoader()
+          .loadClass("org.apache.geode.Module4");
+    }).isInstanceOf(ClassNotFoundException.class);
+  }
+
+  @Test
+  public void loadMultipleModulesFromSingleJarNoDependencies() throws 
ClassNotFoundException {
+    ModuleDescriptor module1Descriptor = new 
ModuleDescriptor.Builder("module1", "1.0")
+        .fromSources(MODULE1_PATH)
+        .build();
+    ModuleDescriptor module2Descriptor = new 
ModuleDescriptor.Builder("module2", "1.0")
+        .fromSources(MODULE2_PATH)
+        .build();
+    assertThat(moduleService.loadModule(module1Descriptor)).isTrue();
+    assertThat(moduleService.loadModule(module2Descriptor)).isTrue();
+
+    
moduleService.getModule(module1Descriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module1");
+    
moduleService.getModule(module2Descriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module2");
+  }
+
+  @Test
+  public void 
modulesCannotAccessOtherModulesMultipleModulesFromSingleJarNoDependencies()
+      throws ClassNotFoundException {
+    ModuleDescriptor module1Descriptor = new 
ModuleDescriptor.Builder("module1", "1.0")
+        .fromSources(MODULE1_PATH)
+        .build();
+    ModuleDescriptor module2Descriptor = new 
ModuleDescriptor.Builder("module2", "1.0")
+        .fromSources(MODULE2_PATH)
+        .build();
+    moduleService.loadModule(module1Descriptor);
+    moduleService.loadModule(module2Descriptor);
+
+    assertThatThrownBy(() -> {
+      
moduleService.getModule(module1Descriptor.getVersionedName()).getClassLoader()
+          .loadClass("org.apache.geode.Module2");
+    }).isInstanceOf(ClassNotFoundException.class);
+
+    assertThatThrownBy(() -> {
+      
moduleService.getModule(module2Descriptor.getVersionedName()).getClassLoader()
+          .loadClass("org.apache.geode.Module1");
+    }).isInstanceOf(ClassNotFoundException.class);
+  }
+
+  @Test
+  public void loadMultipleModulesFromSingleJarWithDependencies() throws 
ClassNotFoundException {
+    ModuleDescriptor module1Descriptor = new 
ModuleDescriptor.Builder("module1", "1.0")
+        .fromSources(MODULE1_PATH)
+        .build();
+    ModuleDescriptor module2Descriptor = new 
ModuleDescriptor.Builder("module2", "1.0")
+        .fromSources(MODULE2_PATH)
+        .dependsOnModules(module1Descriptor.getVersionedName())
+        .build();
+    assertThat(moduleService.loadModule(module1Descriptor)).isTrue();
+    assertThat(moduleService.loadModule(module2Descriptor)).isTrue();
+
+    
moduleService.getModule(module1Descriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module1");
+    
moduleService.getModule(module2Descriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module2");
+    
moduleService.getModule(module2Descriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module1");
+  }
+
+  @Test
+  public void dependenciesDoNotGoBothWaysMultipleModulesFromSingleJar()
+      throws ClassNotFoundException {
+    ModuleDescriptor module1Descriptor = new 
ModuleDescriptor.Builder("module1", "1.0")
+        .fromSources(MODULE1_PATH)
+        .build();
+    ModuleDescriptor module2Descriptor = new 
ModuleDescriptor.Builder("module2", "1.0")
+        .fromSources(MODULE2_PATH)
+        .dependsOnModules(module1Descriptor.getVersionedName())
+        .build();
+    moduleService.loadModule(module1Descriptor);
+    moduleService.loadModule(module2Descriptor);
+
+    assertThatThrownBy(() -> {
+      
moduleService.getModule(module1Descriptor.getVersionedName()).getClassLoader()
+          .loadClass("org.apache.geode.Module2");
+    }).isInstanceOf(ClassNotFoundException.class);
+  }
+
+  @Test
+  public void loadModuleMultipleTimes() throws ClassNotFoundException {
+    ModuleDescriptor module1Descriptor = new 
ModuleDescriptor.Builder("module1", "1.0")
+        .fromSources(MODULE1_PATH)
+        .build();
+    assertThat(moduleService.loadModule(module1Descriptor)).isTrue();
+    assertThat(moduleService.loadModule(module1Descriptor)).isFalse();
+
+    
moduleService.getModule(module1Descriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module1");
+  }
+
+  @Test
+  public void loadModulesWithSameNameAndDifferentVersions() throws 
ClassNotFoundException {
+    ModuleDescriptor module1Descriptor = new 
ModuleDescriptor.Builder("module1", "1.0")
+        .fromSources(MODULE1_PATH)
+        .build();
+    moduleService.loadModule(module1Descriptor);
+    ModuleDescriptor module2Descriptor = new 
ModuleDescriptor.Builder("module1", "2.0")
+        .fromSources(MODULE2_PATH)
+        .build();
+    moduleService.loadModule(module2Descriptor);
+
+    
moduleService.getModule(module1Descriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module1");
+    assertThatThrownBy(() -> {
+      
moduleService.getModule(module1Descriptor.getVersionedName()).getClassLoader()
+          .loadClass("org.apache.geode.Module2");
+    }).isInstanceOf(ClassNotFoundException.class);
+
+    
moduleService.getModule(module2Descriptor.getVersionedName()).getClassLoader()
+        .loadClass("org.apache.geode.Module2");
+    assertThatThrownBy(() -> {
+      
moduleService.getModule(module2Descriptor.getVersionedName()).getClassLoader()
+          .loadClass("org.apache.geode.Module1");
+    }).isInstanceOf(ClassNotFoundException.class);
+  }
+
+  @Test
+  public void loadModuleFromInvalidSource() {
+    ModuleDescriptor module1Descriptor = new 
ModuleDescriptor.Builder("module1", "1.0")
+        .fromSources("/there/is/nothing/here.jar")
+        .build();
+    assertThat(moduleService.loadModule(module1Descriptor)).isFalse();
+    
assertThat(moduleService.getModule(module1Descriptor.getVersionedName())).isNull();
+  }
+
+  @Test
+  public void loadModuleFromMixOfValidAndInvalidSources() {
+    ModuleDescriptor module1Descriptor = new 
ModuleDescriptor.Builder("module1", "1.0")
+        .fromSources("/there/is/nothing/here.jar", MODULE1_PATH)
+        .build();
+    assertThat(moduleService.loadModule(module1Descriptor)).isFalse();
+    
assertThat(moduleService.getModule(module1Descriptor.getVersionedName())).isNull();
+  }
+
+  @Test
+  public void loadModuleWithInvalidDependencies() {
+    ModuleDescriptor module1Descriptor = new 
ModuleDescriptor.Builder("module1", "1.0")
+        .fromSources(MODULE1_PATH)
+        .dependsOnModules("this_is_invalid")
+        .build();
+    assertThat(moduleService.loadModule(module1Descriptor)).isFalse();
+    
assertThat(moduleService.getModule(module1Descriptor.getVersionedName())).isNull();
+  }
+
+  @Test
+  public void loadModuleWithMixOfValidAndInvalidDependencies() {
+    ModuleDescriptor module1Descriptor = new 
ModuleDescriptor.Builder("module1", "1.0")
+        .fromSources(MODULE1_PATH)
+        .build();
+    ModuleDescriptor module2Descriptor = new 
ModuleDescriptor.Builder("module2", "1.0")
+        .fromSources(MODULE2_PATH)
+        .dependsOnModules("this_is_invalid", 
module1Descriptor.getVersionedName())
+        .build();
+    moduleService.loadModule(module1Descriptor);
+    assertThat(moduleService.loadModule(module2Descriptor)).isFalse();
+    
assertThat(moduleService.getModule(module2Descriptor.getVersionedName())).isNull();
+  }
+
+  @Test
+  public void getModuleNoModulesLoaded() {
+    assertThat(moduleService.getModule("module1:1.0")).isNull();
+  }
+
+  @Test
+  public void getModuleWithSingeModuleLoaded() {
+    ModuleDescriptor module1Descriptor = new 
ModuleDescriptor.Builder("module1", "1.0")
+        .fromSources(MODULE1_PATH)
+        .build();
+    moduleService.loadModule(module1Descriptor);
+    Module module = 
moduleService.getModule(module1Descriptor.getVersionedName());
+    assertThat(module).isNotNull();
+    
assertThat(module.getName()).isEqualTo(module1Descriptor.getVersionedName());
+  }
+
+  @Test
+  public void getModuleWithMultipleModulesLoaded() {
+    ModuleDescriptor module1Descriptor = new 
ModuleDescriptor.Builder("module1", "1.0")
+        .fromSources(MODULE1_PATH)
+        .build();
+    moduleService.loadModule(module1Descriptor);
+    ModuleDescriptor module2Descriptor = new 
ModuleDescriptor.Builder("module2", "1.0")
+        .fromSources(MODULE2_PATH)
+        .build();
+    moduleService.loadModule(module2Descriptor);
+
+    Module module1 = 
moduleService.getModule(module1Descriptor.getVersionedName());
+    assertThat(module1).isNotNull();
+    
assertThat(module1.getName()).isEqualTo(module1Descriptor.getVersionedName());
+
+    Module module2 = 
moduleService.getModule(module2Descriptor.getVersionedName());
+    assertThat(module2).isNotNull();
+    
assertThat(module2.getName()).isEqualTo(module2Descriptor.getVersionedName());
+  }
+}
diff --git a/geode-modules/src/test/resources/expected-pom.xml 
b/geode-modules/src/test/resources/expected-pom.xml
new file mode 100644
index 0000000..50c2beb
--- /dev/null
+++ b/geode-modules/src/test/resources/expected-pom.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+  <!--
+  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.
+  -->
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.geode</groupId>
+  <artifactId>geode-modules</artifactId>
+  <version>1.13.0-SNAPSHOT</version>
+  <name>Apache Geode</name>
+  <description>Apache Geode provides a database-like consistency model, 
reliable transaction processing and a shared-nothing architecture to maintain 
very low latency performance with high concurrency processing</description>
+  <url>http://geode.apache.org</url>
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+    </license>
+  </licenses>
+  <scm>
+    <connection>scm:git:https://github.com:apache/geode.git</connection>
+    
<developerConnection>scm:git:https://github.com:apache/geode.git</developerConnection>
+    <url>https://github.com/apache/geode</url>
+  </scm>
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.apache.geode</groupId>
+        <artifactId>geode-all-bom</artifactId>
+        <version>1.13.0-SNAPSHOT</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.geode</groupId>
+      <artifactId>geode-common</artifactId>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geode</groupId>
+      <artifactId>geode-common-services</artifactId>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.modules</groupId>
+      <artifactId>jboss-modules</artifactId>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geode</groupId>
+      <artifactId>geode-logging</artifactId>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geode</groupId>
+      <artifactId>geode-log4j</artifactId>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+      <scope>runtime</scope>
+    </dependency>
+  </dependencies>
+</project>
diff --git 
a/geode-modules/src/testModules/module1/java/org/apache/geode/Module1.java 
b/geode-modules/src/testModules/module1/java/org/apache/geode/Module1.java
new file mode 100644
index 0000000..684a71c
--- /dev/null
+++ b/geode-modules/src/testModules/module1/java/org/apache/geode/Module1.java
@@ -0,0 +1,19 @@
+/*
+ * 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.geode;
+
+public class Module1 {
+}
diff --git 
a/geode-modules/src/testModules/module2/java/org.apache.geode/Module2.java 
b/geode-modules/src/testModules/module2/java/org.apache.geode/Module2.java
new file mode 100644
index 0000000..9cbac0f
--- /dev/null
+++ b/geode-modules/src/testModules/module2/java/org.apache.geode/Module2.java
@@ -0,0 +1,19 @@
+/*
+ * 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.geode;
+
+public class Module2 {
+}
diff --git 
a/geode-modules/src/testModules/module3/java/org/apache/geode/Module3.java 
b/geode-modules/src/testModules/module3/java/org/apache/geode/Module3.java
new file mode 100644
index 0000000..87035eb
--- /dev/null
+++ b/geode-modules/src/testModules/module3/java/org/apache/geode/Module3.java
@@ -0,0 +1,19 @@
+/*
+ * 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.geode;
+
+public class Module3 {
+}
diff --git 
a/geode-modules/src/testModules/module4/java/org/apache/geode/Module4.java 
b/geode-modules/src/testModules/module4/java/org/apache/geode/Module4.java
new file mode 100644
index 0000000..c494905
--- /dev/null
+++ b/geode-modules/src/testModules/module4/java/org/apache/geode/Module4.java
@@ -0,0 +1,19 @@
+/*
+ * 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.geode;
+
+public class Module4 {
+}
diff --git a/settings.gradle b/settings.gradle
index 501a179..cefea67 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -68,6 +68,8 @@ include 'geode-concurrency-test'
 include 'boms:geode-client-bom'
 include 'boms:geode-all-bom'
 include 'static-analysis:pmd-rules'
+include 'geode-common-services'
+include 'geode-modules'
 
 
 ['1.0.0-incubating',

Reply via email to