You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2017/12/07 15:00:58 UTC

[isis] 02/18: ISIS-1782: adds Module interface and ModuleAbstract implementation

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

danhaywood pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git

commit f2caff104366bcfc4f60cc5678d495eb9230c429
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Mon Dec 4 08:37:35 2017 +0000

    ISIS-1782: adds Module interface and ModuleAbstract implementation
---
 .../org/apache/isis/applib/modules/Module.java     | 168 +++++++++++++++++++++
 .../apache/isis/applib/modules/ModuleAbstract.java | 114 ++++++++++++++
 2 files changed, 282 insertions(+)

diff --git a/core/applib/src/main/java/org/apache/isis/applib/modules/Module.java b/core/applib/src/main/java/org/apache/isis/applib/modules/Module.java
new file mode 100644
index 0000000..122346f
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/modules/Module.java
@@ -0,0 +1,168 @@
+/*
+ *  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.isis.applib.modules;
+
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import org.apache.isis.applib.AppManifestAbstract;
+import org.apache.isis.applib.fixturescripts.FixtureScript;
+
+public interface Module {
+
+    /**
+     * As per Maven's &lt;dependencies&gt;&lt;/dependencies&gt; element; in the future might be derived (code generated?) from java 9's <code>module-info.java</code> metadata
+     *
+     * <p>
+     *     We use Set (rather than List) because we rely on {@link Module} being a value type based solely on its
+     *     class.  What this means is that each module can simply instantiate its dependencies, and the framework will
+     *     be able to eliminate duplicates.
+     * </p>
+     */
+    Set<Module> getDependencies();
+
+    /**
+     * Support for "legacy" modules that do not implement {@link Module}.
+     */
+    Set<Class<?>> getDependenciesAsClass();
+
+    FixtureScript getRefDataSetupFixture();
+
+    FixtureScript getTeardownFixture();
+
+    Set<Class<?>> getAdditionalServices();
+
+    class Util {
+        private Util(){}
+
+        /**
+         * Recursively obtain the transitive dependencies.
+         *
+         * <p>
+         *     The dependencies are returned in order, with this (the top-most) module last.
+         * </p>
+         */
+        public static List<Module> transitiveDependenciesOf(Module module) {
+            final List<Module> ordered = Lists.newArrayList();
+            final List<Module> visited = Lists.newArrayList();
+            appendDependenciesTo(ordered, module, visited);
+            final LinkedHashSet<Module> sequencedSet = Sets.newLinkedHashSet(ordered);
+            return Lists.newArrayList(sequencedSet);
+        }
+
+        /**
+         * Obtain the {@link Module#getDependenciesAsClass()} of this module and all its
+         * {@link Module.Util#transitiveDependenciesOf(Module) transitive dependencies}.
+         *
+         * <p>
+         *     No guarantees are made as to the order of these additional module classes.
+         * </p>
+         */
+        public static List<Class<?>> transitiveDependenciesAsClassOf(Module module) {
+            final Set<Class<?>> modules = Sets.newHashSet();
+            final List<Module> transitiveDependencies = transitiveDependenciesOf(module);
+            for (Module transitiveDependency : transitiveDependencies) {
+                final Set<Class<?>> additionalModules = transitiveDependency.getDependenciesAsClass();
+                if(additionalModules != null && !additionalModules.isEmpty()) {
+                    modules.addAll(additionalModules);
+                }
+            }
+            return Lists.newArrayList(modules);
+        }
+
+        /**
+         * Obtain the {@link #getAdditionalServices()} of this module and all its
+         * {@link Module.Util#transitiveDependenciesOf(Module) transitive dependencies}.
+         *
+         * <p>
+         *     No guarantees are made as to the order of these additional service classes.
+         * </p>
+         */
+        public static List<Class<?>> transitiveAdditionalServicesOf(Module module) {
+            final Set<Class<?>> services = Sets.newHashSet();
+            final List<Module> transitiveDependencies = Util.transitiveDependenciesOf(module);
+            for (Module transitiveDependency : transitiveDependencies) {
+                final Set<Class<?>> additionalServices = transitiveDependency.getAdditionalServices();
+                if(additionalServices != null && !additionalServices.isEmpty()) {
+                    services.addAll(additionalServices);
+                }
+            }
+            return Lists.newArrayList(services);
+        }
+
+        private static void appendDependenciesTo(
+                final List<Module> ordered,
+                final Module module,
+                final List<Module> visited) {
+
+            if(visited.contains(module)) {
+                throw new IllegalStateException(String.format(
+                        "Cyclic dependency detected; visited: %s", visited));
+            } else {
+                visited.add(module);
+            }
+
+            final Set<Module> dependencies = module.getDependencies();
+            if(dependencies.isEmpty() || ordered.containsAll(dependencies)) {
+                ordered.add(module);
+                visited.clear(); // reset
+            } else {
+                for (Module dependency : dependencies) {
+                    appendDependenciesTo(ordered, dependency, visited);
+                }
+            }
+            if(!ordered.contains(module)) {
+                ordered.add(module);
+            }
+        }
+
+        public static AppManifestAbstract.Builder builderFor(final Module module) {
+            final List<Module> transitiveDependencies = Module.Util.transitiveDependenciesOf(module);
+            final Class[] moduleTransitiveDependencies = asClasses(transitiveDependencies);
+
+            final List<Class<?>> additionalModules = Module.Util.transitiveDependenciesAsClassOf(module);
+            final List<Class<?>> additionalServices = Module.Util.transitiveAdditionalServicesOf(module);
+
+            final AppManifestAbstract.Builder builder =
+                    AppManifestAbstract.Builder
+                            .forModules(moduleTransitiveDependencies)
+                            .withAdditionalModules(additionalModules)
+                            .withAdditionalServices(additionalServices);
+
+            return builder;
+        }
+
+        private static Class[] asClasses(final List<Module> dependencies) {
+            final List<Class<? extends Module>> list = new ArrayList<>();
+            for (Module dependency : dependencies) {
+                Class<? extends Module> aClass = dependency.getClass();
+                list.add(aClass);
+            }
+            return list.toArray(new Class[] {});
+        }
+
+
+    }
+
+}
diff --git a/core/applib/src/main/java/org/apache/isis/applib/modules/ModuleAbstract.java b/core/applib/src/main/java/org/apache/isis/applib/modules/ModuleAbstract.java
new file mode 100644
index 0000000..2f2405a
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/modules/ModuleAbstract.java
@@ -0,0 +1,114 @@
+/*
+ *  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.isis.applib.modules;
+
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+import org.apache.isis.applib.fixturescripts.FixtureScript;
+
+public abstract class ModuleAbstract implements Module {
+
+
+    /**
+     * As per Maven's &lt;dependencies&gt;&lt;/dependencies&gt; element; in the future might be derived (code generated?) from java 9's <code>module-info.java</code> metadata
+     *
+     * <p>
+     *     We use Set (rather than List) because we rely on {@link Module} being a value type based solely on its
+     *     class.  What this means is that each module can simply instantiate its dependencies, and the framework will
+     *     be able to eliminate duplicates.
+     * </p>
+     */
+    @Override
+    @XmlTransient
+    public Set<Module> getDependencies() {
+        return Collections.emptySet();
+    }
+
+    /**
+     * Support for "legacy" modules that do not implement {@link Module}.
+     */
+    @Override
+    @XmlTransient
+    public Set<Class<?>> getDependenciesAsClass() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    @XmlTransient
+    public FixtureScript getRefDataSetupFixture() {
+        return null;
+    }
+
+    @Override
+    @XmlTransient
+    public FixtureScript getTeardownFixture() {
+        return null;
+    }
+
+    @Override
+    @XmlTransient
+    public Set<Class<?>> getAdditionalServices() {
+        return Collections.emptySet();
+    }
+
+
+
+
+    @XmlAttribute(required = true)
+    public String getName() {
+        return getClass().getSimpleName();
+    }
+
+    private String getFullName() {
+        return getClass().getName();
+    }
+
+
+    @XmlElement(name = "module", required = true)
+    private Set<ModuleAbstract> getModuleDependencies() {
+        return (Set) getDependencies();
+    }
+
+    @Override
+    public String toString() {
+        return getFullName();
+    }
+
+    public boolean equals(final Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (!(o instanceof ModuleAbstract)) {
+            return false;
+        }
+        final ModuleAbstract other = (ModuleAbstract) o;
+        return Objects.equals(getFullName(), other.getFullName());
+    }
+
+    public int hashCode() {
+        return getFullName().hashCode();
+    }
+
+}
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
"commits@isis.apache.org" <co...@isis.apache.org>.