public EjbModule deploy()

in container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java [2469:3042]


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

//            Map<String, EjbDeployment> deployments = ejbModule.getOpenejbJar().getDeploymentsByEjbName();
            final ClassLoader classLoader = ejbModule.getClassLoader();
            final EnterpriseBean[] enterpriseBeans = ejbModule.getEjbJar().getEnterpriseBeans();
            for (final EnterpriseBean bean : enterpriseBeans) {
                final String ejbName = bean.getEjbName();
                final String ejbClassName = realClassName(bean.getEjbClass());

                if (ejbClassName == null) {
                    final List<String> others = new ArrayList<>();
                    for (final EnterpriseBean otherBean : enterpriseBeans) {
                        others.add(otherBean.getEjbName());
                    }
                    fail(ejbName, "xml.noEjbClass", ejbName, Join.join(", ", others));
                }

                final Class<?> clazz;
                try {
                    clazz = classLoader.loadClass(ejbClassName);
                } catch (final ClassNotFoundException e) {
                    // Handled in CheckClasses.java along with other missing classes
                    continue;
                }

                final MetaAnnotatedClass<?> metaClass = new MetaAnnotatedClass(clazz);
                final boolean dynamicBean = DynamicProxyImplFactory.isKnownDynamicallyImplemented(metaClass, clazz);

                AnnotationFinder finder = null; // created lazily since not always needed
                final AnnotationFinder annotationFinder;
                if (ejbModule.getFinder() instanceof AnnotationFinder) {
                    AnnotationFinder af = (AnnotationFinder) ejbModule.getFinder();

                    final List<Class<?>> ancestors = Classes.ancestors(clazz);
                    ancestors.addAll(asList(clazz.getInterfaces()));
                    if (dynamicBean) {
                        final Proxy p = metaClass.getAnnotation(Proxy.class);
                        if (p != null) {
                            ancestors.add(p.value());
                        }
                    }

                    final String[] names = new String[ancestors.size()];
                    int i = 0;
                    for (final Class<?> ancestor : ancestors) {
                        names[i++] = ancestor.getName();
                    }
                    annotationFinder = af.select(names);
                } else { // shouldn't occur
                    if (!dynamicBean) {
                        annotationFinder = createFinder(clazz);
                    } else {
                        final Class<?>[] classes;
                        final Proxy proxy = metaClass.getAnnotation(Proxy.class);
                        if (proxy == null) {
                            classes = new Class<?>[]{clazz};
                        } else {
                            classes = new Class<?>[]{clazz, proxy.value()};
                        }
                        annotationFinder = createFinder(classes);
                    }
                }

                /*
                 * @AroundConstruct can't be on the bean itself per spec
                 * @PostConstruct
                 * @PreDestroy
                 * @AroundInvoke
                 * @Timeout
                 * @PostActivate
                 * @PrePassivate
                 * @Init
                 * @Remove
                 * @AroundTimeout
                 * @AfterBegin
                 * @BeforeCompletion
                 * @AfterCompletion
                 */
                processCallbacks(bean, annotationFinder);

                /*
                 * @TransactionManagement
                 */
                if (bean.getTransactionType() == null) {
                    final 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;
                    }
                }

                final AssemblyDescriptor assemblyDescriptor = ejbModule.getEjbJar().getAssemblyDescriptor();

                /*
                 * @ApplicationException
                 */
                processApplicationExceptions(clazz, assemblyDescriptor);

                /*
                 * TransactionAttribute
                 */
                if (bean.getTransactionType() == TransactionType.CONTAINER) {
                    processAttributes(new TransactionAttributeHandler(assemblyDescriptor, ejbName), clazz, annotationFinder);
                } else {
                    if (finder == null) {
                        finder = annotationFinder.select(clazz.getName());
                    }
                    checkAttributes(new TransactionAttributeHandler(assemblyDescriptor, ejbName), ejbName, ejbModule, finder, "invalidTransactionAttribute");
                }

                /*
                 * @RolesAllowed
                 * @PermitAll
                 * @DenyAll
                 * @RunAs
                 * @DeclareRoles
                 */
                processSecurityAnnotations(clazz, ejbName, ejbModule, annotationFinder, bean);

                /*
                 * @Schedule
                 * @Schedules
                 */
                processSchedules(bean, annotationFinder);

                /*
                 * Add any interceptors they may have referenced in xml but did not declare
                 */
                for (final InterceptorBinding binding : assemblyDescriptor.getInterceptorBinding()) {
                    final EjbJar ejbJar = ejbModule.getEjbJar();

                    final List<String> list = new ArrayList<>(binding.getInterceptorClass());

                    if (binding.getInterceptorOrder() != null) {
                        list.clear();
                        list.addAll(binding.getInterceptorOrder().getInterceptorClass());
                    }

                    for (final String interceptor : list) {
                        if (ejbJar.getInterceptor(interceptor) == null) {
                            logger.debug("Adding '<ejb-jar><interceptors><interceptor>' entry for undeclared interceptor " + interceptor);
                            ejbJar.addInterceptor(new Interceptor(interceptor));
                        }
                    }
                }

                /*
                 * @Interceptors
                 */
                final List<Annotated<Class<?>>> annotatedClasses = sortClasses(annotationFinder.findMetaAnnotatedClasses(Interceptors.class));
                for (final Annotated<Class<?>> interceptorsAnnotatedClass : annotatedClasses) {
                    final Interceptors interceptors = interceptorsAnnotatedClass.getAnnotation(Interceptors.class);
                    final EjbJar ejbJar = ejbModule.getEjbJar();
                    for (final Class interceptor : interceptors.value()) {
                        if (ejbJar.getInterceptor(interceptor.getName()) == null) {
                            ejbJar.addInterceptor(new Interceptor(interceptor.getName()));
                        }
                    }

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

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

                final List<Annotated<Method>> annotatedMethods = sortMethods(annotationFinder.findMetaAnnotatedMethods(Interceptors.class));
                for (final Annotated<Method> method : annotatedMethods) {
                    final Interceptors interceptors = method.getAnnotation(Interceptors.class);
                    if (interceptors != null) {
                        final EjbJar ejbJar = ejbModule.getEjbJar();
                        for (final Class interceptor : interceptors.value()) {
                            if (ejbJar.getInterceptor(interceptor.getName()) == null) {
                                ejbJar.addInterceptor(new Interceptor(interceptor.getName()));
                            }
                        }

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

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

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

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

                for (final Annotated<Method> method : annotationFinder.findMetaAnnotatedMethods(ExcludeDefaultInterceptors.class)) {
                    final InterceptorBinding binding = assemblyDescriptor.addInterceptorBinding(new InterceptorBinding(bean));
                    binding.setExcludeDefaultInterceptors(true);
                    binding.setMethod(new NamedMethod(method.get()));
                }

                for (final Annotated<Method> method : sortMethods(annotationFinder.findMetaAnnotatedMethods(ExcludeClassInterceptors.class))) {
                    final InterceptorBinding binding = assemblyDescriptor.addInterceptorBinding(new InterceptorBinding(bean));
                    binding.setExcludeClassInterceptors(true);
                    binding.setMethod(new NamedMethod(method.get()));
                }

                /**
                 * All beans except MDBs have remoting capabilities (busines or legacy interfaces)
                 */
                if (bean instanceof RemoteBean) {
                    final RemoteBean remoteBean = (RemoteBean) bean;

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

                                final Class<?> remoteClass = create.getReturnType();
                                remoteBean.setHome(homeClass.getName());
                                remoteBean.setRemote(remoteClass.getName());
                            } catch (final 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());
                            }
                        }
                    }

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

                                final Class<?> remoteClass = create.getReturnType();
                                remoteBean.setLocalHome(homeClass.getName());
                                remoteBean.setLocal(remoteClass.getName());
                            } catch (final 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());
                            }
                        }
                    }

                    /*
                     * Annotations specific to @Stateless, @Stateful and @Singleton beans
                     */
                    if (remoteBean instanceof SessionBean) {
                        final SessionBean sessionBean = (SessionBean) remoteBean;

                        // add parents
                        sessionBean.getParents().add(clazz.getName());
                        if (!clazz.isInterface()) {
                            for (Class<?> current = clazz.getSuperclass(); !current.equals(Object.class); current = current.getSuperclass()) {
                                sessionBean.getParents().add(current.getName());
                            }
                        }

                        /*
                        * @Remote
                        * @Local
                        * @WebService
                        * @WebServiceProvider
                        */
                        processSessionInterfaces(sessionBean, clazz, ejbModule);

                        /*
                         * @Asynchronous
                         */
                        processAsynchronous(bean, annotationFinder);

                        /*
                         * Allow for all session bean types
                         * @DependsOn
                         */
                        if (sessionBean.getDependsOn() == null) {
                            final DependsOn dependsOn = getInheritableAnnotation(clazz, DependsOn.class);
                            if (dependsOn != null) {
                                sessionBean.setDependsOn(dependsOn.value());
                            } else {
                                sessionBean.setDependsOn(Collections.EMPTY_LIST);
                            }
                        }

                        /**
                         * Annotations for singletons and stateless
                         */
                        if (sessionBean.getSessionType() != SessionType.STATEFUL) {
                            // REST can be fun
                            if (annotationFinder.isAnnotationPresent(Path.class)) {
                                sessionBean.setRestService(true);
                            }
                        }

                        /*
                         * Annotations specific to @Singleton beans
                         */
                        if (sessionBean.getSessionType() == SessionType.SINGLETON) {

                            /*
                             * @ConcurrencyManagement
                             */
                            if (sessionBean.getConcurrencyManagementType() == null) {
                                final ConcurrencyManagement tx = getInheritableAnnotation(clazz, ConcurrencyManagement.class);
                                jakarta.ejb.ConcurrencyManagementType concurrencyType = jakarta.ejb.ConcurrencyManagementType.CONTAINER;
                                if (tx != null) {
                                    concurrencyType = tx.value();
                                }
                                switch (concurrencyType) {
                                    case BEAN:
                                        sessionBean.setConcurrencyManagementType(ConcurrencyManagementType.BEAN);
                                        break;
                                    case CONTAINER:
                                        sessionBean.setConcurrencyManagementType(ConcurrencyManagementType.CONTAINER);
                                        break;
                                }
                            }

                            /*
                             * @Lock
                             */
                            final LockHandler lockHandler = new LockHandler(assemblyDescriptor, sessionBean);
                            if (sessionBean.getConcurrencyManagementType() == ConcurrencyManagementType.CONTAINER) {
                                processAttributes(lockHandler, clazz, annotationFinder);
                            } else {
                                checkAttributes(lockHandler, ejbName, ejbModule, annotationFinder, "invalidConcurrencyAttribute");
                            }

                            /*
                             * @AccessTimeout
                             */
                            final AccessTimeoutHandler accessTimeoutHandler =
                                new AccessTimeoutHandler(assemblyDescriptor, sessionBean, lockHandler.getContainerConcurrency());
                            processAttributes(accessTimeoutHandler, clazz, annotationFinder);

                            /*
                             * @Startup
                             */
                            if (!sessionBean.hasInitOnStartup()) {
                                final Startup startup = getInheritableAnnotation(clazz, Startup.class);
                                sessionBean.setInitOnStartup(startup != null);
                            }

                        } else if (sessionBean.getSessionType() == SessionType.STATEFUL) {
                            /*
                             * Annotations specific to @Stateful beans
                             */

                            /*
                             * @StatefulTimeout
                             */
                            if (sessionBean.getStatefulTimeout() == null) {
                                final StatefulTimeout annotation = getInheritableAnnotation(clazz, StatefulTimeout.class);
                                if (annotation != null) {
                                    final Timeout timeout = new Timeout();
                                    timeout.setTimeout(annotation.value());
                                    timeout.setUnit(annotation.unit());
                                    sessionBean.setStatefulTimeout(timeout);
                                }
                            }

                            /*
                             * @AccessTimeout
                             */
                            final AccessTimeoutHandler accessTimeoutHandler = new AccessTimeoutHandler(assemblyDescriptor, sessionBean);
                            processAttributes(accessTimeoutHandler, clazz, annotationFinder);

                        }
                    }
                }

                if (bean instanceof MessageDrivenBean) {
                    /*
                     * @ActivationConfigProperty
                     */
                    final MessageDrivenBean mdb = (MessageDrivenBean) bean;
                    final MessageDriven messageDriven = clazz.getAnnotation(MessageDriven.class);
                    if (messageDriven != null) {
                        ActivationConfig activationConfig = mdb.getActivationConfig();
                        if (activationConfig == null) {
                            activationConfig = new ActivationConfig();
                        }

                        if (!messageDriven.mappedName().isEmpty()) {
                            if (mdb.getActivationConfig() == null) {
                                mdb.setActivationConfig(activationConfig);
                            }
                            if (!activationConfig.toProperties().containsKey("destinationType")) {
                                activationConfig.addProperty("destinationType", Queue.class.getName());
                            }
                            activationConfig.addProperty("destination", messageDriven.mappedName());
                        }

                        final ActivationConfigProperty[] configProperties = messageDriven.activationConfig();
                        if (configProperties != null) {
                            if (mdb.getActivationConfig() == null) {
                                mdb.setActivationConfig(activationConfig);
                            }

                            final Properties properties = activationConfig.toProperties();
                            for (final ActivationConfigProperty property : configProperties) {
                                if (!properties.containsKey(property.propertyName())) {
                                    activationConfig.addProperty(property.propertyName(), property.propertyValue());
                                }
                            }
                        }

                        if (mdb.getMessagingType() == null) {
                            final 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());
                            }
                        }
                    }

                    /*
                     * Determine the MessageListener interface
                     */
                    if (mdb.getMessagingType() == null) {
                        final List<Class<?>> interfaces = new ArrayList<>();
                        for (final Class<?> intf : clazz.getInterfaces()) {
                            final String name = intf.getName();
                            if (!name.equals("java.io.Serializable") &&
                                !name.equals("java.io.Externalizable") &&
                                !name.startsWith("jakarta.ejb.") &&
                                !intf.isSynthetic()) {
                                interfaces.add(intf);
                            }
                        }

                        if (interfaces.size() != 1) {
                            StringBuilder msg = new StringBuilder("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 (final Class<?> intf : interfaces) {
                                msg.append(intf.getName()).append(", ");
                            }
                            // TODO: Make this a validation failure, not an exception
                            throw new IllegalStateException(msg.toString());
                        }
                        mdb.setMessagingType(interfaces.get(0).getName());
                    }
                }

                buildAnnotatedRefs(bean, annotationFinder, classLoader);

                processWebServiceHandlers(ejbModule, bean, annotationFinder);

                processWebServiceClientHandlers(bean, annotationFinder, classLoader);

                try {
                    if (BeanContext.Comp.class.getName().equals(bean.getEjbClass())) {
                        buildAnnotatedRefs(bean, ejbModule.getFinder(), classLoader);
                    }
                } catch (final OpenEJBException e) {
                    logger.error("Processing of @Resource, @EJB, and other references failed for CDI managed beans", e);
                }
            }

            for (final Interceptor interceptor : ejbModule.getEjbJar().getInterceptors()) {
                final Class<?> clazz;
                try {
                    clazz = classLoader.loadClass(realClassName(interceptor.getInterceptorClass()));
                } catch (final ClassNotFoundException e) {
                    logger.debug("Could not load interceptor class {1} for enterprise beans module {2} / {3}",
                                 interceptor.getInterceptorClass(), ejbModule.getJarLocation(), ejbModule.getFile().getName());

                    throw new OpenEJBException("Unable to load interceptor class: " + interceptor.getInterceptorClass(), e);
                }

                final AnnotationFinder annotationFinder = createFinder(clazz);

                /*
                 * @PostConstruct
                 * @PreDestroy
                 * @AroundInvoke
                 * @Timeout
                 * @PostActivate
                 * @PrePassivate
                 * @Init
                 * @Remove
                 */
                processCallbacks(interceptor, annotationFinder);

                /*
                 * @PAroundConstruct can only be on the interceptor itself
                 */
                final boolean override = "true".equalsIgnoreCase(getProperty("openejb.callbacks.override", "false"));
                if (apply(override, interceptor.getAroundConstruct())) {
                    for (final Annotated<Method> method : sortMethods(annotationFinder.findMetaAnnotatedMethods(AroundConstruct.class))) {
                        interceptor.getAroundConstruct().add(new LifecycleCallback(method.get()));
                    }
                }

                /*
                 * @ApplicationException
                 */
                processApplicationExceptions(clazz, ejbModule.getEjbJar().getAssemblyDescriptor());

                /*
                 * @EJB
                 * @Resource
                 * @WebServiceRef
                 * @PersistenceUnit
                 * @PersistenceContext
                 */
                buildAnnotatedRefs(interceptor, annotationFinder, classLoader);

                processWebServiceClientHandlers(interceptor, annotationFinder, classLoader);

                /*
                 * Interceptors do not have their own section in ejb-jar.xml for resource references
                 * so we add them to the references of each ejb.  A bit backwards but more or less
                 * mandated by the design of the spec.
                 */
                for (final EnterpriseBean bean : enterpriseBeans) {
                    // Just simply merge the injection targets of the interceptors to enterprise beans
                    mergeJndiReferences(interceptor.getEnvEntryMap(), bean.getEnvEntryMap());
                    mergeJndiReferences(interceptor.getEjbRefMap(), bean.getEjbRefMap());
                    mergeJndiReferences(interceptor.getEjbLocalRefMap(), bean.getEjbLocalRefMap());
                    mergeJndiReferences(interceptor.getResourceRefMap(), bean.getResourceRefMap());
                    mergeJndiReferences(interceptor.getResourceEnvRefMap(), bean.getResourceEnvRefMap());
                    mergeJndiReferences(interceptor.getPersistenceContextRefMap(), bean.getPersistenceContextRefMap());
                    mergeJndiReferences(interceptor.getPersistenceUnitRefMap(), bean.getPersistenceUnitRefMap());
                    mergeJndiReferences(interceptor.getMessageDestinationRefMap(), bean.getMessageDestinationRefMap());
                    mergeJndiReferences(interceptor.getServiceRefMap(), bean.getServiceRefMap());
                }
            }

            return ejbModule;
        }