From 7f28ec94132148207c1848c36fffd06524734add Mon Sep 17 00:00:00 2001 From: Thomas Heilbronner Date: Tue, 27 Sep 2011 22:01:32 +0200 Subject: [PATCH] Guice Module instantiation via cucumber-guice.properties file works --- .../runtime/java/guice/GuiceFactory.java | 17 +++- .../java/guice/ModuleInstantiator.java | 35 ++++++++ .../java/guice/UrlPropertiesLoader.java | 42 ++++++++++ .../java/guice/ModuleInstantiator_Test.java | 51 ++++++++++++ .../java/guice/PrivateConstructor.java | 14 ++++ .../java/guice/UrlPropertiesLoader_Test.java | 82 +++++++++++++++++++ .../guice/loadguicemodule/FirstSteps.java | 29 ++++--- .../loadguicemodule/YourModuleClass.java | 2 +- .../test/resources/cucumber-guice.properties | 1 + 9 files changed, 257 insertions(+), 16 deletions(-) create mode 100644 guice/src/main/java/cucumber/runtime/java/guice/ModuleInstantiator.java create mode 100644 guice/src/main/java/cucumber/runtime/java/guice/UrlPropertiesLoader.java create mode 100644 guice/src/test/java/cucumber/runtime/java/guice/ModuleInstantiator_Test.java create mode 100644 guice/src/test/java/cucumber/runtime/java/guice/PrivateConstructor.java create mode 100644 guice/src/test/java/cucumber/runtime/java/guice/UrlPropertiesLoader_Test.java create mode 100644 guice/src/test/resources/cucumber-guice.properties diff --git a/guice/src/main/java/cucumber/runtime/java/guice/GuiceFactory.java b/guice/src/main/java/cucumber/runtime/java/guice/GuiceFactory.java index 826acd3231..d65f78e243 100644 --- a/guice/src/main/java/cucumber/runtime/java/guice/GuiceFactory.java +++ b/guice/src/main/java/cucumber/runtime/java/guice/GuiceFactory.java @@ -6,13 +6,26 @@ import com.google.inject.Module; import cucumber.runtime.java.ObjectFactory; +import java.net.URL; import java.util.*; public class GuiceFactory implements ObjectFactory { - private final List modules = new ArrayList(); + private final List modules; private final Set> classes = new HashSet>(); private final Map, Object> instances = new HashMap, Object>(); - + + private static URL urlToGuiceProperties() { + return GuiceFactory.class.getClassLoader().getResource("cucumber-guice.properties"); + } + + public GuiceFactory() { + this(new UrlPropertiesLoader().load(urlToGuiceProperties())); + } + + public GuiceFactory(Properties properties) { + this.modules = new ModuleInstantiator().instantiate(properties.getProperty("guiceModule")); + } + public void addClass(Class clazz) { classes.add(clazz); } diff --git a/guice/src/main/java/cucumber/runtime/java/guice/ModuleInstantiator.java b/guice/src/main/java/cucumber/runtime/java/guice/ModuleInstantiator.java new file mode 100644 index 0000000000..28e3480077 --- /dev/null +++ b/guice/src/main/java/cucumber/runtime/java/guice/ModuleInstantiator.java @@ -0,0 +1,35 @@ +package cucumber.runtime.java.guice; + +import static java.text.MessageFormat.format; +import static java.util.logging.Level.SEVERE; + +import java.util.Collections; +import java.util.List; +import java.util.logging.Logger; + +import com.google.inject.Module; + +public class ModuleInstantiator { + + private final Logger logger; + + public ModuleInstantiator() { + this(Logger.getLogger(ModuleInstantiator.class.getCanonicalName())); + } + + public ModuleInstantiator(Logger logger) { + this.logger = logger; + } + + public List instantiate(String moduleClassName) { + try { + Module module = (Module) Class.forName(moduleClassName).newInstance(); + return Collections.singletonList(module); + } catch (Exception e) { + String message = format("Instantiation of ''{0}'' failed", moduleClassName); + logger.log(SEVERE, message, e); + } + return Collections.emptyList(); + + } +} \ No newline at end of file diff --git a/guice/src/main/java/cucumber/runtime/java/guice/UrlPropertiesLoader.java b/guice/src/main/java/cucumber/runtime/java/guice/UrlPropertiesLoader.java new file mode 100644 index 0000000000..984b797fd4 --- /dev/null +++ b/guice/src/main/java/cucumber/runtime/java/guice/UrlPropertiesLoader.java @@ -0,0 +1,42 @@ +package cucumber.runtime.java.guice; + +import java.io.InputStreamReader; +import java.net.URL; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.commons.io.IOUtils; + +public class UrlPropertiesLoader { + private final Logger logger; + + public UrlPropertiesLoader() { + this(Logger.getLogger(UrlPropertiesLoader.class.getCanonicalName())); + } + + public UrlPropertiesLoader(Logger logger) { + this.logger = logger; + } + + public Properties load(URL resource) { + Properties properties = new Properties(); + if (null != resource) { + initializeFrom(resource, properties); + } + return properties; + } + + private void initializeFrom(URL resource, Properties properties) { + InputStreamReader input = null; + try { + input = new InputStreamReader(resource.openStream()); + properties.load(input); + input.close(); + } catch (Exception e) { + logger.log(Level.INFO, "Could not load properties file"+resource.toExternalForm(), e); + } finally { + IOUtils.closeQuietly(input); + } + } +} diff --git a/guice/src/test/java/cucumber/runtime/java/guice/ModuleInstantiator_Test.java b/guice/src/test/java/cucumber/runtime/java/guice/ModuleInstantiator_Test.java new file mode 100644 index 0000000000..0286e1c00a --- /dev/null +++ b/guice/src/test/java/cucumber/runtime/java/guice/ModuleInstantiator_Test.java @@ -0,0 +1,51 @@ +package cucumber.runtime.java.guice; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.contains; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.junit.Test; + +import com.google.inject.Module; + +import cucumber.runtime.java.guice.loadguicemodule.YourModuleClass; + +public class ModuleInstantiator_Test { + private final Logger logger = mock(Logger.class); + private final ModuleInstantiator instantiator = new ModuleInstantiator(logger); + + @Test + public void instantiatesModuleByFullQualifiedName() throws Exception { + Module module = instantiator.instantiate("cucumber.runtime.java.guice.loadguicemodule.YourModuleClass").get(0); + assertThat(module, is(instanceOf(YourModuleClass.class))); + } + + @Test + public void returnsAnEmptyListOnNonExistingClass() throws Exception { + assertThat(instantiator.instantiate("some.bogus.Class").isEmpty(), is(true)); + } + + @Test + public void returnsAnEmptyListOnClassNotImplementingModule() throws Exception { + assertThat(instantiator.instantiate(String.class.getCanonicalName()).isEmpty(), is(true)); + } + + @Test + public void returnsAnEmptyListOnClassWithPrivateConstructor() throws Exception { + assertThat(instantiator.instantiate(PrivateConstructor.class.getCanonicalName()).isEmpty(), is(true)); + } + + @Test + public void logsFailingInstantiation() throws Exception { + instantiator.instantiate("some.bogus.Class"); + verify(logger).log(eq(Level.SEVERE), contains("Instantiation of 'some.bogus.Class' failed"), any(Throwable.class)); + } +} \ No newline at end of file diff --git a/guice/src/test/java/cucumber/runtime/java/guice/PrivateConstructor.java b/guice/src/test/java/cucumber/runtime/java/guice/PrivateConstructor.java new file mode 100644 index 0000000000..aaed9ecfaf --- /dev/null +++ b/guice/src/test/java/cucumber/runtime/java/guice/PrivateConstructor.java @@ -0,0 +1,14 @@ +package cucumber.runtime.java.guice; + +import com.google.inject.AbstractModule; + +public class PrivateConstructor extends AbstractModule{ + private PrivateConstructor() { + + } + + @Override + protected void configure() { + + } +} \ No newline at end of file diff --git a/guice/src/test/java/cucumber/runtime/java/guice/UrlPropertiesLoader_Test.java b/guice/src/test/java/cucumber/runtime/java/guice/UrlPropertiesLoader_Test.java new file mode 100644 index 0000000000..0a7256866e --- /dev/null +++ b/guice/src/test/java/cucumber/runtime/java/guice/UrlPropertiesLoader_Test.java @@ -0,0 +1,82 @@ +package cucumber.runtime.java.guice; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.*; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.contains; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.commons.io.IOUtils; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class UrlPropertiesLoader_Test { + + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + public final Logger logger = mock(Logger.class); + private final UrlPropertiesLoader loader = new UrlPropertiesLoader(logger); + + @Test + public void returnsEmptyPropertiesIfNullIsPassedAsResource() throws Exception { + URL resource = null; + Properties properties = loader.load(resource); + assertThat(properties.isEmpty(), is(true)); + } + + @Test + public void loadsThePropertiesFileFromTheProvidedResource() throws Exception { + Properties originalProperties = new Properties(); + originalProperties.put("key", "value"); + URL propertiesFileUrl = writeToAFile(originalProperties); + + Properties loadedProperties = loader.load(propertiesFileUrl); + assertThat(loadedProperties, is(originalProperties)); + } + + @Test + public void logsOutputIfProvidedUrlDoesNotPointToAPropertyFile() throws Exception { + URL noneExistingPropertiesFile = aNoneExistingFile(); + loader.load(noneExistingPropertiesFile); + verify(logger).log(eq(Level.INFO), contains("Could not load properties file"), any(Throwable.class)); + } + + @Test + public void testName() throws Exception { + URL noneExistingPropertiesFile = aNoneExistingFile(); + UrlPropertiesLoader loader = new UrlPropertiesLoader(); + loader.load(noneExistingPropertiesFile); + } + + private URL aNoneExistingFile() throws IOException, MalformedURLException { + File file = folder.newFile("some.properties"); + URL url = file.toURI().toURL(); + file.delete(); + return url; + } + + private URL writeToAFile(Properties propertiesWithContent) throws IOException, FileNotFoundException, MalformedURLException { + File propertiesFile1 = folder.newFile("some.properties"); + FileOutputStream outputStream = null; + try { + outputStream = new FileOutputStream(propertiesFile1); + propertiesWithContent.store(outputStream, "a comment"); + } finally { + IOUtils.closeQuietly(outputStream); + } + return propertiesFile1.toURI().toURL(); + } +} \ No newline at end of file diff --git a/guice/src/test/java/cucumber/runtime/java/guice/loadguicemodule/FirstSteps.java b/guice/src/test/java/cucumber/runtime/java/guice/loadguicemodule/FirstSteps.java index f8864e6058..1fdfb51cc2 100644 --- a/guice/src/test/java/cucumber/runtime/java/guice/loadguicemodule/FirstSteps.java +++ b/guice/src/test/java/cucumber/runtime/java/guice/loadguicemodule/FirstSteps.java @@ -1,15 +1,21 @@ package cucumber.runtime.java.guice.loadguicemodule; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.Properties; + import javax.inject.Inject; -import cucumber.annotation.Pending; import cucumber.annotation.en.And; import cucumber.annotation.en.Given; import cucumber.annotation.en.When; +import cucumber.runtime.java.guice.UrlPropertiesLoader; public class FirstSteps { private final SharedBetweenSteps shared; + private Properties guiceProperties; @Inject public FirstSteps(SharedBetweenSteps shared) { @@ -17,26 +23,23 @@ public FirstSteps(SharedBetweenSteps shared) { } @Given("^a cucumber-guice.properties file at the classpath root$") - @Pending public void a_cucumber_guice_properties_file_at_the_classpath_root() { - + UrlPropertiesLoader loader = new UrlPropertiesLoader(); + guiceProperties = loader.load(getClass().getClassLoader().getResource("cucumber-guice.properties")); } - @And("^the class SharedBetweenSteps is bound to a single instance$") - @Pending - public void the_class_SharedBetweenSteps_is_bound_to_a_single_instance() { - // Express the Regexp above with the code you wish you had - } - @And("^the properties file points to the module class 'cucumber.runtime.java.guice.loadguicemodule.YourModuleClass'$") - @Pending public void the_properties_file_points_to_the_module_class() { - // Express the Regexp above with the code you wish you had + String moduleClass = guiceProperties.getProperty("guiceModule"); + assertThat(moduleClass, is("cucumber.runtime.java.guice.loadguicemodule.YourModuleClass")); } - + @And("^the class SharedBetweenSteps is bound to a single instance$") + public void the_class_SharedBetweenSteps_is_bound_to_a_single_instance() { + //have a look at the module class + } + @When("^the first step class visits the instance of SharedBetweenSteps$") - @Pending public void the_first_step_class_visits_the_instance_of_SharedBetweenSteps() { shared.visit(); } diff --git a/guice/src/test/java/cucumber/runtime/java/guice/loadguicemodule/YourModuleClass.java b/guice/src/test/java/cucumber/runtime/java/guice/loadguicemodule/YourModuleClass.java index 6db0d14110..17fad81b57 100644 --- a/guice/src/test/java/cucumber/runtime/java/guice/loadguicemodule/YourModuleClass.java +++ b/guice/src/test/java/cucumber/runtime/java/guice/loadguicemodule/YourModuleClass.java @@ -8,4 +8,4 @@ public class YourModuleClass extends AbstractModule{ protected void configure() { bind(SharedBetweenSteps.class).toInstance(new SharedBetweenSteps()); } -} +} \ No newline at end of file diff --git a/guice/src/test/resources/cucumber-guice.properties b/guice/src/test/resources/cucumber-guice.properties new file mode 100644 index 0000000000..da1aa93dfe --- /dev/null +++ b/guice/src/test/resources/cucumber-guice.properties @@ -0,0 +1 @@ +guiceModule=cucumber.runtime.java.guice.loadguicemodule.YourModuleClass \ No newline at end of file