Skip to content
This repository was archived by the owner on May 28, 2018. It is now read-only.

Commit 2f1b934

Browse files
committed
JERSEY-2855: introduced foreign request scope bridge to enable direct injection of factory provided request scoped JAX-RS stuff into factory provided external managed components
Change-Id: Id8074c94692fe6803d6299d16e6cb70d3e7b9fd7 Signed-off-by: Jakub Podlesak <[email protected]>
1 parent 0214b7d commit 2f1b934

File tree

18 files changed

+702
-27
lines changed

18 files changed

+702
-27
lines changed

core-common/src/main/java/org/glassfish/jersey/internal/inject/ContextInjectionResolver.java

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
33
*
4-
* Copyright (c) 2012-2014 Oracle and/or its affiliates. All rights reserved.
4+
* Copyright (c) 2012-2015 Oracle and/or its affiliates. All rights reserved.
55
*
66
* The contents of this file are subject to the terms of either the GNU
77
* General Public License Version 2 only ("GPL") or the Common Development
@@ -39,14 +39,21 @@
3939
*/
4040
package org.glassfish.jersey.internal.inject;
4141

42+
import java.lang.reflect.Field;
4243
import java.lang.reflect.Type;
43-
44-
import javax.ws.rs.core.Context;
44+
import java.util.HashSet;
45+
import java.util.List;
46+
import java.util.Set;
4547

4648
import javax.inject.Inject;
4749
import javax.inject.Singleton;
50+
import javax.ws.rs.core.Context;
4851

4952
import org.glassfish.jersey.internal.util.ReflectionHelper;
53+
import org.glassfish.jersey.internal.util.collection.LazyValue;
54+
import org.glassfish.jersey.internal.util.collection.Value;
55+
import org.glassfish.jersey.internal.util.collection.Values;
56+
import org.glassfish.jersey.process.internal.RequestScoped;
5057

5158
import org.glassfish.hk2.api.ActiveDescriptor;
5259
import org.glassfish.hk2.api.Factory;
@@ -55,6 +62,8 @@
5562
import org.glassfish.hk2.api.ServiceHandle;
5663
import org.glassfish.hk2.api.ServiceLocator;
5764
import org.glassfish.hk2.api.TypeLiteral;
65+
import org.glassfish.hk2.utilities.AbstractActiveDescriptor;
66+
import org.glassfish.hk2.utilities.BuilderHelper;
5867
import org.glassfish.hk2.utilities.InjecteeImpl;
5968
import org.glassfish.hk2.utilities.binding.AbstractBinder;
6069
import org.glassfish.hk2.utilities.cache.Cache;
@@ -64,6 +73,7 @@
6473
* Injection resolver for {@link Context @Context} injection annotation.
6574
*
6675
* @author Marek Potociar (marek.potociar at oracle.com)
76+
* @author Jakub Podlesak (jakub.podlesak at oracle.com)
6777
*/
6878
@Singleton
6979
public class ContextInjectionResolver implements InjectionResolver<Context> {
@@ -100,9 +110,9 @@ public Object resolve(Injectee injectee, ServiceHandle<?> root) {
100110
Injectee newInjectee;
101111

102112
if (isHk2Factory) {
103-
newInjectee = getInjectee(injectee, ReflectionHelper.getTypeArgument(requiredType, 0));
113+
newInjectee = getFactoryInjectee(injectee, ReflectionHelper.getTypeArgument(requiredType, 0));
104114
} else {
105-
newInjectee = injectee;
115+
newInjectee = foreignRequestScopedInjecteeCache.compute(injectee);
106116
}
107117

108118
ActiveDescriptor<?> ad = descriptorCache.compute(newInjectee);
@@ -133,7 +143,7 @@ public void dispose(Object instance) {
133143
};
134144
}
135145

136-
private Injectee getInjectee(final Injectee injectee, final Type requiredType) {
146+
private Injectee getFactoryInjectee(final Injectee injectee, final Type requiredType) {
137147
return new RequiredTypeOverridingInjectee(injectee, requiredType);
138148
}
139149

@@ -147,6 +157,16 @@ private RequiredTypeOverridingInjectee(final Injectee injectee, final Type requi
147157
}
148158
}
149159

160+
private static class DescriptorOverridingInjectee extends InjecteeImpl {
161+
162+
private static final long serialVersionUID = -3740895548611880189L;
163+
164+
private DescriptorOverridingInjectee(final Injectee injectee, final ActiveDescriptor descriptor) {
165+
super(injectee);
166+
setInjecteeDescriptor(descriptor);
167+
}
168+
}
169+
150170
@Override
151171
public boolean isConstructorParameterIndicator() {
152172
return true;
@@ -156,4 +176,49 @@ public boolean isConstructorParameterIndicator() {
156176
public boolean isMethodParameterIndicator() {
157177
return false;
158178
}
179+
180+
181+
private final Cache<Injectee, Injectee> foreignRequestScopedInjecteeCache =
182+
new Cache<Injectee, Injectee>(new Computable<Injectee, Injectee>() {
183+
@Override
184+
public Injectee compute(Injectee injectee) {
185+
if (injectee.getParent() != null) {
186+
if (Field.class.isAssignableFrom(injectee.getParent().getClass())) {
187+
Field f = (Field) injectee.getParent();
188+
if (foreignRequestScopedComponents.get().contains(f.getDeclaringClass())) {
189+
final Class<?> clazz = f.getType();
190+
if (serviceLocator.getServiceHandle(clazz).getActiveDescriptor().getScopeAnnotation()
191+
== RequestScoped.class) {
192+
final AbstractActiveDescriptor<Object> descriptor =
193+
BuilderHelper.activeLink(clazz)
194+
.to(clazz)
195+
.in(RequestScoped.class)
196+
.build();
197+
return new DescriptorOverridingInjectee(injectee, descriptor);
198+
}
199+
}
200+
}
201+
}
202+
return injectee;
203+
}
204+
});
205+
206+
LazyValue<Set<Class<?>>> foreignRequestScopedComponents = Values.lazy(new Value<Set<Class<?>>>() {
207+
@Override
208+
public Set<Class<?>> get() {
209+
return getForeignRequestScopedComponents();
210+
}
211+
});
212+
213+
private Set<Class<?>> getForeignRequestScopedComponents() {
214+
final List<ForeignRequestScopeBridge> scopeBridges = serviceLocator.getAllServices(ForeignRequestScopeBridge.class);
215+
final Set<Class<?>> result = new HashSet<Class<?>>();
216+
for (ForeignRequestScopeBridge bridge : scopeBridges) {
217+
final Set<Class<?>> requestScopedComponents = bridge.getRequestScopedComponents();
218+
if (requestScopedComponents != null) {
219+
result.addAll(requestScopedComponents);
220+
}
221+
}
222+
return result;
223+
}
159224
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3+
*
4+
* Copyright (c) 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+
package org.glassfish.jersey.internal.inject;
41+
42+
import java.util.Set;
43+
44+
/**
45+
* Internal service to help determine
46+
* which HK2 factory provided components should be treated
47+
* as request scoped. This is to help avoid having
48+
* dynamic proxies of request scoped components injected into
49+
* factory created components managed by 3rd party component
50+
* providers
51+
*
52+
* Jakub Podlesak (jakub.podlesak at oracle.com).
53+
*/
54+
public interface ForeignRequestScopeBridge {
55+
56+
/**
57+
* Get me a set of classes that are managed outside of HK2
58+
* and should be treated as if HK2 request scoped.
59+
*
60+
* @return set of classes representing foreign request scoped components.
61+
*/
62+
Set<Class<?>> getRequestScopedComponents();
63+
}

examples/cdi-webapp/src/main/java/org/glassfish/jersey/examples/cdi/resources/MyApplication.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ public Set<Class<?>> getClasses() {
6161
classes.add(EchoParamResource.class);
6262
classes.add(EchoParamFieldResource.class);
6363
classes.add(EchoParamConstructorResource.class);
64+
classes.add(ProxyInjectedAppScopedResource.class);
65+
classes.add(RequestScopedResource.class);
6466
return classes;
6567
}
6668
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3+
*
4+
* Copyright (c) 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+
package org.glassfish.jersey.examples.cdi.resources;
41+
42+
import javax.enterprise.context.ApplicationScoped;
43+
import javax.ws.rs.GET;
44+
import javax.ws.rs.Path;
45+
import javax.ws.rs.core.Context;
46+
import javax.ws.rs.core.UriInfo;
47+
48+
/**
49+
* Application scoped CDI bean to demonstrate a dynamic proxy is being injected
50+
* for URI info so that actual request information is available.
51+
*
52+
* @author Jakub Podlesak (jakub.podlesak at oralcle.com)
53+
*/
54+
@ApplicationScoped
55+
@Path("ui-app")
56+
public class ProxyInjectedAppScopedResource {
57+
58+
@Context UriInfo uiField;
59+
60+
@Path("{p}")
61+
@GET
62+
public String getUri(@Context UriInfo uiParam) {
63+
if (uiParam == uiField) {
64+
throw new IllegalStateException("Dynamic proxy expected in the uiField");
65+
}
66+
return uiField.getRequestUri().getPath();
67+
}
68+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3+
*
4+
* Copyright (c) 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+
package org.glassfish.jersey.examples.cdi.resources;
41+
42+
import javax.enterprise.context.ApplicationScoped;
43+
import javax.enterprise.context.RequestScoped;
44+
import javax.ws.rs.GET;
45+
import javax.ws.rs.Path;
46+
import javax.ws.rs.core.Context;
47+
import javax.ws.rs.core.UriInfo;
48+
49+
/**
50+
* Request scoped CDI bean to demonstrate no dynamic proxy is being injected
51+
* for JAX-RS request scoped URI info.
52+
*
53+
* @author Jakub Podlesak (jakub.podlesak at oralcle.com)
54+
*/
55+
@RequestScoped
56+
@Path("ui-req")
57+
public class RequestScopedResource {
58+
59+
@Context UriInfo uiField;
60+
61+
@Path("{p}")
62+
@GET
63+
public String getUri(@Context UriInfo uiParam) {
64+
if (uiParam != uiField) {
65+
throw new IllegalStateException("No dynamic proxy expected in the uiField");
66+
}
67+
return uiField.getRequestUri().getPath();
68+
}
69+
}

0 commit comments

Comments
 (0)