- Revision
- 934
- Author
- mauro
- Date
- 2008-09-21 04:36:39 -0500 (Sun, 21 Sep 2008)
Log Message
JBEHAVE-133: Added lightweight container facade - and a Pico-based implementation (others to follow suit). Added ContainerSteps abstract class to allow Steps to access container components.
Modified Paths
Added Paths
- trunk/jbehave-core/src/behaviour/org/jbehave/container/
- trunk/jbehave-core/src/behaviour/org/jbehave/container/AComponent.java
- trunk/jbehave-core/src/behaviour/org/jbehave/container/AnotherComponent.java
- trunk/jbehave-core/src/behaviour/org/jbehave/container/pico/
- trunk/jbehave-core/src/behaviour/org/jbehave/container/pico/XMLPicoContainerBehaviour.java
- trunk/jbehave-core/src/behaviour/org/jbehave/container/pico/XMLPicoContainerStepsBehaviour.java
- trunk/jbehave-core/src/behaviour/org/jbehave/container/pico/components.xml
- trunk/jbehave-core/src/behaviour/org/jbehave/container/pico/no-components.xml
- trunk/jbehave-core/src/java/org/jbehave/container/
- trunk/jbehave-core/src/java/org/jbehave/container/ComponentNotFoundException.java
- trunk/jbehave-core/src/java/org/jbehave/container/Container.java
- trunk/jbehave-core/src/java/org/jbehave/container/ContainerSteps.java
- trunk/jbehave-core/src/java/org/jbehave/container/pico/
- trunk/jbehave-core/src/java/org/jbehave/container/pico/AbstractPicoContainer.java
- trunk/jbehave-core/src/java/org/jbehave/container/pico/XMLPicoContainer.java
- trunk/jbehave-core/src/java/org/jbehave/container/pico/XMLPicoContainerSteps.java
Diff
Modified: trunk/jbehave-core/pom.xml (933 => 934)
--- trunk/jbehave-core/pom.xml 2008-09-21 08:27:55 UTC (rev 933) +++ trunk/jbehave-core/pom.xml 2008-09-21 09:36:39 UTC (rev 934) @@ -1,4 +1,5 @@ -<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/maven-v4_0_0.xsd"> +<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.jbehave</groupId> @@ -15,6 +16,10 @@ <groupId>org.apache.ant</groupId> <artifactId>ant</artifactId> </dependency> + <dependency> + <groupId>org.picocontainer.script</groupId> + <artifactId>picocontainer-script-core</artifactId> + </dependency> </dependencies> </project>
Added: trunk/jbehave-core/src/behaviour/org/jbehave/container/AComponent.java (0 => 934)
--- trunk/jbehave-core/src/behaviour/org/jbehave/container/AComponent.java (rev 0) +++ trunk/jbehave-core/src/behaviour/org/jbehave/container/AComponent.java 2008-09-21 09:36:39 UTC (rev 934) @@ -0,0 +1,5 @@ +package org.jbehave.container; + +public class AComponent { + +}
Added: trunk/jbehave-core/src/behaviour/org/jbehave/container/AnotherComponent.java (0 => 934)
--- trunk/jbehave-core/src/behaviour/org/jbehave/container/AnotherComponent.java (rev 0) +++ trunk/jbehave-core/src/behaviour/org/jbehave/container/AnotherComponent.java 2008-09-21 09:36:39 UTC (rev 934) @@ -0,0 +1,5 @@ +package org.jbehave.container; + +public class AnotherComponent { + +}
Added: trunk/jbehave-core/src/behaviour/org/jbehave/container/pico/XMLPicoContainerBehaviour.java (0 => 934)
--- trunk/jbehave-core/src/behaviour/org/jbehave/container/pico/XMLPicoContainerBehaviour.java (rev 0) +++ trunk/jbehave-core/src/behaviour/org/jbehave/container/pico/XMLPicoContainerBehaviour.java 2008-09-21 09:36:39 UTC (rev 934) @@ -0,0 +1,74 @@ +package org.jbehave.container.pico; + +import static org.junit.Assert.assertNotNull; + +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.NoSuchElementException; + +import org.jbehave.container.AComponent; +import org.jbehave.container.AnotherComponent; +import org.jbehave.container.ComponentNotFoundException; +import org.jbehave.container.Container; +import org.junit.Test; + +/** + * @author Mauro Talevi + */ +public class XMLPicoContainerBehaviour { + + @Test + public void canGetComponentByKey() { + Container container = new XMLPicoContainer("org/jbehave/container/pico/components.xml"); + assertNotNull(container.getComponent(AComponent.class, "a-component")); + } + + @Test(expected = ComponentNotFoundException.class) + public void cannotGetComponentByInexistentKey() { + Container container = new XMLPicoContainer("org/jbehave/container/pico/components.xml"); + container.getComponent(AComponent.class, "inexistent-key"); + } + + @Test + public void canGetComponentByType() { + Container container = new XMLPicoContainer("org/jbehave/container/pico/components.xml"); + assertNotNull(container.getComponent(AnotherComponent.class)); + } + + @Test + public void canGetComponentsWithCustomClassLoader() { + Container container = new XMLPicoContainer("org/jbehave/container/pico/components.xml", Thread + .currentThread().getContextClassLoader()); + assertNotNull(container.getComponent(AComponent.class)); + assertNotNull(container.getComponent(AnotherComponent.class)); + } + + @Test(expected = NoSuchElementException.class) + public void cannotGetComponentsWithInvalidClassLoader() throws MalformedURLException { + new XMLPicoContainer("org/jbehave/container/pico/components.xml", new InvalidClassLoader()); + } + + @Test(expected = ComponentNotFoundException.class) + public void cannotGetComponentWithNoneConfigured() { + Container container = new XMLPicoContainer("org/jbehave/container/pico/no-components.xml"); + container.getComponent(AComponent.class); + } + + @Test(expected = NoSuchElementException.class) + public void cannotGetResourceWhenNotFound() { + new XMLPicoContainer("inexistent-resource.xml"); + } + + class InvalidClassLoader extends URLClassLoader { + public InvalidClassLoader() throws MalformedURLException { + super(new URL[] {}); + } + + public InputStream getResourceAsStream(String resource) { + return null; + } + } + +}
Added: trunk/jbehave-core/src/behaviour/org/jbehave/container/pico/XMLPicoContainerStepsBehaviour.java (0 => 934)
--- trunk/jbehave-core/src/behaviour/org/jbehave/container/pico/XMLPicoContainerStepsBehaviour.java (rev 0) +++ trunk/jbehave-core/src/behaviour/org/jbehave/container/pico/XMLPicoContainerStepsBehaviour.java 2008-09-21 09:36:39 UTC (rev 934) @@ -0,0 +1,54 @@ +package org.jbehave.container.pico; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.jbehave.util.JUnit4Ensure.ensureThat; + +import org.jbehave.container.AComponent; +import org.jbehave.container.AnotherComponent; +import org.jbehave.scenario.steps.CandidateStep; +import org.junit.Test; + +public class XMLPicoContainerStepsBehaviour { + + @Test + public void shouldProvideCandidateStepsThatAreContainerAware() { + MySteps steps = new MySteps("org/jbehave/container/pico/components.xml"); + CandidateStep[] candidateSteps = steps.getSteps(); + ensureThat(candidateSteps.length, equalTo(3)); + + candidateSteps[0].createFrom("Given a component").perform(); + candidateSteps[1].createFrom("When another component").perform(); + candidateSteps[2].createFrom("Then say hurray").perform(); + + ensureThat(steps.aComponent != null); + ensureThat(steps.anotherComponent != null); + ensureThat(steps.sayHurray); + + } + + public static class MySteps extends XMLPicoContainerSteps { + + public boolean sayHurray; + public Object aComponent; + public Object anotherComponent; + + public MySteps(String containerResource) { + super(containerResource); + } + + @org.jbehave.scenario.annotations.Given("a component") + public void given() { + aComponent = component(AComponent.class); + } + + @org.jbehave.scenario.annotations.When("another component") + public void when() { + anotherComponent = component(AnotherComponent.class); + } + + @org.jbehave.scenario.annotations.Then("say hurray") + public void then() { + sayHurray = true; + } + } +}
Added: trunk/jbehave-core/src/behaviour/org/jbehave/container/pico/components.xml (0 => 934)
--- trunk/jbehave-core/src/behaviour/org/jbehave/container/pico/components.xml (rev 0) +++ trunk/jbehave-core/src/behaviour/org/jbehave/container/pico/components.xml 2008-09-21 09:36:39 UTC (rev 934) @@ -0,0 +1,10 @@ +<container> + + <component-implementation key='a-component' + class='org.jbehave.container.AComponent'> + </component-implementation> + + <component-implementation class='org.jbehave.container.AnotherComponent'> + </component-implementation> + +</container> \ No newline at end of file
Added: trunk/jbehave-core/src/behaviour/org/jbehave/container/pico/no-components.xml (0 => 934)
--- trunk/jbehave-core/src/behaviour/org/jbehave/container/pico/no-components.xml (rev 0) +++ trunk/jbehave-core/src/behaviour/org/jbehave/container/pico/no-components.xml 2008-09-21 09:36:39 UTC (rev 934) @@ -0,0 +1,3 @@ +<container> + +</container> \ No newline at end of file
Added: trunk/jbehave-core/src/java/org/jbehave/container/ComponentNotFoundException.java (0 => 934)
--- trunk/jbehave-core/src/java/org/jbehave/container/ComponentNotFoundException.java (rev 0) +++ trunk/jbehave-core/src/java/org/jbehave/container/ComponentNotFoundException.java 2008-09-21 09:36:39 UTC (rev 934) @@ -0,0 +1,15 @@ +package org.jbehave.container; + +/** + * Thrown when no component is found for a given key or type in the container + * + * @author Mauro Talevi + */ [EMAIL PROTECTED]("serial") +public class ComponentNotFoundException extends RuntimeException { + + public ComponentNotFoundException(String message) { + super(message); + } + +}
Added: trunk/jbehave-core/src/java/org/jbehave/container/Container.java (0 => 934)
--- trunk/jbehave-core/src/java/org/jbehave/container/Container.java (rev 0) +++ trunk/jbehave-core/src/java/org/jbehave/container/Container.java 2008-09-21 09:36:39 UTC (rev 934) @@ -0,0 +1,32 @@ +package org.jbehave.container; + +/** + * Container represents a simple facade to access components from lightweight + * containers. Different implementations will provide adapters to different + * containers. + * + * @author Mauro Talevi + */ +public interface Container { + + /** + * Returns a component of a given type + * + * @param type the component Class type + * @return The component instance of type <T> + * @throws ComponentNotFoundException when component not found + */ + <T> T getComponent(Class<T> type); + + /** + * Returns a component for a given type and key. It first looks up the + * components by type and then from these the one with the provided key. + * + * @param type the component Class type + * @param key the component Object key + * @return The component instance of type <T> + * @throws ComponentNotFoundException when component not found + */ + <T> T getComponent(Class<T> type, Object key); + +}
Added: trunk/jbehave-core/src/java/org/jbehave/container/ContainerSteps.java (0 => 934)
--- trunk/jbehave-core/src/java/org/jbehave/container/ContainerSteps.java (rev 0) +++ trunk/jbehave-core/src/java/org/jbehave/container/ContainerSteps.java 2008-09-21 09:36:39 UTC (rev 934) @@ -0,0 +1,39 @@ +package org.jbehave.container; + +import org.jbehave.container.pico.XMLPicoContainerSteps; +import org.jbehave.scenario.steps.Steps; + +/** + * <p> + * Abstract steps decorator which adds container support. Users need to extend + * this class and provide a concrete implementation of Container. + * </p> + * <p> + * Concrete implementations provided are [EMAIL PROTECTED] XMLPicoContainerSteps}. + * </p> + * + * @author Mauro Talevi + */ +public abstract class ContainerSteps extends Steps { + + private Container container; + + public ContainerSteps(String containerResource) { + this(containerResource, Thread.currentThread().getContextClassLoader()); + } + + public ContainerSteps(String containerResource, ClassLoader classLoader) { + container = createContainer(containerResource, classLoader); + } + + public <T> T component(Class<T> type) { + return container.getComponent(type); + } + + public <T> T getComponent(Class<T> type, Object key) { + return container.getComponent(type, key); + } + + protected abstract Container createContainer(String containerResource, ClassLoader classLoader); + +}
Added: trunk/jbehave-core/src/java/org/jbehave/container/pico/AbstractPicoContainer.java (0 => 934)
--- trunk/jbehave-core/src/java/org/jbehave/container/pico/AbstractPicoContainer.java (rev 0) +++ trunk/jbehave-core/src/java/org/jbehave/container/pico/AbstractPicoContainer.java 2008-09-21 09:36:39 UTC (rev 934) @@ -0,0 +1,121 @@ +package org.jbehave.container.pico; + +import static java.text.MessageFormat.format; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.NoSuchElementException; + +import org.jbehave.container.ComponentNotFoundException; +import org.jbehave.container.Container; +import org.picocontainer.ComponentAdapter; +import org.picocontainer.PicoContainer; +import org.picocontainer.script.ScriptedContainerBuilder; + +/** + * <p> + * Abstract implementation of Container which uses a PicoContainer as delegate + * container. + * </p> + * + * @author Mauro Talevi + */ +public abstract class AbstractPicoContainer implements Container { + + private final ClassLoader classLoader; + private final PicoContainer container; + + protected AbstractPicoContainer(String resource) { + this(resource, Thread.currentThread().getContextClassLoader()); + } + + protected AbstractPicoContainer(String resource, ClassLoader classLoader) { + this.classLoader = classLoader; + this.container = buildContainer(resource); + } + + public <T> T getComponent(Class<T> type) { + return getPicoComponent(type, null); + } + + public <T> T getComponent(Class<T> type, Object key) { + return getPicoComponent(type, key); + } + + public <T> Collection<Object> getComponentKeys(Class<T> type) { + List<ComponentAdapter<T>> adapters = container.getComponentAdapters(type); + List<Object> keys = new ArrayList<Object>(); + for (ComponentAdapter<T> adapter : adapters) { + keys.add(adapter.getComponentKey()); + } + return keys; + } + + /** + * Returns an instance of a component of a given type and key from the + * delegate PicoContainer. + * + * @param type the component Class + * @param key the component key + * @return A component instance for the given type and key, if provided + * @throws NoComponentOfTypeException if no Component can be found of type + * @throws ComponentNotFoundException if Component not found for key + */ + private <T> T getPicoComponent(Class<T> type, Object key) { + List<ComponentAdapter<T>> adapters = container.getComponentAdapters(type); + if (adapters.isEmpty()) { + String message = format("No component registered in container of type {0}", type); + throw new ComponentNotFoundException(message); + } + if (key != null) { + // a key has been provided: return the component for that key + for (ComponentAdapter<T> adapter : adapters) { + if (key.equals(adapter.getComponentKey())) { + return adapter.getComponentInstance(container, type); + } + } + String message = format("No component registered in container of type {0} and for key {1}", type, key); + throw new ComponentNotFoundException(message); + } else { + // no key has been found: + // return first of registered components + return adapters.iterator().next().getComponentInstance(container, type); + } + } + + /** + * Builds PicoContainer from a given resource + * + * @param resource the String encoding the script path + * @return A PicoContainer + */ + private PicoContainer buildContainer(String resource) { + Reader script = getReader(resource, classLoader); + ScriptedContainerBuilder builder = createContainerBuilder(script, classLoader); + return builder.buildContainer(null, null, true); + } + + private Reader getReader(String resource, ClassLoader classLoader) { + InputStream is = classLoader.getResourceAsStream(resource); + if (is == null) { + String message = format("Resource {0} not found in ClassLoader {1}", resource, classLoader.getClass(), + classLoader); + throw new NoSuchElementException(message); + } + return new InputStreamReader(is); + } + + /** + * Allow concrete implementations to specify a ScriptedContainerBuilder + * + * @param script the Reader containing the container script + * @param classLoader the ClassLoader + * @return A ScriptedContainerBuilder + */ + protected abstract ScriptedContainerBuilder createContainerBuilder(Reader script, ClassLoader classLoader); + +}
Added: trunk/jbehave-core/src/java/org/jbehave/container/pico/XMLPicoContainer.java (0 => 934)
--- trunk/jbehave-core/src/java/org/jbehave/container/pico/XMLPicoContainer.java (rev 0) +++ trunk/jbehave-core/src/java/org/jbehave/container/pico/XMLPicoContainer.java 2008-09-21 09:36:39 UTC (rev 934) @@ -0,0 +1,27 @@ +package org.jbehave.container.pico; + +import java.io.Reader; + +import org.picocontainer.script.ScriptedContainerBuilder; +import org.picocontainer.script.xml.XMLContainerBuilder; + +/** + * PicoContainer which uses XMLContainerBuilder to build the delegate container + * + * @author Mauro Talevi + */ +public class XMLPicoContainer extends AbstractPicoContainer { + + public XMLPicoContainer(String resource) { + super(resource); + } + + public XMLPicoContainer(String resource, ClassLoader classLoader) { + super(resource, classLoader); + } + + protected ScriptedContainerBuilder createContainerBuilder(Reader script, ClassLoader classLoader) { + return new XMLContainerBuilder(script, classLoader); + } + +}
Added: trunk/jbehave-core/src/java/org/jbehave/container/pico/XMLPicoContainerSteps.java (0 => 934)
--- trunk/jbehave-core/src/java/org/jbehave/container/pico/XMLPicoContainerSteps.java (rev 0) +++ trunk/jbehave-core/src/java/org/jbehave/container/pico/XMLPicoContainerSteps.java 2008-09-21 09:36:39 UTC (rev 934) @@ -0,0 +1,25 @@ +package org.jbehave.container.pico; + +import org.jbehave.container.Container; +import org.jbehave.container.ContainerSteps; + +/** + * XMLPicoContainer-based Steps decorator. + * + * @author Mauro Talevi + */ +public class XMLPicoContainerSteps extends ContainerSteps { + + public XMLPicoContainerSteps(String containerResource) { + super(containerResource); + } + + public XMLPicoContainerSteps(String containerResource, ClassLoader classLoader) { + super(containerResource, classLoader); + } + + protected Container createContainer(String containerResource, ClassLoader classLoader) { + return new XMLPicoContainer(containerResource, classLoader); + } + +}
Modified: trunk/pom.xml (933 => 934)
--- trunk/pom.xml 2008-09-21 08:27:55 UTC (rev 933) +++ trunk/pom.xml 2008-09-21 09:36:39 UTC (rev 934) @@ -1,4 +1,5 @@ -<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/maven-v4_0_0.xsd"> +<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.jbehave</groupId> <artifactId>jbehave</artifactId> @@ -30,6 +31,15 @@ <scope>provided</scope> </dependency> <dependency> + <!-- Optional as only used by ContainerSteps --> + <groupId>org.picocontainer.script</groupId> + <artifactId>picocontainer-script-core</artifactId> + <version>2.0</version> + <optional>true</optional> + <scope>provided</scope> + </dependency> + + <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>1.2</version>
To unsubscribe from this list please visit: