All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.weld.WeldDeployer Maven / Gradle / Ivy

The newest version!
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2009-2015 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
// Portions Copyright [2016-2024] [Payara Foundation and/or its affiliates]

package org.glassfish.weld;

import static com.sun.enterprise.deployment.util.DOLUtils.getComponentEnvId;
import static com.sun.enterprise.deployment.util.DOLUtils.getCurrentBundleForContext;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import static java.util.Arrays.stream;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Level.SEVERE;
import static java.util.stream.StreamSupport.stream;
import static org.glassfish.api.invocation.ComponentInvocation.ComponentInvocationType.SERVLET_INVOCATION;
import static org.glassfish.cdi.CDILoggerInfo.ADDING_INJECTION_SERVICES;
import static org.glassfish.cdi.CDILoggerInfo.JMS_MESSAGElISTENER_AVAILABLE;
import static org.glassfish.cdi.CDILoggerInfo.MDB_PIT_EVENT;
import static org.glassfish.cdi.CDILoggerInfo.WELD_BOOTSTRAP_SHUTDOWN_EXCEPTION;
import static org.glassfish.internal.deployment.Deployment.APPLICATION_DISABLED;
import static org.glassfish.internal.deployment.Deployment.APPLICATION_LOADED;
import static org.glassfish.internal.deployment.Deployment.APPLICATION_STOPPED;
import static org.glassfish.internal.deployment.Deployment.APPLICATION_UNLOADED;
import static org.glassfish.weld.BeanDeploymentArchiveImpl.stripApplicationVersion;
import static org.glassfish.weld.BeanDeploymentArchiveImpl.stripMavenVersion;
import static org.glassfish.weld.util.Util.initializeWeldSingletonProvider;
import static org.jboss.weld.bootstrap.api.Environments.SERVLET;
import static org.jboss.weld.bootstrap.spi.BeanDiscoveryMode.NONE;
import static org.jboss.weld.manager.BeanManagerLookupService.lookupBeanManager;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

import jakarta.enterprise.inject.spi.AnnotatedType;
import jakarta.enterprise.inject.spi.Extension;
import jakarta.inject.Inject;
import jakarta.servlet.Filter;
import jakarta.servlet.Servlet;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.ServletRequestListener;
import jakarta.servlet.http.HttpSessionListener;
import jakarta.servlet.jsp.tagext.JspTag;

import org.glassfish.api.deployment.DeployCommandParameters;
import org.glassfish.api.deployment.DeploymentContext;
import org.glassfish.api.deployment.MetaData;
import org.glassfish.api.deployment.archive.ReadableArchive;
import org.glassfish.api.event.EventListener;
import org.glassfish.api.event.EventTypes;
import org.glassfish.api.event.Events;
import org.glassfish.api.invocation.ComponentInvocation;
import org.glassfish.api.invocation.InvocationManager;
import org.glassfish.deployment.common.DeploymentException;
import org.glassfish.deployment.common.SimpleDeployer;
import org.glassfish.hk2.api.PostConstruct;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.internal.data.ApplicationInfo;
import org.glassfish.internal.data.ApplicationRegistry;
import org.glassfish.internal.deployment.Deployment;
import org.glassfish.javaee.core.deployment.ApplicationHolder;
import org.glassfish.web.deployment.descriptor.AppListenerDescriptorImpl;
import org.glassfish.web.deployment.descriptor.ServletFilterDescriptor;
import org.glassfish.web.deployment.descriptor.ServletFilterMappingDescriptor;
import org.glassfish.weld.connector.WeldUtils;
import org.glassfish.weld.services.*;
import org.jboss.weld.bootstrap.WeldBootstrap;
import org.jboss.weld.bootstrap.spi.BeanDeploymentArchive;
import org.jboss.weld.bootstrap.spi.EEModuleDescriptor;
import org.jboss.weld.bootstrap.spi.Metadata;
import org.jboss.weld.bootstrap.spi.helpers.EEModuleDescriptorImpl;
import org.jboss.weld.bootstrap.spi.helpers.MetadataImpl;
import org.jboss.weld.configuration.spi.ExternalConfiguration;
import org.jboss.weld.ejb.spi.EjbServices;
import org.jboss.weld.injection.spi.InjectionServices;
import org.jboss.weld.resources.spi.ResourceLoader;
import org.jboss.weld.security.spi.SecurityServices;
import org.jboss.weld.serialization.spi.ProxyServices;
import org.jboss.weld.transaction.spi.TransactionServices;
import org.jboss.weld.bootstrap.api.ServiceRegistry;
import org.jboss.weld.module.EjbSupport;
import org.jboss.weld.manager.BeanManagerImpl;
import org.jvnet.hk2.annotations.Service;

import com.sun.enterprise.container.common.spi.util.InjectionManager;
import com.sun.enterprise.deploy.shared.ArchiveFactory;
import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.deployment.BundleDescriptor;
import com.sun.enterprise.deployment.EjbBundleDescriptor;
import com.sun.enterprise.deployment.EjbDescriptor;
import com.sun.enterprise.deployment.JndiNameEnvironment;
import com.sun.enterprise.deployment.WebBundleDescriptor;
import com.sun.enterprise.deployment.web.ServletFilterMapping;
import javax.naming.NamingException;
import org.jboss.weld.manager.api.ExecutorServices;

@Service
public class WeldDeployer extends SimpleDeployer implements PostConstruct, EventListener {

    private Logger logger = Logger.getLogger(WeldDeployer.class.getName());

    public static final String WELD_EXTENSION = "org.glassfish.weld";
    public static final String WELD_DEPLOYMENT = "org.glassfish.weld.WeldDeployment";
    /* package */ static final String WELD_BOOTSTRAP = "org.glassfish.weld.WeldBootstrap";
    public static final String SNIFFER_EXTENSIONS = "org.glassfish.weld.sniffers";
    private static final String WELD_CONTEXT_LISTENER = "org.glassfish.weld.WeldContextListener";

    // Note...this constant is also defined in org.apache.catalina.connector.AsyncContextImpl. If it
    // changes here it must
    // change there as well. The reason it is duplicated is so that a dependency from web-core to
    // gf-weld-connector
    // is not necessary.
    private static final String WELD_LISTENER = "org.jboss.weld.module.web.servlet.WeldListener";
    static final String WELD_TERMINATION_LISTENER = "org.jboss.weld.module.web.servlet.WeldTerminalListener";
    private static final String WELD_SHUTDOWN = "weld_shutdown";

    /**
     * This constant is used to indicate if bootstrap shutdown has been called or not.
     */
    private static final String WELD_BOOTSTRAP_SHUTDOWN = "weld_bootstrap_shutdown";
    private static final String WELD_CONVERSATION_FILTER_CLASS = "org.jboss.weld.module.web.servlet.ConversationFilter";
    private static final String WELD_CONVERSATION_FILTER_NAME = "CDI Conversation Filter";
    private static final String JERSEY_PROCESS_ALL_CLASS_NAME = "org.glassfish.jersey.ext.cdi1x.internal.ProcessAllAnnotatedTypes";
    private static final String JERSEY_HK2_CLASS_NAME = "org.glassfish.jersey.ext.cdi1x.spi.Hk2CustomBoundTypesProvider";
    private static final String JERSEY_PROCESS_JAXRS_CLASS_NAME = "org.glassfish.jersey.ext.cdi1x.internal.ProcessJAXRSAnnotatedTypes";

    @Inject
    private Events events;

    @Inject
    private ServiceLocator services;

    @Inject
    private ApplicationRegistry applicationRegistry;

    @Inject
    private InvocationManager invocationManager;

    @Inject
    ArchiveFactory archiveFactory;

    @Inject
    private Deployment deployment;

    private Map appToBootstrap = new HashMap<>();

    private Map bundleToBeanDeploymentArchive = new HashMap<>();

    private static final Class[] NON_CONTEXT_CLASSES = {
            Servlet.class,
            ServletContextListener.class,
            Filter.class,
            HttpSessionListener.class,
            ServletRequestListener.class,
            JspTag.class
            // TODO need to add more classes
    };

    static {
        try {
            initializeWeldSingletonProvider();
        } catch (Throwable ignore) {
        }
    }

    @Override
    public MetaData getMetaData() {
        return new MetaData(true, null, new Class[] { Application.class });
    }

    @Override
    public void postConstruct() {
        events.register(this);
    }

    @Override
    public boolean prepare(DeploymentContext context) {
        context.addTransientAppMetaData(SNIFFER_EXTENSIONS, new HashSet>());

        return super.prepare(context);
    }

    /**
     * Processing in this method is performed for each module that is in the process of being loaded by
     * the container.
     *
     * 

* This method will collect information from each archive (module) and produce * BeanDeploymentArchive information for each module. *

* *

* The * BeanDeploymentArchives are stored in the Deployment (that will * eventually be handed off to Weld. Once this method is called for all modules (and * BeanDeploymentArchive information has been collected for all Weld * modules), a relationship structure is produced defining the accessiblity rules for the * BeanDeploymentArchives. *

* * @param container * @param context * @return */ @Override public WeldApplicationContainer load(WeldContainer container, DeploymentContext context) { DeployCommandParameters deployParams = context.getCommandParameters(DeployCommandParameters.class); ApplicationInfo applicationInfo = applicationRegistry.get(deployParams.name); ReadableArchive archive = context.getSource(); boolean[] setTransientAppMetaData = {false}; // See if a WeldBootsrap has already been created - only want one per app. WeldBootstrap bootstrap = getWeldBootstrap(context, applicationInfo, setTransientAppMetaData); EjbBundleDescriptor ejbBundle = getEjbBundleFromContext(context); EjbServices ejbServices = null; Set ejbs = new HashSet<>(); if (ejbBundle != null) { ejbs.addAll(ejbBundle.getEjbs()); ejbServices = new EjbServicesImpl(services); } // Create a deployment collecting information from the ReadableArchive (archive) // If the archive is a composite, or has version numbers per maven conventions, strip them out String archiveName = getArchiveName(context, applicationInfo, archive); DeploymentImpl deploymentImpl = context.getTransientAppMetaData(WELD_DEPLOYMENT, DeploymentImpl.class); if (deploymentImpl == null) { deploymentImpl = new DeploymentImpl(archive, ejbs, context, archiveFactory, archiveName, services.getService(InjectionManager.class)); // Add services TransactionServices transactionServices = new TransactionServicesImpl(services); deploymentImpl.getServices().add(TransactionServices.class, transactionServices); SecurityServices securityServices = new SecurityServicesImpl(); deploymentImpl.getServices().add(SecurityServices.class, securityServices); ProxyServices proxyServices = new ProxyServicesImpl(services); deploymentImpl.getServices().add(ProxyServices.class, proxyServices); try { ExecutorServices executorServices = new ExecutorServicesImpl(); deploymentImpl.getServices().add(ExecutorServices.class, executorServices); } catch (NamingException ex) { throw new RuntimeException(ex); } addWeldListenerToAllWars(context); } else { deploymentImpl.scanArchive(archive, ejbs, context, archiveName); } deploymentImpl.addDeployedEjbs(ejbs); if (ejbBundle != null && (!deploymentImpl.getServices().contains(EjbServices.class))) { // EJB Services is registered as a top-level service deploymentImpl.getServices().add(EjbServices.class, ejbServices); } ExternalConfigurationImpl externalConfiguration = new ExternalConfigurationImpl(); externalConfiguration.setRollingUpgradesDelimiter(System.getProperty("fish.payara.rollingUpgradesDelimiter", ":")); externalConfiguration.setBeanIndexOptimization(!deployParams.isAvailabilityEnabled()); externalConfiguration.setNonPortableMode(false); configureConcurrentDeployment(context, externalConfiguration); deploymentImpl.getServices().add(ExternalConfiguration.class, externalConfiguration); BeanDeploymentArchive beanDeploymentArchive = deploymentImpl.getBeanDeploymentArchiveForArchive(archiveName); if (beanDeploymentArchive != null && !beanDeploymentArchive.getBeansXml().getBeanDiscoveryMode().equals(NONE)) { if (setTransientAppMetaData[0]) { // Do this only if we have a root BDA appToBootstrap.put(context.getModuleMetaData(Application.class), bootstrap); applicationInfo.addTransientAppMetaData(WELD_BOOTSTRAP, bootstrap); } WebBundleDescriptor webBundleDescriptor = context.getModuleMetaData(WebBundleDescriptor.class); if (webBundleDescriptor != null) { webBundleDescriptor.setExtensionProperty(WELD_EXTENSION, "true"); // Add the Weld Listener. We have to do it here too in case addWeldListenerToAllWars wasn't // able to do it. webBundleDescriptor.addAppListenerDescriptorToFirst(new AppListenerDescriptorImpl(WELD_LISTENER)); // Add Weld Context Listener - this listener will ensure the WeldELContextListener is used // for JSP's.. webBundleDescriptor.addAppListenerDescriptor(new AppListenerDescriptorImpl(WELD_CONTEXT_LISTENER)); // Weld 2.2.1.Final. There is a tck test for this: // org.jboss.cdi.tck.tests.context.session.listener.SessionContextHttpSessionListenerTest // This WeldTerminationListener must come after all application-defined listeners webBundleDescriptor.addAppListenerDescriptor(new AppListenerDescriptorImpl(WeldTerminationListenerProxy.class.getName())); // Adding Weld ConverstationFilter if there is a filterMapping for it and it doesn't exist already. // However, it will be applied only if web.xml has a mapping for it. // Doing this here to make sure that its done only for CDI enabled web applications registerWeldConversationFilter(webBundleDescriptor); } BundleDescriptor bundle = (webBundleDescriptor != null) ? webBundleDescriptor : ejbBundle; if (bundle != null) { if (!beanDeploymentArchive.getBeansXml().getBeanDiscoveryMode().equals(NONE)) { // Register EE injection manager at the bean deployment archive level. // We use the generic InjectionService service to handle all EE-style // injection instead of the per-dependency-type InjectionPoint approach. // Each InjectionServicesImpl instance knows its associated GlassFish bundle. InjectionServices injectionServices = new InjectionServicesImpl(deploymentImpl.injectionManager, bundle, deploymentImpl); if (logger.isLoggable(FINE)) { logger.log(FINE, ADDING_INJECTION_SERVICES, new Object[] { injectionServices, beanDeploymentArchive.getId() }); } beanDeploymentArchive.getServices().add(InjectionServices.class, injectionServices); EEModuleDescriptor eeModuleDescriptor = getEEModuleDescriptor(beanDeploymentArchive); if (eeModuleDescriptor != null) { beanDeploymentArchive.getServices().add(EEModuleDescriptor.class, eeModuleDescriptor); } // Relevant in WAR BDA - WEB-INF/lib BDA scenarios for (BeanDeploymentArchive subBda : beanDeploymentArchive.getBeanDeploymentArchives()) { if (logger.isLoggable(FINE)) { logger.log(FINE, ADDING_INJECTION_SERVICES, new Object[] { injectionServices, subBda.getId() }); } subBda.getServices().add(InjectionServices.class, injectionServices); eeModuleDescriptor = getEEModuleDescriptor(beanDeploymentArchive); // Should not be subBda? if (eeModuleDescriptor != null) { beanDeploymentArchive.getServices().add(EEModuleDescriptor.class, eeModuleDescriptor); } } } bundleToBeanDeploymentArchive.put(bundle, beanDeploymentArchive); } } context.addTransientAppMetaData(WELD_DEPLOYMENT, deploymentImpl); applicationInfo.addTransientAppMetaData(WELD_DEPLOYMENT, deploymentImpl); return new WeldApplicationContainer(); } /** * Specific stages of the Weld bootstrapping process will execute across different stages of the * deployment process. Weld deployment will happen when the load phase of the deployment process is * complete. When all modules have been loaded, a deployment graph is produced defining the * accessibility relationships between BeanDeploymentArchives. * * @param event */ @Override public void event(Event event) { if (event.is(APPLICATION_LOADED)) { processApplicationLoaded((ApplicationInfo) event.hook()); } else if (isOneOf(event, APPLICATION_STOPPED, APPLICATION_UNLOADED, APPLICATION_DISABLED)) { processApplicationStopped((ApplicationInfo) event.hook()); } } @Override protected void generateArtifacts(DeploymentContext dc) throws DeploymentException { } @Override protected void cleanArtifacts(DeploymentContext dc) throws DeploymentException { } @Override public V loadMetaData(Class type, DeploymentContext context) { return null; } public BeanDeploymentArchive getBeanDeploymentArchiveForBundle(BundleDescriptor bundle) { return bundleToBeanDeploymentArchive.get(bundle); } public boolean isCdiEnabled(BundleDescriptor bundle) { return bundleToBeanDeploymentArchive.containsKey(bundle); } public boolean is299Enabled(BundleDescriptor bundle) { return bundleToBeanDeploymentArchive.containsKey(bundle); } public WeldBootstrap getBootstrapForApp(Application app) { return appToBootstrap.get(app); } // ### Private methods private WeldBootstrap getWeldBootstrap(DeploymentContext context, ApplicationInfo appInfo, boolean[] setTransientAppMetaData) { // See if a WeldBootsrap has already been created - only want one per app. WeldBootstrap bootstrap = context.getTransientAppMetaData(WELD_BOOTSTRAP, WeldBootstrap.class); if (bootstrap != null && appInfo.getTransientAppMetaData(WELD_BOOTSTRAP, WeldBootstrap.class) == null) { // No bootstrap if no CDI BDAs exist yet bootstrap = null; } if (bootstrap == null) { bootstrap = new WeldBootstrap(); setTransientAppMetaData[0] = true; // Stash the WeldBootstrap instance, so we may access the WeldManager later.. context.addTransientAppMetaData(WELD_BOOTSTRAP, bootstrap); // Making sure that if WeldBootstrap is added, shutdown is set to false, as it is/would not have // been called. appInfo.addTransientAppMetaData(WELD_BOOTSTRAP_SHUTDOWN, "false"); } return bootstrap; } private void processApplicationLoaded(ApplicationInfo applicationInfo) { WeldBootstrap bootstrap = applicationInfo.getTransientAppMetaData(WELD_BOOTSTRAP, WeldBootstrap.class); if (bootstrap != null) { DeploymentImpl deploymentImpl = applicationInfo.getTransientAppMetaData(WELD_DEPLOYMENT, DeploymentImpl.class); deploymentImpl.buildDeploymentGraph(); List archives = deploymentImpl.getBeanDeploymentArchives(); addResourceLoaders(archives); addCdiServicesToNonModuleBdas(deploymentImpl.getLibJarRootBdas(), services.getService(InjectionManager.class)); addCdiServicesToNonModuleBdas(deploymentImpl.getRarRootBdas(), services.getService(InjectionManager.class)); // Get current TCL ClassLoader oldTCL = Thread.currentThread().getContextClassLoader(); invocationManager.pushAppEnvironment(applicationInfo::getName); ComponentInvocation componentInvocation = createComponentInvocation(applicationInfo); try { invocationManager.preInvoke(componentInvocation); bootstrap.startExtensions(postProcessExtensions(deploymentImpl.getExtensions(), archives)); bootstrap.startContainer(deploymentImpl.getContextId() + ".bda", SERVLET, deploymentImpl); //This changes added to pass the following test // CreateBeanAttributesTest#testBeanAttributesForSessionBean if(!deploymentImpl.getBeanDeploymentArchives().isEmpty()) { BeanDeploymentArchive rootArchive = deploymentImpl.getBeanDeploymentArchives().get(0); ServiceRegistry rootServices = bootstrap.getManager(rootArchive).getServices(); EjbSupport originalEjbSupport = rootServices.get(EjbSupport.class); if (originalEjbSupport != null) { // We need to create a proxy instead of a simple wrapper EjbSupport proxyEjbSupport = (EjbSupport) java.lang.reflect.Proxy.newProxyInstance(EjbSupport.class.getClassLoader(), new Class[]{EjbSupport.class}, new java.lang.reflect.InvocationHandler() { @Override public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) throws Throwable { if (method.getName().equals("isEjb")) { EjbSupport targetEjbSupport = getTargetEjbSupport((Class) args[0]); if (targetEjbSupport != null) { return method.invoke(targetEjbSupport, args); } } else if (method.getName().equals("createSessionBeanAttributes")) { Object enhancedAnnotated = args[0]; Class beanClass = (Class) enhancedAnnotated.getClass() .getMethod("getJavaClass") .invoke(enhancedAnnotated); EjbSupport targetEjbSupport = getTargetEjbSupport(beanClass); if (targetEjbSupport != null) { return method.invoke(targetEjbSupport, args); } } return method.invoke(originalEjbSupport, args); } private EjbSupport getTargetEjbSupport(Class beanClass) { BeanDeploymentArchive ejbArchive = deploymentImpl.getBeanDeploymentArchive(beanClass); if (ejbArchive == null) { return null; } BeanManagerImpl ejbBeanManager = lookupBeanManager(beanClass, bootstrap.getManager(ejbArchive)); return ejbBeanManager.getServices().get(EjbSupport.class); } }); rootServices.add(EjbSupport.class, proxyEjbSupport); } } bootstrap.startInitialization(); fireProcessInjectionTargetEvents(bootstrap, applicationInfo, deploymentImpl); bootstrap.deployBeans(); bootstrap.validateBeans(); bootstrap.endInitialization(); } catch (Throwable t) { doBootstrapShutdown(applicationInfo); throw new DeploymentException(getDeploymentErrorMsgPrefix(t) + t.getMessage(), t); } finally { try { invocationManager.postInvoke(componentInvocation); invocationManager.popAppEnvironment(); deploymentComplete(deploymentImpl); } catch (Throwable t) { logger.log(SEVERE, "Exception dispatching post deploy event", t); } // The TCL is originally the EAR classloader and is reset during Bean deployment to the // corresponding module classloader in BeanDeploymentArchiveImpl.getBeans // for Bean classloading to succeed. // The TCL is reset to its old value here. Thread.currentThread().setContextClassLoader(oldTCL); } } } private void processApplicationStopped(ApplicationInfo applicationInfo) { Application application = applicationInfo.getMetaData(Application.class); if (application != null) { removeBundleDescriptors(application); appToBootstrap.remove(application); } String shutdown = applicationInfo.getTransientAppMetaData(WELD_SHUTDOWN, String.class); if (Boolean.valueOf(shutdown).equals(TRUE)) { return; } ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(applicationInfo.getAppClassLoader()); try { WeldBootstrap bootstrap = applicationInfo.getTransientAppMetaData(WELD_BOOTSTRAP, WeldBootstrap.class); if (bootstrap != null) { invocationManager.pushAppEnvironment(applicationInfo::getName); try { doBootstrapShutdown(applicationInfo); } catch (Exception e) { logger.log(WARNING, WELD_BOOTSTRAP_SHUTDOWN_EXCEPTION, new Object[] { e }); } finally { invocationManager.popAppEnvironment(); } applicationInfo.addTransientAppMetaData(WELD_SHUTDOWN, "true"); } } finally { Thread.currentThread().setContextClassLoader(currentContextClassLoader); } DeploymentImpl deploymentImpl = applicationInfo.getTransientAppMetaData(WELD_DEPLOYMENT, DeploymentImpl.class); if (deploymentImpl != null) { deploymentImpl.cleanup(); } } private void addResourceLoaders(List archives) { for (BeanDeploymentArchive archive : archives) { archive.getServices().add( ResourceLoader.class, new ResourceLoaderImpl(((BeanDeploymentArchiveImpl) archive).getModuleClassLoaderForBDA())); } } private ComponentInvocation createComponentInvocation(ApplicationInfo applicationInfo) { BundleDescriptor bundleDescriptor = getCurrentBundleForContext(deployment.getCurrentDeploymentContext()); ComponentInvocation componentInvocation = new ComponentInvocation( getComponentEnvId((JndiNameEnvironment) bundleDescriptor), SERVLET_INVOCATION, applicationInfo, applicationInfo.getName(), applicationInfo.getName(), applicationInfo.getName() ); componentInvocation.setJNDIEnvironment(bundleDescriptor); return componentInvocation; } private Iterable> postProcessExtensions(Iterable> extensions, List archives) { // See if the Jersey extension that scans all classes in the bean archives is present. // Normally this should always be the case as this extension is statically included with Jersey, // but who knows whether we'll once have distributions without Jersey Optional> optionaProcessAllAnnotatedTypes = findJerseyProcessAll(extensions); if (optionaProcessAllAnnotatedTypes.isPresent()) { // Get the Metadata instance containing the above mentioned extension Metadata processAllMeta = optionaProcessAllAnnotatedTypes.get(); // Get the class loader used by the JAX_RS (Jersey) archive, so we can use this to load // other classes from that same archive ClassLoader jaxRsClassLoader = processAllMeta.getValue().getClass().getClassLoader(); try { // The reason Jersey scans ALL classes is that a Hk2CustomBoundTypesProvider may be present. But if // this // is not there Jersey only has to scan the known JAX-RS classes (@Path etc) if (!hasJerseyHk2Provider(archives, jaxRsClassLoader)) { // Hk2CustomBoundTypesProvider not found, replace the extension that scans everything with // the one that only scans JAX-RS classes return replaceWith(extensions, processAllMeta, newProcessJaxRsMeta(jaxRsClassLoader)); } } catch (Exception e) { // Just log, the net result is only that the extension does a little extra scanning and logs a // warning // about that logger.log(FINE, "Exception trying to replace JaxRs scan all extension", e); } } // If the scan-all extension shouldn't or couldn't be replaced, just return the existing unmodified // list return extensions; } private Optional> findJerseyProcessAll(Iterable> extensions) { return stream(extensions.spliterator(), false) .filter(e -> e.getValue().getClass().getName().equals(JERSEY_PROCESS_ALL_CLASS_NAME)).findAny(); } private boolean hasJerseyHk2Provider(List archives, ClassLoader jaxRsClassLoader) throws ClassNotFoundException { Class hk2Provider = Class.forName(JERSEY_HK2_CLASS_NAME, false, jaxRsClassLoader); for (BeanDeploymentArchive archive : archives) { archive.getBeanClasses(); // implicitly sets thread class loader if (ServiceLoader.load(hk2Provider).iterator().hasNext()) { return true; } } return false; } private Iterable> replaceWith(Iterable> extensions, Metadata processAllMeta, Metadata processJaxRsMeta) { return stream(extensions.spliterator(), false).map(e -> e.equals(processAllMeta) ? processJaxRsMeta : e) .collect(Collectors.toList()); } private Metadata newProcessJaxRsMeta(ClassLoader jaxRsClassLoader) throws InstantiationException, IllegalAccessException, ClassNotFoundException { Extension processJAXRSAnnotatedTypes = (Extension) Class.forName(JERSEY_PROCESS_JAXRS_CLASS_NAME, false, jaxRsClassLoader) .newInstance(); return new MetadataImpl<>(processJAXRSAnnotatedTypes); } @SafeVarargs private static final boolean isOneOf(Event event, EventTypes... eventTypes) { return stream(eventTypes).anyMatch(e -> event.is(e)); } private void removeBundleDescriptors(Application application) { for (BundleDescriptor bundleDescriptor : application.getBundleDescriptors()) { if (bundleDescriptor instanceof EjbBundleDescriptor || bundleDescriptor instanceof WebBundleDescriptor) { bundleToBeanDeploymentArchive.remove(bundleDescriptor); } } } private void deploymentComplete(DeploymentImpl deploymentImpl) { for (BeanDeploymentArchive beanDeploymentArchive : deploymentImpl.getBeanDeploymentArchives()) { ((BeanDeploymentArchiveImpl) beanDeploymentArchive).setDeploymentComplete(true); } } private void doBootstrapShutdown(ApplicationInfo applicationInfo) { WeldBootstrap bootstrap = applicationInfo.getTransientAppMetaData(WELD_BOOTSTRAP, WeldBootstrap.class); String bootstrapShutdown = applicationInfo.getTransientAppMetaData(WELD_BOOTSTRAP_SHUTDOWN, String.class); if (bootstrapShutdown == null || Boolean.valueOf(bootstrapShutdown).equals(FALSE)) { bootstrap.shutdown(); applicationInfo.addTransientAppMetaData(WELD_BOOTSTRAP_SHUTDOWN, "true"); } } private String getArchiveName(DeploymentContext context, ApplicationInfo applicationInfo, ReadableArchive archive) { // Create a Deployment Collecting Information From The ReadableArchive (archive) // if archive is a composite, or has version numbers per maven conventions, strip it out boolean isSubArchive = archive.getParentArchive() != null; String archiveName = !isSubArchive ? applicationInfo.getName() : archive.getName(); if (isSubArchive) { archiveName = stripMavenVersion(archiveName); } if (!context.getArchiveHandler().getArchiveType().isEmpty()) { archiveName = String.format("%s.%s", stripApplicationVersion(archiveName), context.getArchiveHandler().getArchiveType()); } return archiveName; } private String getDeploymentErrorMsgPrefix(Throwable t) { if (t instanceof jakarta.enterprise.inject.spi.DefinitionException) { return "CDI definition failure:"; } else if (t instanceof jakarta.enterprise.inject.spi.DeploymentException) { return "CDI deployment failure:"; } else { Throwable cause = t.getCause(); if (cause == t || cause == null) { return "CDI deployment failure:"; } else { return getDeploymentErrorMsgPrefix(cause); } } } /* * We are only firing ProcessInjectionTarget for non-contextual EE components and not using the * InjectionTarget from the event during instance creation in JCDIServiceImpl.java TODO weld * would provide a better way to do this, otherwise we may need TODO to store InjectionTarget to * be used in instance creation */ private void fireProcessInjectionTargetEvents(WeldBootstrap bootstrap, ApplicationInfo applicationInfo, DeploymentImpl deploymentImpl) { List beanDeploymentArchives = deploymentImpl.getBeanDeploymentArchives(); Class messageListenerClass = getMessageListenerClass(); // Web-Profile and other lighter distributions would not ship the JMS // API and implementations. // So, the weld-integration layer cannot have a direct dependency on the JMS API boolean isFullProfile = messageListenerClass != null; for (BeanDeploymentArchive beanDeploymentArchive : beanDeploymentArchives) { Collection> beanClassObjects = ((BeanDeploymentArchiveImpl) beanDeploymentArchive).getBeanClassObjects(); for (Class bdaClazz : beanClassObjects) { for (Class nonClazz : NON_CONTEXT_CLASSES) { if (nonClazz.isAssignableFrom(bdaClazz)) { firePITEvent(bootstrap, beanDeploymentArchive, bdaClazz); } } // For distributions that have the JMS API, an MDB is a valid non-contextual EE component to which we have to // fire ProcessInjectionTarget events (see GLASSFISH-16730) if (isFullProfile && messageListenerClass.isAssignableFrom(bdaClazz)) { if (logger.isLoggable(FINE)) { logger.log(FINE, MDB_PIT_EVENT, new Object[] { bdaClazz }); } firePITEvent(bootstrap, beanDeploymentArchive, bdaClazz); } } // Fix for CDI TCK test: ContainerEventTest#testProcessInjectionTargetEventFiredForServlet // Check for Servlets which have not yet been loaded and haven't been identified as Beans // From the spec: "The container must also fire an event for every Jakarta EE component class supporting // injection that may be instantiated by the container at runtime". Stress on the "may". Collection injectionTargetClassNames = WeldUtils.getInjectionTargetClassNames( deploymentImpl.getTypes(), beanDeploymentArchive.getKnownClasses()); for (String injectionTargetClassName : injectionTargetClassNames) { // Don't fire twice if (beanDeploymentArchive.getBeanClasses().contains(injectionTargetClassName)) { continue; } Class injectionTargetClass = null; try { injectionTargetClass = applicationInfo.getAppClassLoader().loadClass(injectionTargetClassName); } catch (ClassNotFoundException appClassLoaderClassNotFoundException) { try { logger.log(Level.FINE, "Caught exception loading class using application class loader, " + "trying again with module class loader"); injectionTargetClass = applicationInfo.getModuleClassLoader().loadClass(injectionTargetClassName); } catch (ClassNotFoundException moduleClassLoaderClassNotFoundException) { logger.log(Level.FINE, "Caught exception loading class using module class loader, " + "ProcessInjectionTarget event may not get fired for " + injectionTargetClassName); } } if (injectionTargetClass != null) { for (Class nonClazz : NON_CONTEXT_CLASSES) { if (nonClazz.isAssignableFrom(injectionTargetClass)) { firePITEvent(bootstrap, beanDeploymentArchive, injectionTargetClass); } } if(isFullProfile && messageListenerClass.isAssignableFrom(injectionTargetClass)) { firePITEvent(bootstrap, beanDeploymentArchive, injectionTargetClass); } } } } } private Class getMessageListenerClass() { try { Class messageListenerClass = Thread.currentThread().getContextClassLoader().loadClass("jakarta.jms.MessageListener"); if (logger.isLoggable(FINE)) { logger.log(FINE, JMS_MESSAGElISTENER_AVAILABLE); } return messageListenerClass; } catch (ClassNotFoundException cnfe) { // ignore cnfe } return null; } private void firePITEvent(WeldBootstrap bootstrap, BeanDeploymentArchive beanDeploymentArchive, Class bdaClazz) { // Fix for issue GLASSFISH-17464 // The PIT event should not be fired for interfaces if (bdaClazz.isInterface()) { return; } AnnotatedType annotatedType = bootstrap.getManager(beanDeploymentArchive).createAnnotatedType(bdaClazz); ((BeanDeploymentArchiveImpl) beanDeploymentArchive). putInjectionTarget( annotatedType, bootstrap.getManager(beanDeploymentArchive).fireProcessInjectionTarget(annotatedType)); } private EEModuleDescriptor getEEModuleDescriptor(BeanDeploymentArchive beanDeploymentArchive) { EEModuleDescriptor eeModuleDescriptor = null; if (beanDeploymentArchive instanceof BeanDeploymentArchiveImpl) { WeldUtils.BDAType bdaType = ((BeanDeploymentArchiveImpl) beanDeploymentArchive).getBDAType(); if (bdaType.equals(WeldUtils.BDAType.JAR)) { eeModuleDescriptor = new EEModuleDescriptorImpl(beanDeploymentArchive.getId(), EEModuleDescriptor.ModuleType.EJB_JAR); } else if (bdaType.equals(WeldUtils.BDAType.WAR)) { eeModuleDescriptor = new EEModuleDescriptorImpl(beanDeploymentArchive.getId(), EEModuleDescriptor.ModuleType.WEB); } else if (bdaType.equals(WeldUtils.BDAType.RAR)) { eeModuleDescriptor = new EEModuleDescriptorImpl(beanDeploymentArchive.getId(), EEModuleDescriptor.ModuleType.CONNECTOR); } } return eeModuleDescriptor; } private void registerWeldConversationFilter(WebBundleDescriptor webBundleDescriptor) { for (ServletFilterMapping filterMapping : webBundleDescriptor.getServletFilterMappings()) { if (WELD_CONVERSATION_FILTER_NAME.equals(((ServletFilterMappingDescriptor) filterMapping).getDisplayName())) { ServletFilterDescriptor servletFilter = new ServletFilterDescriptor(); servletFilter.setClassName(WELD_CONVERSATION_FILTER_CLASS); servletFilter.setName(WELD_CONVERSATION_FILTER_NAME); webBundleDescriptor.addServletFilter(servletFilter); break; } } } private void configureConcurrentDeployment(DeploymentContext context, ExternalConfigurationImpl configuration) { configuration.setConcurrentDeployment(WeldUtils.isConcurrentDeploymentEnabled()); configuration.setPreLoaderThreadPoolSize(WeldUtils.getPreLoaderThreads()); } private void addWeldListenerToAllWars(DeploymentContext context) { // if there's at least 1 ejb jar then add the listener to all wars ApplicationHolder applicationHolder = context.getModuleMetaData(ApplicationHolder.class); if (applicationHolder != null) { if (applicationHolder.app.getBundleDescriptors(EjbBundleDescriptor.class).size() > 0) { Set webBundleDescriptors = applicationHolder.app .getBundleDescriptors(WebBundleDescriptor.class); for (WebBundleDescriptor oneWebBundleDescriptor : webBundleDescriptors) { // Add the Weld Listener if it does not already exist.. // we have to do this regardless because the war may not be cdi-enabled but an ejb is. oneWebBundleDescriptor.addAppListenerDescriptorToFirst(new AppListenerDescriptorImpl(WELD_LISTENER)); oneWebBundleDescriptor.addAppListenerDescriptor( new AppListenerDescriptorImpl(WeldTerminationListenerProxy.class.getName())); } } } } private EjbBundleDescriptor getEjbBundleFromContext(DeploymentContext context) { EjbBundleDescriptor ejbBundle = context.getModuleMetaData(EjbBundleDescriptor.class); if (ejbBundle == null) { WebBundleDescriptor wDesc = context.getModuleMetaData(WebBundleDescriptor.class); if (wDesc != null) { Collection ejbBundles = wDesc.getExtensionsDescriptors(EjbBundleDescriptor.class); if (ejbBundles.iterator().hasNext()) { ejbBundle = ejbBundles.iterator().next(); } } } return ejbBundle; } /** * Add the cdi services to a non-module bda (library or rar) */ private void addCdiServicesToNonModuleBdas(Iterator rootBdas, InjectionManager injectionMgr) { if (injectionMgr != null && rootBdas != null) { while (rootBdas.hasNext()) { RootBeanDeploymentArchive oneRootBda = rootBdas.next(); addCdiServicesToBda(injectionMgr, oneRootBda); addCdiServicesToBda(injectionMgr, oneRootBda.getModuleBda()); } } } private void addCdiServicesToBda(InjectionManager injectionMgr, BeanDeploymentArchive bda) { InjectionServices injectionServices = new NonModuleInjectionServices(injectionMgr); bda.getServices().add(InjectionServices.class, injectionServices); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy