From 67d93b91a2a93bc6ed63443bc2da6e8e8542cb86 Mon Sep 17 00:00:00 2001 From: Josha von Gizycki Date: Thu, 16 Feb 2017 17:29:28 +0100 Subject: [PATCH] add method to fetch all imlementations of an interface or class add tests add config to pom to generate sources and javadoc --- pom.xml | 26 ++++++++- .../de/joshavg/simpledic/IntegrityCheck.java | 16 +++++- .../de/joshavg/simpledic/SdiContainer.java | 56 +++++++++++++++++++ src/main/resources/sdic.properties | 0 .../joshavg/simpledic/IntegrityCheckTest.java | 2 +- .../simpledic/SimpleDependenciesTest.java | 27 +++++++++ .../services/DependsOnNoDependencies.java | 2 +- .../simpledic/services/NoDependencies.java | 2 +- .../simpledic/services/ServiceInterface.java | 5 ++ 9 files changed, 131 insertions(+), 5 deletions(-) delete mode 100644 src/main/resources/sdic.properties create mode 100644 src/test/java/de/joshavg/simpledic/services/ServiceInterface.java diff --git a/pom.xml b/pom.xml index 1ad2ea4..e3ea58b 100644 --- a/pom.xml +++ b/pom.xml @@ -19,6 +19,30 @@ 1.8 + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + @@ -43,7 +67,7 @@ org.hamcrest - hamcrest-core + hamcrest-all 1.3 test diff --git a/src/main/java/de/joshavg/simpledic/IntegrityCheck.java b/src/main/java/de/joshavg/simpledic/IntegrityCheck.java index d27aab9..95384ca 100644 --- a/src/main/java/de/joshavg/simpledic/IntegrityCheck.java +++ b/src/main/java/de/joshavg/simpledic/IntegrityCheck.java @@ -19,6 +19,20 @@ import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Takes a loaded Properties file, analyzes the {@link ServiceDefinition}s and + * checks them for sanity and integrity + *

+ * These Checks are performed: + *

    + *
  1. duplicated FQCNs
  2. + *
  3. dependency cycles
  4. + *
  5. dependency availability
  6. + *
  7. class availability
  8. + *
  9. constructor visibility
  10. + *
  11. constructor count
  12. + *
+ */ class IntegrityCheck { private static final Logger LOG = LoggerFactory.getLogger(IntegrityCheck.class); @@ -151,7 +165,7 @@ class IntegrityCheck { } static boolean isServiceName(String name) { - return name.matches("service\\.[^.]+"); + return name.matches("^service\\.[^.]+$"); } List getDefinitions() { diff --git a/src/main/java/de/joshavg/simpledic/SdiContainer.java b/src/main/java/de/joshavg/simpledic/SdiContainer.java index 7b68a2d..5ec7e8b 100644 --- a/src/main/java/de/joshavg/simpledic/SdiContainer.java +++ b/src/main/java/de/joshavg/simpledic/SdiContainer.java @@ -10,9 +10,28 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * The main container that loads a specific properties file + * and creates instances of defined services + *

+ * Services are given arbitrary names and can be defined as singletons: + *

+ * service.servicename: tld.vendor.project.ServiceClass
+ * service.servicename.singleton: true
+ * 
+ * Service names must match the regular expression ^service\.[^.]+$ + *

+ * Services declare their dependencies via their constructor. Only one + * constructor per class is allowed. + * All dependencies must be declared in the same container as the declaring + * service. + *

+ * After loading the properties file, an {@link IntegrityCheck} will be performed. + */ public class SdiContainer implements SdiContainerInterface { private static final Logger LOG = LoggerFactory.getLogger(SdiContainer.class); @@ -25,11 +44,22 @@ public class SdiContainer implements SdiContainerInterface { this.singletons = new HashMap<>(); } + /** + * Creates a Container using the file sdic.properties from the classpath. + * + * @return the loaded and integrity checked container + */ @SuppressWarnings("unused") public static SdiContainer load() { return load("sdic.properties"); } + /** + * Creates a Container using the properties file at the designated location + * + * @param filename the filename that shall be loaded + * @return the loaded and integrity checked container + */ @SuppressWarnings("WeakerAccess") public static SdiContainer load(String filename) { Properties props = new Properties(); @@ -57,6 +87,16 @@ public class SdiContainer implements SdiContainerInterface { .orElse(null); } + /** + * Creates and returns a service instance of the given class + *

+ * Dependency services are automatically created. Services marked + * as singletons will be only created once, either as transient + * or direct dependency. + * + * @param clz the type which shall be created + * @return the created type with declared dependencies fulfilled + */ @Override public T getInstance(Class clz) { LOG.trace("instance ordered: ", clz); @@ -80,6 +120,22 @@ public class SdiContainer implements SdiContainerInterface { } } + /** + * returns all registered services that implement or extend the given class + * + * @param clz parent class or interface + * @return the list with instances, or an empty list if nothing is found + */ + @SuppressWarnings("WeakerAccess") + public List getInstancesThatImplement(Class clz) { + LOG.trace("instances of interface {} ordered", clz); + return definitions.stream() + .filter(d -> clz.isAssignableFrom(d.getClz())) + .map(ServiceDefinition::getClz) + .map(c -> clz.cast(getInstance(c))) + .collect(Collectors.toList()); + } + private void handleSingleton(ServiceDefinition definition, T instance) { if (definition.isSingleton()) { singletons.put(definition, instance); diff --git a/src/main/resources/sdic.properties b/src/main/resources/sdic.properties deleted file mode 100644 index e69de29..0000000 diff --git a/src/test/java/de/joshavg/simpledic/IntegrityCheckTest.java b/src/test/java/de/joshavg/simpledic/IntegrityCheckTest.java index 61f257f..5e92b8c 100644 --- a/src/test/java/de/joshavg/simpledic/IntegrityCheckTest.java +++ b/src/test/java/de/joshavg/simpledic/IntegrityCheckTest.java @@ -12,7 +12,7 @@ public class IntegrityCheckTest { assertThat(IntegrityCheck.isServiceName("dingens"), is(false)); assertThat(IntegrityCheck.isServiceName("service"), is(false)); assertThat(IntegrityCheck.isServiceName("service."), is(false)); - assertThat(IntegrityCheck.isServiceName("service.a"), is(true)); + assertThat(IntegrityCheck.isServiceName("service.aad-s"), is(true)); assertThat(IntegrityCheck.isServiceName("service.a.singleton"), is(false)); } diff --git a/src/test/java/de/joshavg/simpledic/SimpleDependenciesTest.java b/src/test/java/de/joshavg/simpledic/SimpleDependenciesTest.java index 5ea0872..f9af488 100644 --- a/src/test/java/de/joshavg/simpledic/SimpleDependenciesTest.java +++ b/src/test/java/de/joshavg/simpledic/SimpleDependenciesTest.java @@ -1,6 +1,16 @@ package de.joshavg.simpledic; +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.collection.IsCollectionWithSize.hasSize; +import static org.hamcrest.core.IsInstanceOf.instanceOf; + import de.joshavg.simpledic.services.DependsOnNoDependencies; +import de.joshavg.simpledic.services.ServiceInterface; +import java.util.List; import org.junit.Test; public class SimpleDependenciesTest { @@ -17,4 +27,21 @@ public class SimpleDependenciesTest { SdiContainer container = SdiContainer.load(FILENAME); container.getInstance(DependsOnNoDependencies.class); } + + @Test + public void serviceImplementationsAreReturned() { + SdiContainer container = SdiContainer.load(FILENAME); + List list = container.getInstancesThatImplement(ServiceInterface.class); + + assertThat(list, hasSize(2)); + list.forEach(s -> assertThat(s, instanceOf(ServiceInterface.class))); + } + + @Test + public void emptyListIsReturnedOnUnknownInterface() { + SdiContainer container = SdiContainer.load(FILENAME); + List list = container.getInstancesThatImplement(List.class); + + assertThat(list, allOf(empty(), not(nullValue()))); + } } diff --git a/src/test/java/de/joshavg/simpledic/services/DependsOnNoDependencies.java b/src/test/java/de/joshavg/simpledic/services/DependsOnNoDependencies.java index 054ec6e..9538580 100644 --- a/src/test/java/de/joshavg/simpledic/services/DependsOnNoDependencies.java +++ b/src/test/java/de/joshavg/simpledic/services/DependsOnNoDependencies.java @@ -1,6 +1,6 @@ package de.joshavg.simpledic.services; -public class DependsOnNoDependencies { +public class DependsOnNoDependencies implements ServiceInterface { private final NoDependencies b; diff --git a/src/test/java/de/joshavg/simpledic/services/NoDependencies.java b/src/test/java/de/joshavg/simpledic/services/NoDependencies.java index ed1ce59..d432af1 100644 --- a/src/test/java/de/joshavg/simpledic/services/NoDependencies.java +++ b/src/test/java/de/joshavg/simpledic/services/NoDependencies.java @@ -1,4 +1,4 @@ package de.joshavg.simpledic.services; -public class NoDependencies { +public class NoDependencies implements ServiceInterface { } diff --git a/src/test/java/de/joshavg/simpledic/services/ServiceInterface.java b/src/test/java/de/joshavg/simpledic/services/ServiceInterface.java new file mode 100644 index 0000000..7d29807 --- /dev/null +++ b/src/test/java/de/joshavg/simpledic/services/ServiceInterface.java @@ -0,0 +1,5 @@ +package de.joshavg.simpledic.services; + +public interface ServiceInterface { + +}