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
+    {
+    }
+}