Package org.apache.openejb.config

Source Code of org.apache.openejb.config.AnnotationDeployer$ProcessAnnotatedBeans

/**
* 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.openejb.config;

import static java.util.Arrays.asList;
import static java.lang.reflect.Modifier.isAbstract;

import org.apache.openejb.DeploymentInfo;
import org.apache.openejb.OpenEJBException;
import org.apache.openejb.core.webservices.JaxWsUtils;
import org.apache.openejb.jee.ActivationConfig;
import org.apache.openejb.jee.ApplicationClient;
import org.apache.openejb.jee.AroundInvoke;
import org.apache.openejb.jee.AssemblyDescriptor;
import org.apache.openejb.jee.ContainerTransaction;
import org.apache.openejb.jee.EjbJar;
import org.apache.openejb.jee.EjbLocalRef;
import org.apache.openejb.jee.EjbRef;
import org.apache.openejb.jee.EjbReference;
import org.apache.openejb.jee.EnterpriseBean;
import org.apache.openejb.jee.ExcludeList;
import org.apache.openejb.jee.Filter;
import org.apache.openejb.jee.Handler;
import org.apache.openejb.jee.HandlerChains;
import org.apache.openejb.jee.InitMethod;
import org.apache.openejb.jee.InjectionTarget;
import org.apache.openejb.jee.Interceptor;
import org.apache.openejb.jee.InterceptorBinding;
import org.apache.openejb.jee.JndiConsumer;
import org.apache.openejb.jee.JndiReference;
import org.apache.openejb.jee.Lifecycle;
import org.apache.openejb.jee.LifecycleCallback;
import org.apache.openejb.jee.Listener;
import org.apache.openejb.jee.MessageDrivenBean;
import org.apache.openejb.jee.MethodParams;
import org.apache.openejb.jee.MethodPermission;
import org.apache.openejb.jee.MethodTransaction;
import org.apache.openejb.jee.NamedMethod;
import org.apache.openejb.jee.PersistenceContextRef;
import org.apache.openejb.jee.PersistenceContextType;
import org.apache.openejb.jee.PersistenceUnitRef;
import org.apache.openejb.jee.PortComponent;
import org.apache.openejb.jee.Property;
import org.apache.openejb.jee.RemoteBean;
import org.apache.openejb.jee.RemoveMethod;
import org.apache.openejb.jee.ResAuth;
import org.apache.openejb.jee.ResSharingScope;
import org.apache.openejb.jee.ResourceEnvRef;
import org.apache.openejb.jee.ResourceRef;
import org.apache.openejb.jee.SecurityIdentity;
import org.apache.openejb.jee.SecurityRoleRef;
import org.apache.openejb.jee.ServiceRef;
import org.apache.openejb.jee.Servlet;
import org.apache.openejb.jee.SessionBean;
import org.apache.openejb.jee.SessionType;
import org.apache.openejb.jee.StatefulBean;
import org.apache.openejb.jee.StatelessBean;
import org.apache.openejb.jee.Tag;
import org.apache.openejb.jee.TimerConsumer;
import org.apache.openejb.jee.TldTaglib;
import org.apache.openejb.jee.TransAttribute;
import org.apache.openejb.jee.TransactionType;
import org.apache.openejb.jee.WebApp;
import org.apache.openejb.jee.WebserviceDescription;
import static org.apache.openejb.util.Join.join;
import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.Logger;
import org.apache.xbean.finder.ClassFinder;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.annotation.Resources;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.annotation.security.RunAs;
import javax.ejb.ApplicationException;
import javax.ejb.EJB;
import javax.ejb.EJBHome;
import javax.ejb.EJBLocalHome;
import javax.ejb.EJBLocalObject;
import javax.ejb.EJBObject;
import javax.ejb.EJBs;
import javax.ejb.Init;
import javax.ejb.Local;
import javax.ejb.LocalHome;
import javax.ejb.MessageDriven;
import javax.ejb.PostActivate;
import javax.ejb.PrePassivate;
import javax.ejb.Remote;
import javax.ejb.RemoteHome;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.interceptor.ExcludeClassInterceptors;
import javax.interceptor.ExcludeDefaultInterceptors;
import javax.interceptor.Interceptors;
import javax.jws.HandlerChain;
import javax.jws.WebService;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContexts;
import javax.persistence.PersistenceUnit;
import javax.persistence.PersistenceUnits;
import javax.xml.ws.Service;
import javax.xml.ws.WebServiceProvider;
import javax.xml.ws.WebServiceRef;
import javax.xml.ws.WebServiceRefs;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.annotation.Annotation;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;

/**
* @version $Rev: 639147 $ $Date: 2008-03-19 20:49:01 -0700 (Wed, 19 Mar 2008) $
*/
public class AnnotationDeployer implements DynamicDeployer {
    public static final Logger logger = Logger.getInstance(LogCategory.OPENEJB_STARTUP, AnnotationDeployer.class.getPackage().getName());

    private static final ThreadLocal<ValidationContext> validationContext = new ThreadLocal<ValidationContext>();

    private final DiscoverAnnotatedBeans discoverAnnotatedBeans;
    private final ProcessAnnotatedBeans processAnnotatedBeans;
    private final EnvEntriesPropertiesDeployer envEntriesPropertiesDeployer;

    public AnnotationDeployer() {
        discoverAnnotatedBeans = new DiscoverAnnotatedBeans();
        processAnnotatedBeans = new ProcessAnnotatedBeans();
        envEntriesPropertiesDeployer = new EnvEntriesPropertiesDeployer();
    }

    public AppModule deploy(AppModule appModule) throws OpenEJBException {
        getValidationContext().set(appModule.getValidation());
        try {
            appModule = discoverAnnotatedBeans.deploy(appModule);
            appModule = envEntriesPropertiesDeployer.deploy(appModule);
            appModule = processAnnotatedBeans.deploy(appModule);
            return appModule;
        } finally {
            getValidationContext().remove();
        }
    }

    public WebModule deploy(WebModule webModule) throws OpenEJBException {
        getValidationContext().set(webModule.getValidation());
        try {
            webModule = discoverAnnotatedBeans.deploy(webModule);
            webModule = envEntriesPropertiesDeployer.deploy(webModule);
            webModule = processAnnotatedBeans.deploy(webModule);
            return webModule;
        } finally {
            getValidationContext().remove();
        }
    }

    public static ThreadLocal<ValidationContext> getValidationContext() {
//        Throwable throwable = new Throwable();
//        throwable.fillInStackTrace();
//        throwable.printStackTrace();
        return validationContext;
    }

    public static class DiscoverAnnotatedBeans implements DynamicDeployer {
        public static final Set<String> knownResourceEnvTypes = new TreeSet<String>(asList(
                "javax.ejb.SessionContext",
                "javax.ejb.EntityContext",
                "javax.ejb.MessageDrivenContext",
                "javax.transaction.UserTransaction",
                "javax.jms.Queue",
                "javax.jms.Topic",
                "javax.xml.ws.WebServiceContext",
                "javax.ejb.TimerService"
        ));

        public static final Set<String> knownEnvironmentEntries = new TreeSet<String>(asList(
                "boolean", "java.lang.Boolean",
                "char",    "java.lang.Character",
                "byte",    "java.lang.Byte",
                "short",   "java.lang.Short",
                "int",     "java.lang.Integer",
                "long",    "java.lang.Long",
                "float",   "java.lang.Float",
                "double""java.lang.Double",
                "java.lang.String"
        ));

        public AppModule deploy(AppModule appModule) throws OpenEJBException {
            for (EjbModule ejbModule : appModule.getEjbModules()) {
                getValidationContext().set(ejbModule.getValidation());
                try {
                    deploy(ejbModule);
                } finally {
                    getValidationContext().remove();
                }
            }
            for (ClientModule clientModule : appModule.getClientModules()) {
                getValidationContext().set(clientModule.getValidation());
                try {
                    deploy(clientModule);
                } finally {
                    getValidationContext().remove();
                }
            }
            for (ConnectorModule connectorModule : appModule.getResourceModules()) {
                getValidationContext().set(connectorModule.getValidation());
                try {
                    deploy(connectorModule);
                } finally {
                    getValidationContext().remove();
                }
            }
            for (WebModule webModule : appModule.getWebModules()) {
                getValidationContext().set(webModule.getValidation());
                try {
                    deploy(webModule);
                } finally {
                    getValidationContext().remove();
                }
            }
            return appModule;
        }

        public ClientModule deploy(ClientModule clientModule) throws OpenEJBException {
            return clientModule;
        }

        public ConnectorModule deploy(ConnectorModule connectorModule) throws OpenEJBException {
            return connectorModule;
        }

        public WebModule deploy(WebModule webModule) throws OpenEJBException {
            WebApp webApp = webModule.getWebApp();
            if (webApp != null && (webApp.isMetadataComplete() || !webApp.getServlet().isEmpty())) return webModule;

            ClassFinder finder;
            try {
                finder = new ClassFinder(webModule.getClassLoader());
            } catch (Exception e) {
                DeploymentLoader.logger.warning("Unable to scrape for @WebService or @WebServiceProvider annotations. ClassFinder failed.", e);
                return webModule;
            }

            List<Class> classes = new ArrayList<Class>();
            classes.addAll(finder.findAnnotatedClasses(WebService.class));
            classes.addAll(finder.findAnnotatedClasses(WebServiceProvider.class));
            for (Class<?> webServiceClass : classes) {
                int modifiers = webServiceClass.getModifiers();
                if (!Modifier.isPublic(modifiers) || Modifier.isFinal(modifiers) || isAbstract(modifiers)) {
                    continue;
                }

                // create webApp and webservices objects if they don't exist already
                if (webApp == null) {
                    webApp = new WebApp();
                    webModule.setWebApp(webApp);
                }

                // add new <servlet/> element
                Servlet servlet = new Servlet();
                servlet.setServletName(webServiceClass.getName());
                servlet.setServletClass(webServiceClass.getName());
                webApp.getServlet().add(servlet);
            }

            return webModule;
        }

        public EjbModule deploy(EjbModule ejbModule) throws OpenEJBException {
            if (ejbModule.getEjbJar() != null && ejbModule.getEjbJar().isMetadataComplete()) return ejbModule;

            ClassFinder finder;
            if (ejbModule.getJarLocation() != null) {
                try {
                    String location = ejbModule.getJarLocation();
                    File file = new File(location);

                    URL url;
                    if (file.exists()) {
                        url = file.toURL();
                    } else {
                        url = new URL(location);
                    }
                    finder = new ClassFinder(ejbModule.getClassLoader(), url);
                } catch (MalformedURLException e) {
                    DeploymentLoader.logger.warning("startup.scrapeFailedForModule", ejbModule.getJarLocation());
                    return ejbModule;
                }
            } else {
                try {
                    finder = new ClassFinder(ejbModule.getClassLoader());
                } catch (Exception e) {
                    DeploymentLoader.logger.warning("Unable to scrape for @Stateful, @Stateless or @MessageDriven annotations. ClassFinder failed.", e);
                    return ejbModule;
                }
            }

            /* 19.2:  ejb-name: Default is the unqualified name of the bean class */

            EjbJar ejbJar = ejbModule.getEjbJar();
            List<Class> classes = finder.findAnnotatedClasses(Stateless.class);
            for (Class<?> beanClass : classes) {
                Stateless stateless = beanClass.getAnnotation(Stateless.class);
                String ejbName = getEjbName(stateless, beanClass);

                if (!isValidAnnotationUsage(Stateless.class, beanClass, ejbName, ejbModule)) continue;

                EnterpriseBean enterpriseBean = ejbJar.getEnterpriseBean(ejbName);
                if (enterpriseBean == null) {
                    enterpriseBean = new StatelessBean(ejbName, beanClass.getName());
                    ejbJar.addEnterpriseBean(enterpriseBean);
                }
                if (enterpriseBean.getEjbClass() == null) {
                    enterpriseBean.setEjbClass(beanClass.getName());
                }
                if (enterpriseBean instanceof SessionBean) {
                    SessionBean sessionBean = (SessionBean) enterpriseBean;
                    sessionBean.setSessionType(SessionType.STATELESS);
                }
            }

            classes = finder.findAnnotatedClasses(Stateful.class);
            for (Class<?> beanClass : classes) {
                Stateful stateful = beanClass.getAnnotation(Stateful.class);
                String ejbName = getEjbName(stateful, beanClass);

                if (!isValidAnnotationUsage(Stateful.class, beanClass, ejbName, ejbModule)) continue;

                EnterpriseBean enterpriseBean = ejbJar.getEnterpriseBean(ejbName);
                if (enterpriseBean == null) {
                    enterpriseBean = new StatefulBean(ejbName, beanClass.getName());
                    ejbJar.addEnterpriseBean(enterpriseBean);
                }
                if (enterpriseBean.getEjbClass() == null) {
                    enterpriseBean.setEjbClass(beanClass.getName());
                }
                if (enterpriseBean instanceof SessionBean) {
                    SessionBean sessionBean = (SessionBean) enterpriseBean;
                    sessionBean.setSessionType(SessionType.STATEFUL);
                }
            }

            classes = finder.findAnnotatedClasses(MessageDriven.class);
            for (Class<?> beanClass : classes) {
                MessageDriven mdb = beanClass.getAnnotation(MessageDriven.class);
                String ejbName = getEjbName(mdb, beanClass);

                if (!isValidAnnotationUsage(MessageDriven.class, beanClass, ejbName, ejbModule)) continue;

                MessageDrivenBean messageBean = (MessageDrivenBean) ejbJar.getEnterpriseBean(ejbName);
                if (messageBean == null) {
                    messageBean = new MessageDrivenBean(ejbName);
                    ejbJar.addEnterpriseBean(messageBean);
                }
                if (messageBean.getEjbClass() == null) {
                    messageBean.setEjbClass(beanClass.getName());
                }
            }

            classes = finder.findAnnotatedClasses(ApplicationException.class);
            if (!classes.isEmpty()) {
                if (ejbJar.getAssemblyDescriptor() == null) {
                    ejbJar.setAssemblyDescriptor(new AssemblyDescriptor());
                }
            }
            for (Class<?> exceptionClass : classes) {
                ApplicationException annotation = exceptionClass.getAnnotation(ApplicationException.class);
                org.apache.openejb.jee.ApplicationException exception = new org.apache.openejb.jee.ApplicationException(exceptionClass.getName(), annotation.rollback());
                ejbJar.getAssemblyDescriptor().getApplicationException().add(exception);
            }

            return ejbModule;
        }

        private String getEjbName(MessageDriven mdb, Class<?> beanClass) {
            String ejbName = mdb.name().length() == 0 ? beanClass.getSimpleName() : mdb.name();
            return ejbName;
        }

        private String getEjbName(Stateful stateful, Class<?> beanClass) {
            String ejbName = stateful.name().length() == 0 ? beanClass.getSimpleName() : stateful.name();
            return ejbName;
        }

        private String getEjbName(Stateless stateless, Class<?> beanClass) {
            String ejbName = stateless.name().length() == 0 ? beanClass.getSimpleName() : stateless.name();
            return ejbName;
        }

        private boolean isValidAnnotationUsage(Class annotationClass, Class<?> beanClass, String ejbName, EjbModule ejbModule) {
            List<Class<? extends Annotation>> annotations = new ArrayList(asList(Stateless.class, Stateful.class, MessageDriven.class));
            annotations.remove(annotationClass);

            Map<String,Class<? extends Annotation>> names = new HashMap<String,Class<? extends Annotation>>();

            boolean b = true;
            for (Class<? extends Annotation> secondAnnotation : annotations) {
                Annotation annotation = beanClass.getAnnotation(secondAnnotation);

                if (annotation == null) continue;

                String secondEjbName = null;
                if (annotation instanceof Stateful) {
                    secondEjbName = getEjbName((Stateful) annotation, beanClass);
                } else if (annotation instanceof Stateless) {
                    secondEjbName = getEjbName((Stateless) annotation, beanClass);
                } else if (annotation instanceof MessageDriven) {
                    secondEjbName = getEjbName((MessageDriven) annotation, beanClass);
                }

                if (ejbName.equals(secondEjbName)) {
                    ejbModule.getValidation().fail(ejbName, "multiplyAnnotatedAsBean", annotationClass.getSimpleName(), secondAnnotation.getSimpleName(), ejbName, beanClass.getName());
                }
            }

            if (beanClass.isInterface()){
                ejbModule.getValidation().fail(ejbName, "interfaceAnnotatedAsBean", annotationClass.getSimpleName(), beanClass.getName());
                return false;
            }

            if (isAbstract(beanClass.getModifiers())){
                ejbModule.getValidation().fail(ejbName, "abstractAnnotatedAsBean", annotationClass.getSimpleName(), beanClass.getName());
                return false;
            }

            return b;
        }
    }

    public static class ProcessAnnotatedBeans implements DynamicDeployer {
        public static final Set<String> knownResourceEnvTypes = new TreeSet<String>(asList(
                "javax.ejb.SessionContext",
                "javax.ejb.EntityContext",
                "javax.ejb.MessageDrivenContext",
                "javax.transaction.UserTransaction",
                "javax.jms.Queue",
                "javax.jms.Topic",
                "javax.xml.ws.WebServiceContext",
                "javax.ejb.TimerService"
        ));

        public static final Set<String> knownEnvironmentEntries = new TreeSet<String>(asList(
                "boolean", "java.lang.Boolean",
                "char",    "java.lang.Character",
                "byte",    "java.lang.Byte",
                "short",   "java.lang.Short",
                "int",     "java.lang.Integer",
                "long",    "java.lang.Long",
                "float",   "java.lang.Float",
                "double""java.lang.Double",
                "java.lang.String"
        ));

        public AppModule deploy(AppModule appModule) throws OpenEJBException {
            for (EjbModule ejbModule : appModule.getEjbModules()) {
                getValidationContext().set(ejbModule.getValidation());
                try {
                    deploy(ejbModule);
                } finally {
                    getValidationContext().remove();
                }
            }
            for (ClientModule clientModule : appModule.getClientModules()) {
                getValidationContext().set(clientModule.getValidation());
                try {
                    deploy(clientModule);
                } finally {
                    getValidationContext().remove();
                }
            }
            for (ConnectorModule connectorModule : appModule.getResourceModules()) {
                getValidationContext().set(connectorModule.getValidation());
                try {
                    deploy(connectorModule);
                } finally {
                    getValidationContext().remove();
                }
            }
            for (WebModule webModule : appModule.getWebModules()) {
                getValidationContext().set(webModule.getValidation());
                try {
                    deploy(webModule);
                } finally {
                    getValidationContext().remove();
                }
            }
            return appModule;
        }

        public ClientModule deploy(ClientModule clientModule) throws OpenEJBException {
            if (clientModule.getApplicationClient() != null && clientModule.getApplicationClient().isMetadataComplete()) return clientModule;

            ClassLoader classLoader = clientModule.getClassLoader();
            Class<?> clazz;
            try {
                clazz = classLoader.loadClass(clientModule.getMainClass());
            } catch (ClassNotFoundException e) {
                throw new OpenEJBException("Unable to load Client main-class: " + clientModule.getMainClass(), e);
            }
            ApplicationClient client = clientModule.getApplicationClient();
            ClassFinder inheritedClassFinder = createInheritedClassFinder(clazz);
            buildAnnotatedRefs(client, inheritedClassFinder, classLoader);
            processWebServiceClientHandlers(client, classLoader);

            return clientModule;
        }

        public ConnectorModule deploy(ConnectorModule connectorModule) throws OpenEJBException {
            // resource modules currently don't have any annotations
            return connectorModule;
        }

        public WebModule deploy(WebModule webModule) throws OpenEJBException {
            WebApp webApp = webModule.getWebApp();
            if (webApp != null && webApp.isMetadataComplete()) return webModule;

            Set<Class<?>> classes = new HashSet<Class<?>>();
            ClassLoader classLoader = webModule.getClassLoader();
            for (Servlet servlet : webApp.getServlet()) {
                String servletClass = servlet.getServletClass();
                if (servletClass != null) {
                    try {
                        Class clazz = classLoader.loadClass(servletClass);
                        classes.add(clazz);
                    } catch (ClassNotFoundException e) {
                        throw new OpenEJBException("Unable to load servlet class: " + servletClass, e);
                    }
                }
            }
            for (Filter filter : webApp.getFilter()) {
                String filterClass = filter.getFilterClass();
                if (filterClass != null) {
                    try {
                        Class clazz = classLoader.loadClass(filterClass);
                        classes.add(clazz);
                    } catch (ClassNotFoundException e) {
                        throw new OpenEJBException("Unable to load servlet filter class: " + filterClass, e);
                    }
                }
            }
            for (Listener listener : webApp.getListener()) {
                String listenerClass = listener.getListenerClass();
                if (listenerClass != null) {
                    try {
                        Class clazz = classLoader.loadClass(listenerClass);
                        classes.add(clazz);
                    } catch (ClassNotFoundException e) {
                        throw new OpenEJBException("Unable to load servlet listener class: " + listenerClass, e);
                    }
                }
            }
            for (TldTaglib taglib : webModule.getTaglibs()) {
                for (Listener listener : taglib.getListener()) {
                    String listenerClass = listener.getListenerClass();
                    if (listenerClass != null) {
                        try {
                            Class clazz = classLoader.loadClass(listenerClass);
                            classes.add(clazz);
                        } catch (ClassNotFoundException e) {
                            throw new OpenEJBException("Unable to load tag library servlet listener class: " + listenerClass, e);
                        }
                    }
                }
                for (Tag tag : taglib.getTag()) {
                    String tagClass = tag.getTagClass();
                    if (tagClass != null) {
                        try {
                            Class clazz = classLoader.loadClass(tagClass);
                            classes.add(clazz);
                        } catch (ClassNotFoundException e) {
                            throw new OpenEJBException("Unable to load tag library tag class: " + tagClass, e);
                        }
                    }
                }
            }
            if (webModule.getWebservices() != null) {
                for (WebserviceDescription webservice : webModule.getWebservices().getWebserviceDescription()) {
                    for (PortComponent port : webservice.getPortComponent()) {
                        // skip ejb port defs
                        if (port.getServiceImplBean().getEjbLink() != null) continue;

                        if (port.getHandlerChains() == null) continue;
                        for (org.apache.openejb.jee.HandlerChain handlerChain : port.getHandlerChains().getHandlerChain()) {
                            for (Handler handler : handlerChain.getHandler()) {
                                String handlerClass = handler.getHandlerClass();
                                if (handlerClass != null) {
                                    try {
                                        Class clazz = classLoader.loadClass(handlerClass);
                                        classes.add(clazz);
                                    } catch (ClassNotFoundException e) {
                                        throw new OpenEJBException("Unable to load webservice handler class: " + handlerClass, e);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            ClassFinder inheritedClassFinder = createInheritedClassFinder(classes.toArray(new Class<?>[classes.size()]));

            // Currently we only process the JNDI annotations for web applications
            buildAnnotatedRefs(webApp, inheritedClassFinder, classLoader);
            processWebServiceClientHandlers(webApp, classLoader);

            return webModule;
        }

        public EjbModule deploy(EjbModule ejbModule) throws OpenEJBException {
            if (ejbModule.getEjbJar() != null && ejbModule.getEjbJar().isMetadataComplete()) return ejbModule;

            ClassLoader classLoader = ejbModule.getClassLoader();
            EnterpriseBean[] enterpriseBeans = ejbModule.getEjbJar().getEnterpriseBeans();
            for (EnterpriseBean bean : enterpriseBeans) {
                final String ejbName = bean.getEjbName();

                Class<?> clazz;
                try {
                    clazz = classLoader.loadClass(bean.getEjbClass());
                } catch (ClassNotFoundException e) {
                    throw new OpenEJBException("Unable to load bean class: " + bean.getEjbClass(), e);
                }
                ClassFinder classFinder = new ClassFinder(clazz);

                ClassFinder inheritedClassFinder = createInheritedClassFinder(clazz);

                processCallbacks(bean, inheritedClassFinder);

                if (bean.getTransactionType() == null) {
                    TransactionManagement tx = getInheritableAnnotation(clazz, TransactionManagement.class);
                    TransactionManagementType transactionType = TransactionManagementType.CONTAINER;
                    if (tx != null) {
                        transactionType = tx.value();
                    }
                    switch (transactionType) {
                        case BEAN:
                            bean.setTransactionType(TransactionType.BEAN);
                            break;
                        case CONTAINER:
                            bean.setTransactionType(TransactionType.CONTAINER);
                            break;
                    }
                }

                AssemblyDescriptor assemblyDescriptor = ejbModule.getEjbJar().getAssemblyDescriptor();
                if (assemblyDescriptor == null) {
                    assemblyDescriptor = new AssemblyDescriptor();
                    ejbModule.getEjbJar().setAssemblyDescriptor(assemblyDescriptor);
                }

                if (bean.getTransactionType() == TransactionType.CONTAINER) {
                    processTransactionAttributes(clazz, ejbName, assemblyDescriptor, inheritedClassFinder);
                }

                processSecurityAnnotations(clazz, ejbName, ejbModule, inheritedClassFinder, bean);

                for (Class<?> interceptorsAnnotatedClass : inheritedClassFinder.findAnnotatedClasses(Interceptors.class)) {
                    Interceptors interceptors = interceptorsAnnotatedClass.getAnnotation(Interceptors.class);
                    EjbJar ejbJar = ejbModule.getEjbJar();
                    for (Class interceptor : interceptors.value()) {
                        if (ejbJar.getInterceptor(interceptor.getName()) == null) {
                            ejbJar.addInterceptor(new Interceptor(interceptor.getName()));
                        }
                    }

                    InterceptorBinding binding = new InterceptorBinding(bean);
                    assemblyDescriptor.getInterceptorBinding().add(0, binding);

                    for (Class interceptor : interceptors.value()) {
                        binding.getInterceptorClass().add(interceptor.getName());
                    }
                }

                for (Method method : inheritedClassFinder.findAnnotatedMethods(Interceptors.class)) {
                    Interceptors interceptors = method.getAnnotation(Interceptors.class);
                    if (interceptors != null) {
                        EjbJar ejbJar = ejbModule.getEjbJar();
                        for (Class interceptor : interceptors.value()) {
                            if (ejbJar.getInterceptor(interceptor.getName()) == null) {
                                ejbJar.addInterceptor(new Interceptor(interceptor.getName()));
                            }
                        }

                        InterceptorBinding binding = new InterceptorBinding(bean);
                        assemblyDescriptor.getInterceptorBinding().add(0, binding);

                        for (Class interceptor : interceptors.value()) {
                            binding.getInterceptorClass().add(interceptor.getName());
                        }

                        binding.setMethod(new NamedMethod(method));
                    }
                }

                ExcludeDefaultInterceptors excludeDefaultInterceptors = clazz.getAnnotation(ExcludeDefaultInterceptors.class);
                if (excludeDefaultInterceptors != null) {
                    InterceptorBinding binding = assemblyDescriptor.addInterceptorBinding(new InterceptorBinding(bean));
                    binding.setExcludeDefaultInterceptors(true);
                }

                for (Method method : classFinder.findAnnotatedMethods(ExcludeDefaultInterceptors.class)) {
                    InterceptorBinding binding = assemblyDescriptor.addInterceptorBinding(new InterceptorBinding(bean));
                    binding.setExcludeDefaultInterceptors(true);
                    binding.setMethod(new NamedMethod(method));
                }

                ExcludeClassInterceptors excludeClassInterceptors = clazz.getAnnotation(ExcludeClassInterceptors.class);
                if (excludeClassInterceptors != null) {
                    InterceptorBinding binding = assemblyDescriptor.addInterceptorBinding(new InterceptorBinding(bean));
                    binding.setExcludeClassInterceptors(true);
                }

                for (Method method : classFinder.findAnnotatedMethods(ExcludeClassInterceptors.class)) {
                    InterceptorBinding binding = assemblyDescriptor.addInterceptorBinding(new InterceptorBinding(bean));
                    binding.setExcludeClassInterceptors(true);
                    binding.setMethod(new NamedMethod(method));
                }

                if (bean instanceof RemoteBean) {
                    RemoteBean remoteBean = (RemoteBean) bean;

                    if (remoteBean.getHome() == null) {
                        RemoteHome remoteHome = getInheritableAnnotation(clazz, RemoteHome.class);
                        if (remoteHome != null) {
                            Class<?> homeClass = remoteHome.value();
                            try {
                                Method create = null;
                                for (Method method : homeClass.getMethods()) {
                                    if (method.getName().startsWith("create")) {
                                        create = method;
                                        break;
                                    }
                                }
                                if (create == null) throw new NoSuchMethodException("create");

                                Class<?> remoteClass = create.getReturnType();
                                remoteBean.setHome(homeClass.getName());
                                remoteBean.setRemote(remoteClass.getName());
                            } catch (NoSuchMethodException e) {
                                logger.error("Class annotated as a RemoteHome has no 'create()' method.  Unable to determine remote interface type.  Bean class: " + clazz.getName() + ",  Home class: " + homeClass.getName());
                            }
                        }
                    }

                    if (remoteBean.getLocalHome() == null) {
                        LocalHome localHome = getInheritableAnnotation(clazz, LocalHome.class);
                        if (localHome != null) {
                            Class<?> homeClass = localHome.value();
                            try {
                                Method create = null;
                                for (Method method : homeClass.getMethods()) {
                                    if (method.getName().startsWith("create")) {
                                        create = method;
                                        break;
                                    }
                                }
                                if (create == null) throw new NoSuchMethodException("create");

                                Class<?> remoteClass = create.getReturnType();
                                remoteBean.setLocalHome(homeClass.getName());
                                remoteBean.setLocal(remoteClass.getName());
                            } catch (NoSuchMethodException e) {
                                logger.error("Class annotated as a LocalHome has no 'create()' method.  Unable to determine remote interface type.  Bean class: " + clazz.getName() + ",  Home class: " + homeClass.getName());
                            }
                        }
                    }

                    if (remoteBean instanceof SessionBean) {
                        SessionBean sessionBean = (SessionBean) remoteBean;

                        processSessionInterfaces(sessionBean, clazz, ejbModule);
                    }
                }

                if (bean instanceof MessageDrivenBean) {
                    MessageDrivenBean mdb = (MessageDrivenBean) bean;
                    MessageDriven messageDriven = clazz.getAnnotation(MessageDriven.class);
                    if (messageDriven != null) {
                        javax.ejb.ActivationConfigProperty[] configProperties = messageDriven.activationConfig();
                        if (configProperties != null) {
                            ActivationConfig activationConfig = mdb.getActivationConfig();
                            if (activationConfig == null) {
                                activationConfig = new ActivationConfig();
                                mdb.setActivationConfig(activationConfig);
                            }
                            Properties properties = activationConfig.toProperties();
                            for (javax.ejb.ActivationConfigProperty property : configProperties) {
                                if (!properties.containsKey(property.propertyName())) {
                                    activationConfig.addProperty(property.propertyName(), property.propertyValue());
                                }
                            }
                        }

                        if (mdb.getMessagingType() == null) {
                            Class<?> interfce = messageDriven.messageListenerInterface();
                            if (interfce != null && !interfce.equals(Object.class)) {
                                if (!interfce.isInterface()) {
                                    // TODO: Move this check to o.a.o.c.rules.CheckClasses and do it for all MDBs, annotated or not
                                    throw new OpenEJBException("MessageListenerInterface property of @MessageDriven is not an interface");
                                }
                                mdb.setMessagingType(interfce.getName());
                            }
                        }
                    }

                    if (mdb.getMessagingType() == null) {
                        List<Class<?>> interfaces = new ArrayList<Class<?>>();
                        for (Class<?> intf : clazz.getInterfaces()) {
                            String name = intf.getName();
                            if (!name.equals("java.io.Serializable") &&
                                    !name.equals("java.io.Externalizable") &&
                                    !name.startsWith("javax.ejb.")) {
                                interfaces.add(intf);
                            }
                        }

                        if (interfaces.size() != 1) {
                            String msg = "When annotating a bean class as @MessageDriven without declaring messageListenerInterface, the bean must implement exactly one interface, no more and no less. beanClass=" + clazz.getName() + " interfaces=";
                            for (Class<?> intf : interfaces) {
                                msg += intf.getName() + ", ";
                            }
                            // TODO: Make this a validation failure, not an exception
                            throw new IllegalStateException(msg);
                        }
                        mdb.setMessagingType(interfaces.get(0).getName());
                    }
                }

                // add webservice handler classes to the class finder used in annotation processing
                Set<Class<?>> classes = new HashSet<Class<?>>();
                classes.add(clazz);
                if (ejbModule.getWebservices() != null) {
                    for (WebserviceDescription webservice : ejbModule.getWebservices().getWebserviceDescription()) {
                        for (PortComponent port : webservice.getPortComponent()) {
                            // only process port definitions for this ejb
                            if (!ejbName.equals(port.getServiceImplBean().getEjbLink())) continue;

                            if (port.getHandlerChains() == null) continue;
                            for (org.apache.openejb.jee.HandlerChain handlerChain : port.getHandlerChains().getHandlerChain()) {
                                for (Handler handler : handlerChain.getHandler()) {
                                    String handlerClass = handler.getHandlerClass();
                                    if (handlerClass != null) {
                                        try {
                                            Class handlerClazz = classLoader.loadClass(handlerClass);
                                            classes.add(handlerClazz);
                                        } catch (ClassNotFoundException e) {
                                            throw new OpenEJBException("Unable to load webservice handler class: " + handlerClass, e);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                inheritedClassFinder = createInheritedClassFinder(classes.toArray(new Class<?>[classes.size()]));

                buildAnnotatedRefs(bean, inheritedClassFinder, classLoader);
                processWebServiceClientHandlers(bean, classLoader);
            }

            for (Interceptor interceptor : ejbModule.getEjbJar().getInterceptors()) {
                Class<?> clazz;
                try {
                    clazz = classLoader.loadClass(interceptor.getInterceptorClass());
                } catch (ClassNotFoundException e) {
                    throw new OpenEJBException("Unable to load interceptor class: " + interceptor.getInterceptorClass(), e);
                }

                ClassFinder inheritedClassFinder = createInheritedClassFinder(clazz);

                processCallbacks(interceptor, inheritedClassFinder);

                buildAnnotatedRefs(interceptor, inheritedClassFinder, classLoader);
                processWebServiceClientHandlers(interceptor, classLoader);

                for (EnterpriseBean bean : enterpriseBeans) {
                    // DMB: TODO, we should actually check to see if the ref exists in the bean's enc.
                    bean.getEnvEntry().addAll(interceptor.getEnvEntry());
                    bean.getEjbRef().addAll(interceptor.getEjbRef());
                    bean.getEjbLocalRef().addAll(interceptor.getEjbLocalRef());
                    bean.getResourceRef().addAll(interceptor.getResourceRef());
                    bean.getResourceEnvRef().addAll(interceptor.getResourceEnvRef());
                    bean.getPersistenceContextRef().addAll(interceptor.getPersistenceContextRef());
                    bean.getPersistenceUnitRef().addAll(interceptor.getPersistenceUnitRef());
                    bean.getMessageDestinationRef().addAll(interceptor.getMessageDestinationRef());
                    bean.getServiceRef().addAll(interceptor.getServiceRef());
                }
            }

            return ejbModule;
        }

        private void processSessionInterfaces(SessionBean sessionBean, Class<?> beanClass, EjbModule ejbModule) {

            ValidationContext validation = ejbModule.getValidation();
            String ejbName = sessionBean.getEjbName();

            for (Class<?> clazz : ancestors(beanClass)) {
                // Anything declared in the xml is also not eligable
                List<String> declared = new ArrayList<String>();
                declared.addAll(sessionBean.getBusinessLocal());
                declared.addAll(sessionBean.getBusinessRemote());
                declared.add(sessionBean.getHome());
                declared.add(sessionBean.getRemote());
                declared.add(sessionBean.getLocalHome());
                declared.add(sessionBean.getLocal());
                declared.add(sessionBean.getServiceEndpoint());

                List<Class<?>> interfaces = new ArrayList<Class<?>>();
                for (Class<?> interfce : clazz.getInterfaces()) {
                    String name = interfce.getName();
                    if (!name.equals("java.io.Serializable") &&
                            !name.equals("java.io.Externalizable") &&
                            !name.startsWith("javax.ejb.") &&
                            !declared.contains(interfce.getName())) {
                        interfaces.add(interfce);
                    }
                }

                List<Class> remotes = new ArrayList<Class>();
                Remote remote = clazz.getAnnotation(Remote.class);
                if (remote != null) {
                    if (remote.value().length == 0) {
                        if (interfaces.size() != 1) {
                            validation.fail(ejbName, "ann.remote.noAttributes", join(", ", interfaces));
                        } else if (clazz.getAnnotation(Local.class) != null) {
                            validation.fail(ejbName, "ann.remoteLocal.ambiguous", join(", ", interfaces));
                        } else if (interfaces.get(0).getAnnotation(Local.class) != null) {
                            validation.fail(ejbName, "ann.remoteLocal.conflict", join(", ", interfaces));
                        } else {
                            if (validateRemoteInterface(interfaces.get(0), validation, ejbName)){
                                remotes.add(interfaces.get(0));
                            }
                            interfaces.remove(0);
                        }
                    } else for (Class interfce : remote.value()) {
                        if (validateRemoteInterface(interfce, validation, ejbName)){
                            remotes.add(interfce);
                        }
                        interfaces.remove(interfce);
                    }
                }

                List<Class> locals = new ArrayList<Class>();
                Local local = clazz.getAnnotation(Local.class);
                if (local != null) {
                    if (local.value().length == 0) {
                        if (interfaces.size() != 1) {
                            validation.fail(ejbName, "ann.local.noAttributes", join(", ", interfaces));
                        } else if (clazz.getAnnotation(Remote.class) != null) {
                            validation.fail(ejbName, "ann.localRemote.ambiguous", join(", ", interfaces));
                        } else if (interfaces.get(0).getAnnotation(Remote.class) != null) {
                            validation.fail(ejbName, "ann.localRemote.conflict", join(", ", interfaces));
                        } else {
                            if (validateLocalInterface(interfaces.get(0), validation, ejbName)){
                                locals.add(interfaces.get(0));
                            }
                            interfaces.remove(0);
                        }
                    } else for (Class interfce : local.value()) {
                        if (validateLocalInterface(interfce, validation, ejbName)){
                            locals.add(interfce);
                        }
                        interfaces.remove(interfce);
                    }
                }

                if (sessionBean.getServiceEndpoint() == null) {
                    WebService webService = clazz.getAnnotation(WebService.class);
                    if (webService != null) {
                        String endpointInterfaceName = webService.endpointInterface();
                        if (!endpointInterfaceName.equals("")){
                            try {
                                sessionBean.setServiceEndpoint(endpointInterfaceName);
                                Class endpointInterface = Class.forName(endpointInterfaceName, false, ejbModule.getClassLoader());
                                interfaces.remove(endpointInterface);
                            } catch (ClassNotFoundException e) {
                                throw new IllegalStateException("Class not found @WebService.endpointInterface: "+endpointInterfaceName, e);
                            }
                        } else {
                            sessionBean.setServiceEndpoint(DeploymentInfo.ServiceEndpoint.class.getName());
                        }
                    } else if (clazz.isAnnotationPresent(WebServiceProvider.class)) {
                        sessionBean.setServiceEndpoint(DeploymentInfo.ServiceEndpoint.class.getName());
                    }
                }

                for (Class interfce : copy(interfaces)) {
                    if (interfce.isAnnotationPresent(WebService.class)) {
                        if (sessionBean.getServiceEndpoint().equals(DeploymentInfo.ServiceEndpoint.class.getName())) {
                            sessionBean.setServiceEndpoint(interfce.getName());
                        }
                        interfaces.remove(interfce);
                    } else if (interfce.isAnnotationPresent(Remote.class)) {
                        remotes.add(interfce);
                        interfaces.remove(interfce);
                    } else {
                        locals.add(interfce);
                        interfaces.remove(interfce);
                    }
                }

                for (Class interfce : remotes) {
                    sessionBean.addBusinessRemote(interfce.getName());
                }

                for (Class interfce : locals) {
                    sessionBean.addBusinessLocal(interfce.getName());
                }
            }
        }

        private void processSecurityAnnotations(Class<?> beanClass, String ejbName, EjbModule ejbModule, ClassFinder classFinder, EnterpriseBean bean) {
            AssemblyDescriptor assemblyDescriptor = ejbModule.getEjbJar().getAssemblyDescriptor();

            List<String> classPermissions = getDeclaredClassPermissions(assemblyDescriptor, ejbName);

            for (Class<?> clazz : ancestors(beanClass)) {

                if (!classPermissions.contains("*") || !classPermissions.contains(clazz.getName())){

                    RolesAllowed rolesAllowed = clazz.getAnnotation(RolesAllowed.class);
                    PermitAll permitAll = clazz.getAnnotation(PermitAll.class);

                    if (rolesAllowed != null && permitAll != null){
                        ejbModule.getValidation().fail(ejbName, "permitAllAndRolesAllowedOnClass", clazz.getName());
                    }

                    if (rolesAllowed != null) {
                        MethodPermission methodPermission = new MethodPermission();
                        methodPermission.getRoleName().addAll(asList(rolesAllowed.value()));
                        methodPermission.getMethod().add(new org.apache.openejb.jee.Method(ejbName, clazz.getName(), "*"));
                        assemblyDescriptor.getMethodPermission().add(methodPermission);
                    }

                    if (permitAll != null) {
                        MethodPermission methodPermission = new MethodPermission();
                        methodPermission.setUnchecked(true);
                        methodPermission.getMethod().add(new org.apache.openejb.jee.Method(ejbName, clazz.getName(), "*"));
                        assemblyDescriptor.getMethodPermission().add(methodPermission);
                    }
                }

                RunAs runAs = clazz.getAnnotation(RunAs.class);
                if (runAs != null && bean.getSecurityIdentity() == null) {
                    SecurityIdentity securityIdentity = new SecurityIdentity();
                    securityIdentity.setRunAs(runAs.value());
                    bean.setSecurityIdentity(securityIdentity);
                }

                DeclareRoles declareRoles = clazz.getAnnotation(DeclareRoles.class);
                if (declareRoles != null && bean instanceof RemoteBean){
                    RemoteBean remoteBean = (RemoteBean) bean;
                    List<SecurityRoleRef> securityRoleRefs = remoteBean.getSecurityRoleRef();
                    for (String role : declareRoles.value()) {
                        securityRoleRefs.add(new SecurityRoleRef(role));
                    }
                }
            }

            List<Method> seen = new ArrayList<Method>();

            for (Method method : classFinder.findAnnotatedMethods(RolesAllowed.class)) {
                checkConflictingSecurityAnnotations(method, ejbName, ejbModule, seen);
                RolesAllowed rolesAllowed = method.getAnnotation(RolesAllowed.class);
                MethodPermission methodPermission = new MethodPermission();
                methodPermission.getRoleName().addAll(asList(rolesAllowed.value()));
                methodPermission.getMethod().add(new org.apache.openejb.jee.Method(ejbName, method));
                assemblyDescriptor.getMethodPermission().add(methodPermission);
            }

            for (Method method : classFinder.findAnnotatedMethods(PermitAll.class)) {
                checkConflictingSecurityAnnotations(method, ejbName, ejbModule, seen);
                MethodPermission methodPermission = new MethodPermission();
                methodPermission.setUnchecked(true);
                methodPermission.getMethod().add(new org.apache.openejb.jee.Method(ejbName, method));
                assemblyDescriptor.getMethodPermission().add(methodPermission);
            }

            for (Method method : classFinder.findAnnotatedMethods(DenyAll.class)) {
                checkConflictingSecurityAnnotations(method, ejbName, ejbModule, seen);
                ExcludeList excludeList = assemblyDescriptor.getExcludeList();
                excludeList.addMethod(new org.apache.openejb.jee.Method(ejbName, method));
            }

        }

        private void checkConflictingSecurityAnnotations(Method method, String ejbName, EjbModule ejbModule, List<Method> seen) {
            if (seen.contains(method)) return;
            seen.add(method);

            List<String> annotations = new ArrayList<String>();
            for (Class<? extends Annotation> annotation : asList(RolesAllowed.class, PermitAll.class, DenyAll.class)) {
                if (method.getAnnotation(annotation) != null){
                    annotations.add("@"+annotation.getSimpleName());
                }
            }

            if (annotations.size() > 1){
                ejbModule.getValidation().fail(ejbName, "conflictingSecurityAnnotations", method.getName(), join(" and ", annotations), method.getDeclaringClass());
            }
        }


        private List<String> getDeclaredClassPermissions(AssemblyDescriptor assemblyDescriptor, String ejbName) {
            List<MethodPermission> permissions = assemblyDescriptor.getMethodPermission();
            List<String> classPermissions = new ArrayList<String>();
            for (MethodPermission permission : permissions) {
                for (org.apache.openejb.jee.Method method : permission.getMethod()) {
                    if (!method.getEjbName().equals(ejbName)) continue;
                    if (!"*".equals(method.getMethodName())) continue;

                    String className = method.getClassName();
                    if (className == null){
                        className = "*";
                    }
                    classPermissions.add(className);
                }
            }
            return classPermissions;
        }

        private void processTransactionAttributes(Class<?> clazz, String ejbName, AssemblyDescriptor assemblyDescriptor, ClassFinder classFinder) {

            Map<String, List<MethodTransaction>> methodTransactions = assemblyDescriptor.getMethodTransactions(ejbName);

            // SET THE DEFAULT
            if (!hasMethodTransaction("*", null, methodTransactions)) {
                for (Class<?> type : ancestors(clazz)) {
                    if (!hasMethodTransaction("*", type, methodTransactions)){
                        TransactionAttribute attribute = type.getAnnotation(TransactionAttribute.class);
                        if (attribute != null) {
                            ContainerTransaction ctx = new ContainerTransaction(cast(attribute.value()), type.getName(), ejbName, "*");
                            assemblyDescriptor.getContainerTransaction().add(ctx);
                        }
                    }
                }

            }


            List<Method> methods = classFinder.findAnnotatedMethods(TransactionAttribute.class);
            for (Method method : methods) {
                TransactionAttribute attribute = method.getAnnotation(TransactionAttribute.class);
                if (!methodTransactions.containsKey(method.getName())) {
                    // no method with this name in descriptor
                    addContainerTransaction(attribute, ejbName, method, assemblyDescriptor);
                } else {
                    // method name already declared
                    List<MethodTransaction> list = methodTransactions.get(method.getName());
                    for (MethodTransaction mtx : list) {
                        MethodParams methodParams = mtx.getMethodParams();
                        if (methodParams == null) {
                            // params not specified, so this is more specific
                            addContainerTransaction(attribute, ejbName, method, assemblyDescriptor);
                        } else {
                            List<String> params1 = methodParams.getMethodParam();
                            String[] params2 = asStrings(method.getParameterTypes());
                            if (params1.size() != params2.length) {
                                // params not the same
                                addContainerTransaction(attribute, ejbName, method, assemblyDescriptor);
                            } else {
                                for (int i = 0; i < params1.size(); i++) {
                                    String a = params1.get(i);
                                    String b = params2[i];
                                    if (!a.equals(b)) {
                                        // params not the same
                                        addContainerTransaction(attribute, ejbName, method, assemblyDescriptor);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        public static void main(String[] args) {
            System.out.println(null + "");
        }

        private boolean hasMethodTransaction(String methodName, Class clazz, Map<String, List<MethodTransaction>> map){
            return getMethodTransaction(methodName, clazz, map) != null;
        }

        private MethodTransaction getMethodTransaction(String methodName, Class clazz, Map<String, List<MethodTransaction>> map) {
            List<MethodTransaction> methodTransactions = map.get(methodName);
            if (methodTransactions == null) return null;

            for (MethodTransaction methodTransaction : methodTransactions) {
                String className = (clazz != null) ? clazz.getName() : null + "";

                if (className.equals(methodTransaction.getClassName() + "")) {
                    return methodTransaction;
                }
            }
            return null;
        }

        private <A extends Annotation> A getInheritableAnnotation(Class clazz, Class<A> annotationClass) {
            if (clazz == null || clazz.equals(Object.class)) return null;

            Annotation annotation = clazz.getAnnotation(annotationClass);
            if (annotation != null) {
                return (A) annotation;
            }

            return getInheritableAnnotation(clazz.getSuperclass(), annotationClass);
        }

        private List<Class<?>> ancestors(Class clazz){
            ArrayList<Class<?>> ancestors = new ArrayList<Class<?>>();

            while (clazz != null && !clazz.equals(Object.class)) {
                ancestors.add(clazz);
                clazz = clazz.getSuperclass();
            }

            return ancestors;
        }

        private ClassFinder createInheritedClassFinder(Class<?>... classes) {
            List<Class> parents = new ArrayList<Class>();
            for (Class<?> clazz : classes) {
                parents.addAll(ancestors(clazz));
            }

            return new ClassFinder(parents);
        }

        private void processCallbacks(Lifecycle bean, ClassFinder classFinder) {
            LifecycleCallback postConstruct = getFirst(bean.getPostConstruct());
            if (postConstruct == null) {
                for (Method method : classFinder.findAnnotatedMethods(PostConstruct.class)) {
                    bean.getPostConstruct().add(new LifecycleCallback(method));
                }
            }

            LifecycleCallback preDestroy = getFirst(bean.getPreDestroy());
            if (preDestroy == null) {
                for (Method method : classFinder.findAnnotatedMethods(PreDestroy.class)) {
                    bean.getPreDestroy().add(new LifecycleCallback(method));
                }
            }

            AroundInvoke aroundInvoke = getFirst(bean.getAroundInvoke());
            if (aroundInvoke == null) {
                for (Method method : classFinder.findAnnotatedMethods(javax.interceptor.AroundInvoke.class)) {
                    bean.getAroundInvoke().add(new AroundInvoke(method));
                }
            }

            if (bean instanceof TimerConsumer) {
                TimerConsumer timerConsumer = (TimerConsumer) bean;
                if (timerConsumer.getTimeoutMethod() == null) {
                    List<Method> timeoutMethods = classFinder.findAnnotatedMethods(javax.ejb.Timeout.class);
                    for (Method method : timeoutMethods) {
                        timerConsumer.setTimeoutMethod(new NamedMethod(method));
                    }
                }
            }

            if (bean instanceof org.apache.openejb.jee.Session) {
                org.apache.openejb.jee.Session session = (org.apache.openejb.jee.Session) bean;

                LifecycleCallback postActivate = getFirst(session.getPostActivate());
                if (postActivate == null) {
                    for (Method method : classFinder.findAnnotatedMethods(PostActivate.class)) {
                        session.getPostActivate().add(new LifecycleCallback(method));
                    }
                }

                LifecycleCallback prePassivate = getFirst(session.getPrePassivate());
                if (prePassivate == null) {
                    for (Method method : classFinder.findAnnotatedMethods(PrePassivate.class)) {
                        session.getPrePassivate().add(new LifecycleCallback(method));
                    }
                }

                List<Method> initMethods = classFinder.findAnnotatedMethods(Init.class);
                for (Method method : initMethods) {
                    InitMethod initMethod = new InitMethod(method);

                    Init init = method.getAnnotation(Init.class);
                    if (init.value() != null && !init.value().equals("")) {
                        initMethod.setCreateMethod(init.value());
                    }

                    session.getInitMethod().add(initMethod);
                }

                List<Method> removeMethods = classFinder.findAnnotatedMethods(Remove.class);
                Map<NamedMethod,RemoveMethod> declaredRemoveMethods = new HashMap<NamedMethod,RemoveMethod>();
                for (RemoveMethod removeMethod : session.getRemoveMethod()) {
                    declaredRemoveMethods.put(removeMethod.getBeanMethod(), removeMethod);
                }
                for (Method method : removeMethods) {
                    Remove remove = method.getAnnotation(Remove.class);
                    RemoveMethod removeMethod = new RemoveMethod(method, remove.retainIfException());

                    RemoveMethod declaredRemoveMethod = declaredRemoveMethods.get(removeMethod.getBeanMethod());

                    if (declaredRemoveMethod == null) {
                        session.getRemoveMethod().add(removeMethod);
                    } else if (!declaredRemoveMethod.isExplicitlySet()){
                        declaredRemoveMethod.setRetainIfException(remove.retainIfException());
                    }
                }
            }
        }

        private void buildAnnotatedRefs(JndiConsumer consumer, ClassFinder classFinder, ClassLoader classLoader) throws OpenEJBException {
            //
            // @EJB
            //

            List<EJB> ejbList = new ArrayList<EJB>();
            for (Class<?> clazz : classFinder.findAnnotatedClasses(EJBs.class)) {
                EJBs ejbs = clazz.getAnnotation(EJBs.class);
                ejbList.addAll(asList(ejbs.value()));
            }
            for (Class<?> clazz : classFinder.findAnnotatedClasses(EJB.class)) {
                EJB e = clazz.getAnnotation(EJB.class);
                ejbList.add(e);
            }

            for (EJB ejb : ejbList) {
                buildEjbRef(consumer, ejb, null);
            }

            for (Field field : classFinder.findAnnotatedFields(EJB.class)) {
                EJB ejb = field.getAnnotation(EJB.class);

                Member member = new FieldMember(field);

                buildEjbRef(consumer, ejb, member);
            }

            for (Method method : classFinder.findAnnotatedMethods(EJB.class)) {
                EJB ejb = method.getAnnotation(EJB.class);

                Member member = new MethodMember(method);

                buildEjbRef(consumer, ejb, member);
            }


            //
            // @Resource
            //

            List<Resource> resourceList = new ArrayList<Resource>();
            for (Class<?> clazz : classFinder.findAnnotatedClasses(Resources.class)) {
                Resources resources = clazz.getAnnotation(Resources.class);
                resourceList.addAll(asList(resources.value()));
            }
            for (Class<?> clazz : classFinder.findAnnotatedClasses(Resource.class)) {
                Resource resource = clazz.getAnnotation(Resource.class);
                resourceList.add(resource);
            }

            for (Resource resource : resourceList) {
                buildResource(consumer, resource, null);
            }

            for (Field field : classFinder.findAnnotatedFields(Resource.class)) {
                Resource resource = field.getAnnotation(Resource.class);

                Member member = new FieldMember(field);

                buildResource(consumer, resource, member);
            }

            for (Method method : classFinder.findAnnotatedMethods(Resource.class)) {
                Resource resource = method.getAnnotation(Resource.class);

                Member member = new MethodMember(method);

                buildResource(consumer, resource, member);
            }

            //
            // @WebServiceRef
            //

            List<WebServiceRef> webservicerefList = new ArrayList<WebServiceRef>();
            for (Class<?> clazz : classFinder.findAnnotatedClasses(WebServiceRefs.class)) {
                WebServiceRefs webServiceRefs = clazz.getAnnotation(WebServiceRefs.class);
                webservicerefList.addAll(asList(webServiceRefs.value()));
            }
            for (Class<?> clazz : classFinder.findAnnotatedClasses(WebServiceRef.class)) {
                WebServiceRef webServiceRef = clazz.getAnnotation(WebServiceRef.class);
                webservicerefList.add(webServiceRef);
            }

            for (WebServiceRef webserviceref : webservicerefList) {

                buildWebServiceRef(consumer, webserviceref, null, null, classLoader);
            }

            for (Field field : classFinder.findAnnotatedFields(WebServiceRef.class)) {
                WebServiceRef webserviceref = field.getAnnotation(WebServiceRef.class);
                HandlerChain handlerChain = field.getAnnotation(HandlerChain.class);

                Member member = new FieldMember(field);

                buildWebServiceRef(consumer, webserviceref, handlerChain, member, classLoader);
            }

            for (Method method : classFinder.findAnnotatedMethods(WebServiceRef.class)) {
                WebServiceRef webserviceref = method.getAnnotation(WebServiceRef.class);
                HandlerChain handlerChain = method.getAnnotation(HandlerChain.class);

                Member member = new MethodMember(method);

                buildWebServiceRef(consumer, webserviceref, handlerChain, member, classLoader);
            }

            //
            // @PersistenceUnit
            //

            List<PersistenceUnit> persistenceUnitList = new ArrayList<PersistenceUnit>();
            for (Class<?> clazz : classFinder.findAnnotatedClasses(PersistenceUnits.class)) {
                PersistenceUnits persistenceUnits = clazz.getAnnotation(PersistenceUnits.class);
                persistenceUnitList.addAll(asList(persistenceUnits.value()));
            }
            for (Class<?> clazz : classFinder.findAnnotatedClasses(PersistenceUnit.class)) {
                PersistenceUnit persistenceUnit = clazz.getAnnotation(PersistenceUnit.class);
                persistenceUnitList.add(persistenceUnit);
            }
            for (PersistenceUnit pUnit : persistenceUnitList) {
                buildPersistenceUnit(consumer, pUnit, null);
            }
            for (Field field : classFinder.findAnnotatedFields(PersistenceUnit.class)) {
                PersistenceUnit pUnit = field.getAnnotation(PersistenceUnit.class);
                Member member = new FieldMember(field);
                buildPersistenceUnit(consumer, pUnit, member);
            }
            for (Method method : classFinder.findAnnotatedMethods(PersistenceUnit.class)) {
                PersistenceUnit pUnit = method.getAnnotation(PersistenceUnit.class);
                Member member = new MethodMember(method);
                buildPersistenceUnit(consumer, pUnit, member);
            }

            //
            // @PersistenceContext
            //

            PersistenceContextAnnFactory pcFactory = new PersistenceContextAnnFactory();
            List<PersistenceContext> persistenceContextList = new ArrayList<PersistenceContext>();
            for (Class<?> clazz : classFinder.findAnnotatedClasses(PersistenceContexts.class)) {
                PersistenceContexts persistenceContexts = clazz.getAnnotation(PersistenceContexts.class);
                persistenceContextList.addAll(asList(persistenceContexts.value()));
                pcFactory.addAnnotations(clazz);
            }
            for (Class<?> clazz : classFinder.findAnnotatedClasses(PersistenceContext.class)) {
                PersistenceContext persistenceContext = clazz.getAnnotation(PersistenceContext.class);
                persistenceContextList.add(persistenceContext);
                pcFactory.addAnnotations(clazz);
            }
            for (PersistenceContext pCtx : persistenceContextList) {
                buildPersistenceContext(consumer, pcFactory.create(pCtx, null), null);
            }
            for (Field field : classFinder.findAnnotatedFields(PersistenceContext.class)) {
                PersistenceContext pCtx = field.getAnnotation(PersistenceContext.class);
                Member member = new FieldMember(field);
                buildPersistenceContext(consumer, pcFactory.create(pCtx, member), member);
            }
            for (Method method : classFinder.findAnnotatedMethods(PersistenceContext.class)) {
                PersistenceContext pCtx = method.getAnnotation(PersistenceContext.class);
                Member member = new MethodMember(method);
                buildPersistenceContext(consumer, pcFactory.create(pCtx, member), member);
            }

        }

        private void processWebServiceClientHandlers(JndiConsumer consumer, ClassLoader classLoader) throws OpenEJBException {
            if (System.getProperty("duct tape") != null) return;
            Set<Class<?>> processedClasses = new HashSet<Class<?>>();
            Set<Class<?>> handlerClasses = new HashSet<Class<?>>();
            do {
                // get unprocessed handler classes
                handlerClasses.clear();
                for (ServiceRef serviceRef : consumer.getServiceRef()) {
                    HandlerChains chains = serviceRef.getAllHandlers();
                    if (chains == null) continue;
                    for (org.apache.openejb.jee.HandlerChain handlerChain : chains.getHandlerChain()) {
                        for (Handler handler : handlerChain.getHandler()) {
                            if (handler.getHandlerClass() != null) {
                                try {
                                    Class clazz = classLoader.loadClass(handler.getHandlerClass());
                                    handlerClasses.add(clazz);
                                } catch (ClassNotFoundException e) {
                                    throw new OpenEJBException("Unable to load webservice handler class: " + handler.getHandlerClass(), e);
                                }
                            }
                        }
                    }
                }
                handlerClasses.removeAll(processedClasses);

                // process handler classes
                ClassFinder handlerClassFinder = createInheritedClassFinder(handlerClasses.toArray(new Class<?>[handlerClasses.size()]));
                buildAnnotatedRefs(consumer, handlerClassFinder, classLoader);
                processedClasses.addAll(handlerClasses);
            } while (!handlerClasses.isEmpty());
        }

        private void buildPersistenceUnit(JndiConsumer consumer, PersistenceUnit persistenceUnit, Member member) throws OpenEJBException {
            // Get the ref-name
            String refName = persistenceUnit.name();
            if (refName.equals("")) {
                refName = (member == null) ? null : member.getDeclaringClass().getName() + "/" + member.getName();
            }

            if (refName == null && member == null) {
                getValidationContext().get().fail(consumer.getJndiConsumerName(), "presistenceUnitAnnotation.onClassWithNoName", persistenceUnit.unitName());
                return;
            }

            PersistenceUnitRef persistenceUnitRef = consumer.getPersistenceUnitRefMap().get(refName);
            if (persistenceUnitRef == null) {
                persistenceUnitRef = new PersistenceUnitRef();
                persistenceUnitRef.setPersistenceUnitName(persistenceUnit.unitName());
                persistenceUnitRef.setPersistenceUnitRefName(refName);
                consumer.getPersistenceUnitRef().add(persistenceUnitRef);
            }
            if (member != null) {
                Class type = member.getType();
                if (EntityManager.class.isAssignableFrom(type)){
                    ValidationContext validationContext = AnnotationDeployer.getValidationContext().get();
                    String jndiConsumerName = consumer.getJndiConsumerName();
                    String name = persistenceUnitRef.getName();
                    validationContext.fail(jndiConsumerName, "presistenceUnitAnnotation.onEntityManager", name);
                } else if (!EntityManagerFactory.class.isAssignableFrom(type)){
                    getValidationContext().get().fail(consumer.getJndiConsumerName(), "presistenceUnitAnnotation.onNonEntityManagerFactory", persistenceUnitRef.getName());
                } else {
                    // Set the member name where this will be injected
                    InjectionTarget target = new InjectionTarget();
                    target.setInjectionTargetClass(member.getDeclaringClass().getName());
                    target.setInjectionTargetName(member.getName());
                    persistenceUnitRef.getInjectionTarget().add(target);
                }
            }

            if (persistenceUnitRef.getPersistenceUnitName() == null && !persistenceUnit.unitName().equals("")) {
                persistenceUnitRef.setPersistenceUnitName(persistenceUnit.unitName());
            }
        }

        private void buildResource(JndiConsumer consumer, Resource resource, Member member) {
            // Get the ref-name
            String refName = resource.name();
            if (refName.equals("")) {
                refName = (member == null) ? null : member.getDeclaringClass().getName() + "/" + member.getName();
            }

            if (member == null) {
                boolean shouldReturn = false;
                if (resource.name().equals("")){
                    getValidationContext().get().fail(consumer.getJndiConsumerName(), "resourceAnnotation.onClassWithNoName");
                    shouldReturn = true;
                }
                if (resource.type().equals(Object.class)){
                    getValidationContext().get().fail(consumer.getJndiConsumerName(), "resourceAnnotation.onClassWithNoType");
                    shouldReturn = true;
                }
                if (shouldReturn) return;
            }

            JndiReference reference = consumer.getEnvEntryMap().get(refName);
            if (reference == null) {

                if (member != null) { // Little quick validation for common mistake
                    Class type = member.getType();
                    boolean shouldReturn = false;
                    if (EntityManager.class.isAssignableFrom(type)){
                        getValidationContext().get().fail(consumer.getJndiConsumerName(), "resourceRef.onEntityManager", refName);
                        shouldReturn = true;
                    } else if (EntityManagerFactory.class.isAssignableFrom(type)){
                        getValidationContext().get().fail(consumer.getJndiConsumerName(), "resourceRef.onEntityManagerFactory", refName);
                        shouldReturn = true;
                    }
                    if (shouldReturn) return;
                }
                String type;
                if (resource.type() != java.lang.Object.class) {
                    type = resource.type().getName();
                } else {
                    type = member.getType().getName();
                }

                if (knownResourceEnvTypes.contains(type)) {
                    ResourceEnvRef resourceEnvRef = consumer.getResourceEnvRefMap().get(refName);
                    if (resourceEnvRef == null) {
                        resourceEnvRef = new ResourceEnvRef();
                        resourceEnvRef.setName(refName);
                        consumer.getResourceEnvRef().add(resourceEnvRef);
                    }

                    if (resourceEnvRef.getResourceEnvRefType() == null || ("").equals(resourceEnvRef.getResourceEnvRefType())) {
                        if (resource.type() != java.lang.Object.class) {
                            resourceEnvRef.setResourceEnvRefType(resource.type().getName());
                        } else {
                            resourceEnvRef.setResourceEnvRefType(member.getType().getName());
                        }
                    }
                    reference = resourceEnvRef;
                } else if (!knownEnvironmentEntries.contains(type)) {
                    ResourceRef resourceRef = consumer.getResourceRefMap().get(refName);

                    if (resourceRef == null) {
                        resourceRef = new ResourceRef();
                        resourceRef.setName(refName);
                        consumer.getResourceRef().add(resourceRef);
                    }

                    if (resourceRef.getResAuth() == null) {
                        if (resource.authenticationType() == Resource.AuthenticationType.APPLICATION) {
                            resourceRef.setResAuth(ResAuth.APPLICATION);
                        } else {
                            resourceRef.setResAuth(ResAuth.CONTAINER);
                        }
                    }

                    if (resourceRef.getResType() == null || ("").equals(resourceRef.getResType())) {
                        if (resource.type() != java.lang.Object.class) {
                            resourceRef.setResType(resource.type().getName());
                        } else {
                            resourceRef.setResType(member.getType().getName());
                        }
                    }

                    if (resourceRef.getResSharingScope() == null) {
                        if (resource.shareable()) {
                            resourceRef.setResSharingScope(ResSharingScope.SHAREABLE);
                        } else {
                            resourceRef.setResSharingScope(ResSharingScope.UNSHAREABLE);
                        }
                    }
                    reference = resourceRef;
                }
            }
            if (reference == null) {
                return;
            }

//            reference.setName(refName);

            if (member != null) {
                // Set the member name where this will be injected
                InjectionTarget target = new InjectionTarget();
                target.setInjectionTargetClass(member.getDeclaringClass().getName());
                target.setInjectionTargetName(member.getName());
                reference.getInjectionTarget().add(target);
            }

            // Override the mapped name if not set
            if (reference.getMappedName() == null && !resource.mappedName().equals("")) {
                reference.setMappedName(resource.mappedName());
            }

        }

        private void buildWebServiceRef(JndiConsumer consumer, WebServiceRef webService, HandlerChain handlerChain, Member member, ClassLoader classLoader) throws OpenEJBException {

            ServiceRef serviceRef;

            String refName = webService.name();
            if (refName.equals("")) {
                refName = (member == null) ? null : member.getDeclaringClass().getName() + "/" + member.getName();
            }

            serviceRef = consumer.getServiceRefMap().get(refName);

            if (serviceRef == null) {
                serviceRef = new ServiceRef();
                serviceRef.setServiceRefName(refName);

                consumer.getServiceRef().add(serviceRef);
            }

            if (member != null) {
                // Set the member name where this will be injected
                InjectionTarget target = new InjectionTarget();
                target.setInjectionTargetClass(member.getDeclaringClass().getName());
                target.setInjectionTargetName(member.getName());
                serviceRef.getInjectionTarget().add(target);
            }

            // Set service interface
            Class<?> serviceInterface = null;
            if (serviceRef.getServiceInterface() == null) {
                serviceInterface = webService.type();
                if (serviceInterface.equals(Object.class)) {
                    if (member != null) {
                        serviceInterface = member.getType();
                    } else {
                        serviceInterface = webService.value();
                    }
                }
            }
            if (serviceInterface == null || !serviceInterface.isAssignableFrom(Service.class)) {
                serviceInterface = Service.class;
            }
            serviceRef.setServiceInterface(serviceInterface.getName());

            // reference type
            if (serviceRef.getServiceRefType() == null || ("").equals(serviceRef.getServiceRefType())) {
                if (webService.type() != java.lang.Object.class) {
                    serviceRef.setServiceRefType(webService.type().getName());
                } else {
                    serviceRef.setServiceRefType(member.getType().getName());
                }
            }
            Class<?> refType = null;
            try {
                refType = classLoader.loadClass(serviceRef.getType());
            } catch (ClassNotFoundException e) {
            }

            // Set the mappedName
            if (serviceRef.getMappedName() == null) {
                String mappedName = webService.mappedName();
                if (mappedName.equals("")) {
                    mappedName = null;
                }
                serviceRef.setMappedName(mappedName);
            }

            // wsdl file
            if (serviceRef.getWsdlFile() == null) {
                String wsdlLocation = webService.wsdlLocation();
                if (!wsdlLocation.equals("")) {
                    serviceRef.setWsdlFile(wsdlLocation);
                }
            }

            if (System.getProperty("duct tape") != null) return;

            if (serviceRef.getWsdlFile() == null && refType != null) {
                serviceRef.setWsdlFile(JaxWsUtils.getServiceWsdlLocation(refType, classLoader));
            }
            if (serviceRef.getWsdlFile() == null && serviceInterface != null) {
                serviceRef.setWsdlFile(JaxWsUtils.getServiceWsdlLocation(serviceInterface, classLoader));
            }

            // service qname
            if (serviceRef.getServiceQname() == null && refType != null) {
                serviceRef.setServiceQname(JaxWsUtils.getServiceQName(refType));
            }
            if (serviceRef.getServiceQname() == null && serviceInterface != null) {
                serviceRef.setServiceQname(JaxWsUtils.getServiceQName(serviceInterface));
            }

            // handlers
            if (serviceRef.getHandlerChains() == null && handlerChain != null) {
                try {
                    URL handlerFileURL = member.getDeclaringClass().getResource(handlerChain.file());
                    HandlerChains handlerChains = ReadDescriptors.readHandlerChains(handlerFileURL);
                    serviceRef.setHandlerChains(handlerChains);
                } catch (Throwable e) {
                    throw new OpenEJBException("Unable to load handler chain file: " + handlerChain.file(), e);
                }
            }
        }

        /**
         * Refer 16.11.2.1 Overriding Rules of EJB Core Spec for overriding rules
         *
         * @param consumer
         * @param persistenceContext
         * @param member
         * @throws OpenEJBException
         */
        private void buildPersistenceContext(JndiConsumer consumer, PersistenceContextAnn persistenceContext, Member member) throws OpenEJBException {
            String refName = persistenceContext.name();

            if (refName.equals("")) {
                refName = (member == null) ? null : member.getDeclaringClass().getName() + "/" + member.getName();
            }

            if (refName == null && member == null) {
                getValidationContext().get().fail(consumer.getJndiConsumerName(), "presistenceContextAnnotation.onClassWithNoName", persistenceContext.unitName());
                return;
            }

            PersistenceContextRef persistenceContextRef = consumer.getPersistenceContextRefMap().get(refName);
            if (persistenceContextRef == null) {
                persistenceContextRef = new PersistenceContextRef();
                persistenceContextRef.setPersistenceUnitName(persistenceContext.unitName());
                persistenceContextRef.setPersistenceContextRefName(refName);
                if ("EXTENDED".equalsIgnoreCase(persistenceContext.type())) {
                    persistenceContextRef.setPersistenceContextType(PersistenceContextType.EXTENDED);
                } else {
                    persistenceContextRef.setPersistenceContextType(PersistenceContextType.TRANSACTION);
                }
                consumer.getPersistenceContextRef().add(persistenceContextRef);
            } else {
                if (persistenceContextRef.getPersistenceUnitName() == null || ("").equals(persistenceContextRef.getPersistenceUnitName())) {
                    persistenceContextRef.setPersistenceUnitName(persistenceContext.unitName());
                }
                if (persistenceContextRef.getPersistenceContextType() == null || ("").equals(persistenceContextRef.getPersistenceContextType())) {
                    if ("EXTENDED".equalsIgnoreCase(persistenceContext.type())) {
                        persistenceContextRef.setPersistenceContextType(PersistenceContextType.EXTENDED);
                    } else {
                        persistenceContextRef.setPersistenceContextType(PersistenceContextType.TRANSACTION);
                    }
                }
            }

            List<Property> persistenceProperties = persistenceContextRef.getPersistenceProperty();
            if (persistenceProperties == null) {
                persistenceProperties = new ArrayList<Property>();
                persistenceContextRef.setPersistenceProperty(persistenceProperties);
            }

            for (Map.Entry<String, String> persistenceProperty : persistenceContext.properties().entrySet()) {
                boolean flag = true;
                for (Property prpty : persistenceProperties) {
                    if (prpty.getName().equals(persistenceProperty.getKey())) {
                        flag = false;
                        break;
                    }
                }
                if (flag) {
                    Property property = new Property();
                    property.setName(persistenceProperty.getKey());
                    property.setValue(persistenceProperty.getValue());
                    persistenceProperties.add(property);
                }
            }

            if (member != null) {
                Class type = member.getType();
                if (EntityManagerFactory.class.isAssignableFrom(type)){
                    getValidationContext().get().fail(consumer.getJndiConsumerName(), "presistenceContextAnnotation.onEntityManagerFactory", persistenceContextRef.getName());
                } else if (!EntityManager.class.isAssignableFrom(type)){
                    getValidationContext().get().fail(consumer.getJndiConsumerName(), "presistenceContextAnnotation.onNonEntityManager", persistenceContextRef.getName());
                } else {
                    // Set the member name where this will be injected
                    InjectionTarget target = new InjectionTarget();
                    target.setInjectionTargetClass(member.getDeclaringClass().getName());
                    target.setInjectionTargetName(member.getName());
                    persistenceContextRef.getInjectionTarget().add(target);
                }
            }
        }

        private void buildEjbRef(JndiConsumer consumer, EJB ejb, Member member) {

            if (member == null) {
                boolean shouldReturn = false;
                if (ejb.name().equals("")){
                    getValidationContext().get().fail(consumer.getJndiConsumerName(), "ejbAnnotation.onClassWithNoName");
                    shouldReturn = true;
                }
                if (ejb.beanInterface().equals(Object.class)){
                    getValidationContext().get().fail(consumer.getJndiConsumerName(), "ejbAnnotation.onClassWithNoBeanInterface");
                    shouldReturn = true;
                }
                if (shouldReturn) return;
            }

            EjbRef ejbRef = new EjbRef();

            // This is how we deal with the fact that we don't know
            // whether to use an EjbLocalRef or EjbRef (remote).
            // We flag it uknown and let the linking code take care of
            // figuring out what to do with it.
            ejbRef.setRefType(EjbReference.Type.UNKNOWN);

            if (member != null) {
                // Set the member name where this will be injected
                InjectionTarget target = new InjectionTarget();
                target.setInjectionTargetClass(member.getDeclaringClass().getName());
                target.setInjectionTargetName(member.getName());
                ejbRef.getInjectionTarget().add(target);
            }

            Class<?> interfce = ejb.beanInterface();
            if (interfce.equals(Object.class)) {
                interfce = (member == null) ? null : member.getType();
            }

            if (interfce != null && !interfce.equals(Object.class)) {
                if (EJBHome.class.isAssignableFrom(interfce)) {
                    ejbRef.setHome(interfce.getName());
                    Method[] methods = interfce.getMethods();
                    for (Method method : methods) {
                        if (method.getName().startsWith("create")) {
                            ejbRef.setRemote(method.getReturnType().getName());
                            break;
                        }
                    }
                    ejbRef.setRefType(EjbReference.Type.REMOTE);
                } else if (EJBLocalHome.class.isAssignableFrom(interfce)) {
                    ejbRef.setHome(interfce.getName());
                    Method[] methods = interfce.getMethods();
                    for (Method method : methods) {
                        if (method.getName().startsWith("create")) {
                            ejbRef.setRemote(method.getReturnType().getName());
                            break;
                        }
                    }
                    ejbRef.setRefType(EjbReference.Type.LOCAL);
                } else {
                    ejbRef.setRemote(interfce.getName());
                    if (interfce.getAnnotation(Local.class) != null) {
                        ejbRef.setRefType(EjbReference.Type.LOCAL);
                    } else if (interfce.getAnnotation(Remote.class) != null) {
                        ejbRef.setRefType(EjbReference.Type.REMOTE);
                    }
                }
            }

            // Get the ejb-ref-name
            String refName = ejb.name();
            if (refName.equals("")) {
                refName = (member == null) ? null : member.getDeclaringClass().getName() + "/" + member.getName();
            }
            ejbRef.setEjbRefName(refName);

            // Set the ejb-link, if any
            String ejbName = ejb.beanName();
            if (ejbName.equals("")) {
                ejbName = null;
            }
            ejbRef.setEjbLink(ejbName);

            // Set the mappedName, if any
            String mappedName = ejb.mappedName();
            if (mappedName.equals("")) {
                mappedName = null;
            }
            ejbRef.setMappedName(mappedName);


            Map<String, EjbRef> remoteRefs = consumer.getEjbRefMap();
            if (remoteRefs.containsKey(ejbRef.getName())){
                EjbRef ref = remoteRefs.get(ejbRef.getName());
                if (ref.getRemote() == null) ref.setRemote(ejbRef.getRemote());
                if (ref.getHome() == null) ref.setHome(ejbRef.getHome());
                if (ref.getMappedName() == null) ref.setMappedName(ejbRef.getMappedName());
                ref.getInjectionTarget().addAll(ejbRef.getInjectionTarget());
                return;
            }

            Map<String, EjbLocalRef> localRefs = consumer.getEjbLocalRefMap();
            if (localRefs.containsKey(ejbRef.getName())){
                EjbLocalRef ejbLocalRef = new EjbLocalRef(ejbRef);
                EjbLocalRef ref = localRefs.get(ejbLocalRef.getName());
                if (ref.getLocal() == null) ref.setLocal(ejbLocalRef.getLocal());
                if (ref.getLocalHome() == null) ref.setLocalHome(ejbLocalRef.getLocalHome());
                if (ref.getMappedName() == null) ref.setMappedName(ejbLocalRef.getMappedName());
                ref.getInjectionTarget().addAll(ejbLocalRef.getInjectionTarget());
                return;
            }

            switch (ejbRef.getRefType()) {
                case UNKNOWN:
                case REMOTE:
                    consumer.getEjbRef().add(ejbRef);
                    break;
                case LOCAL:
                    consumer.getEjbLocalRef().add(new EjbLocalRef(ejbRef));
                    break;
            }
        }

        private List<Class<?>> copy(List<Class<?>> classes) {
            return new ArrayList<Class<?>>(classes);
        }

        private void addContainerTransaction(TransactionAttribute attribute, String ejbName, Method method, AssemblyDescriptor assemblyDescriptor) {
            ContainerTransaction ctx = new ContainerTransaction(cast(attribute.value()), ejbName, method);
            assemblyDescriptor.getContainerTransaction().add(ctx);
        }

        private String[] asStrings(Class[] types) {
            List<String> names = new ArrayList<String>();
            for (Class clazz : types) {
                names.add(clazz.getName());
            }
            return names.toArray(new String[names.size()]);
        }

        private TransAttribute cast(TransactionAttributeType transactionAttributeType) {
            return TransAttribute.valueOf(transactionAttributeType.toString());
        }

        private <T> T getFirst(List<T> list) {
            if (list.size() > 0) {
                return list.get(0);
            }
            return null;
        }


        private boolean validateRemoteInterface(Class interfce, ValidationContext validation, String ejbName) {
            return isValidInterface(interfce, validation, ejbName, "Remote");
        }

        private boolean validateLocalInterface(Class interfce, ValidationContext validation, String ejbName) {
            return isValidInterface(interfce, validation, ejbName, "Local");
        }

        private boolean isValidInterface(Class interfce, ValidationContext validation, String ejbName, String annotationName) {
            if (!interfce.isInterface()){
                validation.fail(ejbName, "ann.notAnInterface", annotationName, interfce.getName());
                return false;
            } else if (EJBHome.class.isAssignableFrom(interfce)){
                validation.fail(ejbName, "ann.remoteOrLocal.ejbHome", annotationName, interfce.getName());
                return false;
            } else if (EJBObject.class.isAssignableFrom(interfce)){
                validation.fail(ejbName, "ann.remoteOrLocal.ejbObject", annotationName, interfce.getName());
                return false;
            } else if (EJBLocalHome.class.isAssignableFrom(interfce)) {
                validation.fail(ejbName, "ann.remoteOrLocal.ejbLocalHome", annotationName, interfce.getName());
                return false;
            } else if (EJBLocalObject.class.isAssignableFrom(interfce)){
                validation.fail(ejbName, "ann.remoteOrLocal.ejbLocalObject", annotationName, interfce.getName());
                return false;
            }
            return true;
        }
    }

    public static interface Member {
        Class getDeclaringClass();

        String getName();

        Class getType();
    }

    public static class MethodMember implements Member {
        private final Method setter;

        public MethodMember(Method method) {
            this.setter = method;
        }

        public Class getType() {
            return setter.getParameterTypes()[0];
        }

        public Class getDeclaringClass() {
            return setter.getDeclaringClass();
        }

        public String getName() {
            StringBuilder name = new StringBuilder(setter.getName());

            // remove 'set'
            name.delete(0, 3);

            // lowercase first char
            name.setCharAt(0, Character.toLowerCase(name.charAt(0)));

            return name.toString();
        }

        public String toString() {
            return setter.toString();
        }
    }

    public static class FieldMember implements Member {
        private final Field field;

        public FieldMember(Field field) {
            this.field = field;
        }

        public Class getType() {
            return field.getType();
        }

        public String toString() {
            return field.toString();
        }

        public Class getDeclaringClass() {
            return field.getDeclaringClass();
        }

        public String getName() {
            return field.getName();
        }
    }

}
TOP

Related Classes of org.apache.openejb.config.AnnotationDeployer$ProcessAnnotatedBeans

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.