Skip to content

[OpenWebBeans] Add ObjectFactory for Apache OpenWebBeans #971

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package cucumber.runtime.java.openwebbeans;

import cucumber.api.java.ObjectFactory;
import org.junit.Test;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;

public class OpenWebBeansObjectFactoryTest {
@Test
public void shouldGiveUsNewInstancesForEachScenario() {
ObjectFactory factory = new OpenWebBeansObjectFactory();
factory.addClass(BellyStepdefs.class);

// Scenario 1
factory.start();
BellyStepdefs o1 = factory.getInstance(BellyStepdefs.class);
factory.stop();

// Scenario 2
factory.start();
BellyStepdefs o2 = factory.getInstance(BellyStepdefs.class);
factory.stop();

assertNotNull(o1);
assertNotSame(o1, o2);
}

}
58 changes: 58 additions & 0 deletions openwebbeans/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>info.cukes</groupId>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has become io.cucumber.

<artifactId>cucumber-jvm</artifactId>
<relativePath>../pom.xml</relativePath>
Copy link
Contributor

@mpkorstanje mpkorstanje May 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

relativePath is not needed.

<version>1.2.5-SNAPSHOT</version>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably needs an update. 😆

</parent>

<artifactId>cucumber-openwebbeans</artifactId>
<packaging>jar</packaging>
<name>Cucumber-JVM: OpenWebBeans</name>

<dependencies>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-java</artifactId>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-jvm-deps</artifactId>
<scope>provided</scope>
Copy link
Contributor

@mpkorstanje mpkorstanje May 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dependency cucumber-jvm-deps is not needed.

</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>gherkin</artifactId>
<scope>provided</scope>
Copy link
Contributor

@mpkorstanje mpkorstanje May 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dependency gherkin is not needed.

</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<scope>provided</scope>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've refactored the various POM files to reduce the coupling between modules. You'll have to provide a version for the CDI API here. For reference:

https://github.com/cucumber/cucumber-jvm/blob/master/weld/pom.xml

</dependency>
<dependency>
<groupId>org.apache.openwebbeans</groupId>
<artifactId>openwebbeans-impl</artifactId>
<version>${openwebbeans.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.sourceforge.cobertura</groupId>
<artifactId>cobertura</artifactId>
<scope>test</scope>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed.

</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package cucumber.api.openwebbeans;

public interface OpenWebBeansConfig {
boolean userManaged();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not happy about this. We currently don't have a good way to configure ObjectFactories. But that doesn't mean we should allow add-hoc configurations. I would prefer to keep this simple and working with sane defaults for now. If people want something more configurable they can implement their own version and deal with that complexity.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package cucumber.api.openwebbeans;


public class README {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<body>
<p>
There is no API for this module, but by including the <code>cucumber-openwebbeans</code> jar
on your <code>CLASSPATH</code> your Step Definitions will be instantiated by OpenWebBeans.
</p>
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package cucumber.runtime.java.openwebbeans;

import cucumber.api.java.ObjectFactory;
import cucumber.api.openwebbeans.OpenWebBeansConfig;
import org.apache.webbeans.config.WebBeansContext;
import org.apache.webbeans.container.BeanManagerImpl;
import org.apache.webbeans.context.creational.CreationalContextImpl;
import org.apache.webbeans.spi.ContainerLifecycle;

import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.ServiceLoader;

public class OpenWebBeansObjectFactory implements ObjectFactory {
private final Map<Class<?>, Object> notNormalScopedInstances = new HashMap<Class<?>, Object>();
private final Collection<CreationalContext<?>> contexts = new ArrayList<CreationalContext<?>>();
private WebBeansContext webBeansContext;
private boolean managed;

@Override
public void start() {
webBeansContext = WebBeansContext.currentInstance();
final ContainerLifecycle cl = webBeansContext.getService(ContainerLifecycle.class);

final Iterator<OpenWebBeansConfig> config = ServiceLoader.load(OpenWebBeansConfig.class).iterator();
managed = !config.hasNext() || !config.next().userManaged();
if (managed) {
cl.startApplication(null);
}
}

@Override
public void stop() {
synchronized (contexts) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stop will not be called concurrently. There should be no need to synchronize on contexts.

for (final CreationalContext<?> cc : contexts) {
cc.release();
}
contexts.clear();
notNormalScopedInstances.clear();
}
if (managed) {
webBeansContext.getService(ContainerLifecycle.class).stopApplication(null);
}
}

@Override
public boolean addClass(final Class<?> clazz) {
return true;
}

@Override
public <T> T getInstance(Class<T> type) {
final Object instance = notNormalScopedInstances.get(type);
if (instance != null) {
return type.cast(instance);
}

final BeanManagerImpl bm = webBeansContext.getBeanManagerImpl();
final Bean<?> bean = bm.resolve(bm.getBeans(type));
final CreationalContextImpl<Object> creationalContext = bm.createCreationalContext(null);
T created = type.cast(bm.getReference(bean, type, creationalContext));
if (!bm.isNormalScope(bean.getScope())) {
synchronized (contexts) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. getInstance will not be called concurrently.

contexts.add(creationalContext);
final Object existing = notNormalScopedInstances.put(type, created);
if (existing != null) {
created = type.cast(existing);
creationalContext.release();
}
}
}
return created;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package cucumber.runtime.java.openwebbeans;

public class Belly {
private int cukes;

public void setCukes(int cukes) {
this.cukes = cukes;
}

public int getCukes() {
return cukes;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package cucumber.runtime.java.openwebbeans;

import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;

import javax.inject.Inject;

import static org.junit.Assert.assertEquals;

public class BellyStepdefs {

@Inject
private Belly belly;

@Given("^I have (\\d+) cukes in my belly")
public void haveCukes(int n) {
belly.setCukes(n);
}

@Then("^there are (\\d+) cukes in my belly")
public void checkCukes(int n) {
assertEquals(n, belly.getCukes());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package cucumber.runtime.java.openwebbeans;

import cucumber.api.openwebbeans.OpenWebBeansConfig;

// not mandatory but allow to start it manually somewhere else
public class Config implements OpenWebBeansConfig {
@Override
public boolean userManaged() {
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package cucumber.runtime.java.openwebbeans;

public class OpenWebBeansObjectFactoryTest {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty class?

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package cucumber.runtime.java.openwebbeans;

import cucumber.api.junit.Cucumber;
import org.junit.runner.RunWith;

@RunWith(Cucumber.class)
public class RunCukesTest {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package cucumber.runtime.java.openwebbeans;

import cucumber.api.java.Before;
import cucumber.api.java.en.Given;

public class UnusedGlue {
public UnusedGlue() {
throw new IllegalStateException();
}

@Given("unused")
public void unused() {
throw new IllegalStateException();
}

@Before("@unused")
public void unusedHook() {
throw new IllegalStateException();
}
}
7 changes: 7 additions & 0 deletions openwebbeans/src/test/resources/META-INF/beans.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">

</beans>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Feature: Cukes

Scenario: Eat some cukes
Given I have 4 cukes in my belly
Then there are 4 cukes in my belly
2 changes: 2 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
<weld-se.version>2.2.11.Final</weld-se.version>
<cdi-api.version>1.2</cdi-api.version>
<openejb-core.version>4.7.1</openejb-core.version>
<openwebbeans.version>1.6.2</openwebbeans.version>
<needle.version>2.2</needle.version>
<javaee-api.version>7.0</javaee-api.version>
<javax.inject.version>1</javax.inject.version>
Expand Down Expand Up @@ -559,6 +560,7 @@
<module>groovy</module>
<module>rhino</module>
<module>openejb</module>
<module>openwebbeans</module>
<module>scala</module>
<module>needle</module>
<module>android</module>
Expand Down