You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by dj...@apache.org on 2010/07/13 01:52:52 UTC
svn commit: r963535 - in /incubator/aries/trunk/jndi: ./ jndi-url/
jndi-url/src/main/java/org/apache/aries/jndi/services/
jndi-url/src/main/java/org/apache/aries/jndi/url/
jndi-url/src/test/java/org/apache/aries/jndi/url/
Author: djencks
Date: Mon Jul 12 23:52:51 2010
New Revision: 963535
URL: http://svn.apache.org/viewvc?rev=963535&view=rev
Log:
ARIES-356 Make jndi proxy creation more flexible with cglib, and make proxy creation optional in the aries: namespace
Modified:
incubator/aries/trunk/jndi/jndi-url/pom.xml
incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/services/ServiceHelper.java
incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryContext.java
incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryListContext.java
incubator/aries/trunk/jndi/jndi-url/src/test/java/org/apache/aries/jndi/url/ServiceRegistryContextTest.java
incubator/aries/trunk/jndi/pom.xml
Modified: incubator/aries/trunk/jndi/jndi-url/pom.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jndi/jndi-url/pom.xml?rev=963535&r1=963534&r2=963535&view=diff
==============================================================================
--- incubator/aries/trunk/jndi/jndi-url/pom.xml (original)
+++ incubator/aries/trunk/jndi/jndi-url/pom.xml Mon Jul 12 23:52:51 2010
@@ -59,6 +59,11 @@
<scope>provided</scope>
</dependency>
<dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.cglib</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
<groupId>org.apache.aries.jndi</groupId>
<artifactId>org.apache.aries.jndi.core</artifactId>
<scope>test</scope>
Modified: incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/services/ServiceHelper.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/services/ServiceHelper.java?rev=963535&r1=963534&r2=963535&view=diff
==============================================================================
--- incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/services/ServiceHelper.java (original)
+++ incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/services/ServiceHelper.java Mon Jul 12 23:52:51 2010
@@ -22,20 +22,26 @@ import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.naming.NamingException;
+import net.sf.cglib.proxy.Dispatcher;
+import net.sf.cglib.proxy.Enhancer;
import org.apache.aries.jndi.url.OsgiName;
import org.apache.aries.util.BundleToClassLoaderAdapter;
import org.osgi.framework.Bundle;
@@ -70,6 +76,7 @@ public final class ServiceHelper
/** The cache to purge */
private final ConcurrentMap<ServiceKey, WeakReference<Object>> cache;
+
public CacheClearoutListener(ConcurrentMap<ServiceKey, WeakReference<Object>> pc)
{
cache = pc;
@@ -153,7 +160,7 @@ public final class ServiceHelper
}
}
- private static class JNDIServiceDamper implements InvocationHandler
+ private static class JNDIServiceDamper implements Callable<Object>
{
private BundleContext ctx;
private ServicePair pair;
@@ -171,8 +178,7 @@ public final class ServiceHelper
dynamic = d;
}
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
- {
+ public Object call() throws NamingException {
if (pair == null || pair.ref.getBundle() == null) {
if (dynamic) {
pair = findService(ctx, interfaceName, filter);
@@ -184,12 +190,7 @@ public final class ServiceHelper
if (pair == null) {
throw new ServiceException(interfaceName, ServiceException.UNREGISTERED);
}
-
- try {
- return method.invoke(pair.service, args);
- } catch (InvocationTargetException ite) {
- throw ite.getTargetException();
- }
+ return pair.service;
}
}
@@ -201,11 +202,12 @@ public final class ServiceHelper
/** A cache of proxies returned to the client */
private static final ConcurrentMap<ServiceKey, WeakReference<Object>> proxyCache = new ConcurrentHashMap<ServiceKey, WeakReference<Object>>();
- private static final CacheClearoutListener cacheClearoutListener = new CacheClearoutListener(
- proxyCache);
+ private static final CacheClearoutListener cacheClearoutListener = new CacheClearoutListener(proxyCache);
+
+ private static ProxyFactory proxyFactory;
public static Object getService(BundleContext ctx, OsgiName lookupName, String id,
- boolean dynamicRebind, Map<String, Object> env) throws NamingException
+ boolean dynamicRebind, Map<String, Object> env, boolean requireProxy) throws NamingException
{
Object result = null;
@@ -239,14 +241,14 @@ public final class ServiceHelper
}
if (pair != null) {
- result = proxy(interfaceName, filter, dynamicRebind, ctx, pair);
+ result = proxy(interfaceName, filter, dynamicRebind, ctx, pair, requireProxy);
}
return result;
}
private static Object proxy(final String interface1, final String filter, final boolean rebind,
- final BundleContext ctx, final ServicePair pair)
+ final BundleContext ctx, final ServicePair pair, final boolean requireProxy)
{
Object result = null;
Bundle owningBundle = ctx.getBundle();
@@ -266,7 +268,7 @@ public final class ServiceHelper
result = AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run()
{
- return proxyPriviledged(interface1, filter, rebind, ctx, pair);
+ return proxyPriviledged(interface1, filter, rebind, ctx, pair, requireProxy);
}
});
@@ -280,8 +282,7 @@ public final class ServiceHelper
return result;
}
- private static Object proxyPriviledged(String interface1, String filter, boolean dynamicRebind,
- BundleContext ctx, ServicePair pair)
+ private static Object proxyPriviledged(String interface1, String filter, boolean dynamicRebind, BundleContext ctx, ServicePair pair, boolean requireProxy)
{
String[] interfaces = null;
if (interface1 != null) {
@@ -317,14 +318,37 @@ public final class ServiceHelper
Bundle serviceProviderBundle = pair.ref.getBundle();
Bundle owningBundle = ctx.getBundle();
+ ProxyFactory proxyFactory = getProxyFactory();
+
for (String interfaceName : interfaces) {
try {
Class<?> potentialClass = serviceProviderBundle.loadClass(interfaceName);
-
+ if (Modifier.isFinal(potentialClass.getModifiers())) {
+ if (requireProxy) {
+ continue;
+ }
+ return pair.service;
+ }
+ if (!potentialClass.isInterface()) {
+ if (requireProxy && !proxyFactory.proxiesClasses()) {
+ continue;
+ }
+ try {
+ potentialClass.getConstructor(new Class[0]);
+ } catch (NoSuchMethodException e) {
+ if (requireProxy) {
+ continue;
+ }
+ return pair.service;
+ }
+ }
if (pair.ref.isAssignableTo(owningBundle, interfaceName)) {
clazz.add(potentialClass);
}
} catch (ClassNotFoundException e) {
+ if (!requireProxy) {
+ return pair.service;
+ }
}
}
@@ -332,15 +356,22 @@ public final class ServiceHelper
throw new IllegalArgumentException(Arrays.asList(interfaces).toString());
}
- InvocationHandler ih = new JNDIServiceDamper(ctx, interface1, filter, pair, dynamicRebind);
+ Callable<Object> ih = new JNDIServiceDamper(ctx, interface1, filter, pair, dynamicRebind);
// The ClassLoader needs to be able to load the service interface
// classes so it needs to be
// wrapping the service provider bundle. The class is actually defined
// on this adapter.
- return Proxy.newProxyInstance(new BundleToClassLoaderAdapter(serviceProviderBundle), clazz
- .toArray(new Class<?>[clazz.size()]), ih);
+ try {
+ return proxyFactory.createProxy(new BundleToClassLoaderAdapter(serviceProviderBundle), clazz
+ .toArray(new Class<?>[clazz.size()]), ih);
+ } catch (IllegalArgumentException e) {
+ if (requireProxy) {
+ throw e;
+ }
+ return pair.service;
+ }
}
private static ServicePair findService(BundleContext ctx, String interface1, String filter)
@@ -422,10 +453,106 @@ public final class ServiceHelper
pair.ref = ref;
pair.service = service;
- result = proxy(null, null, false, ctx, pair);
+ result = proxy(null, null, false, ctx, pair, true);
}
return result;
}
+ protected static synchronized ProxyFactory getProxyFactory() {
+ if (proxyFactory == null) {
+ try {
+ // Try load load a cglib class (to make sure it's actually available
+ // then create the cglib factory
+ ServiceHelper.class.getClassLoader().loadClass("net.sf.cglib.proxy.Enhancer");
+ proxyFactory = new CgLibProxyFactory();
+ } catch (Throwable t) {
+ proxyFactory = new JdkProxyFactory();
+ }
+ }
+ return proxyFactory;
+ }
+
+ private static Class[] getInterfaces(Class[] classes) {
+ Set<Class> interfaces = new HashSet<Class>();
+ for (Class clazz : classes) {
+ if (clazz.isInterface()) {
+ interfaces.add(clazz);
+ }
+ }
+ return toClassArray(interfaces);
+ }
+
+ private static Class[] toClassArray(Set<Class> classes) {
+ return classes.toArray(new Class[classes.size()]);
+ }
+
+ public static interface ProxyFactory {
+
+ Object createProxy(ClassLoader classLoader, Class[] classes, Callable<Object> dispatcher);
+
+ boolean proxiesClasses();
+ }
+
+ public static class JdkProxyFactory implements ProxyFactory {
+
+ public Object createProxy(final ClassLoader classLoader, final Class[] classes, final Callable<Object> dispatcher) {
+ return Proxy.newProxyInstance(classLoader, getInterfaces(classes), new InvocationHandler() {
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ try {
+ return method.invoke(dispatcher.call(), args);
+ } catch (InvocationTargetException ite) {
+ throw ite.getTargetException();
+ }
+ }
+ });
+ }
+
+ public boolean proxiesClasses() {
+ return false;
+ }
+
+ }
+
+ public static class CgLibProxyFactory implements ProxyFactory {
+
+ public Object createProxy(final ClassLoader classLoader, final Class[] classes, final Callable<Object> dispatcher) {
+ Enhancer e = new Enhancer();
+ e.setClassLoader(classLoader);
+ e.setSuperclass(getTargetClass(classes));
+ e.setInterfaces(getInterfaces(classes));
+ e.setInterceptDuringConstruction(false);
+ e.setCallback(new Dispatcher() {
+ public Object loadObject() throws Exception {
+ return dispatcher.call();
+ }
+ });
+ e.setUseFactory(false);
+ return e.create();
+ }
+
+ public boolean proxiesClasses() {
+ return true;
+ }
+
+ protected Class<?> getTargetClass(Class<?>[] interfaceNames) {
+ // Only allow class proxying if specifically asked to
+ Class<?> root = Object.class;
+ for (Class<?> clazz : interfaceNames) {
+ if (!clazz.isInterface()) {
+ if (root.isAssignableFrom(clazz)) {
+ root = clazz;
+ } else if (clazz.isAssignableFrom(root)) {
+ //nothing to do, root is correct
+ } else {
+ throw new IllegalArgumentException("Classes " + root.getClass().getName() + " and " + clazz.getName() + " are not in the same hierarchy");
+ }
+ }
+ }
+ return root;
+ }
+
+ }
+
+
}
Modified: incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryContext.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryContext.java?rev=963535&r1=963534&r2=963535&view=diff
==============================================================================
--- incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryContext.java (original)
+++ incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryContext.java Mon Jul 12 23:52:51 2010
@@ -96,7 +96,7 @@ public class ServiceRegistryContext exte
}
} else if ((OsgiName.SERVICE_PATH.equals(pathFragment) && OsgiName.OSGI_SCHEME.equals(schemeName))
|| (OsgiName.SERVICES_PATH.equals(pathFragment) && OsgiName.ARIES_SCHEME.equals(schemeName))) {
- result = ServiceHelper.getService(callerContext, validName, null, true, env);
+ result = ServiceHelper.getService(callerContext, validName, null, true, env, OsgiName.OSGI_SCHEME.equals(schemeName));
} else if (OsgiName.SERVICE_LIST_PATH.equals(pathFragment)) {
result = new ServiceRegistryListContext(callerContext, env, validName);
} else {
Modified: incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryListContext.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryListContext.java?rev=963535&r1=963534&r2=963535&view=diff
==============================================================================
--- incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryListContext.java (original)
+++ incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryListContext.java Mon Jul 12 23:52:51 2010
@@ -169,7 +169,7 @@ public class ServiceRegistryListContext
{
Object result = null;
- result = ServiceHelper.getService(callerContext, parentName, name, false, env);
+ result = ServiceHelper.getService(callerContext, parentName, name, false, env, true);
if (result == null) {
throw new NameNotFoundException(name.toString());
Modified: incubator/aries/trunk/jndi/jndi-url/src/test/java/org/apache/aries/jndi/url/ServiceRegistryContextTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jndi/jndi-url/src/test/java/org/apache/aries/jndi/url/ServiceRegistryContextTest.java?rev=963535&r1=963534&r2=963535&view=diff
==============================================================================
--- incubator/aries/trunk/jndi/jndi-url/src/test/java/org/apache/aries/jndi/url/ServiceRegistryContextTest.java (original)
+++ incubator/aries/trunk/jndi/jndi-url/src/test/java/org/apache/aries/jndi/url/ServiceRegistryContextTest.java Mon Jul 12 23:52:51 2010
@@ -476,7 +476,7 @@ public class ServiceRegistryContextTest
Binding bnd = ne.nextElement();
assertEquals(String.valueOf(reg.getReference().getProperty(Constants.SERVICE_ID)), bnd.getName());
- assertTrue("Class name not correct. Was: " + bnd.getClassName(), bnd.getClassName().contains("Proxy"));
+ assertTrue("Class name not correct. Was: " + bnd.getClassName(), bnd.getClassName().contains("Proxy") || bnd.getClassName().contains("EnhancerByCGLIB"));
Runnable r = (Runnable) bnd.getObject();
@@ -492,7 +492,7 @@ public class ServiceRegistryContextTest
bnd = ne.nextElement();
assertEquals(String.valueOf(reg2.getReference().getProperty(Constants.SERVICE_ID)), bnd.getName());
- assertTrue("Class name not correct. Was: " + bnd.getClassName(), bnd.getClassName().contains("Proxy"));
+ assertTrue("Class name not correct. Was: " + bnd.getClassName(), bnd.getClassName().contains("Proxy") || bnd.getClassName().contains("EnhancerByCGLIB"));
r = (Runnable) bnd.getObject();
Modified: incubator/aries/trunk/jndi/pom.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jndi/pom.xml?rev=963535&r1=963534&r2=963535&view=diff
==============================================================================
--- incubator/aries/trunk/jndi/pom.xml (original)
+++ incubator/aries/trunk/jndi/pom.xml Mon Jul 12 23:52:51 2010
@@ -75,6 +75,13 @@
<artifactId>org.apache.aries.util</artifactId>
<version>0.2-incubating-SNAPSHOT</version>
</dependency>
+ <!-- Use an OSGi enabled cglib version, so that BND can find the version information
+ and we can use it in integration tests -->
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.cglib</artifactId>
+ <version>2.1_3_4</version>
+ </dependency>
</dependencies>
</dependencyManagement>