Skip to content

Commit 829cb6e

Browse files
Merge pull request cucumber#1 from christianbellinaef/feature/hk2-ef
Feature/hk2-ef
2 parents 8864972 + b07e4a0 commit 829cb6e

38 files changed

+1465
-0
lines changed

hk2/pom.xml

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<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">
2+
<modelVersion>4.0.0</modelVersion>
3+
4+
<parent>
5+
<groupId>info.cukes</groupId>
6+
<artifactId>cucumber-jvm</artifactId>
7+
<relativePath>../pom.xml</relativePath>
8+
<version>1.2.6-SNAPSHOT</version>
9+
</parent>
10+
11+
<artifactId>cucumber-hk2</artifactId>
12+
<packaging>jar</packaging>
13+
<name>Cucumber-JVM: Hk2</name>
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>info.cukes</groupId>
18+
<artifactId>cucumber-java</artifactId>
19+
</dependency>
20+
<dependency>
21+
<groupId>info.cukes</groupId>
22+
<artifactId>cucumber-jvm-deps</artifactId>
23+
<scope>provided</scope>
24+
</dependency>
25+
<dependency>
26+
<groupId>info.cukes</groupId>
27+
<artifactId>gherkin</artifactId>
28+
<scope>provided</scope>
29+
</dependency>
30+
<dependency>
31+
<groupId>javax.enterprise</groupId>
32+
<artifactId>cdi-api</artifactId>
33+
<scope>provided</scope>
34+
</dependency>
35+
<dependency>
36+
<groupId>org.glassfish.hk2</groupId>
37+
<artifactId>hk2</artifactId>
38+
<scope>compile</scope>
39+
</dependency>
40+
<dependency>
41+
<groupId>info.cukes</groupId>
42+
<artifactId>cucumber-junit</artifactId>
43+
<scope>test</scope>
44+
</dependency>
45+
<dependency>
46+
<groupId>junit</groupId>
47+
<artifactId>junit</artifactId>
48+
<scope>test</scope>
49+
</dependency>
50+
<dependency>
51+
<groupId>net.sourceforge.cobertura</groupId>
52+
<artifactId>cobertura</artifactId>
53+
<scope>test</scope>
54+
</dependency>
55+
</dependencies>
56+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package cucumber.api.hk2;
2+
3+
/**
4+
* Please see package documentation in package.html
5+
*/
6+
public class README {
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<body>
2+
<div>
3+
<p>The HK2 module follows the patterns used by the Guice dependency module. An annotation binding scope named <code>@ScenarioScoped</code>
4+
has been added, which when set as the binding scope for a class, will limit the object's lifespan to the
5+
lifespan of a Cucumber scenario. I.e. a new instance of this object will be created for each Cucumber scenario.
6+
</p>
7+
<p>The ServiceLocator used by the module is provided by the user's implementation of ServiceLocatorSource. Expose
8+
your implementation to the Cucumber runtime by setting the environment key <code>hk2.locator-source</code> to
9+
the fully qualified name of the implementing class.
10+
</p>
11+
<p>The easiest way to do this is by creating a cucumber.properties file with the configuration values, and placing
12+
this file at the root of your classpath.
13+
</p>
14+
<p>
15+
Note: Your provided ServiceLocator MUST have the <code>ScenarioScopeModule</code> binder installed!
16+
</p>
17+
<p>
18+
If you do not provide your own custom ServiceLocatorSource, a default ServiceLocatorSource will be created by
19+
the module. This default ServiceLocator will be populated by services found in the <code>META-INF/hk2-locator/default</code> file.
20+
</p>
21+
<p>
22+
Please refer to the <a href="https://hk2-project.github.io/" target="_parent">HK2 project page</a> for further information on HK2.
23+
</p>
24+
</div>
25+
</body>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package cucumber.runtime.java.hk2;
2+
3+
import javax.inject.Scope;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.Target;
6+
7+
import static java.lang.annotation.ElementType.METHOD;
8+
import static java.lang.annotation.ElementType.TYPE;
9+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
10+
11+
/**
12+
* Cucumber Scenario scope binding annotation. Limit the scope of an object to the lifecycle of a Scenario.
13+
*/
14+
@Target({TYPE, METHOD})
15+
@Retention(RUNTIME)
16+
@Scope
17+
public @interface ScenarioScoped {
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package cucumber.runtime.java.hk2;
2+
3+
import org.glassfish.hk2.api.ServiceLocator;
4+
5+
/**
6+
* Provides the ServiceLocator source to use during Cucumber tests
7+
*/
8+
public interface ServiceLocatorSource {
9+
10+
ServiceLocator getServiceLocator();
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package cucumber.runtime.java.hk2.impl;
2+
3+
import cucumber.runtime.CucumberException;
4+
5+
/**
6+
* Exception class for cucumber-hk2 exceptions
7+
*/
8+
class CucumberHK2Exception extends CucumberException {
9+
10+
CucumberHK2Exception(String message) {
11+
super(message);
12+
}
13+
14+
CucumberHK2Exception(String message, Throwable e) {
15+
super(message, e);
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package cucumber.runtime.java.hk2.impl;
2+
3+
import cucumber.api.java.ObjectFactory;
4+
import cucumber.runtime.Env;
5+
import cucumber.runtime.java.hk2.ScenarioScoped;
6+
import cucumber.runtime.java.hk2.ServiceLocatorSource;
7+
import org.glassfish.hk2.api.ServiceLocator;
8+
import org.glassfish.hk2.utilities.Binder;
9+
import org.glassfish.hk2.utilities.ServiceLocatorUtilities;
10+
import org.glassfish.hk2.utilities.binding.AbstractBinder;
11+
12+
import java.util.HashSet;
13+
import java.util.Set;
14+
15+
/**
16+
* Guice implementation of the <code>cucumber.api.java.ObjectFactory</code>.
17+
*/
18+
public class HK2Factory implements ObjectFactory {
19+
20+
private final ServiceLocatorSource locatorSource;
21+
22+
private Set<Class<?>> cucumberClasses = new HashSet<Class<?>>();
23+
24+
private ScenarioContext context;
25+
private Binder binder;
26+
27+
public HK2Factory() {
28+
this.locatorSource = new ServiceLocatorSourceFactory(Env.INSTANCE).create();
29+
}
30+
31+
/**
32+
* Package private constructor that is called by the public constructor at runtime and is also called directly by
33+
* tests.
34+
*
35+
* @param serviceLocator a service locator configured with a ScenarioScoped binding
36+
*/
37+
HK2Factory(final ServiceLocator serviceLocator) {
38+
this.locatorSource = new ServiceLocatorSource() {
39+
@Override
40+
public ServiceLocator getServiceLocator() {
41+
return serviceLocator;
42+
}
43+
};
44+
}
45+
46+
public boolean addClass(Class<?> clazz) {
47+
cucumberClasses.add(clazz);
48+
return true;
49+
}
50+
51+
public void start() {
52+
// Waiting as long as possible before making the first call to getServiceLocator()
53+
initContext();
54+
bindCucumberClasses();
55+
}
56+
57+
private void initContext() {
58+
if (context != null) {
59+
return;
60+
}
61+
context = locatorSource.getServiceLocator().getService(ScenarioContext.class);
62+
if (context == null) {
63+
throw new CucumberHK2Exception("The ServiceLocator could not find a ScenarioContext, have you installed the ScenarioScopeModule?");
64+
}
65+
}
66+
67+
private void bindCucumberClasses() {
68+
if (binder != null) {
69+
return;
70+
}
71+
binder = new AbstractBinder() {
72+
@Override
73+
protected void configure() {
74+
for (Class<?> clazz : cucumberClasses) {
75+
bindAsContract(clazz).in(ScenarioScoped.class);
76+
}
77+
}
78+
};
79+
ServiceLocatorUtilities.bind(locatorSource.getServiceLocator(), binder);
80+
}
81+
82+
public void stop() {
83+
context.shutdown();
84+
}
85+
86+
public <T> T getInstance(Class<T> clazz) {
87+
return locatorSource.getServiceLocator().getService(clazz);
88+
}
89+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3+
*
4+
* Copyright (c) 2010-2015 Oracle and/or its affiliates. All rights reserved.
5+
*
6+
* The contents of this file are subject to the terms of either the GNU
7+
* General Public License Version 2 only ("GPL") or the Common Development
8+
* and Distribution License("CDDL") (collectively, the "License"). You
9+
* may not use this file except in compliance with the License. You can
10+
* obtain a copy of the License at
11+
* http://glassfish.java.net/public/CDDL+GPL_1_1.html
12+
* or packager/legal/LICENSE.txt. See the License for the specific
13+
* language governing permissions and limitations under the License.
14+
*
15+
* When distributing the software, include this License Header Notice in each
16+
* file and include the License file at packager/legal/LICENSE.txt.
17+
*
18+
* GPL Classpath Exception:
19+
* Oracle designates this particular file as subject to the "Classpath"
20+
* exception as provided by Oracle in the GPL Version 2 section of the License
21+
* file that accompanied this code.
22+
*
23+
* Modifications:
24+
* If applicable, add the following below the License Header, with the fields
25+
* enclosed by brackets [] replaced by your own identifying information:
26+
* "Portions Copyright [year] [name of copyright owner]"
27+
*
28+
* Contributor(s):
29+
* If you wish your version of this file to be governed by only the CDDL or
30+
* only the GPL Version 2, indicate your decision by adding "[Contributor]
31+
* elects to include this software in this distribution under the [CDDL or GPL
32+
* Version 2] license." If you don't indicate a single choice of license, a
33+
* recipient has the option to distribute your version of this file under
34+
* either the CDDL, the GPL Version 2 or to extend the choice of license to
35+
* its licensees as provided above. However, if you add GPL Version 2 code
36+
* and therefore, elected the GPL Version 2 license, then the option applies
37+
* only if the new code is made subject to such option by the copyright
38+
* holder.
39+
*/
40+
41+
package cucumber.runtime.java.hk2.impl;
42+
43+
import cucumber.runtime.java.hk2.ScenarioScoped;
44+
import org.glassfish.hk2.api.ActiveDescriptor;
45+
import org.glassfish.hk2.api.Context;
46+
import org.glassfish.hk2.api.ServiceHandle;
47+
48+
import javax.inject.Singleton;
49+
import java.lang.annotation.Annotation;
50+
import java.util.HashMap;
51+
52+
@Singleton
53+
public class ScenarioContext implements Context<ScenarioScoped> {
54+
55+
private HashMap<ActiveDescriptor<?>, Object> map = new HashMap<ActiveDescriptor<?>, Object>();
56+
57+
@Override
58+
public Class<? extends Annotation> getScope() {
59+
return ScenarioScoped.class;
60+
}
61+
62+
@Override
63+
public <U> U findOrCreate(ActiveDescriptor<U> activeDescriptor, ServiceHandle<?> root) {
64+
65+
Object val = map.get(activeDescriptor);
66+
67+
if (val == null) {
68+
val = activeDescriptor.create(root);
69+
map.put(activeDescriptor, val);
70+
}
71+
72+
return (U) val;
73+
}
74+
75+
@Override
76+
public boolean containsKey(ActiveDescriptor<?> descriptor) {
77+
return map.containsKey(descriptor);
78+
}
79+
80+
@Override
81+
public void destroyOne(ActiveDescriptor<?> descriptor) {
82+
map.remove(descriptor);
83+
}
84+
85+
@Override
86+
public boolean supportsNullCreation() {
87+
return false;
88+
}
89+
90+
@Override
91+
public boolean isActive() {
92+
return map != null;
93+
}
94+
95+
@Override
96+
public void shutdown() {
97+
map.clear();
98+
}
99+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package cucumber.runtime.java.hk2.impl;
2+
3+
import cucumber.runtime.java.hk2.ScenarioScoped;
4+
import cucumber.runtime.java.hk2.ServiceLocatorSource;
5+
import org.glassfish.hk2.utilities.binding.AbstractBinder;
6+
7+
/**
8+
* Enables the {@link ScenarioScoped} context, must be installed in all user specified {@link ServiceLocatorSource}
9+
*/
10+
public class ScenarioScopeModule extends AbstractBinder {
11+
12+
@Override
13+
protected void configure() {
14+
addActiveDescriptor(ScenarioContext.class);
15+
}
16+
}

0 commit comments

Comments
 (0)