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

com.sun.enterprise.container.common.impl.managedbean.ManagedBeanManagerImpl Maven / Gradle / Ivy

There is a newer version: 7.2024.1.Alpha1
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2013 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-2021] [Payara Foundation]

package com.sun.enterprise.container.common.impl.managedbean;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import jakarta.inject.Inject;
import javax.naming.InitialContext;

import org.glassfish.api.admin.ProcessEnvironment;
import org.glassfish.api.admin.ProcessEnvironment.ProcessType;
import org.glassfish.api.event.EventListener;
import org.glassfish.api.event.Events;
import org.glassfish.api.naming.GlassfishNamingManager;
import org.glassfish.api.naming.NamingObjectProxy;
import org.glassfish.hk2.api.PostConstruct;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.runlevel.RunLevel;
import org.glassfish.internal.api.PostStartupRunLevel;
import org.glassfish.internal.data.ApplicationInfo;
import org.glassfish.internal.deployment.Deployment;
import org.jvnet.hk2.annotations.Service;

import com.sun.enterprise.container.common.spi.InterceptorInvoker;
import com.sun.enterprise.container.common.spi.JCDIService;
import com.sun.enterprise.container.common.spi.JavaEEInterceptorBuilder;
import com.sun.enterprise.container.common.spi.JavaEEInterceptorBuilderFactory;
import com.sun.enterprise.container.common.spi.ManagedBeanManager;
import com.sun.enterprise.container.common.spi.util.ComponentEnvManager;
import com.sun.enterprise.container.common.spi.util.InjectionManager;
import com.sun.enterprise.container.common.spi.util.InterceptorInfo;
import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.deployment.ApplicationClientDescriptor;
import com.sun.enterprise.deployment.BundleDescriptor;
import com.sun.enterprise.deployment.EjbBundleDescriptor;
import com.sun.enterprise.deployment.EjbDescriptor;
import com.sun.enterprise.deployment.InterceptorDescriptor;
import com.sun.enterprise.deployment.JndiNameEnvironment;
import com.sun.enterprise.deployment.LifecycleCallbackDescriptor;
import com.sun.enterprise.deployment.ManagedBeanDescriptor;
import com.sun.enterprise.deployment.WebBundleDescriptor;
import com.sun.logging.LogDomains;

/**
 */
@Service(name="ManagedBeanManagerImpl")
@RunLevel(value=PostStartupRunLevel.VAL, mode=RunLevel.RUNLEVEL_MODE_NON_VALIDATING)
public class ManagedBeanManagerImpl implements ManagedBeanManager, PostConstruct, EventListener {

     private static final Logger _logger = LogDomains.getLogger(ManagedBeanManagerImpl.class,
            LogDomains.CORE_LOGGER, false);

    @Inject
    private ComponentEnvManager compEnvManager;

    @Inject
    private InjectionManager injectionMgr;

    @Inject
    private GlassfishNamingManager namingManager;

    @Inject
    private ServiceLocator habitat;

    @Inject
    private Events events;

    @Inject
    private ProcessEnvironment processEnv;

    private ProcessType processType;

    // Keep track of contexts for managed bean instances instantiated via JCDI
    private Map>> jcdiManagedBeanInstanceMap = new HashMap<>();

    // Used to hold managed beans in app client container
    private Map appClientManagedBeans = new HashMap<>();

    @Override
    public void postConstruct() {
        events.register(this);
        processType = processEnv.getProcessType();
    }

    @Override
    public void event(Event event) {
        Deployment.APPLICATION_LOADED.onMatch(event, info -> {
            loadManagedBeans(info);
            registerAppLevelDependencies(info);
        });
        Deployment.APPLICATION_UNLOADED.onMatch(event, info -> doCleanup(info.getMetaData(Application.class)));
        Deployment.DEPLOYMENT_FAILURE.onMatch(event, info -> doCleanup(info.getModuleMetaData(Application.class)));
    }

    private void doCleanup(Application app) {
        if( app != null ) {
            unloadManagedBeans(app);
            unregisterAppLevelDependencies(app);
        }
    }

    private void registerAppLevelDependencies(ApplicationInfo appInfo) {

        Application app = appInfo.getMetaData(Application.class);

        if( app == null ) {
            return;
        }

        try {
            compEnvManager.bindToComponentNamespace(app);
        } catch(Exception e) {
            throw new RuntimeException("Error binding app-level env dependencies " +
                    app.getAppName(), e);
        }

    }


    private void unregisterAppLevelDependencies(Application app) {

         if( app != null ) {
            try {
                compEnvManager.unbindFromComponentNamespace(app);
            } catch(Exception e) {
                _logger.log(Level.FINE, "Exception unbinding app objects", e);
            }
         }
     }



    private void loadManagedBeans(ApplicationInfo appInfo) {

        Application app = appInfo.getMetaData(Application.class);

        if( app == null ) {
            return;
        }

        loadManagedBeans(app);
    }

    @Override
    public void loadManagedBeans(Application app) {

        JCDIService jcdiService = habitat.getService(JCDIService.class);

        for(BundleDescriptor bundle : app.getBundleDescriptors()) {
            if (!bundleEligible(bundle)) {
                continue;
            }

            boolean isCDIBundle = (jcdiService != null && jcdiService.isJCDIEnabled(bundle));

            for(ManagedBeanDescriptor next : bundle.getManagedBeans()) {

                try {
                    Set interceptorClasses = next.getAllInterceptorClasses();

                    Class targetClass = bundle.getClassLoader().loadClass(next.getBeanClassName());
                    InterceptorInfo interceptorInfo = new InterceptorInfo();
                    interceptorInfo.setTargetClass(targetClass);
                    interceptorInfo.setInterceptorClassNames(interceptorClasses);
                    interceptorInfo.setAroundConstructInterceptors
                            (next.getAroundConstructCallbackInterceptors(targetClass,
                                     getConstructor(targetClass, isCDIBundle)));
                    interceptorInfo.setPostConstructInterceptors
                            (next.getCallbackInterceptors(LifecycleCallbackDescriptor.CallbackType.POST_CONSTRUCT));
                      interceptorInfo.setPreDestroyInterceptors
                            (next.getCallbackInterceptors(LifecycleCallbackDescriptor.CallbackType.PRE_DESTROY));
                    if( next.hasAroundInvokeMethod() ) {
                        interceptorInfo.setHasTargetClassAroundInvoke(true);
                    }

                    Map> interceptorChains = new HashMap<>();
                    for(Method m : targetClass.getMethods()) {
                        interceptorChains.put(m, next.getAroundInvokeInterceptors(m) );
                    }

                    interceptorInfo.setAroundInvokeInterceptorChains(interceptorChains);

                    // TODO can optimize this out for the non-JAXRS, non-application specified interceptor case
                    interceptorInfo.setSupportRuntimeDelegate(true);

                    JavaEEInterceptorBuilderFactory interceptorBuilderFactory =
                            habitat.getService(JavaEEInterceptorBuilderFactory.class);

                    JavaEEInterceptorBuilder builder = interceptorBuilderFactory.createBuilder(interceptorInfo);

                    next.setInterceptorBuilder(builder);


                    compEnvManager.bindToComponentNamespace(next);

                    String jndiName = next.getGlobalJndiName();
                    ManagedBeanNamingProxy namingProxy =
                        new ManagedBeanNamingProxy(next, habitat);

                    if( processType.isServer() ) {
                        namingManager.publishObject(jndiName, namingProxy, true);
                    } else {
                        // Can't store them in server's global naming service so keep
                        // them in local map.
                        appClientManagedBeans.put(jndiName, namingProxy);
                    }


                } catch(Exception e) {
                    throw new RuntimeException("Error binding ManagedBean " + next.getBeanClassName() +
                    " with name = " + next.getName(), e);
                }
            }

            jcdiManagedBeanInstanceMap.put(bundle,
                Collections.synchronizedMap(new HashMap<>()));
        }

    }

    private static Constructor getConstructor(Class clz, boolean isCDIBundle) throws Exception {
        if (isCDIBundle) {
            Constructor[] ctors = clz.getDeclaredConstructors();
            for(Constructor ctor : ctors) {
                if (ctor.getAnnotation(jakarta.inject.Inject.class) != null) {
                    // @Inject constructor
                    return ctor;
                }
            }
        }
        // Not a CDI bundle or no @Inject constructor - use no-arg constructor
        return clz.getConstructor();
    }

    @Override
    public Object getManagedBean(String globalJndiName) throws Exception {
        NamingObjectProxy proxy = appClientManagedBeans.get(globalJndiName);
        return proxy == null ? null :  proxy.create(new InitialContext());
    }

    /**
     * Apply a runtime interceptor instance to all managed beans in the given module
     * @param interceptorInstance
     * @param bundle bundle descripto
     *
     */
    @Override
    public void registerRuntimeInterceptor(Object interceptorInstance, BundleDescriptor bundle) {
        for(ManagedBeanDescriptor next :  bundle.getManagedBeans()) {
            JavaEEInterceptorBuilder builder = (JavaEEInterceptorBuilder) next.getInterceptorBuilder();
            builder.addRuntimeInterceptor(interceptorInstance);
        }
    }

    @Override
    public void unloadManagedBeans(Application app) {

        for(BundleDescriptor bundle : app.getBundleDescriptors()) {

            if (!bundleEligible(bundle)) {
                continue;
            }

            Map> jcdiInstances =
                    jcdiManagedBeanInstanceMap.remove(bundle);

            if( jcdiInstances != null ) {
                for(JCDIService.JCDIInjectionContext next : jcdiInstances.values()) {
                    try {
                        next.cleanup(true);
                    } catch(Exception e) {
                        _logger.log(Level.FINE, "Exception during JCDI cleanup for " + next, e);
                    }
                }
            }

            for(ManagedBeanDescriptor next : bundle.getManagedBeans()) {

                for(Object instance : next.getBeanInstances()) {

                    InterceptorInvoker invoker = (InterceptorInvoker)
                        next.getSupportingInfoForBeanInstance(instance);

                    try {
                        invoker.invokePreDestroy();
                    } catch(Exception e) {
                        _logger.log(Level.FINE, "Managed bean " + next.getBeanClassName() + " PreDestroy", e);
                    }

                }

                com.sun.enterprise.container.common.spi.util.ComponentEnvManager compEnvManager =
                    habitat.getService(com.sun.enterprise.container.common.spi.util.ComponentEnvManager.class);

                try {
                    compEnvManager.unbindFromComponentNamespace(next);
                } catch(javax.naming.NamingException ne) {
                    _logger.log(Level.FINE, "Managed bean " + next.getBeanClassName() + " unbind", ne);
                }

                org.glassfish.api.naming.GlassfishNamingManager namingManager =
                        habitat.getService(org.glassfish.api.naming.GlassfishNamingManager.class);
                String jndiName = next.getGlobalJndiName();

                if( processType.isServer() ) {
                    try {
                        namingManager.unpublishObject(jndiName);
                    } catch(javax.naming.NamingException ne) {
                        _logger.log(Level.FINE, "Error unpubishing managed bean " +
                               next.getBeanClassName() + " with jndi name " + jndiName, ne);
                    }
                } else {
                    appClientManagedBeans.remove(jndiName);
                }

                next.clearAllBeanInstanceInfo();

            }
        }

    }

    private boolean bundleEligible(BundleDescriptor bundle) {
        if (processType.isServer()) {
            return (bundle instanceof WebBundleDescriptor || bundle instanceof EjbBundleDescriptor);
        }
        if (processType == ProcessType.ACC) {
            return bundle instanceof ApplicationClientDescriptor;
        }
        return false;
    }

    @Override
    public  T createManagedBean(Class managedBeanClass) throws Exception {
        ManagedBeanDescriptor managedBeanDesc = null;

        try {
            BundleDescriptor bundle = getBundle();
            managedBeanDesc = bundle.getManagedBeanByBeanClass(managedBeanClass.getName());
        } catch(Exception e) {
            // OK.  Can mean that it's not annotated with @ManagedBean but 299 can handle it.
        }

        return createManagedBean(managedBeanDesc, managedBeanClass);
    }

    @Override
    public  T createManagedBean(Class managedBeanClass, boolean invokePostConstruct) throws Exception {
        ManagedBeanDescriptor managedBeanDesc = null;

        try {
            BundleDescriptor bundle = getBundle();
            managedBeanDesc = bundle.getManagedBeanByBeanClass(managedBeanClass.getName());
        } catch(Exception e) {
            // OK.  Can mean that it's not annotated with @ManagedBean but 299 can handle it.
        }

        return createManagedBean(managedBeanDesc, managedBeanClass, invokePostConstruct);
    }

    /**
     *
     * @param desc can be null if JCDI enabled bundle.
     * @param managedBeanClass
     * @return
     * @throws Exception
     */
    @Override
    public  T createManagedBean(ManagedBeanDescriptor desc, Class managedBeanClass) throws Exception {

        JCDIService jcdiService = habitat.getService(JCDIService.class);

        BundleDescriptor bundleDescriptor = null;

        if( desc == null ) {
            bundleDescriptor = getBundle();
        } else {
            bundleDescriptor = desc.getBundleDescriptor();
        }

        if( bundleDescriptor == null ) {
            throw new IllegalStateException
                ("Class " + managedBeanClass + " is not a valid EE ManagedBean class");
        }

        T callerObject = null;

        if( (jcdiService != null) && jcdiService.isJCDIEnabled(bundleDescriptor)) {

            // Have 299 create, inject, and call PostConstruct on managed bean

            JCDIService.JCDIInjectionContext jcdiContext =
                jcdiService.createManagedObject(managedBeanClass, bundleDescriptor);
            callerObject = (T) jcdiContext.getInstance();

            // Need to keep track of context in order to destroy properly
            Map> bundleNonManagedObjs =
                jcdiManagedBeanInstanceMap.get(bundleDescriptor);
            bundleNonManagedObjs.put(callerObject, jcdiContext);
        } else {
            if (desc == null) {
                throw new IllegalArgumentException(
                        "CDI not enabled and no managed bean found for class: " + managedBeanClass.getName());
            }
            JavaEEInterceptorBuilder interceptorBuilder = (JavaEEInterceptorBuilder)
                desc.getInterceptorBuilder();

            InterceptorInvoker interceptorInvoker =
                    interceptorBuilder.createInvoker(null);

            // This is the object passed back to the caller.
            callerObject = (T) interceptorInvoker.getProxy();

            Object[] interceptorInstances = interceptorInvoker.getInterceptorInstances();

            // Inject interceptor instances
            for(int i = 0; i < interceptorInstances.length; i++) {
                inject(interceptorInstances[i], desc);
            }

            interceptorInvoker.invokeAroundConstruct();

            // This is the managed bean class instance
            Object managedBean = interceptorInvoker.getTargetInstance();

            inject(managedBean, desc);

            interceptorInvoker.invokePostConstruct();

            desc.addBeanInstanceInfo(managedBean, interceptorInvoker);

        }

        return callerObject;

    }

    /**
     *
     * @param desc can be null if JCDI enabled bundle.
     * @param managedBeanClass
     * @param invokePostConstruct
     * @return
     * @throws Exception
     */
    @Override
    public  T createManagedBean(ManagedBeanDescriptor desc, Class managedBeanClass,
        boolean invokePostConstruct) throws Exception {

        JCDIService jcdiService = habitat.getService(JCDIService.class);

        BundleDescriptor bundleDescriptor = null;

        if( desc == null ) {
            bundleDescriptor = getBundle();
        } else {
            bundleDescriptor = desc.getBundleDescriptor();
        }

        if( bundleDescriptor == null ) {
            throw new IllegalStateException
                ("Class " + managedBeanClass + " is not a valid EE ManagedBean class");
        }

        T callerObject = null;

        if( (jcdiService != null) && jcdiService.isJCDIEnabled(bundleDescriptor)) {

            // Have 299 create, inject, and call PostConstruct (if desired) on managed bean

            JCDIService.JCDIInjectionContext jcdiContext =
                jcdiService.createManagedObject(managedBeanClass, bundleDescriptor, invokePostConstruct);
            callerObject = (T) jcdiContext.getInstance();
            // Need to keep track of context in order to destroy properly
            Map> bundleNonManagedObjs =
                jcdiManagedBeanInstanceMap.get(bundleDescriptor);
            bundleNonManagedObjs.put(callerObject, jcdiContext);

        } else {
            if (desc == null) {
                throw new IllegalArgumentException(
                        "CDI not enabled and no managed bean found for class: " + managedBeanClass.getName());
            }
            JavaEEInterceptorBuilder interceptorBuilder = (JavaEEInterceptorBuilder)
                desc.getInterceptorBuilder();

            // This is the managed bean class instance
            T managedBean = managedBeanClass.newInstance();

            InterceptorInvoker interceptorInvoker =
                    interceptorBuilder.createInvoker(managedBean);

            // This is the object passed back to the caller.
            callerObject = (T) interceptorInvoker.getProxy();

            Object[] interceptorInstances = interceptorInvoker.getInterceptorInstances();

            inject(managedBean, desc);

            // Inject interceptor instances
            for(int i = 0; i < interceptorInstances.length; i++) {
                inject(interceptorInstances[i], desc);
            }

            interceptorInvoker.invokePostConstruct();

            desc.addBeanInstanceInfo(managedBean, interceptorInvoker);

        }
        return callerObject;
    }

    @Override
    public boolean isManagedBean(Object object) {
        JavaEEInterceptorBuilderFactory factory = habitat.getService(JavaEEInterceptorBuilderFactory.class);
        return factory != null && factory.isClientProxy(object);
    }

    private void inject(Object instance, ManagedBeanDescriptor managedBeanDesc)
        throws Exception {
        BundleDescriptor bundle = managedBeanDesc.getBundle();
        if( (bundle instanceof EjbBundleDescriptor) || (bundle instanceof ApplicationClientDescriptor) ) {
            injectionMgr.injectInstance(instance, managedBeanDesc.getGlobalJndiName(), false);
        } else {
            //  Inject instances, but use injection invoker for PostConstruct
            injectionMgr.injectInstance(instance, (JndiNameEnvironment) bundle, false);
        }
    }

    @Override
    public void destroyManagedBean(Object managedBean)  {
        destroyManagedBean(managedBean, true);
    }

    @Override
    public void destroyManagedBean(Object managedBean, boolean validate)  {

        BundleDescriptor bundle = getBundle();

        JCDIService jcdiService = habitat.getService(JCDIService.class);

        if( (jcdiService != null) && jcdiService.isJCDIEnabled(bundle)) {
            Map> bundleNonManagedObjs = jcdiManagedBeanInstanceMap.get(bundle);
            // in a failure scenario it's possible that bundleNonManagedObjs is null
            if ( bundleNonManagedObjs == null ) {
                if (validate) {
                    throw new IllegalStateException("Unknown JCDI-enabled managed bean " +
                                                     managedBean + " of class " + managedBean.getClass());
                }
                _logger.log(Level.FINE, "Unknown JCDI-enabled managed bean " +
                            managedBean + " of class " + managedBean.getClass());
            } else {
                JCDIService.JCDIInjectionContext context = bundleNonManagedObjs.remove(managedBean);
                if( context == null ) {
                    if (validate) {
                        throw new IllegalStateException("Unknown JCDI-enabled managed bean " +
                                                            managedBean + " of class " + managedBean.getClass());
                    }
                    _logger.log(Level.FINE, "Unknown JCDI-enabled managed bean " +
                        managedBean + " of class " + managedBean.getClass());
                    return;
                }

                // Call PreDestroy and cleanup
                context.cleanup(true);
            }
        } else {

            Object managedBeanInstance = null;

            try {

                Field proxyField = managedBean.getClass().getDeclaredField("__ejb31_delegate");

                final Field finalF = proxyField;
                PrivilegedExceptionAction action = () -> {
                    if (!finalF.isAccessible()) {
                        finalF.setAccessible(true);
                    }
                    return null;
                };
                AccessController.doPrivileged(action);

                Proxy proxy = (Proxy) proxyField.get(managedBean);

                InterceptorInvoker invoker = (InterceptorInvoker) Proxy.getInvocationHandler(proxy);

                managedBeanInstance = invoker.getTargetInstance();

            } catch(Exception e) {
                throw new IllegalArgumentException("invalid managed bean " + managedBean, e);
            }

            ManagedBeanDescriptor desc = bundle.getManagedBeanByBeanClass(
                    managedBeanInstance.getClass().getName());

            if( desc == null ) {
                throw new IllegalStateException("Could not retrieve managed bean descriptor for " +
                    managedBean + " of class " + managedBean.getClass());
            }

            InterceptorInvoker invoker = (InterceptorInvoker)
                desc.getSupportingInfoForBeanInstance(managedBeanInstance);

            try {
                invoker.invokePreDestroy();
            } catch(Exception e) {
                _logger.log(Level.FINE, "Managed bean " + desc.getBeanClassName() + " PreDestroy", e);
            }

            desc.clearBeanInstanceInfo(managedBeanInstance);
        }
    }

    private BundleDescriptor getBundle() {
        ComponentEnvManager compEnvManager = habitat.getService(ComponentEnvManager.class);

        JndiNameEnvironment env = compEnvManager.getCurrentJndiNameEnvironment();

        BundleDescriptor bundle = null;

        if( env instanceof BundleDescriptor) {

           bundle = (BundleDescriptor) env;

        } else if( env instanceof EjbDescriptor ) {

           bundle = (BundleDescriptor)
                   ((EjbDescriptor)env).getEjbBundleDescriptor().getModuleDescriptor().getDescriptor();
        }

        if( bundle == null ) {
           throw new IllegalStateException("Invalid context for managed bean creation");
        }

        return bundle;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy