You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by oz...@apache.org on 2010/01/11 15:37:47 UTC
svn commit: r897881 [1/2] - in
/incubator/aries/trunk/blueprint/blueprint-core: ./
src/main/java/org/apache/aries/blueprint/container/
src/main/java/org/apache/aries/blueprint/proxy/
src/test/java/org/apache/aries/blueprint/proxy/
Author: ozzy
Date: Mon Jan 11 14:37:45 2010
New Revision: 897881
URL: http://svn.apache.org/viewvc?rev=897881&view=rev
Log:
ARIES-85 integrate asm interceptor patch
Added:
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/AsmInterceptorWrapper.java
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/FinalModifierException.java
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxyClassBytecodeGenerationException.java
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxyClassDefinitionException.java
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxyClassInstantiationException.java
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassAdapter.java
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassGenerator.java
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassHierarchyAdapter.java
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassMethodHashSet.java
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/UnableToLoadProxyException.java
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/UnableToProxyException.java
incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/proxy/
incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/proxy/ProxySubclassGeneratorTest.java
incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassCovariant.java
incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassCovariantOverride.java
incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassFinal.java
incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassFinalMethod.java
incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassGeneral.java
incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassGeneric.java
incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassGenericSuper.java
incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassPrivateConstructor.java
incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/proxy/ProxyTestClassSuper.java
Modified:
incubator/aries/trunk/blueprint/blueprint-core/pom.xml
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java
incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/Collaborator.java
Modified: incubator/aries/trunk/blueprint/blueprint-core/pom.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/pom.xml?rev=897881&r1=897880&r2=897881&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/pom.xml (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/pom.xml Mon Jan 11 14:37:45 2010
@@ -70,6 +70,11 @@
<artifactId>slf4j-simple</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>asm</groupId>
+ <artifactId>asm-all</artifactId>
+ <optional>true</optional>
+ </dependency>
</dependencies>
<build>
Modified: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java?rev=897881&r1=897880&r2=897881&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java Mon Jan 11 14:37:45 2010
@@ -36,10 +36,9 @@
import org.apache.aries.blueprint.ComponentDefinitionRegistry;
import org.apache.aries.blueprint.ExtendedBlueprintContainer;
import org.apache.aries.blueprint.Interceptor;
-import org.apache.aries.blueprint.container.AbstractServiceReferenceRecipe.CgLibProxyFactory;
-import org.apache.aries.blueprint.container.AbstractServiceReferenceRecipe.JdkProxyFactory;
import org.apache.aries.blueprint.di.AbstractRecipe;
import org.apache.aries.blueprint.di.Recipe;
+import org.apache.aries.blueprint.proxy.AsmInterceptorWrapper;
import org.apache.aries.blueprint.proxy.CgLibInterceptorWrapper;
import org.apache.aries.blueprint.utils.ReflectionUtils;
import org.osgi.service.blueprint.container.ComponentDefinitionException;
@@ -613,27 +612,53 @@
return obj;
}
- private Object addInterceptors(Object original) throws ComponentDefinitionException{
-
+ private Object addInterceptors(Object original)
+ throws ComponentDefinitionException {
+
Object intercepted = null;
String beanName = getName();
- ComponentDefinitionRegistry reg = blueprintContainer.getComponentDefinitionRegistry();
+ ComponentDefinitionRegistry reg = blueprintContainer
+ .getComponentDefinitionRegistry();
ComponentMetadata metaData = reg.getComponentDefinition(beanName);
- List<Interceptor> interceptors = reg.getInterceptors(metaData);
- if(interceptors!=null && interceptors.size()>0){
+ List<Interceptor> interceptors = reg.getInterceptors(metaData);
+ if (interceptors != null && interceptors.size() > 0) {
+ boolean asmAvailable = false;
try {
- // Try load load a cglib class (to make sure it's actually available
- getClass().getClassLoader().loadClass("net.sf.cglib.proxy.Enhancer");
+ // Try load load an asm class (to make sure it's actually
+ // available)
+ getClass().getClassLoader().loadClass(
+ "org.objectweb.asm.ClassVisitor");
+ LOGGER.debug("asm available for interceptors");
+ asmAvailable = true;
} catch (Throwable t) {
- throw new ComponentDefinitionException("Interceptors have been configured but cglib can not be used", t);
- }
-
- intercepted = CgLibInterceptorWrapper.createProxyObject(original.getClass().getClassLoader(),
- metaData,
- interceptors,
- original,
- original.getClass().getInterfaces());
- }else{
+ try {
+ // Try load load a cglib class (to make sure it's actually
+ // available)
+ getClass().getClassLoader().loadClass(
+ "net.sf.cglib.proxy.Enhancer");
+ } catch (Throwable u) {
+ throw new ComponentDefinitionException(
+ "Interceptors have been configured but neither asm nor cglib are available",
+ u);
+ }
+ }
+ if (asmAvailable) {
+ // if asm is available we can proxy the original object with the
+ // AsmInterceptorWrapper
+ intercepted = AsmInterceptorWrapper.createProxyObject(original
+ .getClass().getClassLoader(), metaData, interceptors,
+ original, original.getClass());
+ } else {
+ LOGGER.debug("cglib available for interceptors");
+ // otherwise we're using cglib and need to use the interfaces
+ // with the CgLibInterceptorWrapper
+ intercepted = CgLibInterceptorWrapper.createProxyObject(
+ original.getClass().getClassLoader(), metaData,
+ interceptors, original, original.getClass()
+ .getInterfaces());
+ }
+
+ } else {
intercepted = original;
}
return intercepted;
Added: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/AsmInterceptorWrapper.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/AsmInterceptorWrapper.java?rev=897881&view=auto
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/AsmInterceptorWrapper.java (added)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/AsmInterceptorWrapper.java Mon Jan 11 14:37:45 2010
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint.proxy;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Proxy;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.aries.blueprint.Interceptor;
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+import org.osgi.service.blueprint.reflect.ComponentMetadata;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AsmInterceptorWrapper
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(AsmInterceptorWrapper.class);
+ final static String LOG_ENTRY = "Method entry: {}, args {}";
+ final static String LOG_EXIT = "Method exit: {}, returning {}";
+ final static String LOG_EXCEPTION = "Caught exception";
+
+ public static Object createProxyObject(ClassLoader cl, ComponentMetadata cm,
+ List<Interceptor> interceptors, Object delegate, Class<?>... classesToProxy)
+ {
+
+ LOGGER.debug(LOG_ENTRY, "createProxyObject", new Object[] { cl, cm, interceptors, delegate,
+ classesToProxy });
+
+ Object proxyObject = null;
+ try {
+ if (classesToProxy.length == 1 && !classesToProxy[0].isInterface()) {
+
+ Class<?> classToProxy = classesToProxy[0];
+ LOGGER.debug("Single class to proxy: {}", classToProxy.getName());
+
+ boolean isProxy = isProxyClass(classToProxy);
+ LOGGER.debug("Class already a proxy: {}", isProxy);
+
+ if (isProxy) {
+ try {
+ LOGGER.debug("Get a new instance of existing proxy class");
+ /*
+ * the class is already a proxy, we should just invoke
+ * the constructor to get a new instance of the proxy
+ * with a new Collaborator using the specified delegate
+ */
+ proxyObject = classToProxy.getConstructor(InvocationHandler.class).newInstance(
+ new Collaborator(cm, interceptors, delegate));
+ LOGGER.debug("New proxy object instance {}", proxyObject);
+ } catch (InvocationTargetException e) {
+ LOGGER.debug(LOG_EXCEPTION, e);
+ } catch (NoSuchMethodException e) {
+ LOGGER.debug(LOG_EXCEPTION, e);
+ } catch (InstantiationException e) {
+ LOGGER.debug(LOG_EXCEPTION, e);
+ } catch (IllegalArgumentException e) {
+ LOGGER.debug(LOG_EXCEPTION, e);
+ } catch (SecurityException e) {
+ LOGGER.debug(LOG_EXCEPTION, e);
+ } catch (IllegalAccessException e) {
+ LOGGER.debug(LOG_EXCEPTION, e);
+ }
+ } else {
+ // we should generate a subclass proxy of the given class
+ LOGGER.debug("Generating a subclass proxy for: {}", classToProxy.getName());
+ proxyObject = createSubclassProxy(classToProxy, cm, interceptors, delegate);
+ }
+
+ } else {
+ // we had more than one class specified or only an interface
+ LOGGER.debug("Multiple classes or interface(s) to proxy: {}", classesToProxy);
+ // if we just have interfaces and no classes we default to using
+ // the interface proxy because we can't dynamically
+ // subclass more than one interface
+ // unless we have a class
+ // that implements all of them
+
+ // default to not subclass
+ boolean useSubclassProxy = false;
+
+ // loop through the classes checking if they are java interfaces
+ // if we find any class that isn't an interface we need to use
+ // the subclass proxy
+ Set<Class<?>> notInterfaces = new HashSet<Class<?>>();
+ for (Class<?> clazz : classesToProxy) {
+ if (!clazz.isInterface()) {
+ useSubclassProxy = true;
+ notInterfaces.add(clazz);
+ }
+ }
+
+ if (useSubclassProxy) {
+ LOGGER.debug("Going to use subclass proxy");
+ // if we need to use the subclass proxy then we need to find
+ // the most specific class
+ Class<?> classToProxy = null;
+ int deepest = 0;
+ // for each of the classes find out how deep it is in the
+ // hierarchy
+ for (Class<?> clazz : notInterfaces) {
+ Class<?> nextHighestClass = clazz;
+ int depth = 0;
+ do {
+ nextHighestClass = nextHighestClass.getSuperclass();
+ depth++;
+ } while (nextHighestClass != null);
+ if (depth > deepest) {
+ // if we find a class deeper than the one we already
+ // had
+ // it becomes the new most specific
+ deepest = depth;
+ classToProxy = clazz;
+ }
+ }
+ LOGGER.debug("Most specific class to proxy: {}", classToProxy);
+ proxyObject = createSubclassProxy(classToProxy, cm, interceptors, delegate);
+ } else {
+ LOGGER.debug("Going to use interface proxy");
+ proxyObject = Proxy.newProxyInstance(cl, classesToProxy, new Collaborator(cm,
+ interceptors, delegate));
+ }
+
+ }
+ } catch (UnableToProxyException e) {
+ // translate UnableToProxyException into
+ // ComponentDefinitionException
+ // if the bean is final, or otherwise unable to be proxied.
+ LOGGER.debug(LOG_EXIT, "createProxyObject", e);
+ throw new ComponentDefinitionException("Unable to proxy bean for interceptors: " + e);
+ }
+
+ LOGGER.debug(LOG_EXIT, "createProxyObject", proxyObject);
+
+ return proxyObject;
+ }
+
+ private static Object createSubclassProxy(Class<?> classToProxy, ComponentMetadata cm,
+ List<Interceptor> interceptors, Object delegate) throws UnableToProxyException
+ {
+ LOGGER.debug(LOG_ENTRY, "createSubclassProxy", new Object[] { classToProxy, cm, interceptors,
+ delegate });
+ LOGGER.debug("Generating a subclass proxy for: {}", classToProxy.getName());
+ try {
+ Object proxyObject = ProxySubclassGenerator.newProxySubclassInstance(classToProxy,
+ new Collaborator(cm, interceptors, delegate));
+
+ LOGGER.debug("Generated subclass proxy object: {}", proxyObject);
+ LOGGER.debug(LOG_EXIT, "createSubclassProxy", proxyObject);
+ return proxyObject;
+ } catch (UnableToProxyException e) {
+ LOGGER.debug(LOG_EXCEPTION, e);
+ LOGGER.debug(LOG_EXIT, "createSubclassProxy", e);
+ throw e;
+ }
+ }
+
+ static boolean isProxyClass(Class<?> clazz)
+ {
+ LOGGER.debug(LOG_ENTRY, "isProxyClass", new Object[] { clazz });
+ boolean isProxyObject = false;
+ isProxyObject = ProxySubclassGenerator.isProxySubclass(clazz);
+ LOGGER.debug(LOG_EXIT, "isProxyClass", isProxyObject);
+ return isProxyObject;
+ }
+
+ static Object unwrapObject(Object o)
+ {
+ LOGGER.debug(LOG_ENTRY, "unwrapObject", new Object[] { o });
+ InvocationHandler ih = null;
+ Object unwrappedObject = null;
+ if (ProxySubclassGenerator.isProxySubclass(o.getClass())) {
+ ih = ProxySubclassGenerator.getInvocationHandler(o);
+ } else {
+ ih = Proxy.getInvocationHandler(o);
+ }
+ if (ih instanceof Collaborator) {
+ unwrappedObject = ((Collaborator) ih).object;
+ }
+ LOGGER.debug(LOG_EXIT, "unwrapObject", unwrappedObject);
+ return unwrappedObject;
+ }
+
+}
Modified: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/Collaborator.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/Collaborator.java?rev=897881&r1=897880&r2=897881&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/Collaborator.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/Collaborator.java Mon Jan 11 14:37:45 2010
@@ -116,19 +116,23 @@
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object toReturn = null;
-
+
// Added method to unwrap from the collaborator.
if (method.getName().equals("unwrapObject")
&& method.getDeclaringClass() == WrapperedObject.class) {
toReturn = object;
} else
- // Unwrap calls for equals
+ // Unwrap calls for equals
if (method.getName().equals("equals")
&& method.getDeclaringClass() == Object.class) {
+ // replace the wrapper with the unwrapped object, to
+ // enable object identity etc to function.
if (args[0] instanceof WrapperedObject) {
- //replace the wrapper with the unwrapped object, to
- //enable object identity etc to function.
+ // unwrap in the WrapperedObject case
args[0] = ((WrapperedObject) args[0]).unwrapObject();
+ } else if (AsmInterceptorWrapper.isProxyClass(args[0].getClass())) {
+ // unwrap in the asm case
+ args[0] = AsmInterceptorWrapper.unwrapObject(args[0]);
}
toReturn = delegate.invoke(proxy, method, args);
} else
Added: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/FinalModifierException.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/FinalModifierException.java?rev=897881&view=auto
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/FinalModifierException.java (added)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/FinalModifierException.java Mon Jan 11 14:37:45 2010
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint.proxy;
+
+public class FinalModifierException extends UnableToProxyException
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -3139392096074404448L;
+ public String finalMethods = null;
+
+ public FinalModifierException(Class<?> clazz)
+ {
+ super(clazz);
+ }
+
+ public FinalModifierException(Class<?> clazz, String finalMethods)
+ {
+ super(clazz);
+ this.finalMethods = finalMethods;
+ }
+
+ public boolean isFinalClass()
+ {
+ return (finalMethods == null || finalMethods.equals(""));
+ }
+
+ public String getFinalMethods()
+ {
+ return finalMethods;
+ }
+
+}
Added: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxyClassBytecodeGenerationException.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxyClassBytecodeGenerationException.java?rev=897881&view=auto
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxyClassBytecodeGenerationException.java (added)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxyClassBytecodeGenerationException.java Mon Jan 11 14:37:45 2010
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint.proxy;
+
+public class ProxyClassBytecodeGenerationException extends UnableToProxyException
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -8015178382210046784L;
+
+ public ProxyClassBytecodeGenerationException(String string, Throwable throwable)
+ {
+ super(string, throwable);
+ }
+}
Added: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxyClassDefinitionException.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxyClassDefinitionException.java?rev=897881&view=auto
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxyClassDefinitionException.java (added)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxyClassDefinitionException.java Mon Jan 11 14:37:45 2010
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint.proxy;
+
+public class ProxyClassDefinitionException extends UnableToProxyException
+{
+ /**
+ *
+ */
+ private static final long serialVersionUID = 604215734831044743L;
+
+ public ProxyClassDefinitionException(String className, Exception e)
+ {
+ super(className, e);
+ }
+}
Added: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxyClassInstantiationException.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxyClassInstantiationException.java?rev=897881&view=auto
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxyClassInstantiationException.java (added)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxyClassInstantiationException.java Mon Jan 11 14:37:45 2010
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint.proxy;
+
+public class ProxyClassInstantiationException extends UnableToProxyException
+{
+ /**
+ *
+ */
+ private static final long serialVersionUID = -2303296601108980837L;
+
+ public ProxyClassInstantiationException(Class<?> clazz, Exception e)
+ {
+ super(clazz, e);
+ }
+
+}
Added: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassAdapter.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassAdapter.java?rev=897881&view=auto
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassAdapter.java (added)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassAdapter.java Mon Jan 11 14:37:45 2010
@@ -0,0 +1,618 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint.proxy;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.GeneratorAdapter;
+import org.objectweb.asm.commons.Method;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ProxySubclassAdapter extends ClassAdapter implements Opcodes
+{
+
+ private static final Type STRING_TYPE = Type.getType(String.class);
+ private static final Type CLASS_TYPE = Type.getType(Class.class);
+ private static final Type OBJECT_TYPE = Type.getType(Object.class);
+ private static final Type METHOD_TYPE = Type.getType(java.lang.reflect.Method.class);
+ private static final Type IH_TYPE = Type.getType(InvocationHandler.class);
+ private static final Type[] NO_ARGS = new Type[] {};
+
+ private static final String IH_FIELD = "ih";
+
+ private static Logger LOGGER = LoggerFactory.getLogger(ProxySubclassAdapter.class);
+
+ private String newClassName = null;
+ private String superclassBinaryName = null;
+ private Class<?> superclassClass = null;
+ private ClassLoader loader = null;
+ private Type newClassType = null;
+ private GeneratorAdapter staticAdapter = null;
+ private String currentlyAnalysedClassName = null;
+ private Class<?> currentlyAnalysedClass = null;
+ private String currentClassFieldName = null;
+
+ public ProxySubclassAdapter(ClassVisitor writer, String newClassName, ClassLoader loader)
+ {
+ // call the superclass constructor
+ super(writer);
+ // the writer is now the cv in the superclass of ClassAdapter
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "ProxySubclassAdapter", new Object[] { this, writer,
+ newClassName });
+
+ // set the newClassName field
+ this.newClassName = newClassName;
+ // set the newClassType descriptor
+ newClassType = Type.getType("L" + newClassName + ";");
+
+ // set the classloader
+ this.loader = loader;
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "ProxySubclassAdapter", this);
+ }
+
+ /*
+ * This method visits the class to generate the new subclass.
+ *
+ * The following things happen here: 1. The class is renamed to a dynamic
+ * name 2. The existing class name is changed to be the superclass name so
+ * that the generated class extends the original class. 3. A private field
+ * is added to store an invocation handler 4. A constructor is added that
+ * takes an invocation handler as an argument 5. The constructor method
+ * instantiates an instance of the superclass 6. The constructor method sets
+ * the invocation handler so the invoke method can be called from all the
+ * subsequently rewritten methods 7. Add a getInvocationHandler() method 8.
+ * store a static Class object of the superclass so we can reflectively find
+ * methods later
+ */
+ public void visit(int version, int access, String name, String signature, String superName,
+ String[] interfaces)
+ {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "visit", new Object[] { version, access, name,
+ signature, superName, interfaces });
+
+ // store the superclass binary name
+ this.superclassBinaryName = name.replaceAll("/", "\\.");
+
+ try {
+ this.superclassClass = Class.forName(superclassBinaryName, false, loader);
+ } catch (ClassNotFoundException cnfe) {
+ throw new TypeNotPresentException(superclassBinaryName, cnfe);
+ }
+
+ // move the existing class name to become the superclass
+ // modify the version of the dynamic subclass to be Java 1.6
+ int newVersion = Opcodes.V1_6;
+ // keep the same access and signature as the superclass
+ // remove all the superclass interfaces because they will be inherited
+ // from the superclass anyway
+ cv.visit(newVersion, access, newClassName, signature, name, null);
+
+ // add a private field for the invocation handler
+ // this isn't static in case we have multiple instances of the same
+ // proxy
+ cv.visitField(ACC_PRIVATE, IH_FIELD, Type.getDescriptor(InvocationHandler.class), null, null);
+
+ // create a static adapter for generating a static initialiser method in
+ // the generated subclass
+ staticAdapter = new GeneratorAdapter(ACC_STATIC,
+ new Method("<clinit>", Type.VOID_TYPE, NO_ARGS), null, null, cv);
+
+ // add a constructor method that takes an invocation handler as an
+ // argument
+ Method m = new Method("<init>", Type.VOID_TYPE, new Type[] { IH_TYPE });
+ GeneratorAdapter methodAdapter = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cv);
+ // loadthis
+ methodAdapter.loadThis();
+ // if we have java.* as a supertype call that zero args constructor
+ if (superclassBinaryName.startsWith("java.") || superclassBinaryName.startsWith("javax.")) {
+ methodAdapter.invokeConstructor(Type.getType(superclassClass), new Method("<init>",
+ Type.VOID_TYPE, NO_ARGS));
+ }
+ // otherwise invoke the java.lang.Object no args constructor
+ else {
+ methodAdapter.invokeConstructor(OBJECT_TYPE, new Method("<init>", Type.VOID_TYPE, NO_ARGS));
+ }
+ // call from the constructor to setInvocationHandler
+ Method setter = new Method("setInvocationHandler", Type.VOID_TYPE, new Type[] { IH_TYPE });
+ // load this
+ methodAdapter.loadThis();
+ // load the supplied invocation handler arg
+ methodAdapter.loadArgs();
+ // invoke the setter method
+ methodAdapter.invokeVirtual(newClassType, setter);
+ methodAdapter.returnValue();
+ methodAdapter.endMethod();
+
+ // add a method for getting the invocation handler
+ m = new Method("getInvocationHandler", IH_TYPE, NO_ARGS);
+ methodAdapter = new GeneratorAdapter(ACC_PUBLIC | ACC_FINAL, m, null, null, cv);
+ // load this to get the field
+ methodAdapter.loadThis();
+ // get the ih field and return
+ methodAdapter.getField(newClassType, IH_FIELD, IH_TYPE);
+ methodAdapter.returnValue();
+ methodAdapter.endMethod();
+
+ // add a method for setting the invocation handler
+ methodAdapter = new GeneratorAdapter(ACC_PUBLIC | ACC_FINAL, setter, null, null, cv);
+ // load this to put the field
+ methodAdapter.loadThis();
+ // load the method arguments (i.e. the invocation handler) to the stack
+ methodAdapter.loadArgs();
+ // set the ih field using the method argument
+ methodAdapter.putField(newClassType, IH_FIELD, IH_TYPE);
+ methodAdapter.returnValue();
+ methodAdapter.endMethod();
+
+ // loop through the class hierarchy to get any needed methods off the
+ // supertypes
+ // start by finding the methods declared on the class of interest (the
+ // superclass of our dynamic subclass)
+ java.lang.reflect.Method[] observedMethods = superclassClass.getDeclaredMethods();
+ // add the methods to a set of observedMethods
+ ProxySubclassMethodHashSet<String> setOfObservedMethods = new ProxySubclassMethodHashSet<String>(
+ observedMethods.length);
+ setOfObservedMethods.addMethodArray(observedMethods);
+ // get the next superclass in the hierarchy
+ Class<?> nextSuperClass = superclassClass.getSuperclass();
+ while (nextSuperClass != null) {
+ // set the fields for the current class
+ setCurrentAnalysisClassFields(nextSuperClass);
+
+ // add a static field and static initializer code to the generated
+ // subclass
+ // for each of the superclasses in the hierarchy
+ addClassStaticField(currentlyAnalysedClassName);
+
+ LOGGER.debug("Class currently being analysed: {} {}", currentlyAnalysedClassName,
+ currentlyAnalysedClass);
+
+ // now find the methods declared on the current class and add them
+ // to a set of foundMethods
+ java.lang.reflect.Method[] foundMethods = currentlyAnalysedClass.getDeclaredMethods();
+ ProxySubclassMethodHashSet<String> setOfFoundMethods = new ProxySubclassMethodHashSet<String>(
+ foundMethods.length);
+ setOfFoundMethods.addMethodArray(foundMethods);
+ // remove from the set of foundMethods any methods we saw on a
+ // subclass
+ // because we want to use the lowest level declaration of a method
+ setOfFoundMethods.removeAll(setOfObservedMethods);
+ try {
+ // read the current class and use a
+ // ProxySubclassHierarchyAdapter
+ // to process only methods on that class that are in the list
+ ClassReader cr = new ClassReader(loader.getResourceAsStream(currentlyAnalysedClass
+ .getName().replaceAll("\\.", "/")
+ + ".class"));
+ ClassVisitor hierarchyAdapter = new ProxySubclassHierarchyAdapter(this, setOfFoundMethods);
+ cr.accept(hierarchyAdapter, ClassReader.SKIP_DEBUG);
+ } catch (IOException e) {
+ throw new TypeNotPresentException(currentlyAnalysedClassName, e);
+ }
+ // now add the foundMethods to the overall list of observed methods
+ setOfObservedMethods.addAll(setOfFoundMethods);
+ // get the next class up in the hierarchy and go again
+ nextSuperClass = currentlyAnalysedClass.getSuperclass();
+ }
+
+ // we've finished looking at the superclass hierarchy
+ // set the fields for the immediate superclass of our dynamic subclass
+ setCurrentAnalysisClassFields(superclassClass);
+
+ // add the class static field
+ addClassStaticField(currentlyAnalysedClassName);
+ // we do the lowest class last because we are already visiting the class
+ // when in this adapter code
+ // now we are ready to visit all the methods on the lowest class
+ // which will happen by the ASM ClassVisitor implemented in this adapter
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "visit");
+ }
+
+ public void visitSource(String source, String debug)
+ {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "visitSource", new Object[] { source, debug });
+
+ // set the source to null since the class is generated on the fly and
+ // not compiled
+ cv.visitSource(null, null);
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "visitSource");
+ }
+
+ public void visitEnd()
+ {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "visitEnd");
+
+ // this method is called when we reach the end of the class
+ // so it is time to make sure the static initialiser method is closed
+ staticAdapter.returnValue();
+ staticAdapter.endMethod();
+ // now delegate to the cv
+ cv.visitEnd();
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "visitEnd");
+ }
+
+ /*
+ * This method is called on each method of the superclass (and all parent
+ * classes up to Object) Each of these methods is visited in turn and the
+ * code here generates the byte code for the InvocationHandler to call the
+ * methods on the superclass.
+ */
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+ String[] exceptions)
+ {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "visitMethod", new Object[] { access, name, desc,
+ signature, exceptions });
+
+ /*
+ * Check the method access and handle the method types we don't want to
+ * copy: final methods (issue warnings if these are not methods from
+ * java.* classes) static methods (initialiser and others) private
+ * methods constructors (for now we don't copy any constructors)
+ * abstract (we don't proxy/implement but we must copy the method or the
+ * subclass is invalid) everything else we process to proxy
+ */
+
+ LOGGER.debug("Method name: {} with descriptor: {}", name, desc);
+
+ MethodVisitor methodVisitorToReturn = null;
+
+ if (name.equals("<init>")) {
+ // we may need to do something extra with constructors later
+ // e.g. include bytecode for calling super with the same args
+ // since we currently rely on the super having a zero args
+ // constructor
+ // we need to issue an error if we don't find one
+
+ // for now we return null to ignore them
+ methodVisitorToReturn = null;
+ } else if (name.equals("<clinit>")) {
+ // don't copy static initialisers from the superclass into the new
+ // subclass
+ methodVisitorToReturn = null;
+ } else if ((access & ACC_FINAL) != 0) {
+ // since we check for final methods in the ProxySubclassGenerator we
+ // should never get here
+ methodVisitorToReturn = null;
+ } else if ((access & ACC_SYNTHETIC) != 0) {
+ // synthetic methods are generated by the compiler for covariance
+ // etc
+ // we shouldn't copy them or we will have duplicate methods
+ methodVisitorToReturn = null;
+ } else if ((access & ACC_PRIVATE) != 0) {
+ // don't copy private methods from the superclass
+ methodVisitorToReturn = null;
+ } else if ((access & ACC_STATIC) != 0) {
+ // don't copy static methods
+ methodVisitorToReturn = null;
+ } else if ((access & ACC_ABSTRACT) != 0) {
+ // if we find an abstract method we need to copy it as is to make
+ // the subclass valid
+ methodVisitorToReturn = cv.visitMethod(access, name, desc, signature, exceptions);
+ } else if (!(((access & ACC_PUBLIC) != 0) || ((access & ACC_PROTECTED) != 0) || ((access & ACC_PRIVATE) != 0))) {
+ // the default (package) modifier value is 0, so by using & with any
+ // of the other
+ // modifier values and getting a result of zero means that we have
+ // default accessibility
+
+ // check the package in which the method is declared against the
+ // package
+ // where the generated subclass will be
+ // if they are the same process the method otherwise ignore it
+ if (currentlyAnalysedClass.getPackage().equals(superclassClass.getPackage())) {
+ processMethod(access, name, desc, signature, exceptions);
+ methodVisitorToReturn = null;
+ } else {
+ methodVisitorToReturn = null;
+ }
+ } else {
+ processMethod(access, name, desc, signature, exceptions);
+ // return null because we don't want the original method code from
+ // the superclass
+ methodVisitorToReturn = null;
+ }
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "visitMethod", methodVisitorToReturn);
+
+ return methodVisitorToReturn;
+
+ }
+
+ private void processMethod(int access, String name, String desc, String signature,
+ String[] exceptions)
+ {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "processMethod", new Object[] { access, name, desc,
+ signature, exceptions });
+
+ LOGGER.debug("Processing method: {} with descriptor {}", name, desc);
+
+ // identify the target method parameters and return type
+ Method currentTransformMethod = new Method(name, desc);
+ Type[] targetMethodParameters = currentTransformMethod.getArgumentTypes();
+ Type returnType = currentTransformMethod.getReturnType();
+
+ // we create a static field for each method we encounter with a name
+ // like method_parm1_parm2...
+ StringBuilder methodStaticFieldNameBuilder = new StringBuilder(name);
+ // for each a parameter get the name and add it to the field removing
+ // the dots first
+ for (Type t : targetMethodParameters) {
+ methodStaticFieldNameBuilder.append("_");
+ methodStaticFieldNameBuilder.append(t.getClassName().replaceAll("\\[\\]", "Array")
+ .replaceAll("\\.", ""));
+ }
+ String methodStaticFieldName = methodStaticFieldNameBuilder.toString();
+
+ // add a private static field for the method
+ cv.visitField(ACC_PRIVATE | ACC_STATIC, methodStaticFieldName, METHOD_TYPE.getDescriptor(),
+ null, null);
+
+ // visit the method using the class writer, delegated through the method
+ // visitor and generator
+ // modify the method access so that any native methods aren't
+ // described as native
+ // since they won't be native in proxy form
+ // also stop methods being marked synchronized on the proxy as they will
+ // be sync
+ // on the real object
+ int newAccess = access & (~ACC_NATIVE) & (~ACC_SYNCHRONIZED);
+ MethodVisitor mv = cv.visitMethod(newAccess, name, desc, signature, exceptions);
+ // use a GeneratorAdapter to build the invoke call directly in byte code
+ GeneratorAdapter methodAdapter = new GeneratorAdapter(mv, newAccess, name, desc);
+
+ /*
+ * Stage 1 creates the bytecode for adding the reflected method of the
+ * superclass to a static field in the subclass: private static Method
+ * methodName_parm1_parm2... = null; static{ methodName_parm1_parm2... =
+ * superClass.getDeclaredMethod(methodName,new Class[]{method args}; }
+ *
+ * Stage 2 is to call the ih.invoke(this,methodName_parm1_parm2,args) in
+ * the new subclass methods Stage 3 is to cast the return value to the
+ * correct type
+ */
+
+ /*
+ * Stage 1 use superClass.getMethod(methodName,new Class[]{method args}
+ * from the Class object on the stack
+ */
+
+ // load the static superclass Class onto the stack
+ staticAdapter.getStatic(newClassType, currentClassFieldName, CLASS_TYPE);
+
+ // push the method name string arg onto the stack
+ staticAdapter.push(name);
+
+ // create an array of the method parm class[] arg
+ staticAdapter.push(targetMethodParameters.length);
+ staticAdapter.newArray(CLASS_TYPE);
+ int index = 0;
+ for (Type t : targetMethodParameters) {
+ staticAdapter.dup();
+ staticAdapter.push(index);
+ switch (t.getSort())
+ {
+ case Type.BOOLEAN:
+ staticAdapter.getStatic(Type.getType(java.lang.Boolean.class), "TYPE", CLASS_TYPE);
+ break;
+ case Type.BYTE:
+ staticAdapter.getStatic(Type.getType(java.lang.Byte.class), "TYPE", CLASS_TYPE);
+ break;
+ case Type.CHAR:
+ staticAdapter.getStatic(Type.getType(java.lang.Character.class), "TYPE", CLASS_TYPE);
+ break;
+ case Type.DOUBLE:
+ staticAdapter.getStatic(Type.getType(java.lang.Double.class), "TYPE", CLASS_TYPE);
+ break;
+ case Type.FLOAT:
+ staticAdapter.getStatic(Type.getType(java.lang.Float.class), "TYPE", CLASS_TYPE);
+ break;
+ case Type.INT:
+ staticAdapter.getStatic(Type.getType(java.lang.Integer.class), "TYPE", CLASS_TYPE);
+ break;
+ case Type.LONG:
+ staticAdapter.getStatic(Type.getType(java.lang.Long.class), "TYPE", CLASS_TYPE);
+ break;
+ case Type.SHORT:
+ staticAdapter.getStatic(Type.getType(java.lang.Short.class), "TYPE", CLASS_TYPE);
+ break;
+ default:
+ case Type.OBJECT:
+ staticAdapter.push(t);
+ break;
+ }
+ staticAdapter.arrayStore(CLASS_TYPE);
+ index++;
+ }
+
+ // invoke the getMethod
+ staticAdapter.invokeVirtual(CLASS_TYPE, new Method("getDeclaredMethod", METHOD_TYPE,
+ new Type[] { STRING_TYPE, Type.getType(java.lang.Class[].class) }));
+
+ // store the reflected method in the static field
+ staticAdapter.putStatic(newClassType, methodStaticFieldName, METHOD_TYPE);
+
+ /*
+ * Stage 2 call the ih.invoke(this,supermethod,parms)
+ */
+
+ // load this to get the ih field
+ methodAdapter.loadThis();
+ // load the invocation handler from the field (the location of the
+ // InvocationHandler.invoke)
+ methodAdapter.getField(newClassType, IH_FIELD, IH_TYPE);
+ // loadThis (the first arg of the InvocationHandler.invoke)
+ methodAdapter.loadThis();
+ // load the method to invoke (the second arg of the
+ // InvocationHandler.invoke)
+ methodAdapter.getStatic(newClassType, methodStaticFieldName, METHOD_TYPE);
+ // load all the method arguments onto the stack as an object array (the
+ // third arg of the InvocationHandler.invoke)
+ methodAdapter.loadArgArray();
+ // generate the invoke method
+ Method invocationHandlerInvokeMethod = new Method("invoke", OBJECT_TYPE, new Type[] {
+ OBJECT_TYPE, METHOD_TYPE, Type.getType(java.lang.Object[].class) });
+ // call the invoke method of the invocation handler
+ methodAdapter.invokeInterface(IH_TYPE, invocationHandlerInvokeMethod);
+
+ /*
+ * Stage 3 the returned object is now on the top of the stack We need to
+ * check the type and cast as necessary
+ */
+ switch (returnType.getSort())
+ {
+ case Type.BOOLEAN:
+ methodAdapter.cast(OBJECT_TYPE, Type.getType(Boolean.class));
+ methodAdapter.unbox(Type.BOOLEAN_TYPE);
+ break;
+ case Type.BYTE:
+ methodAdapter.cast(OBJECT_TYPE, Type.getType(Byte.class));
+ methodAdapter.unbox(Type.BYTE_TYPE);
+ break;
+ case Type.CHAR:
+ methodAdapter.cast(OBJECT_TYPE, Type.getType(Character.class));
+ methodAdapter.unbox(Type.CHAR_TYPE);
+ break;
+ case Type.DOUBLE:
+ methodAdapter.cast(OBJECT_TYPE, Type.getType(Double.class));
+ methodAdapter.unbox(Type.DOUBLE_TYPE);
+ break;
+ case Type.FLOAT:
+ methodAdapter.cast(OBJECT_TYPE, Type.getType(Float.class));
+ methodAdapter.unbox(Type.FLOAT_TYPE);
+ break;
+ case Type.INT:
+ methodAdapter.cast(OBJECT_TYPE, Type.getType(Integer.class));
+ methodAdapter.unbox(Type.INT_TYPE);
+ break;
+ case Type.LONG:
+ methodAdapter.cast(OBJECT_TYPE, Type.getType(Long.class));
+ methodAdapter.unbox(Type.LONG_TYPE);
+ break;
+ case Type.SHORT:
+ methodAdapter.cast(OBJECT_TYPE, Type.getType(Short.class));
+ methodAdapter.unbox(Type.SHORT_TYPE);
+ break;
+ case Type.VOID:
+ methodAdapter.cast(OBJECT_TYPE, Type.getType(Void.class));
+ methodAdapter.unbox(Type.VOID_TYPE);
+ break;
+ default:
+ case Type.OBJECT:
+ // in this case check the cast and cast the object to the return
+ // type
+ methodAdapter.checkCast(returnType);
+ methodAdapter.cast(OBJECT_TYPE, returnType);
+ break;
+ }
+ // return the (appropriately cast) result of the invocation from the
+ // stack
+ methodAdapter.returnValue();
+ // end the method
+ methodAdapter.endMethod();
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "processMethod");
+ }
+
+ private void addClassStaticField(String classBinaryName)
+ {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "addClassStaticField",
+ new Object[] { classBinaryName });
+
+ currentClassFieldName = classBinaryName.replaceAll("\\.", "_");
+
+ /*
+ * use Class.forName on the superclass so we can reflectively find
+ * methods later
+ *
+ * produces bytecode for retrieving the superclass and storing in a
+ * private static field: private static Class superClass = null; static{
+ * superClass = Class.forName(superclass); }
+ */
+
+ // add a private static field for the superclass Class
+ cv.visitField(ACC_PRIVATE | ACC_STATIC, currentClassFieldName, CLASS_TYPE.getDescriptor(),
+ null, null);
+
+ // push the String arg for the Class.forName onto the stack
+ staticAdapter.push(classBinaryName);
+
+ // invoke the Class forName putting the Class on the stack
+ staticAdapter.invokeStatic(CLASS_TYPE, new Method("forName", CLASS_TYPE,
+ new Type[] { STRING_TYPE }));
+
+ // put the Class in the static field
+ staticAdapter.putStatic(newClassType, currentClassFieldName, CLASS_TYPE);
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "addClassStaticField");
+ }
+
+ private void setCurrentAnalysisClassFields(Class<?> aClass)
+ {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "setCurrentAnalysisClassFields",
+ new Object[] { aClass });
+
+ currentlyAnalysedClassName = aClass.getName();
+ currentlyAnalysedClass = aClass;
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "setCurrentAnalysisClassFields");
+ }
+
+ // we don't want to copy fields from the class into the proxy
+ public FieldVisitor visitField(int access, String name, String desc, String signature,
+ Object value)
+ {
+ return null;
+ }
+
+ // for now we don't do any processing in these methods
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible)
+ {
+ return null;
+ }
+
+ public void visitAttribute(Attribute attr)
+ {
+ // no-op
+ }
+
+ public void visitInnerClass(String name, String outerName, String innerName, int access)
+ {
+ // no-op
+ }
+
+ public void visitOuterClass(String owner, String name, String desc)
+ {
+ // no-op
+ }
+}
Added: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassGenerator.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassGenerator.java?rev=897881&view=auto
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassGenerator.java (added)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassGenerator.java Mon Jan 11 14:37:45 2010
@@ -0,0 +1,359 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint.proxy;
+
+import static java.lang.reflect.Modifier.isFinal;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.ProtectionDomain;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ProxySubclassGenerator
+{
+
+ private final static Logger LOGGER = LoggerFactory.getLogger(ProxySubclassGenerator.class);
+
+ // This map holds references to the names of classes created by this Class
+ // It is a weak map (so when a ClassLoader is garbage collected we remove
+ // the map of
+ // Class names to sub-Class names)
+ private static final Map<ClassLoader, ConcurrentMap<String, String>> proxyClassesByClassLoader;
+
+ static {
+ // Ensure that this is a synchronized map as we may use it from multiple
+ // threads concurrently
+ //
+ proxyClassesByClassLoader = Collections
+ .synchronizedMap(new WeakHashMap<ClassLoader, ConcurrentMap<String, String>>());
+ }
+
+ private static final char FINAL_MODIFIER = '!';
+ private static final char UNABLE_TO_PROXY = '#';
+
+ public static Class<?> getProxySubclass(Class<?> aClass) throws UnableToProxyException
+ {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "getProxySubclass", new Object[] { aClass });
+
+ ClassLoader loader = aClass.getClassLoader();
+ // in the special case where the loader is null we use the thread
+ // ContextClassLoader
+ // this is for subclassing java.* or javax.* packages
+ if (loader == null) loader = Thread.currentThread().getContextClassLoader();
+
+ ConcurrentMap<String, String> proxyMap;
+ synchronized (loader) {
+ proxyMap = proxyClassesByClassLoader.get(loader);
+ if (proxyMap == null) {
+ proxyMap = new ConcurrentHashMap<String, String>();
+ proxyClassesByClassLoader.put(loader, proxyMap);
+ }
+ }
+
+ // check the map to see if we have already generated a subclass for this
+ // class
+ // if we have return the mapped class object
+ // if we haven't generate the subclass and return it
+ Class<?> classToReturn = null;
+ synchronized (aClass) {
+ String key = aClass.getName();
+ String className = proxyMap.get(key);
+ if (className != null) {
+
+ LOGGER.debug("Found proxy subclass with key {} and name {}.", key, className);
+
+ if (className.charAt(0) == FINAL_MODIFIER) {
+ String[] exceptionParts = className.substring(1).split(":");
+ if (exceptionParts.length == 1) {
+ throw new FinalModifierException(aClass);
+ } else {
+ throw new FinalModifierException(aClass, exceptionParts[1]);
+ }
+ } else if (className.charAt(0) == UNABLE_TO_PROXY) {
+ throw new UnableToProxyException(aClass);
+ }
+
+ try {
+ classToReturn = loader.loadClass(className);
+ } catch (ClassNotFoundException cnfe) {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, cnfe);
+ throw new UnableToLoadProxyException(className, cnfe);
+ }
+ } else {
+
+ LOGGER.debug("Need to generate subclass. Using key {}.", key);
+ try {
+ scanForFinalModifiers(aClass);
+
+ classToReturn = generateAndLoadSubclass(aClass, loader);
+
+ if (classToReturn != null) {
+ proxyMap.put(key, classToReturn.getName());
+ } else {
+ proxyMap.put(key, UNABLE_TO_PROXY + aClass.getName());
+ throw new UnableToProxyException(aClass);
+ }
+ } catch (FinalModifierException e) {
+ if (e.isFinalClass()) {
+ proxyMap.put(key, FINAL_MODIFIER + e.getClassName());
+ throw e;
+ } else {
+ proxyMap.put(key, FINAL_MODIFIER + e.getClassName() + ':' + e.getFinalMethods());
+ throw e;
+ }
+ }
+
+ }
+ }
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "getProxySubclass", classToReturn);
+
+ return classToReturn;
+ }
+
+ public static Object newProxySubclassInstance(Class<?> classToProxy, InvocationHandler ih)
+ throws UnableToProxyException
+ {
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "newProxySubclassInstance", new Object[] {
+ classToProxy, ih });
+
+ Object proxySubclassInstance = null;
+ try {
+ Class<?> generatedProxySubclass = getProxySubclass(classToProxy);
+ LOGGER.debug("Getting the proxy subclass constructor");
+ Constructor<?> subclassConstructor = generatedProxySubclass
+ .getConstructor(new Class[] { InvocationHandler.class });
+ LOGGER.debug("Invoking the proxy subclass constructor");
+ proxySubclassInstance = subclassConstructor.newInstance(ih);
+ LOGGER.debug("Invoked proxy subclass constructor");
+ } catch (NoSuchMethodException nsme) {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, nsme);
+ throw new ProxyClassInstantiationException(classToProxy, nsme);
+ } catch (InvocationTargetException ite) {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, ite);
+ throw new ProxyClassInstantiationException(classToProxy, ite);
+ } catch (InstantiationException ie) {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, ie);
+ throw new ProxyClassInstantiationException(classToProxy, ie);
+ } catch (IllegalAccessException iae) {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, iae);
+ throw new ProxyClassInstantiationException(classToProxy, iae);
+ }
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "newProxySubclassInstance", proxySubclassInstance);
+
+ return proxySubclassInstance;
+ }
+
+ private static Class<?> generateAndLoadSubclass(Class<?> aClass, ClassLoader loader)
+ throws UnableToProxyException
+ {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "generateAndLoadSubclass", new Object[] { aClass,
+ loader });
+
+ // set the newClassName
+ String newClassName = "$" + aClass.getSimpleName() + aClass.hashCode();
+ String packageName = aClass.getPackage().getName();
+ if (packageName.startsWith("java.") || packageName.startsWith("javax.")) {
+ packageName = "com.ibm.osgi.blueprint.proxy." + packageName;
+ }
+ String fullNewClassName = (packageName + "." + newClassName).replaceAll("\\.", "/");
+
+ LOGGER.debug("New class name: {}", newClassName);
+ LOGGER.debug("Full new class name: {}", fullNewClassName);
+
+ Class<?> clazz = null;
+ try {
+ ClassReader cReader = new ClassReader(loader.getResourceAsStream(aClass.getName().replaceAll(
+ "\\.", "/")
+ + ".class"));
+ ClassWriter cWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+ ClassVisitor dynamicSubclassAdapter = new ProxySubclassAdapter(cWriter, fullNewClassName,
+ loader);
+ byte[] byteClassData = processClass(cReader, cWriter, dynamicSubclassAdapter);
+ clazz = loadClassFromBytes(loader, getBinaryName(fullNewClassName), byteClassData, aClass
+ .getName());
+ } catch (IOException ioe) {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, ioe);
+ throw new ProxyClassBytecodeGenerationException(aClass.getName(), ioe);
+ } catch (TypeNotPresentException tnpe) {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, tnpe);
+ throw new ProxyClassBytecodeGenerationException(tnpe.typeName(), tnpe.getCause());
+ }
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "generateAndLoadSubclass", clazz);
+
+ return clazz;
+ }
+
+ private static byte[] processClass(ClassReader cReader, ClassWriter cWriter, ClassVisitor cVisitor)
+ {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "processClass", new Object[] { cReader, cWriter,
+ cVisitor });
+
+ cReader.accept(cVisitor, ClassReader.SKIP_DEBUG);
+ byte[] byteClassData = cWriter.toByteArray();
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "processClass", byteClassData);
+
+ return byteClassData;
+ }
+
+ private static String getBinaryName(String name)
+ {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "getBinaryName", name);
+
+ String binaryName = name.replaceAll("/", "\\.");
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "getBinaryName", binaryName);
+
+ return binaryName;
+ }
+
+ private static Class<?> loadClassFromBytes(ClassLoader loader, String name, byte[] classData,
+ String classToProxyName) throws UnableToProxyException
+ {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "loadClassFromBytes", new Object[] { loader, name,
+ classData });
+
+ Class<?> clazz = null;
+ try {
+ Method defineClassMethod = Class.forName("java.lang.ClassLoader").getDeclaredMethod(
+ "defineClass", String.class, byte[].class, int.class, int.class, ProtectionDomain.class);
+ defineClassMethod.setAccessible(true);
+ // define the class in the same classloader where aClass is loaded,
+ // but use the protection domain of our code
+ clazz = (Class<?>) defineClassMethod.invoke(loader, name, classData, 0, classData.length,
+ ProxySubclassGenerator.class.getProtectionDomain());
+ defineClassMethod.setAccessible(false);
+ } catch (ClassNotFoundException cnfe) {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, cnfe);
+ throw new ProxyClassDefinitionException(classToProxyName, cnfe);
+ } catch (NoSuchMethodException nsme) {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, nsme);
+ throw new ProxyClassDefinitionException(classToProxyName, nsme);
+ } catch (InvocationTargetException ite) {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, ite);
+ throw new ProxyClassDefinitionException(classToProxyName, ite);
+ } catch (IllegalAccessException iae) {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, iae);
+ throw new ProxyClassDefinitionException(classToProxyName, iae);
+ }
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "loadClassFromBytes", clazz);
+
+ return clazz;
+ }
+
+ public static boolean isProxySubclass(Class<?> aClass)
+ {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "isProxySubclass", new Object[] { aClass });
+
+ // We will always have a proxy map for the class loader of any proxy
+ // class, so if
+ // this is null we know to return false
+ Map<String, String> proxies = proxyClassesByClassLoader.get(aClass.getClassLoader());
+
+ boolean isProxySubclass = (proxies != null && proxies.containsValue(aClass.getName()));
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "isProxySubclass", isProxySubclass);
+
+ return isProxySubclass;
+ }
+
+ private static void scanForFinalModifiers(Class<?> clazz) throws FinalModifierException
+ {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "scanForFinalModifiers", new Object[] { clazz });
+
+ if (isFinal(clazz.getModifiers())) {
+ throw new FinalModifierException(clazz);
+ }
+
+ List<String> finalMethods = new ArrayList<String>();
+
+ // we don't want to check for final methods on java.* or javax.* Class
+ // also, clazz can never be null here (we will always hit
+ // java.lang.Object first)
+ while (!clazz.getName().startsWith("java.") && !clazz.getName().startsWith("javax.")) {
+ for (Method m : clazz.getDeclaredMethods()) {
+ if (isFinal(m.getModifiers())) {
+ finalMethods.add(m.toGenericString());
+ }
+ }
+ clazz = clazz.getSuperclass();
+ }
+
+ if (!finalMethods.isEmpty()) {
+
+ String methodList = finalMethods.toString();
+ methodList = methodList.substring(1, methodList.length() - 1);
+ throw new FinalModifierException(clazz, methodList);
+ }
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "scanForFinalModifiers");
+
+ }
+
+ public static InvocationHandler getInvocationHandler(Object o)
+ {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "getInvoationHandler", new Object[] { o });
+
+ InvocationHandler ih = null;
+ if (isProxySubclass(o.getClass())) {
+ // we have to catch exceptions here, but we just log them
+ // the reason for this is that it should be impossible to get these
+ // exceptions
+ // since the Object we are dealing with is a class we generated on
+ // the fly
+ try {
+ ih = (InvocationHandler) o.getClass().getDeclaredMethod("getInvocationHandler",
+ new Class[] {}).invoke(o, new Object[] {});
+ } catch (IllegalArgumentException e) {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, e);
+ } catch (SecurityException e) {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, e);
+ } catch (IllegalAccessException e) {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, e);
+ } catch (InvocationTargetException e) {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, e);
+ } catch (NoSuchMethodException e) {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXCEPTION, e);
+ }
+ }
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "getInvoationHandler", ih);
+ return ih;
+ }
+
+}
Added: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassHierarchyAdapter.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassHierarchyAdapter.java?rev=897881&view=auto
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassHierarchyAdapter.java (added)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassHierarchyAdapter.java Mon Jan 11 14:37:45 2010
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint.proxy;
+
+import java.util.Collection;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/*
+ * Although we implement ClassVisitor we are only interested in the methods of
+ * the superclasses in the hierarchy. For this reason although visitMethod is
+ * implemented the other methods of ClassVisitor are currently no-op.
+ *
+ *
+ */
+public class ProxySubclassHierarchyAdapter implements ClassVisitor, Opcodes
+{
+
+ private ProxySubclassAdapter adapter = null;
+ private Collection<String> methodsToImplement = null;
+
+ private static Logger LOGGER = LoggerFactory.getLogger(ProxySubclassHierarchyAdapter.class);
+
+ ProxySubclassHierarchyAdapter(ProxySubclassAdapter adapter, Collection<String> methodsToImplement)
+ {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "ProxySubclassHeirarchyAdapter", new Object[] {
+ this, adapter, methodsToImplement });
+
+ this.methodsToImplement = methodsToImplement;
+ this.adapter = adapter;
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "ProxySubclassHeirarchyAdapter", this);
+ }
+
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+ String[] exceptions)
+ {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "visitMethod", new Object[] { access, name, desc,
+ signature, exceptions });
+
+ // if the method we find in the superclass is one that is available on
+ // the class
+ // we are dynamically subclassing then we need to implement an
+ // invocation for it
+ String argDesc = ProxySubclassMethodHashSet.typeArrayToStringArgDescriptor(Type
+ .getArgumentTypes(desc));
+ if (methodsToImplement.contains(name + argDesc)) {
+ // create the method in bytecode
+ adapter.visitMethod(access, name, desc, signature, exceptions);
+ }
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "visitMethod");
+
+ // always return null because we don't want to copy any method code
+ return null;
+ }
+
+ public void visit(int arg0, int arg1, String arg2, String arg3, String arg4, String[] arg5)
+ {
+ // no-op
+ }
+
+ public AnnotationVisitor visitAnnotation(String arg0, boolean arg1)
+ {
+ // don't process any annotations at this stage
+ return null;
+ }
+
+ public void visitAttribute(Attribute arg0)
+ {
+ // no-op
+ }
+
+ public void visitEnd()
+ {
+ // no-op
+ }
+
+ public FieldVisitor visitField(int arg0, String arg1, String arg2, String arg3, Object arg4)
+ {
+ // don't process fields
+ return null;
+ }
+
+ public void visitInnerClass(String arg0, String arg1, String arg2, int arg3)
+ {
+ // no-op
+ }
+
+ public void visitOuterClass(String arg0, String arg1, String arg2)
+ {
+ // no-op
+ }
+
+ public void visitSource(String arg0, String arg1)
+ {
+ // no-op
+ }
+
+}
Added: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassMethodHashSet.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassMethodHashSet.java?rev=897881&view=auto
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassMethodHashSet.java (added)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/ProxySubclassMethodHashSet.java Mon Jan 11 14:37:45 2010
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint.proxy;
+
+import java.util.HashSet;
+
+import org.objectweb.asm.Type;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ProxySubclassMethodHashSet<E> extends HashSet<String>
+{
+ private static final long serialVersionUID = 7674408912532811084L;
+
+ private static Logger LOGGER = LoggerFactory.getLogger(ProxySubclassMethodHashSet.class);
+
+ public ProxySubclassMethodHashSet(int i)
+ {
+ super(i);
+ }
+
+ public void addMethodArray(java.lang.reflect.Method[] arrayOfEntries)
+ {
+ LOGGER.debug(AsmInterceptorWrapper.LOG_ENTRY, "addMethodArray", new Object[] { arrayOfEntries });
+
+ for (java.lang.reflect.Method entry : arrayOfEntries) {
+ String methodName = entry.getName();
+
+ LOGGER.debug("Method name: {}", methodName);
+
+ Type[] methodArgTypes = Type.getArgumentTypes(entry);
+ String argDescriptor = typeArrayToStringArgDescriptor(methodArgTypes);
+
+ LOGGER.debug("Descriptor: {}", argDescriptor);
+
+ boolean added = super.add(methodName + argDescriptor);
+
+ LOGGER.debug("Added: {}", added);
+ }
+
+ LOGGER.debug(AsmInterceptorWrapper.LOG_EXIT, "addMethodArray");
+ }
+
+ static String typeArrayToStringArgDescriptor(Type[] argTypes)
+ {
+ StringBuilder descriptor = new StringBuilder();
+ for (Type t : argTypes) {
+ descriptor.append(t.toString());
+ }
+ return descriptor.toString();
+ }
+
+}
Added: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/UnableToLoadProxyException.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/UnableToLoadProxyException.java?rev=897881&view=auto
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/UnableToLoadProxyException.java (added)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/UnableToLoadProxyException.java Mon Jan 11 14:37:45 2010
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint.proxy;
+
+public class UnableToLoadProxyException extends UnableToProxyException
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 506487573157016476L;
+
+ public UnableToLoadProxyException(String className, Exception e)
+ {
+ super(className, e);
+ }
+}
Added: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/UnableToProxyException.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/UnableToProxyException.java?rev=897881&view=auto
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/UnableToProxyException.java (added)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/proxy/UnableToProxyException.java Mon Jan 11 14:37:45 2010
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.blueprint.proxy;
+
+public class UnableToProxyException extends Exception
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -17516969014644128L;
+ String className = null;
+
+ public UnableToProxyException(Class<?> clazz)
+ {
+ className = clazz.getName();
+ }
+
+ public UnableToProxyException(Class<?> clazz, Exception e)
+ {
+ this(clazz.getName(), e);
+ }
+
+ public UnableToProxyException(String className, Throwable e)
+ {
+ super(e);
+ this.className = className;
+ }
+
+ public String getClassName()
+ {
+ return className;
+ }
+
+}