You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by rm...@apache.org on 2012/12/04 22:07:51 UTC
svn commit: r1417182 [17/22] - in /openejb/trunk/openejb:
container/openejb-core/ deps/ deps/webbeans-impl/ deps/webbeans-impl/src/
deps/webbeans-impl/src/main/ deps/webbeans-impl/src/main/java/
deps/webbeans-impl/src/main/java/org/ deps/webbeans-impl/...
Added: openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GProcessProducerField.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GProcessProducerField.java?rev=1417182&view=auto
==============================================================================
--- openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GProcessProducerField.java (added)
+++ openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GProcessProducerField.java Tue Dec 4 21:07:25 2012
@@ -0,0 +1,45 @@
+/*
+ * 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.webbeans.portable.events.generics;
+
+import javax.enterprise.inject.spi.AnnotatedField;
+
+import org.apache.webbeans.component.ProducerFieldBean;
+import org.apache.webbeans.portable.events.ProcessProducerFieldImpl;
+import org.apache.webbeans.util.ClassUtil;
+
+@SuppressWarnings("unchecked")
+public class GProcessProducerField extends ProcessProducerFieldImpl implements GenericProducerObserverEvent
+{
+ public GProcessProducerField(ProducerFieldBean<?> bean,AnnotatedField<?> annotatedField)
+ {
+ super(bean, annotatedField);
+ }
+
+ public Class<?> getBeanClass()
+ {
+ return getBean().getBeanClass();
+ }
+
+ public Class<?> getProducerOrObserverType()
+ {
+ return ClassUtil.getClazz(getAnnotatedProducerField().getBaseType());
+ }
+
+}
Added: openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GProcessProducerMethod.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GProcessProducerMethod.java?rev=1417182&view=auto
==============================================================================
--- openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GProcessProducerMethod.java (added)
+++ openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GProcessProducerMethod.java Tue Dec 4 21:07:25 2012
@@ -0,0 +1,47 @@
+/*
+ * 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.webbeans.portable.events.generics;
+
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.inject.spi.AnnotatedParameter;
+
+import org.apache.webbeans.component.ProducerMethodBean;
+import org.apache.webbeans.portable.events.ProcessProducerMethodImpl;
+import org.apache.webbeans.util.ClassUtil;
+
+@SuppressWarnings("unchecked")
+public class GProcessProducerMethod extends ProcessProducerMethodImpl implements GenericProducerObserverEvent
+{
+ public GProcessProducerMethod(ProducerMethodBean<?> bean,AnnotatedMethod<?> annotatedMethod, AnnotatedParameter dispose)
+ {
+ super(bean, annotatedMethod,dispose);
+ }
+
+ public Class<?> getBeanClass()
+ {
+ return getBean().getBeanClass();
+ }
+
+ public Class<?> getProducerOrObserverType()
+ {
+ return ClassUtil.getClazz(getAnnotatedProducerMethod().getBaseType());
+ }
+
+
+}
Added: openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GProcessSessionBean.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GProcessSessionBean.java?rev=1417182&view=auto
==============================================================================
--- openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GProcessSessionBean.java (added)
+++ openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GProcessSessionBean.java Tue Dec 4 21:07:25 2012
@@ -0,0 +1,58 @@
+/*
+ * 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.webbeans.portable.events.generics;
+
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.ProcessSessionBean;
+import javax.enterprise.inject.spi.SessionBeanType;
+
+import org.apache.webbeans.portable.events.ProcessSessionBeanImpl;
+
+@SuppressWarnings("unchecked")
+public class GProcessSessionBean extends ProcessSessionBeanImpl implements GenericBeanEvent
+{
+ public GProcessSessionBean(Bean<Object> bean, AnnotatedType<?> annotatedType, String name, SessionBeanType type)
+ {
+ super(bean, annotatedType, name, type);
+ }
+
+ /**
+ * This is an exceptional case due to the definition
+ * ProcessSessionBean<X> extends ProcessManagedBean<Object>
+ *
+ * If we are thinking of this event as a ProcessSessionBean then the bean class is X
+ * but if we are thinking of it as a ProcessManagedBean or superclass then the bean class
+ * is Object. See https://issues.jboss.org/browse/CDITCK-215
+ *
+ * @param eventClass the class of event we are treating this event as
+ * @return X.class or Object.class
+ */
+ public Class<?> getBeanClassFor(Class<?> eventClass)
+ {
+ if (ProcessSessionBean.class.isAssignableFrom(eventClass))
+ {
+ return getBean().getBeanClass();
+ }
+ else
+ {
+ return Object.class;
+ }
+ }
+}
Added: openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GenericBeanEvent.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GenericBeanEvent.java?rev=1417182&view=auto
==============================================================================
--- openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GenericBeanEvent.java (added)
+++ openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GenericBeanEvent.java Tue Dec 4 21:07:25 2012
@@ -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.webbeans.portable.events.generics;
+
+public interface GenericBeanEvent
+{
+
+ /**
+ * If this is a Foo<X> event and we are considering it as a Bar<Y> event,
+ * returns the generic type of Foo as a Bar. Normally this is X, but in at least one case
+ * (ProcessSessionBean) the generic type is different.
+ * @param eventClass the class of event we are treating this event as
+ * @return the generic type parameter of this event considered as an "eventClass"
+ */
+ public Class<?> getBeanClassFor(Class<?> eventClass);
+}
Added: openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GenericProducerObserverEvent.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GenericProducerObserverEvent.java?rev=1417182&view=auto
==============================================================================
--- openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GenericProducerObserverEvent.java (added)
+++ openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/portable/events/generics/GenericProducerObserverEvent.java Tue Dec 4 21:07:25 2012
@@ -0,0 +1,26 @@
+/*
+ * 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.webbeans.portable.events.generics;
+
+public interface GenericProducerObserverEvent
+{
+ public Class<?> getBeanClass();
+
+ public Class<?> getProducerOrObserverType();
+}
Added: openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/Factory.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/Factory.java?rev=1417182&view=auto
==============================================================================
--- openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/Factory.java (added)
+++ openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/Factory.java Tue Dec 4 21:07:25 2012
@@ -0,0 +1,38 @@
+/*
+ * 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.webbeans.proxy;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public interface Factory
+{
+ Class<?> getProxyClass(Class<?> superClass, Class<?>[] interfaces);
+
+ boolean isProxyInstance(Object o);
+
+ Object createProxy(MethodHandler handler, Class<?>[] interfaces)
+ throws InstantiationException, IllegalAccessException;
+
+ Object createProxy(Class<?> proxyClass)
+ throws InstantiationException, IllegalAccessException;
+
+
+ void setHandler(Object proxy, MethodHandler handler);
+}
Added: openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/MethodHandler.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/MethodHandler.java?rev=1417182&view=auto
==============================================================================
--- openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/MethodHandler.java (added)
+++ openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/MethodHandler.java Tue Dec 4 21:07:25 2012
@@ -0,0 +1,28 @@
+/*
+ * 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.webbeans.proxy;
+
+import java.lang.reflect.InvocationHandler;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public interface MethodHandler extends javassist.util.proxy.MethodHandler, InvocationHandler
+{
+}
Added: openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/ProxyFactory.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/ProxyFactory.java?rev=1417182&view=auto
==============================================================================
--- openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/ProxyFactory.java (added)
+++ openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/ProxyFactory.java Tue Dec 4 21:07:25 2012
@@ -0,0 +1,501 @@
+/*
+ * 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.webbeans.proxy;
+
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.Decorator;
+
+import org.apache.webbeans.component.InjectionTargetBean;
+import org.apache.webbeans.component.OwbBean;
+import org.apache.webbeans.component.ResourceBean;
+import org.apache.webbeans.config.OpenWebBeansConfiguration;
+import org.apache.webbeans.context.creational.CreationalContextImpl;
+import org.apache.webbeans.decorator.DelegateHandler;
+import org.apache.webbeans.decorator.WebBeansDecorator;
+import org.apache.webbeans.exception.WebBeansConfigurationException;
+import org.apache.webbeans.intercept.DependentScopedBeanInterceptorHandler;
+import org.apache.webbeans.intercept.InterceptorData;
+import org.apache.webbeans.intercept.InterceptorHandler;
+import org.apache.webbeans.intercept.NormalScopedBeanInterceptorHandler;
+import org.apache.webbeans.intercept.webbeans.WebBeansInterceptor;
+import org.apache.webbeans.proxy.javassist.JavassistFactory;
+import org.apache.webbeans.util.ClassUtil;
+import org.apache.webbeans.util.WebBeansUtil;
+
+public final class ProxyFactory
+{
+ private ConcurrentMap<OwbBean<?>, Class<?>> buildInBeanProxyClasses = new ConcurrentHashMap<OwbBean<?>, Class<?>>();
+ private ConcurrentMap<OwbBean<?>, Class<?>> normalScopedBeanProxyClasses = new ConcurrentHashMap<OwbBean<?>, Class<?>>();
+ private ConcurrentMap<OwbBean<?>, Class<?>> dependentScopedBeanProxyClasses = new ConcurrentHashMap<OwbBean<?>, Class<?>>();
+ private ConcurrentMap<OwbBean<?>, Class<?>> interceptorProxyClasses = new ConcurrentHashMap<OwbBean<?>, Class<?>>();
+ private ConcurrentMap<ResourceBean<?, ?>, Class<?>> resourceBeanProxyClasses = new ConcurrentHashMap<ResourceBean<?,?>, Class<?>>();
+ // second level map is indexed on local interface
+ private ConcurrentMap<OwbBean<?>, ConcurrentMap<Class<?>, Class<?>>> ejbProxyClasses = new ConcurrentHashMap<OwbBean<?>, ConcurrentMap<Class<?>, Class<?>>>();
+ private Factory factory;
+
+ public ProxyFactory()
+ {
+ this(new JavassistFactory());
+ }
+
+ public ProxyFactory(Factory factory)
+ {
+ this.factory = factory;
+ }
+
+ /**
+ * This map contains all configured special Scope->InterceptorHandler mappings.
+ * If no mapping is configured, a {@link org.apache.webbeans.intercept.NormalScopedBeanInterceptorHandler} will get created.
+ */
+ private Map<String, Class<? extends InterceptorHandler>> interceptorHandlerClasses =
+ new ConcurrentHashMap<String, Class<? extends InterceptorHandler>>();
+
+ public void setHandler(Object proxy, MethodHandler handler)
+ {
+ factory.setHandler(proxy, handler);
+ }
+
+
+ public Map<OwbBean<?>, Class<?>> getInterceptorProxyClasses()
+ {
+ return interceptorProxyClasses;
+ }
+
+ public void clear()
+ {
+ normalScopedBeanProxyClasses.clear();
+ dependentScopedBeanProxyClasses.clear();
+ interceptorProxyClasses.clear();
+ ejbProxyClasses.clear();
+ }
+ /**
+ * Provides the proxy for the given bean and interface, if defined
+ *
+ * @param bean the contextual representing the EJB
+ * @param iface the injected business local interface
+ * @return the proxy Class if one has been defined, else null
+ */
+ public Class<?> getEjbBeanProxyClass(OwbBean<?> bean, Class<?> iface)
+ {
+ Class<?> proxyClass = null;
+
+ ConcurrentMap<Class<?>, Class<?>> typeToProxyClassMap = ejbProxyClasses.get(bean);
+ if (typeToProxyClassMap == null)
+ {
+ typeToProxyClassMap = new ConcurrentHashMap<Class<?>, Class<?>>();
+ ConcurrentMap<Class<?>, Class<?>> existingMap = ejbProxyClasses.putIfAbsent(bean, typeToProxyClassMap);
+
+ // use the map that beat us, because our new one definitely had no classes in it.
+ typeToProxyClassMap = (existingMap != null) ? existingMap : typeToProxyClassMap;
+ }
+
+ proxyClass = typeToProxyClassMap.get(iface);
+
+ if (proxyClass == null)
+ {
+ Class<?> superClazz = null;
+ List<Class<?>> list = new ArrayList<Class<?>>();
+ Class<?>[] interfaces = null;
+
+ if (iface.isInterface())
+ {
+ list.add(iface);
+ }
+ else
+ {
+ // @LocalBean no-interface local view requested
+ superClazz = iface;
+ //Stateless beans with no interface
+ //To failover bean instance
+ Class<?>[] ifaces = iface.getInterfaces();
+ if(ifaces != null && ifaces.length > 0)
+ {
+ //check for serializable
+ for(Class<?> temp : ifaces)
+ {
+ if(temp == Serializable.class)
+ {
+ list.add(Serializable.class);
+ break;
+ }
+ }
+ }
+ }
+
+ interfaces = new Class<?>[list.size()];
+ interfaces = list.toArray(interfaces);
+ proxyClass = factory.getProxyClass(superClazz, interfaces);
+
+ typeToProxyClassMap.putIfAbsent(iface, proxyClass);
+ // don't care if we were beaten in updating the iface->proxyclass map
+ }
+
+ return proxyClass;
+ }
+
+ public Object createDecoratorDelegate(OwbBean<?> bean, DelegateHandler newDelegateHandler)
+ throws Exception
+ {
+
+ Class<?> proxyClass = this.getInterceptorProxyClasses().get(bean);
+ if (proxyClass == null)
+ {
+ proxyClass = createProxyClass(bean);
+ this.getInterceptorProxyClasses().put(bean, proxyClass);
+ }
+
+ final Object delegate = createProxy(proxyClass);
+ setHandler(delegate, newDelegateHandler);
+ return delegate;
+ }
+
+ public Class<?> getResourceBeanProxyClass(ResourceBean<?, ?> resourceBean)
+ {
+ try
+ {
+ Class<?> proxyClass = resourceBeanProxyClasses.get(resourceBean);
+ if (proxyClass == null)
+ {
+ proxyClass = createProxyClass(resourceBean);
+
+ Class<?> oldClazz = resourceBeanProxyClasses.putIfAbsent(resourceBean, proxyClass);
+ if (oldClazz != null)
+ {
+ return oldClazz;
+ }
+ }
+ return proxyClass;
+ }
+ catch (Exception e)
+ {
+ WebBeansUtil.throwRuntimeExceptions(e);
+ }
+
+ return null;
+ }
+
+
+ public Object createNormalScopedBeanProxy(OwbBean<?> bean, CreationalContext<?> creationalContext)
+ {
+ Object result = null;
+ try
+ {
+ Class<?> proxyClass = normalScopedBeanProxyClasses.get(bean);
+ if (proxyClass == null)
+ {
+ proxyClass = createProxyClass(bean);
+ normalScopedBeanProxyClasses.putIfAbsent(bean, proxyClass);
+ }
+
+
+ result = createProxy(proxyClass);
+
+ if (!(bean instanceof WebBeansDecorator<?>) && !(bean instanceof WebBeansInterceptor<?>))
+ {
+ InterceptorHandler interceptorHandler = createInterceptorHandler(bean, creationalContext);
+
+ setHandler(result, interceptorHandler);
+ }
+ }
+ catch (Exception e)
+ {
+ WebBeansUtil.throwRuntimeExceptions(e);
+ }
+
+ return result;
+ }
+
+ private Object createProxy(Class<?> proxyClass)
+ throws InstantiationException, IllegalAccessException
+ {
+ return factory.createProxy(proxyClass);
+ }
+
+ private InterceptorHandler createInterceptorHandler(OwbBean<?> bean, CreationalContext<?> creationalContext)
+ {
+ String scopeClassName = bean.getScope().getName();
+ Class<? extends InterceptorHandler> interceptorHandlerClass = null;
+ if (!interceptorHandlerClasses.containsKey(scopeClassName))
+ {
+ String proxyMappingConfigKey = OpenWebBeansConfiguration.PROXY_MAPPING_PREFIX + scopeClassName;
+ String className = bean.getWebBeansContext().getOpenWebBeansConfiguration().getProperty(proxyMappingConfigKey);
+ if (className != null)
+ {
+ try
+ {
+ interceptorHandlerClass = (Class<? extends InterceptorHandler>) Class.forName(className, true, WebBeansUtil.getCurrentClassLoader());
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new WebBeansConfigurationException("Configured InterceptorHandler "
+ + className
+ +" cannot be found",
+ e);
+ }
+ }
+ else
+ {
+ // we need to explicitely store a class because ConcurrentHashMap will throw a NPE if value == null
+ interceptorHandlerClass = NormalScopedBeanInterceptorHandler.class;
+ }
+
+ interceptorHandlerClasses.put(scopeClassName, interceptorHandlerClass);
+ }
+ else
+ {
+ interceptorHandlerClass = interceptorHandlerClasses.get(scopeClassName);
+ }
+
+ if (interceptorHandlerClass.equals(NormalScopedBeanInterceptorHandler.class))
+ {
+ // this is faster that way...
+ return new NormalScopedBeanInterceptorHandler(bean, creationalContext);
+ }
+ else
+ {
+ try
+ {
+ Constructor ct = interceptorHandlerClass.getConstructor(OwbBean.class, CreationalContext.class);
+ return (InterceptorHandler) ct.newInstance(bean, creationalContext);
+ }
+ catch (NoSuchMethodException e)
+ {
+ throw new WebBeansConfigurationException("Configured InterceptorHandler "
+ + interceptorHandlerClass.getName()
+ +" has the wrong contructor",
+ e);
+ }
+ catch (InvocationTargetException e)
+ {
+ throw new WebBeansConfigurationException("Configured InterceptorHandler "
+ + interceptorHandlerClass.getName()
+ +" has the wrong contructor",
+ e);
+ }
+ catch (InstantiationException e)
+ {
+ throw new WebBeansConfigurationException("Configured InterceptorHandler "
+ + interceptorHandlerClass.getName()
+ +" has the wrong contructor",
+ e);
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new WebBeansConfigurationException("Configured InterceptorHandler "
+ + interceptorHandlerClass.getName()
+ +" has the wrong contructor",
+ e);
+ }
+ }
+ }
+
+ public Object createBuildInBeanProxy(OwbBean<?> bean)
+ {
+ Object result = null;
+ try
+ {
+ Class<?> proxyClass = buildInBeanProxyClasses.get(bean);
+ if (proxyClass == null)
+ {
+ proxyClass = createProxyClass(bean);
+ buildInBeanProxyClasses.putIfAbsent(bean, proxyClass);
+ }
+ result = createProxy(proxyClass);
+ }
+ catch (Exception e)
+ {
+ WebBeansUtil.throwRuntimeExceptions(e);
+ }
+ return result;
+ }
+
+
+ public Object createDependentScopedBeanProxy(OwbBean<?> bean, Object actualInstance, CreationalContext<?> creastionalContext)
+ {
+
+ List<InterceptorData> interceptors = null;
+ List<Decorator<?>> decorators = null;
+ InjectionTargetBean<?> injectionTargetBean = null;
+ if(bean instanceof InjectionTargetBean<?>)
+ {
+ injectionTargetBean = (InjectionTargetBean<?>)bean;
+ interceptors = injectionTargetBean.getInterceptorStack();
+ decorators = injectionTargetBean.getDecoratorStack();
+ }
+
+ if(interceptors == null && decorators == null)
+ {
+ return actualInstance;
+ }
+
+ boolean notInInterceptorClassAndLifecycle = false;
+ if(interceptors != null && interceptors.size() > 0)
+ {
+ Iterator<InterceptorData> its = interceptors.iterator();
+ while(its.hasNext())
+ {
+ InterceptorData id = its.next();
+ if(!id.isDefinedInInterceptorClass() && id.isLifecycleInterceptor())
+ {
+ continue;
+ }
+ notInInterceptorClassAndLifecycle = true;
+ break;
+ }
+ }
+
+ //No need to return proxy
+ if(!notInInterceptorClassAndLifecycle && decorators.isEmpty())
+ {
+ //Adding this dependent instance into creational context
+ //This occurs when no owner of this dependent instance
+ if(creastionalContext instanceof CreationalContextImpl)
+ {
+ //If this creational context is owned by itself, add it
+ //For example, getting it directly BeanManager#getReference(bean,creational context)
+ CreationalContextImpl<?> ccImpl = (CreationalContextImpl<?>)creastionalContext;
+
+ //Non contextual instance --> Bean --> Null
+ //See OWBInjector
+ if(ccImpl.getBean() != null)
+ {
+ if(ccImpl.getBean().equals(bean))
+ {
+ //Owner of the dependent is itself
+ ccImpl.addDependent(actualInstance, bean, actualInstance);
+ }
+ }
+ }
+
+ return actualInstance;
+ }
+
+ try
+ {
+ Class<?> proxyClass = dependentScopedBeanProxyClasses.get(bean);
+ if (proxyClass == null)
+ {
+ proxyClass = createProxyClass(bean);
+ dependentScopedBeanProxyClasses.putIfAbsent(bean, proxyClass);
+ }
+
+ Object result = createProxy(proxyClass);
+ if (!(bean instanceof WebBeansDecorator<?>) && !(bean instanceof WebBeansInterceptor<?>))
+ {
+ setHandler(result, new DependentScopedBeanInterceptorHandler(bean, actualInstance, creastionalContext));
+ }
+
+ return result;
+ }
+ catch (Exception e)
+ {
+ WebBeansUtil.throwRuntimeExceptions(e);
+ }
+
+ return null;
+ }
+
+ public Class<?> createProxyClass(OwbBean<?> bean)
+ {
+ final ProxyInfo info = getProxyInfo(bean);
+ return factory.getProxyClass(info.getSuperClass(), info.getInterfaces());
+ }
+
+ public Class<?> createAbstractDecoratorProxyClass(OwbBean<?> bean)
+ {
+ return createProxyClass(bean);
+ }
+
+ public boolean isProxyInstance(Object o)
+ {
+ return factory.isProxyInstance(o);
+ }
+
+ public Object createProxy(MethodHandler handler, Class<?>[] interfaces)
+ throws IllegalAccessException, InstantiationException
+ {
+ return factory.createProxy(handler, interfaces);
+ }
+
+ private static class ProxyInfo
+ {
+ private final Class<?> superClass;
+ private final Class<?>[] interfaces;
+
+ private ProxyInfo(Class<?> superClass, Class<?>[] interfaces)
+ {
+ this.superClass = superClass;
+ this.interfaces = interfaces;
+ }
+
+ public Class<?> getSuperClass()
+ {
+ return superClass;
+ }
+
+ public Class<?>[] getInterfaces()
+ {
+ return interfaces;
+ }
+ }
+
+ private static ProxyInfo getProxyInfo(Bean<?> bean)
+ {
+ final Set<Class<?>> interfaceList = new HashSet<Class<?>>();
+ Class<?> superClass = null;
+ for (Type generic : bean.getTypes())
+ {
+ Class<?> type = ClassUtil.getClazz(generic);
+
+ if (type.isInterface())
+ {
+ interfaceList.add(type);
+ }
+
+ else if ((superClass == null) || (superClass.isAssignableFrom(type) && type != Object.class))
+ {
+ superClass = type;
+ }
+
+ }
+ if (!interfaceList.contains(Serializable.class))
+ {
+ interfaceList.add(Serializable.class);
+ }
+
+ Class<?>[] interfaceArray = new Class<?>[interfaceList.size()];
+ interfaceArray = interfaceList.toArray(interfaceArray);
+
+ return new ProxyInfo(superClass, interfaceArray);
+ }
+}
Added: openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/ProxyGenerationException.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/ProxyGenerationException.java?rev=1417182&view=auto
==============================================================================
--- openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/ProxyGenerationException.java (added)
+++ openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/ProxyGenerationException.java Tue Dec 4 21:07:25 2012
@@ -0,0 +1,44 @@
+/*
+ * 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.webbeans.proxy;
+
+public class ProxyGenerationException
+ extends Exception
+{
+
+ public ProxyGenerationException()
+ {
+ }
+
+ public ProxyGenerationException(String message)
+ {
+ super(message);
+ }
+
+ public ProxyGenerationException(Throwable cause)
+ {
+ super(cause);
+ }
+
+ public ProxyGenerationException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+}
Added: openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/ResourceProxyHandler.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/ResourceProxyHandler.java?rev=1417182&view=auto
==============================================================================
--- openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/ResourceProxyHandler.java (added)
+++ openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/ResourceProxyHandler.java Tue Dec 4 21:07:25 2012
@@ -0,0 +1,104 @@
+/*
+ * 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.webbeans.proxy;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.Serializable;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.webbeans.component.ResourceBean;
+import org.apache.webbeans.config.WebBeansContext;
+import org.apache.webbeans.spi.ResourceInjectionService;
+
+public class ResourceProxyHandler implements InvocationHandler, MethodHandler, Serializable, Externalizable
+{
+ /**
+ *
+ */
+ private static final long serialVersionUID = 2608686651845218158L;
+
+ private transient Object actualResource;
+
+ private transient ResourceBean bean;
+
+ public ResourceProxyHandler()
+ {
+ //DO NOT REMOVE, used by failover and passivation.
+ }
+
+ public ResourceProxyHandler(ResourceBean bean, Object actualResource)
+ {
+ this.bean = bean;
+ this.actualResource = actualResource;
+ }
+
+ public Object invoke(Object instance, Method method, Method proceed, Object[] arguments) throws Throwable
+ {
+ return invoke(instance, method, arguments);
+ }
+
+ public Object invoke(Object instance, Method method, Object[] arguments) throws Throwable
+ {
+ try
+ {
+ return method.invoke(actualResource, arguments);
+ }
+ catch (InvocationTargetException e)
+ {
+ throw e.getTargetException();
+ }
+ }
+
+ /**
+ * When serialized, first try container provided failover service. If the failover service
+ * does not handle the actual instance, the default behavior is:
+ * 1. If actual object is serializable, then serialize it directly.
+ * 2. If not, serialize the DUMMY_STRING.
+ */
+ public void writeExternal(ObjectOutput out) throws IOException
+ {
+ // write bean id first
+ out.writeObject(bean.getId());
+ WebBeansContext webBeansContext = WebBeansContext.getInstance();
+ ResourceInjectionService resourceInjectionService = webBeansContext.getService(ResourceInjectionService.class);
+ resourceInjectionService.writeExternal(bean, actualResource, out);
+ }
+
+ /**
+ * When deserialized, first try container provided failover service. If the failover service does not
+ * handle the actual instance, the default behavior is:
+ * 1. Read the object from the stream,
+ * 2. If the object is renote ejb stub, reconnect it.
+ * 3. if the object is DUMMY_STRING, invoke ResourceBean.getActualInstance to get a new instance of the resource.
+ */
+ public void readExternal(ObjectInput in) throws IOException,
+ ClassNotFoundException
+ {
+ String id = (String)in.readObject();
+ WebBeansContext webBeansContext = WebBeansContext.currentInstance();
+ bean = (ResourceBean) webBeansContext.getBeanManagerImpl().getPassivationCapableBean(id);
+ ResourceInjectionService resourceInjectionService = webBeansContext.getService(ResourceInjectionService.class);
+ actualResource = resourceInjectionService.readExternal(bean, in);
+ }
+}
Added: openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/asm/AsmFactory.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/asm/AsmFactory.java?rev=1417182&view=auto
==============================================================================
--- openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/asm/AsmFactory.java (added)
+++ openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/asm/AsmFactory.java Tue Dec 4 21:07:25 2012
@@ -0,0 +1,64 @@
+/*
+ * 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.webbeans.proxy.asm;
+
+import org.apache.webbeans.proxy.Factory;
+import org.apache.webbeans.proxy.MethodHandler;
+import org.apache.webbeans.util.WebBeansUtil;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class AsmFactory
+ implements Factory
+{
+
+ public Object createProxy(MethodHandler handler, Class<?> superClass, Class<?>[] interfaceArray)
+ {
+ return AsmProxyFactory.newProxyInstance(WebBeansUtil.getCurrentClassLoader(), handler, superClass,
+ interfaceArray);
+ }
+
+ public Class<?> getProxyClass(Class<?> superClass, Class<?>[] interfaces)
+ {
+ return AsmProxyFactory.getProxyClass(WebBeansUtil.getCurrentClassLoader(), superClass, interfaces);
+ }
+
+ public boolean isProxyInstance(Object o)
+ {
+ return AsmProxyFactory.isProxyClass(o.getClass());
+ }
+
+ public Object createProxy(MethodHandler handler, Class<?>[] interfaces)
+ throws InstantiationException, IllegalAccessException
+ {
+ return createProxy(handler, null, interfaces);
+ }
+
+ public Object createProxy(Class<?> proxyClass)
+ throws InstantiationException, IllegalAccessException
+ {
+ return AsmProxyFactory.constructProxy(proxyClass, null);
+ }
+
+ public void setHandler(Object proxy, MethodHandler handler)
+ {
+ AsmProxyFactory.setInvocationHandler(proxy, handler);
+ }
+}
Added: openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/asm/AsmProxyFactory.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/asm/AsmProxyFactory.java?rev=1417182&view=auto
==============================================================================
--- openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/asm/AsmProxyFactory.java (added)
+++ openejb/trunk/openejb/deps/webbeans-impl/src/main/java/org/apache/webbeans/proxy/asm/AsmProxyFactory.java Tue Dec 4 21:07:25 2012
@@ -0,0 +1,1233 @@
+/*
+ * 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.webbeans.proxy.asm;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.io.Serializable;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.webbeans.proxy.ProxyGenerationException;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+public class AsmProxyFactory
+ implements Opcodes
+{
+
+ private static final AtomicInteger ID = new AtomicInteger(1);
+
+ public static final InvocationHandler NON_BUSINESS_HANDLER = new NonBusinessHandler();
+
+ private static final String BUSSINESS_HANDLER_NAME = "businessHandler";
+
+ private static final String NON_BUSINESS_HANDLER_NAME = "nonBusinessHandler";
+
+ // This whole class could be turned static
+ private static final AsmProxyFactory GENERATOR = new AsmProxyFactory();
+
+ public static Object newProxyInstance(ClassLoader classLoader, InvocationHandler handler, Class classToSubclass,
+ final Class... interfaces)
+ throws IllegalArgumentException
+ {
+ try
+ {
+
+ final Class proxyClass = GENERATOR.getProxyClass(classLoader, classToSubclass, interfaces);
+ final Object object = GENERATOR.constructProxy(proxyClass, handler);
+
+ return object;
+ }
+ catch (Throwable e)
+ {
+ throw new InternalError(printStackTrace(e));
+ }
+ }
+
+ public static String printStackTrace(Throwable t)
+ {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ t.printStackTrace(new PrintStream(baos));
+ return new String(baos.toByteArray());
+ }
+
+ public static InvocationHandler getInvocationHandler(Object proxy)
+ {
+ try
+ {
+ final Field field = proxy.getClass().getDeclaredField(BUSSINESS_HANDLER_NAME);
+ field.setAccessible(true);
+ try
+ {
+ return (InvocationHandler) field.get(proxy);
+ }
+ finally
+ {
+ field.setAccessible(false);
+ }
+ }
+ catch (NoSuchFieldException e)
+ {
+ throw new IllegalArgumentException(e);
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public static void setInvocationHandler(Object proxy, InvocationHandler invocationHandler)
+ {
+ try
+ {
+ final Field field = proxy.getClass().getDeclaredField(BUSSINESS_HANDLER_NAME);
+ field.setAccessible(true);
+ try
+ {
+ field.set(proxy, invocationHandler);
+ }
+ finally
+ {
+ field.setAccessible(false);
+ }
+ }
+ catch (NoSuchFieldException e)
+ {
+ throw new IllegalArgumentException(e);
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public static Object constructProxy(final Class clazz, InvocationHandler handler)
+ throws IllegalStateException
+ {
+ if (handler == null)
+ {
+ handler = new NoHandler();
+ }
+
+ final Object instance = Unsafe.allocateInstance(clazz);
+
+ Unsafe.setValue(getDeclaredField(clazz, BUSSINESS_HANDLER_NAME), instance, handler);
+ Unsafe.setValue(getDeclaredField(clazz, NON_BUSINESS_HANDLER_NAME), instance, NON_BUSINESS_HANDLER);
+
+ return instance;
+ }
+
+ private static class NoHandler
+ implements InvocationHandler
+ {
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable
+ {
+ throw new UnsupportedOperationException("No valid MethodHandler has been set");
+ }
+ }
+
+
+ private static Field getDeclaredField(final Class clazz, final String fieldName)
+ {
+ try
+ {
+ return clazz.getDeclaredField(fieldName);
+ }
+ catch (NoSuchFieldException e)
+ {
+ final String message =
+ String.format("Proxy class does not contain expected field \"%s\": %s", fieldName, clazz.getName());
+ throw new IllegalStateException(message, e);
+ }
+ }
+
+ public static boolean isProxyClass(final Class<?> clazz)
+ {
+ return clazz.isAnnotationPresent(Proxy.class);
+ }
+
+ public static Class getProxyClass(final ClassLoader cl, final Class<?> classToProxy, final Class... interfaces)
+ {
+ final String proxyName;
+ if (classToProxy == null || classToProxy.getName().startsWith("java.") ||
+ classToProxy.getName().startsWith("javax."))
+ {
+ proxyName = "BeanProxy$" + ID.incrementAndGet();
+ }
+ else
+ {
+ proxyName = classToProxy.getName() + "$BeanProxy";
+ }
+ final String classFileName = proxyName.replace('.', '/');
+
+ try
+ {
+ return cl.loadClass(proxyName);
+ }
+ catch (Exception e)
+ {
+ }
+
+ synchronized (AsmProxyFactory.class)
+ { // it can be done by concurrent threads
+ try
+ { // try it again
+ return cl.loadClass(proxyName);
+ }
+ catch (Exception e)
+ {
+ }
+ try
+ {
+ final byte[] proxyBytes = generateProxy(classToProxy, classFileName, interfaces);
+ return Unsafe.defineClass(proxyName, proxyBytes, cl, null);
+ }
+ catch (Exception e)
+ {
+ final InternalError internalError = new InternalError();
+ internalError.initCause(e);
+ throw internalError;
+ }
+ }
+ }
+
+ private static byte[] generateProxy(final Class<?> classToProxy, final String proxyName,
+ final Class<?>... interfaces)
+ throws ProxyGenerationException
+ {
+ final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+
+ final String proxyClassFileName = proxyName.replace('.', '/');
+ final String classFileName = classToProxy.getName().replace('.', '/');
+
+ // push class signature
+ final String[] interfaceNames = new String[interfaces.length];
+ for (int i = 0; i < interfaces.length; i++)
+ {
+ final Class<?> anInterface = interfaces[i];
+ interfaceNames[i] = anInterface.getName().replace('.', '/');
+ }
+
+ cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, proxyClassFileName, null, classFileName, interfaceNames);
+ cw.visitSource(classFileName + ".java", null);
+
+ cw.visitAnnotation("L" + Proxy.class.getName().replace('.', '/') + ";", true).visitEnd();
+
+ // push InvocationHandler fields
+ cw.visitField(ACC_FINAL + ACC_PRIVATE, BUSSINESS_HANDLER_NAME, "Ljava/lang/reflect/InvocationHandler;", null,
+ null).visitEnd();
+ cw.visitField(ACC_FINAL + ACC_PRIVATE, NON_BUSINESS_HANDLER_NAME, "Ljava/lang/reflect/InvocationHandler;", null,
+ null).visitEnd();
+
+ propagateConstructors(classToProxy, cw, classFileName);
+
+ final Map<String, List<Method>> methodMap = new HashMap<String, List<Method>>();
+
+ getNonPrivateMethods(classToProxy, methodMap);
+
+ for (Class<?> anInterface : interfaces)
+ {
+ getNonPrivateMethods(anInterface, methodMap);
+ }
+
+ // Iterate over the public methods
+ for (final Map.Entry<String, List<Method>> entry : methodMap.entrySet())
+ {
+
+ for (final Method method : entry.getValue())
+ {
+ final String name = method.getName();
+
+ addDirectAccessMethod(classToProxy, cw, method, name);
+
+ if (Modifier.isPublic(method.getModifiers()) ||
+ (method.getParameterTypes().length == 0 && ("finalize".equals(name) || "clone".equals(name))))
+ {
+ // forward invocations of any public methods or
+ // finalize/clone methods to businessHandler
+ processMethod(cw, method, proxyClassFileName, BUSSINESS_HANDLER_NAME);
+ }
+ else
+ {
+ // forward invocations of any other methods to nonBusinessHandler
+ processMethod(cw, method, proxyClassFileName, NON_BUSINESS_HANDLER_NAME);
+ }
+ }
+ }
+
+ return cw.toByteArray();
+ }
+
+ private static void propagateConstructors(Class<?> classToProxy, ClassWriter cw, String classFileName)
+ {
+ for (Constructor<?> constructor : classToProxy.getDeclaredConstructors())
+ {
+
+ final String descriptor = Type.getConstructorDescriptor(constructor);
+ final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", descriptor, null, null);
+ mv.visitCode();
+ mv.visitVarInsn(ALOAD, 0);
+
+ int offset = 1;
+ for (Class<?> aClass : constructor.getParameterTypes())
+ {
+ final Type type = Type.getType(aClass);
+ mv.visitVarInsn(type.getOpcode(ILOAD), offset);
+ offset += type.getSize();
+ }
+
+ mv.visitMethodInsn(INVOKESPECIAL, classFileName, "<init>", descriptor);
+ mv.visitInsn(RETURN);
+ mv.visitMaxs(-1, -1);
+ mv.visitEnd();
+
+ }
+ }
+
+ private static void addDirectAccessMethod(Class<?> classToProxy, ClassWriter cw, Method method, String name)
+ {
+ try
+ {
+ final Method impl = classToProxy.getMethod(name, method.getParameterTypes());
+ if (!Modifier.isAbstract(impl.getModifiers()))
+ {
+ final String[] exceptions = new String[impl.getExceptionTypes().length];
+ for (int i = 0; i < exceptions.length; i++)
+ {
+ exceptions[i] = Type.getType(impl.getExceptionTypes()[i]).getInternalName();
+ }
+
+ final String methodDescriptor = Type.getMethodDescriptor(impl);
+ final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "_$$" + name, methodDescriptor,
+ null, exceptions);
+ mv.visitCode();
+ mv.visitVarInsn(ALOAD, 0);
+
+ int offset = 1;
+ for (Class<?> aClass : impl.getParameterTypes())
+ {
+ final Type type = Type.getType(aClass);
+ mv.visitVarInsn(type.getOpcode(ILOAD), offset);
+ offset += type.getSize();
+ }
+
+ final Type declaringClass = Type.getType(impl.getDeclaringClass());
+ mv.visitMethodInsn(INVOKESPECIAL, declaringClass.getInternalName(), name, methodDescriptor);
+
+ final Type returnType = Type.getType(method.getReturnType());
+ mv.visitInsn(returnType.getOpcode(IRETURN));
+ mv.visitMaxs(-1, -1);
+ mv.visitEnd();
+ }
+ }
+ catch (NoSuchMethodException e)
+ {
+ }
+ }
+
+ private static void getNonPrivateMethods(Class<?> clazz, Map<String, List<Method>> methodMap)
+ {
+ while (clazz != null)
+ {
+ for (Method method : clazz.getDeclaredMethods())
+ {
+ final int modifiers = method.getModifiers();
+
+ if (Modifier.isFinal(modifiers) || Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers))
+ {
+ continue;
+ }
+
+ List<Method> methods = methodMap.get(method.getName());
+ if (methods == null)
+ {
+ methods = new ArrayList<Method>();
+ methods.add(method);
+ methodMap.put(method.getName(), methods);
+ }
+ else
+ {
+ if (isOverridden(methods, method))
+ {
+ // method is overridden in superclass, so do nothing
+ }
+ else
+ {
+ // method is not overridden, so add it
+ methods.add(method);
+ }
+ }
+ }
+
+ clazz = clazz.getSuperclass();
+ }
+ }
+
+ private static boolean isOverridden(final List<Method> methods, final Method method)
+ {
+ for (final Method m : methods)
+ {
+ if (Arrays.equals(m.getParameterTypes(), method.getParameterTypes()))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ private static void processMethod(final ClassWriter cw, final Method method, final String proxyName,
+ final String handlerName)
+ throws ProxyGenerationException
+ {
+ if ("<init>".equals(method.getName()))
+ {
+ return;
+ }
+
+ final Class<?> returnType = method.getReturnType();
+ final Class<?>[] parameterTypes = method.getParameterTypes();
+ final Class<?>[] exceptionTypes = method.getExceptionTypes();
+ final int modifiers = method.getModifiers();
+
+ // push the method definition
+ int modifier = 0;
+ if (Modifier.isPublic(modifiers))
+ {
+ modifier = ACC_PUBLIC;
+ }
+ else if (Modifier.isProtected(modifiers))
+ {
+ modifier = ACC_PROTECTED;
+ }
+
+ final MethodVisitor mv =
+ cw.visitMethod(modifier, method.getName(), getMethodSignatureAsString(returnType, parameterTypes), null,
+ null);
+ mv.visitCode();
+
+ // push try/catch block, to catch declared exceptions, and to catch java.lang.Throwable
+ final Label l0 = new Label();
+ final Label l1 = new Label();
+ final Label l2 = new Label();
+
+ if (exceptionTypes.length > 0)
+ {
+ mv.visitTryCatchBlock(l0, l1, l2, "java/lang/reflect/InvocationTargetException");
+ }
+
+ // push try code
+ mv.visitLabel(l0);
+ final String classNameToOverride = method.getDeclaringClass().getName().replace('.', '/');
+ mv.visitLdcInsn(Type.getType("L" + classNameToOverride + ";"));
+
+ // the following code generates the bytecode for this line of Java:
+ // Method method = <proxy>.class.getMethod("add", new Class[] { <array of function argument classes> });
+
+ // get the method name to invoke, and push to stack
+ mv.visitLdcInsn(method.getName());
+
+ // create the Class[]
+ createArrayDefinition(mv, parameterTypes.length, Class.class);
+
+ int length = 1;
+
+ // push parameters into array
+ for (int i = 0; i < parameterTypes.length; i++)
+ {
+ // keep copy of array on stack
+ mv.visitInsn(DUP);
+
+ final Class<?> parameterType = parameterTypes[i];
+
+ // push number onto stack
+ pushIntOntoStack(mv, i);
+
+ if (parameterType.isPrimitive())
+ {
+ String wrapperType = getWrapperType(parameterType);
+ mv.visitFieldInsn(GETSTATIC, wrapperType, "TYPE", "Ljava/lang/Class;");
+ }
+ else
+ {
+ mv.visitLdcInsn(Type.getType(getAsmTypeAsString(parameterType, true)));
+ }
+
+ mv.visitInsn(AASTORE);
+
+ if (Long.TYPE.equals(parameterType) || Double.TYPE.equals(parameterType))
+ {
+ length += 2;
+ }
+ else
+ {
+ length++;
+ }
+ }
+
+ // invoke getMethod() with the method name and the array of types
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getDeclaredMethod",
+ "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");
+
+ // store the returned method for later
+ mv.visitVarInsn(ASTORE, length);
+
+ // the following code generates bytecode equivalent to:
+ // return ((<returntype>) invocationHandler.invoke(this, method, new Object[] { <function arguments }))[.<primitive>Value()];
+
+ final Label l4 = new Label();
+ mv.visitLabel(l4);
+ mv.visitVarInsn(ALOAD, 0);
+
+ // get the invocationHandler field from this class
+ mv.visitFieldInsn(GETFIELD, proxyName, handlerName, "Ljava/lang/reflect/InvocationHandler;");
+
+ // we want to pass "this" in as the first parameter
+ mv.visitVarInsn(ALOAD, 0);
+
+ // and the method we fetched earlier
+ mv.visitVarInsn(ALOAD, length);
+
+ // need to construct the array of objects passed in
+
+ // create the Object[]
+ createArrayDefinition(mv, parameterTypes.length, Object.class);
+
+ int index = 1;
+ // push parameters into array
+ for (int i = 0; i < parameterTypes.length; i++)
+ {
+ // keep copy of array on stack
+ mv.visitInsn(DUP);
+
+ final Class<?> parameterType = parameterTypes[i];
+
+ // push number onto stack
+ pushIntOntoStack(mv, i);
+
+ if (parameterType.isPrimitive())
+ {
+ String wrapperType = getWrapperType(parameterType);
+ mv.visitVarInsn(getVarInsn(parameterType), index);
+
+ mv.visitMethodInsn(INVOKESTATIC, wrapperType, "valueOf",
+ "(" + getPrimitiveLetter(parameterType) + ")L" + wrapperType + ";");
+ mv.visitInsn(AASTORE);
+
+ if (Long.TYPE.equals(parameterType) || Double.TYPE.equals(parameterType))
+ {
+ index += 2;
+ }
+ else
+ {
+ index++;
+ }
+ }
+ else
+ {
+ mv.visitVarInsn(ALOAD, index);
+ mv.visitInsn(AASTORE);
+ index++;
+ }
+ }
+
+ // invoke the invocationHandler
+ mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/reflect/InvocationHandler", "invoke",
+ "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;");
+
+ // cast the result
+ mv.visitTypeInsn(CHECKCAST, getCastType(returnType));
+
+ if (returnType.isPrimitive() && (!Void.TYPE.equals(returnType)))
+ {
+ // get the primitive value
+ mv.visitMethodInsn(INVOKEVIRTUAL, getWrapperType(returnType), getPrimitiveMethod(returnType),
+ "()" + getPrimitiveLetter(returnType));
+ }
+
+ // push return
+ mv.visitLabel(l1);
+ if (!Void.TYPE.equals(returnType))
+ {
+ mv.visitInsn(getReturnInsn(returnType));
+ }
+ else
+ {
+ mv.visitInsn(POP);
+ mv.visitInsn(RETURN);
+ }
+
+ // catch InvocationTargetException
+ if (exceptionTypes.length > 0)
+ {
+ mv.visitLabel(l2);
+ mv.visitVarInsn(ASTORE, length);
+
+ final Label l5 = new Label();
+ mv.visitLabel(l5);
+
+ for (int i = 0; i < exceptionTypes.length; i++)
+ {
+ final Class<?> exceptionType = exceptionTypes[i];
+
+ mv.visitLdcInsn(Type.getType("L" + exceptionType.getCanonicalName().replace('.', '/') + ";"));
+ mv.visitVarInsn(ALOAD, length);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "getCause",
+ "()Ljava/lang/Throwable;");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z");
+
+ final Label l6 = new Label();
+ mv.visitJumpInsn(IFEQ, l6);
+
+ final Label l7 = new Label();
+ mv.visitLabel(l7);
+
+ mv.visitVarInsn(ALOAD, length);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "getCause",
+ "()Ljava/lang/Throwable;");
+ mv.visitTypeInsn(CHECKCAST, exceptionType.getCanonicalName().replace('.', '/'));
+ mv.visitInsn(ATHROW);
+ mv.visitLabel(l6);
+
+ if (i == (exceptionTypes.length - 1))
+ {
+ mv.visitTypeInsn(NEW, "java/lang/reflect/UndeclaredThrowableException");
+ mv.visitInsn(DUP);
+ mv.visitVarInsn(ALOAD, length);
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/reflect/UndeclaredThrowableException", "<init>",
+ "(Ljava/lang/Throwable;)V");
+ mv.visitInsn(ATHROW);
+ }
+ }
+ }
+
+ // finish this method
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Gets the appropriate bytecode instruction for RETURN, according to what type we need to return
+ *
+ * @param type Type the needs to be returned
+ * @return The matching bytecode instruction
+ */
+ private static int getReturnInsn(final Class<?> type)
+ {
+ if (type.isPrimitive())
+ {
+ if (Integer.TYPE.equals(type))
+ {
+ return IRETURN;
+ }
+ else if (Boolean.TYPE.equals(type))
+ {
+ return IRETURN;
+ }
+ else if (Character.TYPE.equals(type))
+ {
+ return IRETURN;
+ }
+ else if (Byte.TYPE.equals(type))
+ {
+ return IRETURN;
+ }
+ else if (Short.TYPE.equals(type))
+ {
+ return IRETURN;
+ }
+ else if (Float.TYPE.equals(type))
+ {
+ return FRETURN;
+ }
+ else if (Long.TYPE.equals(type))
+ {
+ return LRETURN;
+ }
+ else if (Double.TYPE.equals(type))
+ {
+ return DRETURN;
+ }
+ }
+
+ return ARETURN;
+ }
+
+
+ /**
+ * Returns the appropriate bytecode instruction to load a value from a variable to the stack
+ *
+ * @param type Type to load
+ * @return Bytecode instruction to use
+ */
+ private static int getVarInsn(final Class<?> type)
+ {
+ if (type.isPrimitive())
+ {
+ if (Integer.TYPE.equals(type))
+ {
+ return ILOAD;
+ }
+ else if (Boolean.TYPE.equals(type))
+ {
+ return ILOAD;
+ }
+ else if (Character.TYPE.equals(type))
+ {
+ return ILOAD;
+ }
+ else if (Byte.TYPE.equals(type))
+ {
+ return ILOAD;
+ }
+ else if (Short.TYPE.equals(type))
+ {
+ return ILOAD;
+ }
+ else if (Float.TYPE.equals(type))
+ {
+ return FLOAD;
+ }
+ else if (Long.TYPE.equals(type))
+ {
+ return LLOAD;
+ }
+ else if (Double.TYPE.equals(type))
+ {
+ return DLOAD;
+ }
+ }
+
+ throw new IllegalStateException("Type: " + type.getCanonicalName() + " is not a primitive type");
+ }
+
+ /**
+ * Returns the name of the Java method to call to get the primitive value from an Object - e.g. intValue for java.lang.Integer
+ *
+ * @param type Type whose primitive method we want to lookup
+ * @return The name of the method to use
+ */
+ private static String getPrimitiveMethod(final Class<?> type)
+ {
+ if (Integer.TYPE.equals(type))
+ {
+ return "intValue";
+ }
+ else if (Boolean.TYPE.equals(type))
+ {
+ return "booleanValue";
+ }
+ else if (Character.TYPE.equals(type))
+ {
+ return "charValue";
+ }
+ else if (Byte.TYPE.equals(type))
+ {
+ return "byteValue";
+ }
+ else if (Short.TYPE.equals(type))
+ {
+ return "shortValue";
+ }
+ else if (Float.TYPE.equals(type))
+ {
+ return "floatValue";
+ }
+ else if (Long.TYPE.equals(type))
+ {
+ return "longValue";
+ }
+ else if (Double.TYPE.equals(type))
+ {
+ return "doubleValue";
+ }
+
+ throw new IllegalStateException("Type: " + type.getCanonicalName() + " is not a primitive type");
+ }
+
+ /**
+ * Gets the string to use for CHECKCAST instruction, returning the correct value for any type, including primitives and arrays
+ *
+ * @param returnType The type to cast to with CHECKCAST
+ * @return CHECKCAST parameter
+ */
+ static String getCastType(final Class<?> returnType)
+ {
+ if (returnType.isPrimitive())
+ {
+ return getWrapperType(returnType);
+ }
+ else
+ {
+ return getAsmTypeAsString(returnType, false);
+ }
+ }
+
+ /**
+ * Returns the wrapper type for a primitive, e.g. java.lang.Integer for int
+ *
+ * @param type
+ * @return
+ */
+ private static String getWrapperType(final Class<?> type)
+ {
+ if (Integer.TYPE.equals(type))
+ {
+ return Integer.class.getCanonicalName().replace('.', '/');
+ }
+ else if (Boolean.TYPE.equals(type))
+ {
+ return Boolean.class.getCanonicalName().replace('.', '/');
+ }
+ else if (Character.TYPE.equals(type))
+ {
+ return Character.class.getCanonicalName().replace('.', '/');
+ }
+ else if (Byte.TYPE.equals(type))
+ {
+ return Byte.class.getCanonicalName().replace('.', '/');
+ }
+ else if (Short.TYPE.equals(type))
+ {
+ return Short.class.getCanonicalName().replace('.', '/');
+ }
+ else if (Float.TYPE.equals(type))
+ {
+ return Float.class.getCanonicalName().replace('.', '/');
+ }
+ else if (Long.TYPE.equals(type))
+ {
+ return Long.class.getCanonicalName().replace('.', '/');
+ }
+ else if (Double.TYPE.equals(type))
+ {
+ return Double.class.getCanonicalName().replace('.', '/');
+ }
+ else if (Void.TYPE.equals(type))
+ {
+ return Void.class.getCanonicalName().replace('.', '/');
+ }
+
+ throw new IllegalStateException("Type: " + type.getCanonicalName() + " is not a primitive type");
+ }
+
+ /**
+ * Invokes the most appropriate bytecode instruction to put a number on the stack
+ *
+ * @param mv
+ * @param i
+ */
+ private static void pushIntOntoStack(final MethodVisitor mv, final int i)
+ {
+ if (i == 0)
+ {
+ mv.visitInsn(ICONST_0);
+ }
+ else if (i == 1)
+ {
+ mv.visitInsn(ICONST_1);
+ }
+ else if (i == 2)
+ {
+ mv.visitInsn(ICONST_2);
+ }
+ else if (i == 3)
+ {
+ mv.visitInsn(ICONST_3);
+ }
+ else if (i == 4)
+ {
+ mv.visitInsn(ICONST_4);
+ }
+ else if (i == 5)
+ {
+ mv.visitInsn(ICONST_5);
+ }
+ else if (i > 5 && i <= 255)
+ {
+ mv.visitIntInsn(BIPUSH, i);
+ }
+ else
+ {
+ mv.visitIntInsn(SIPUSH, i);
+ }
+ }
+
+ /**
+ * pushes an array of the specified size to the method visitor. The generated bytecode will leave
+ * the new array at the top of the stack.
+ *
+ * @param mv MethodVisitor to use
+ * @param size Size of the array to create
+ * @param type Type of array to create
+ * @throws ProxyGenerationException
+ */
+ private static void createArrayDefinition(final MethodVisitor mv, final int size, final Class<?> type)
+ throws ProxyGenerationException
+ {
+ // create a new array of java.lang.class (2)
+
+ if (size < 0)
+ {
+ throw new ProxyGenerationException("Array size cannot be less than zero");
+ }
+
+ pushIntOntoStack(mv, size);
+
+ mv.visitTypeInsn(ANEWARRAY, type.getCanonicalName().replace('.', '/'));
+ }
+
+
+ static String getMethodSignatureAsString(final Class<?> returnType, final Class<?>[] parameterTypes)
+ {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("(");
+ for (Class<?> parameterType : parameterTypes)
+ {
+ builder.append(getAsmTypeAsString(parameterType, true));
+ }
+
+ builder.append(")");
+ builder.append(getAsmTypeAsString(returnType, true));
+
+ return builder.toString();
+ }
+
+ /**
+ * Returns the single letter that matches the given primitive in bytecode instructions
+ *
+ * @param type
+ * @return
+ */
+ private static String getPrimitiveLetter(final Class<?> type)
+ {
+ if (Integer.TYPE.equals(type))
+ {
+ return "I";
+ }
+ else if (Void.TYPE.equals(type))
+ {
+ return "V";
+ }
+ else if (Boolean.TYPE.equals(type))
+ {
+ return "Z";
+ }
+ else if (Character.TYPE.equals(type))
+ {
+ return "C";
+ }
+ else if (Byte.TYPE.equals(type))
+ {
+ return "B";
+ }
+ else if (Short.TYPE.equals(type))
+ {
+ return "S";
+ }
+ else if (Float.TYPE.equals(type))
+ {
+ return "F";
+ }
+ else if (Long.TYPE.equals(type))
+ {
+ return "J";
+ }
+ else if (Double.TYPE.equals(type))
+ {
+ return "D";
+ }
+
+ throw new IllegalStateException("Type: " + type.getCanonicalName() + " is not a primitive type");
+ }
+
+ /**
+ * Converts a class to a String suitable for ASM.
+ *
+ * @param parameterType Class to convert
+ * @param wrap True if a non-array object should be wrapped with L and ; - e.g. Ljava/lang/Integer;
+ * @return String to use for ASM
+ */
+ public static String getAsmTypeAsString(final Class<?> parameterType, final boolean wrap)
+ {
+ if (parameterType.isArray())
+ {
+ if (parameterType.getComponentType().isPrimitive())
+ {
+ final Class<?> componentType = parameterType.getComponentType();
+ return "[" + getPrimitiveLetter(componentType);
+ }
+ else
+ {
+ return "[" + getAsmTypeAsString(parameterType.getComponentType(), true);
+ }
+ }
+ else
+ {
+ if (parameterType.isPrimitive())
+ {
+ return getPrimitiveLetter(parameterType);
+ }
+ else
+ {
+ String className = parameterType.getCanonicalName();
+
+ if (parameterType.isMemberClass())
+ {
+ int lastDot = className.lastIndexOf(".");
+ className = className.substring(0, lastDot) + "$" + className.substring(lastDot + 1);
+ }
+
+ if (wrap)
+ {
+ return "L" + className.replace('.', '/') + ";";
+ }
+ else
+ {
+ return className.replace('.', '/');
+ }
+ }
+ }
+ }
+
+ static class NonBusinessHandler
+ implements InvocationHandler, Serializable
+ {
+
+ public Object invoke(final Object proxy, final Method method, final Object[] args)
+ throws Throwable
+ {
+ throw new RuntimeException(
+ "Calling non-public methods of a local bean without any interfaces is not allowed");
+ }
+
+ }
+
+ /**
+ * The methods of this class model sun.misc.Unsafe which is used reflectively
+ */
+ private static class Unsafe
+ {
+
+ // sun.misc.Unsafe
+ private static final Object UNSAFE;
+
+ private static final Method DEFINE_CLASS;
+
+ private static final Method ALLOCATE_INSTANCE;
+
+ private static final Method PUT_OBJECT;
+
+ private static final Method OBJECT_FIELD_OFFSET;
+
+ static
+ {
+ final Class<?> unsafeClass;
+ try
+ {
+ unsafeClass = AccessController.doPrivileged(new PrivilegedAction<Class<?>>()
+ {
+ public Class<?> run()
+ {
+ try
+ {
+ return Thread.currentThread().getContextClassLoader().loadClass("sun.misc.Unsafe");
+ }
+ catch (Exception e)
+ {
+ try
+ {
+ return ClassLoader.getSystemClassLoader().loadClass("sun.misc.Unsafe");
+ }
+ catch (ClassNotFoundException e1)
+ {
+ throw new IllegalStateException("Cannot get sun.misc.Unsafe", e);
+ }
+ }
+ }
+ });
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("Cannot get sun.misc.Unsafe class", e);
+ }
+
+ UNSAFE = AccessController.doPrivileged(new PrivilegedAction<Object>()
+ {
+ public Object run()
+ {
+ try
+ {
+ Field field = unsafeClass.getDeclaredField("theUnsafe");
+ field.setAccessible(true);
+ return field.get(null);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("Cannot get sun.misc.Unsafe", e);
+ }
+ }
+ });
+ ALLOCATE_INSTANCE = AccessController.doPrivileged(new PrivilegedAction<Method>()
+ {
+ public Method run()
+ {
+ try
+ {
+ Method mtd = unsafeClass.getDeclaredMethod("allocateInstance", Class.class);
+ mtd.setAccessible(true);
+ return mtd;
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("Cannot get sun.misc.Unsafe.allocateInstance", e);
+ }
+ }
+ });
+ OBJECT_FIELD_OFFSET = AccessController.doPrivileged(new PrivilegedAction<Method>()
+ {
+ public Method run()
+ {
+ try
+ {
+ Method mtd = unsafeClass.getDeclaredMethod("objectFieldOffset", Field.class);
+ mtd.setAccessible(true);
+ return mtd;
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("Cannot get sun.misc.Unsafe.objectFieldOffset", e);
+ }
+ }
+ });
+ PUT_OBJECT = AccessController.doPrivileged(new PrivilegedAction<Method>()
+ {
+ public Method run()
+ {
+ try
+ {
+ Method mtd = unsafeClass.getDeclaredMethod("putObject", Object.class, long.class, Object.class);
+ mtd.setAccessible(true);
+ return mtd;
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("Cannot get sun.misc.Unsafe.putObject", e);
+ }
+ }
+ });
+ DEFINE_CLASS = AccessController.doPrivileged(new PrivilegedAction<Method>()
+ {
+ public Method run()
+ {
+ try
+ {
+ Method mtd = unsafeClass.getDeclaredMethod("defineClass", String.class, byte[].class, int.class,
+ int.class, ClassLoader.class,
+ ProtectionDomain.class);
+ mtd.setAccessible(true);
+ return mtd;
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("Cannot get sun.misc.Unsafe.defineClass", e);
+ }
+ }
+ });
+ }
+
+ private static Object allocateInstance(final Class clazz)
+ {
+ try
+ {
+ return ALLOCATE_INSTANCE.invoke(UNSAFE, clazz);
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new IllegalStateException("Failed to allocateInstance of Proxy class " + clazz.getName(), e);
+ }
+ catch (InvocationTargetException e)
+ {
+ Throwable throwable = e.getTargetException() != null ? e.getTargetException() : e;
+ throw new IllegalStateException("Failed to allocateInstance of Proxy class " + clazz.getName(),
+ throwable);
+ }
+ }
+
+ private static void setValue(final Field field, final Object object, final Object value)
+ {
+ final long offset;
+ try
+ {
+ offset = (Long) OBJECT_FIELD_OFFSET.invoke(UNSAFE, field);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("Failed getting offset for: field=" + field.getName() + " class=" +
+ field.getDeclaringClass().getName(), e);
+ }
+
+ try
+ {
+ PUT_OBJECT.invoke(UNSAFE, object, offset, value);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException(
+ "Failed putting field=" + field.getName() + " class=" + field.getDeclaringClass().getName(), e);
+ }
+ }
+
+ private static Class defineClass(String proxyName, byte[] proxyBytes, final ClassLoader classLoader,
+ ProtectionDomain o)
+ throws IllegalAccessException, InvocationTargetException
+ {
+ return (Class<?>) DEFINE_CLASS.invoke(UNSAFE, proxyName, proxyBytes, 0, proxyBytes.length, classLoader, o);
+ }
+ }
+
+ @Target(ElementType.TYPE)
+ @Retention(RetentionPolicy.RUNTIME)
+ private static @interface Proxy
+ {
+ }
+}