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/08/02 13:33:16 UTC

[2/2] isis git commit: ISIS-1686: adds IntegrationTestAbstract2, and extends AppManifestAbstract ...

ISIS-1686: adds IntegrationTestAbstract2, and extends AppManifestAbstract ...

... the latter now has a corresponding Builder and supports overrides, to allow variations of manifests to be created using either composition (the builder) or inheritance (overrides)


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/98048bb9
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/98048bb9
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/98048bb9

Branch: refs/heads/master
Commit: 98048bb9065a9cfc50ebba485343db84fef93298
Parents: e604de4
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Wed Aug 2 14:29:25 2017 +0100
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Wed Aug 2 14:29:25 2017 +0100

----------------------------------------------------------------------
 .../org/apache/isis/applib/AppManifest.java     |   2 +
 .../apache/isis/applib/AppManifestAbstract.java | 283 ++++++++++++++++---
 .../IntegrationTestAbstract2.java               | 107 +++++++
 .../application/HelloWorldAppManifest.java      |   5 +-
 4 files changed, 350 insertions(+), 47 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/98048bb9/core/applib/src/main/java/org/apache/isis/applib/AppManifest.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/AppManifest.java b/core/applib/src/main/java/org/apache/isis/applib/AppManifest.java
index 51d5e57..22c4fe4 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/AppManifest.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/AppManifest.java
@@ -32,6 +32,7 @@ import java.util.Set;
 import javax.jdo.annotations.PersistenceCapable;
 
 import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 
 import org.reflections.vfs.SystemDir;
 import org.reflections.vfs.Vfs;
@@ -391,4 +392,5 @@ public interface AppManifest {
 
 
     }
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/98048bb9/core/applib/src/main/java/org/apache/isis/applib/AppManifestAbstract.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/AppManifestAbstract.java b/core/applib/src/main/java/org/apache/isis/applib/AppManifestAbstract.java
index 6b5ee0d..9c3fb0b 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/AppManifestAbstract.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/AppManifestAbstract.java
@@ -20,17 +20,18 @@ package org.apache.isis.applib;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.Collections;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
+import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
 import org.apache.isis.applib.fixturescripts.FixtureScript;
 
 /**
- * Convenience adapter.
+ * Convenience adapter, configured using an {@link Builder}.
  */
 public abstract class AppManifestAbstract implements AppManifest {
 
@@ -38,82 +39,276 @@ public abstract class AppManifestAbstract implements AppManifest {
     private final List<Class<?>> additionalServices;
     private final String authMechanism;
     private final List<Class<? extends FixtureScript>> fixtures;
-    private final String propertiesFile;
+    private final Map<String, String> configurationProperties;
 
-    public AppManifestAbstract(final List<Class<?>> modules) {
-        this(modules,
-                Collections.<Class<?>>emptyList(),
-                "shiro",
-                Collections.<Class<? extends FixtureScript>>emptyList(),
-                "isis-non-changing.properties");
+    public AppManifestAbstract(final Builder builder) {
+
+        final List<Class<?>> builderModules = builder.modules;
+        overrideModules(builderModules);
+        this.modules = builderModules;
+
+        final List<Class<?>> builderAdditionalServices = builder.additionalServices;
+        overrideAdditionalServices(builderAdditionalServices);
+
+        this.additionalServices = builderAdditionalServices;
+
+        final String overriddenAuthMechanism = overrideAuthMechanism();
+        this.authMechanism = overriddenAuthMechanism != null ? overriddenAuthMechanism : builder.authMechanism;
+
+        final List<Class<? extends FixtureScript>> builderFixtures = builder.fixtures;
+        overrideFixtures(builderFixtures);
+        this.fixtures = builderFixtures;
+
+        // note uses this.fixtures, so must come afterwards...
+        this.configurationProperties = createConfigurationProperties(builder.propertyResources, builder.individualConfigProps, this.fixtures);
     }
 
-    public AppManifestAbstract(
-            final List<Class<?>> modules,
-            final List<Class<?>> additionalServices,
-            final String authMechanism,
-            final List<Class<? extends FixtureScript>> fixtures,
-            final String propertiesFile) {
-        this.modules = modules;
-        this.additionalServices = additionalServices;
-        this.authMechanism = authMechanism;
-        this.fixtures = fixtures;
-        this.propertiesFile = propertiesFile;
+    private Map<String, String> createConfigurationProperties(
+            final List<PropertyResource> propertyResources,
+            final List<ConfigurationProperty> individualConfigProps,
+            final List<Class<? extends FixtureScript>> fixtures) {
+        final Map<String, String> props = Maps.newHashMap();
+        for (PropertyResource propertyResource : propertyResources) {
+            propertyResource.loadPropsInto(props);
+        }
+        for (ConfigurationProperty individualConfigProp : individualConfigProps) {
+            individualConfigProp.put(props);
+        }
+        if(!fixtures.isEmpty()) {
+            props.put("isis.persistor.datanucleus.install-fixtures","true");
+        }
+        overrideConfigurationProperties(props);
+        return props;
     }
 
     @Override
-    public List<Class<?>> getModules() {
+    public final List<Class<?>> getModules() {
         return modules;
     }
 
+    /**
+     * Optional hook to allow subclasses to tweak modules previously defined in constructor.
+     *
+     * <p>
+     *     Alternatively, can compose a different builder and pass into the constructor,
+     *     using {@link Builder#withAdditionalModules(Class[])}.
+     * </p>
+     */
+    protected void overrideModules(List<Class<?>> modules) {
+        // default implementation does nothing.
+    }
+
     @Override
-    public List<Class<?>> getAdditionalServices() {
+    public final List<Class<?>> getAdditionalServices() {
         return additionalServices;
     }
 
+    /**
+     * Optional hook to allow subclasses to tweak services previously defined
+     *
+     * <p>
+     *     Alternatively, can compose a different builder and pass into the constructor,
+     *     using {@link Builder#withAdditionalServices(Class[])}
+     * </p>
+     */
+    protected void overrideAdditionalServices(final List<Class<?>> additionalServices) {
+        // default implementation does nothing.
+    }
+
     @Override
-    public String getAuthenticationMechanism() {
+    public final String getAuthenticationMechanism() {
         return authMechanism;
     }
 
+    /**
+     * Optional hook to override both the {@link #getAuthenticationMechanism()} and {@link #getAuthorizationMechanism()}.
+     *
+     * <p>
+     *     Alternatively, can compose a different builder and pass into the constructor,
+     *     using {@link Builder#withAuthMechanism(String)} .
+     * </p>
+     */
+    protected String overrideAuthMechanism() {
+        return null;
+    }
+
     @Override
-    public String getAuthorizationMechanism() {
+    public final String getAuthorizationMechanism() {
         return authMechanism;
     }
 
     @Override
-    public List<Class<? extends FixtureScript>> getFixtures() {
+    public final List<Class<? extends FixtureScript>> getFixtures() {
         return fixtures;
     }
 
+    /**
+     * Optional hook to allow subclasses to tweak fixtures previously specified
+     *
+     * <p>
+     *     Alternatively, can compose a different builder and pass into the constructor,
+     *     using {@link Builder#withFixtureScripts(Class[])} .
+     * </p>
+     */
+    protected void overrideFixtures(final List<Class<? extends FixtureScript>> fixtureScripts) {
+        // default implementation does nothing.
+    }
+
     @Override
-    public Map<String, String> getConfigurationProperties() {
-        final Map<String, String> props = Maps.newHashMap();
+    public final Map<String, String> getConfigurationProperties() {
+        return this.configurationProperties;
+    }
+
+
+    /**
+     * Optional hook to allow subclasses to tweak configuration properties previously specified
+     *
+     * <p>
+     *     Alternatively, can compose a different builder and pass into the constructor,
+     *     using {@link Builder#withConfigurationProperties(Map)} .
+     * </p>
+     */
+    protected void overrideConfigurationProperties(final Map<String, String> configurationProperties) {
+        // default implementation does nothing.
+    }
+
+    /**
+     * Used to build an {@link AppManifest} either {@link #build() directly}, or implicitly by passing into
+     * {@link AppManifestAbstract}'s {@link AppManifestAbstract#AppManifestAbstract(Builder) constructor}.
+     */
+    public static class Builder {
+
+
+        final List<Class<?>> modules = Lists.newArrayList();
+        List<Class<?>> additionalServices  = Lists.newArrayList();
+        String authMechanism = "shiro";
+        List<Class<? extends FixtureScript>> fixtures = Lists.newArrayList();
 
-        if(propertiesFile != null) {
-            loadPropsInto(props, propertiesFile);
+        List<ConfigurationProperty> individualConfigProps = Lists.newArrayList();
+        List<PropertyResource> propertyResources = Lists.newArrayList();
+
+        private Map<String,String> configurationProperties = Maps.newHashMap();
+
+        private Builder() {}
+
+        /**
+         * Factory method.
+         */
+        public static Builder withModules(final List<Class<?>> modules) {
+            return new Builder().withAdditionalModules(modules);
+        }
+        public static Builder withModules(final Class<?>... modules) {
+            return withModules(Arrays.asList(modules));
+        }
+
+        public Builder withAdditionalModules(final Class<?>... modules) {
+            return withAdditionalModules(Arrays.asList(modules));
+        }
+
+        public Builder withAdditionalModules(final List<Class<?>> modules) {
+            if(modules == null) {
+                throw new IllegalArgumentException("List of modules must not be null");
+            }
+            this.modules.addAll(modules);
+            return this;
+        }
+
+        public Builder withAuthMechanism(final String authMechanism) {
+            this.authMechanism = authMechanism;
+            return this;
+        }
+
+        public Builder withAdditionalServices(final Class<?>... additionalServices) {
+            return withAdditionalServices(Arrays.asList(additionalServices));
+        }
+
+        public Builder withAdditionalServices(final List<Class<?>> additionalServices) {
+            if(additionalServices == null) {
+                throw new IllegalArgumentException("List of additional services must not be null");
+            }
+            this.additionalServices = Lists.newArrayList(additionalServices);
+            return this;
+        }
+
+        public Builder withFixtureScripts(final Class<? extends FixtureScript>... fixtures) {
+            return withFixtureScripts(Arrays.asList(fixtures));
+        }
+
+        public Builder withFixtureScripts(final List<Class<? extends FixtureScript>> fixtures) {
+            if(fixtures == null) {
+                throw new IllegalArgumentException("List of fixtures must not be null");
+            }
+            this.fixtures = Lists.newArrayList(fixtures);
+            return this;
+        }
+
+        public Builder withConfigurationProperties(final Map<String,String> configurationProperties) {
+            this.configurationProperties.putAll(configurationProperties);
+            return this;
+        }
+
+        public Builder withPropertiesFile(final String propertiesFile) {
+            return withPropertiesFile(propertiesFile, getClass());
+        }
+
+        public Builder withPropertiesFile(
+                final String propertiesFile,
+                final Class<?> propertiesFileContext) {
+            propertyResources.add(new PropertyResource(propertiesFileContext, propertiesFile));
+            return this;
+        }
+
+        public Builder withConfigurationProperty(final String key, final String value) {
+            individualConfigProps.add(new ConfigurationProperty(key,value));
+            return this;
+        }
+
+        public AppManifest build() {
+            return new AppManifestAbstract(this) {};
         }
 
-        return props;
     }
 
-    protected void loadPropsInto(final Map<String, String> props, final String propertiesFile) {
-        final Properties properties = new Properties();
-        try {
-            try (final InputStream stream =
-                    getClass().getResourceAsStream(propertiesFile)) {
-                properties.load(stream);
-                for (Object key : properties.keySet()) {
-                    final Object value = properties.get(key);
-                    if(key instanceof String && value instanceof String) {
-                        props.put((String)key, (String)value);
+    static class ConfigurationProperty {
+        private final String key;
+        private final String value;
+
+        ConfigurationProperty(final String key, final String value) {
+            this.key = key;
+            this.value = value;
+        }
+
+        void put(final Map<String, String> props) {
+            props.put(key, value);
+        }
+    }
+
+    static class PropertyResource {
+        private final Class<?> propertiesFileContext;
+        private final String propertiesFile;
+
+        PropertyResource(final Class<?> propertiesFileContext, final String propertiesFile) {
+            this.propertiesFileContext = propertiesFileContext;
+            this.propertiesFile = propertiesFile;
+        }
+
+        void loadPropsInto(
+                final Map<String, String> props) {
+            final Properties properties = new Properties();
+            try {
+                try (final InputStream stream = propertiesFileContext.getResourceAsStream(propertiesFile)) {
+                    properties.load(stream);
+                    for (Object key : properties.keySet()) {
+                        final Object value = properties.get(key);
+                        if (key instanceof String && value instanceof String) {
+                            props.put((String) key, (String) value);
+                        }
                     }
                 }
+            } catch (IOException e) {
+                throw new RuntimeException(
+                        String.format("Failed to load '%s' file ", this), e);
             }
-        } catch (IOException e) {
-            throw new RuntimeException(
-                    String.format("Failed to load '%s' file ", propertiesFile), e);
         }
     }
-
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/98048bb9/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IntegrationTestAbstract2.java
----------------------------------------------------------------------
diff --git a/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IntegrationTestAbstract2.java b/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IntegrationTestAbstract2.java
new file mode 100644
index 0000000..240d739
--- /dev/null
+++ b/core/integtestsupport/src/main/java/org/apache/isis/core/integtestsupport/IntegrationTestAbstract2.java
@@ -0,0 +1,107 @@
+/*
+ *  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.core.integtestsupport;
+
+import java.util.List;
+
+import javax.inject.Inject;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.FluentIterable;
+
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.isis.applib.AppManifest;
+import org.apache.isis.applib.fixturescripts.FixtureScript;
+import org.apache.isis.applib.fixturescripts.FixtureScripts;
+import org.apache.isis.applib.services.xactn.TransactionService;
+import org.apache.isis.core.integtestsupport.scenarios.ScenarioExecutionForIntegration;
+import org.apache.isis.objectstore.jdo.datanucleus.IsisConfigurationForJdoIntegTests;
+
+/**
+ * Extended base class for integration tests.
+ */
+public abstract class IntegrationTestAbstract2 extends IntegrationTestAbstract {
+
+    private static final Logger LOG = LoggerFactory.getLogger(IntegrationTestAbstract2.class);
+
+    /**
+     * Intended to be called from the subclass' <code>@BeforeClass init()</code> method.
+     */
+    protected static void bootstrapUsing(final AppManifest appManifest) {
+        org.apache.log4j.PropertyConfigurator.configure("logging-integtest.properties");
+        IsisSystemForTest isft = IsisSystemForTest.getElseNull();
+        if(isft == null) {
+            isft = new IsisSystemForTest.Builder()
+                    .withLoggingAt(org.apache.log4j.Level.INFO)
+                    .with(appManifest)
+                    .with(new IsisConfigurationForJdoIntegTests())
+                    .build()
+                    .setUpSystem();
+            IsisSystemForTest.set(isft);
+        }
+
+        // instantiating will install onto ThreadLocal
+        new ScenarioExecutionForIntegration();
+    }
+
+    /**
+     * Replacement for the deprecated {@link #runScript(FixtureScript...)}.
+     */
+    protected void runFixtureScript(final FixtureScript... fixtureScriptList) {
+        if(fixtureScriptList.length == 1) {
+            fixtureScripts.runFixtureScript(fixtureScriptList[0], null);
+        } else {
+            fixtureScripts.runFixtureScript(new FixtureScript() {
+                @Override
+                protected void execute(final FixtureScript.ExecutionContext executionContext) {
+                    for (FixtureScript fixtureScript : fixtureScriptList) {
+                        executionContext.executeChild(this, fixtureScript);
+                    }
+                }
+            }, null);
+        }
+        nextTransaction();
+    }
+
+    protected static TypeSafeMatcher<Throwable> of(final Class<?> type) {
+        return new TypeSafeMatcher<Throwable>() {
+            @Override
+            protected boolean matchesSafely(final Throwable throwable) {
+                final List<Throwable> causalChain = Throwables.getCausalChain(throwable);
+                return !FluentIterable.from(causalChain).filter(type).isEmpty();
+            }
+
+            @Override public void describeTo(final Description description) {
+                description.appendText("Caused by " + type.getName());
+            }
+        };
+    }
+
+    @Inject
+    protected TransactionService transactionService;
+
+    @Inject
+    protected FixtureScripts fixtureScripts;
+
+}
+

http://git-wip-us.apache.org/repos/asf/isis/blob/98048bb9/example/application/helloworld/src/main/java/domainapp/application/HelloWorldAppManifest.java
----------------------------------------------------------------------
diff --git a/example/application/helloworld/src/main/java/domainapp/application/HelloWorldAppManifest.java b/example/application/helloworld/src/main/java/domainapp/application/HelloWorldAppManifest.java
index aa23f8e..1357540 100644
--- a/example/application/helloworld/src/main/java/domainapp/application/HelloWorldAppManifest.java
+++ b/example/application/helloworld/src/main/java/domainapp/application/HelloWorldAppManifest.java
@@ -18,8 +18,6 @@
  */
 package domainapp.application;
 
-import com.google.common.collect.Lists;
-
 import org.apache.isis.applib.AppManifestAbstract;
 
 import domainapp.dom.HelloWorldModule;
@@ -30,7 +28,8 @@ import domainapp.dom.HelloWorldModule;
 public class HelloWorldAppManifest extends AppManifestAbstract {
 
     public HelloWorldAppManifest() {
-        super(Lists.<Class<?>>newArrayList(HelloWorldModule.class));
+        super(Builder.withModules(HelloWorldModule.class)
+                       .withPropertiesFile("isis-non-changing.properties"));
     }
 
 }