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

org.glassfish.weld.services.InjectionServicesImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2022 Contributors to the Eclipse Foundation
 * Copyright (c) 2009, 2020 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package org.glassfish.weld.services;

import com.sun.enterprise.container.common.spi.util.ComponentEnvManager;
import com.sun.enterprise.container.common.spi.util.InjectionException;
import com.sun.enterprise.container.common.spi.util.InjectionManager;
import com.sun.enterprise.deployment.BundleDescriptor;
import com.sun.enterprise.deployment.EjbBundleDescriptor;
import com.sun.enterprise.deployment.EjbDescriptor;
import com.sun.enterprise.deployment.InjectionCapable;
import com.sun.enterprise.deployment.InjectionInfo;
import com.sun.enterprise.deployment.JndiNameEnvironment;
import com.sun.enterprise.deployment.ManagedBeanDescriptor;

import jakarta.annotation.Resource;
import jakarta.ejb.EJB;
import jakarta.enterprise.inject.Produces;
import jakarta.enterprise.inject.spi.AnnotatedField;
import jakarta.enterprise.inject.spi.AnnotatedType;
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.enterprise.inject.spi.DefinitionException;
import jakarta.enterprise.inject.spi.InjectionTarget;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.PersistenceUnit;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;

import org.glassfish.api.naming.SimpleJndiName;
import org.glassfish.ejb.api.EjbContainerServices;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.internal.api.Globals;
import org.glassfish.weld.DeploymentImpl;
import org.glassfish.weld.connector.WeldUtils;
import org.jboss.weld.injection.spi.InjectionContext;
import org.jboss.weld.injection.spi.InjectionServices;

import static org.glassfish.api.naming.SimpleJndiName.JNDI_CTX_JAVA_COMPONENT;
import static org.glassfish.api.naming.SimpleJndiName.JNDI_CTX_JAVA_COMPONENT_ENV;

public class InjectionServicesImpl implements InjectionServices {

    private final InjectionManager injectionManager;

    // Associated bundle context
    private final BundleDescriptor bundleContext;

    private final DeploymentImpl deployment;

    private WsInjectionHandler wsHandler;

    public InjectionServicesImpl(InjectionManager injectionMgr, BundleDescriptor context, DeploymentImpl deployment) {
        injectionManager = injectionMgr;
        bundleContext = context;
        this.deployment = deployment;
    }

    private boolean isInterceptor(Class beanClass) {
        HashSet annos = new HashSet<>();
        annos.add(jakarta.interceptor.Interceptor.class.getName());
        boolean res = false;
        while (!res && beanClass != Object.class) {
            res = WeldUtils.hasValidAnnotation(beanClass, annos, null);
            beanClass = beanClass.getSuperclass();
        }
        return res;
    }

    @Override
    public  void aroundInject(InjectionContext injectionContext) {
        try {
            ServiceLocator serviceLocator = Globals.getDefaultHabitat();
            ComponentEnvManager compEnvManager = serviceLocator.getService(ComponentEnvManager.class);
            EjbContainerServices containerServices = serviceLocator.getService(EjbContainerServices.class);

            JndiNameEnvironment componentEnv = compEnvManager.getCurrentJndiNameEnvironment();

            ManagedBeanDescriptor mbDesc = null;

            JndiNameEnvironment injectionEnv = (JndiNameEnvironment) bundleContext;

            AnnotatedType annotatedType = injectionContext.getAnnotatedType();
            Class targetClass = annotatedType.getJavaClass();
            String targetClassName = targetClass.getName();
            Object target = injectionContext.getTarget();

            if (isInterceptor(targetClass) && !componentEnv.equals(injectionEnv)) {
                // Resources injected into interceptors must come from the environment in which the interceptor is
                // intercepting, not the environment in which the interceptor resides (for everything else!)
                // Must use the injectionEnv to get the injection info to determine where in jndi to look for the objects to inject.
                // must use the current jndi component env to lookup the objects to inject
                injectionManager.inject(targetClass, target, injectionEnv, null, false);
            } else {
                if (componentEnv == null) {
                    //throw new IllegalStateException("No valid EE environment for injection of " + targetClassName);
                    System.err.println("No valid EE environment for injection of " + targetClassName);
                    injectionContext.proceed();
                    return;
                }

                // Perform EE-style injection on the target.  Skip PostConstruct since
                // in this case 299 impl is responsible for calling it.

                if (componentEnv instanceof EjbDescriptor) {

                    EjbDescriptor ejbDesc = (EjbDescriptor) componentEnv;

                    if (containerServices.isEjbManagedObject(ejbDesc, targetClass)) {
                        injectionEnv = componentEnv;
                    } else if (bundleContext instanceof EjbBundleDescriptor) {

                        // Check if it's a @ManagedBean class within an ejb-jar.  In that case,
                        // special handling is needed to locate the EE env dependencies
                        mbDesc = bundleContext.getManagedBeanByBeanClass(targetClassName);
                    }
                }

                if (mbDesc != null) {
                    SimpleJndiName componentId = mbDesc.getGlobalJndiName();
                    injectionManager.injectInstance(target, componentId, false);
                } else if (injectionEnv instanceof EjbBundleDescriptor) {

                    // CDI-style managed bean that doesn't have @ManagedBean annotation but
                    // is injected within the context of an ejb.  Need to explicitly
                    // set the environment of the ejb bundle.
                    SimpleJndiName componentId = SimpleJndiName.of(compEnvManager.getComponentEnvId(injectionEnv));
                    if (target == null) {
                        injectionManager.injectClass(targetClass, componentId, false);
                    } else {
                        injectionManager.injectInstance(target, componentId, false);
                    }
                } else {
                    if (target == null) {
                        injectionManager.injectClass(targetClass, injectionEnv, false);
                    } else {
                        injectionManager.injectInstance(target, injectionEnv, false);
                    }
                }

            }

            injectionContext.proceed();

        } catch (InjectionException ie) {
            throw new IllegalStateException(ie.getMessage(), ie);
        }
    }

    @Override
    public  void registerInjectionTarget(InjectionTarget injectionTarget, AnnotatedType annotatedType) {
        if (bundleContext instanceof EjbBundleDescriptor) {
            // we can't handle validting producer fields for ejb bundles because the JNDI environment is not setup
            // yet for ejbs and so we can't get the correct JndiNameEnvironment to call getInjectionInfoByClass.
            // getInjectionInfoByClass caches the results and so causes subsequent calls to return invalid information.
            return;
        }

        // We are only validating producer fields of resources.  See spec section 3.7.1
        Class annotatedClass = annotatedType.getJavaClass();
        JndiNameEnvironment jndiNameEnvironment = (JndiNameEnvironment) bundleContext;

        InjectionInfo injectionInfo = jndiNameEnvironment.getInjectionInfoByClass(annotatedClass);
        List injectionResources = injectionInfo.getInjectionResources();

        for (AnnotatedField annotatedField : annotatedType.getFields()) {
            if (annotatedField.isAnnotationPresent(Produces.class)) {
                if (annotatedField.isAnnotationPresent(EJB.class)) {
                    validateEjbProducer(annotatedClass, annotatedField, injectionResources);
                } else if (annotatedField.isAnnotationPresent(Resource.class)) {
                    validateResourceProducer(annotatedClass, annotatedField, injectionResources);
                } else if (annotatedField.isAnnotationPresent(PersistenceUnit.class)) {
                    validateResourceClass(annotatedField, EntityManagerFactory.class);
                } else if (annotatedField.isAnnotationPresent(PersistenceContext.class)) {
                    validateResourceClass(annotatedField, EntityManager.class);
                } else if (getWsHandler().handles(annotatedField)) {
                    getWsHandler().validateWebServiceRef(annotatedField);
                }
            }
        }

    }


    private  void validateEjbProducer(Class annotatedClass, AnnotatedField annotatedField,
        List injectionResources) {
        EJB ejbAnnotation = annotatedField.getAnnotation(EJB.class);
        if (ejbAnnotation != null) {
            SimpleJndiName lookupName = getLookupName(annotatedClass, annotatedField, injectionResources);
            EjbDescriptor foundEjb = null;
            Collection ejbs = deployment.getDeployedEjbs();
            for (EjbDescriptor oneEjb : ejbs) {
                SimpleJndiName jndiName = oneEjb.getJndiName();
                if (lookupName.contains(jndiName.toString())) {
                    foundEjb = oneEjb;
                    break;
                }
            }
            if (foundEjb != null) {
                String className = foundEjb.getEjbImplClassName();
                try {
                    Class clazz = Class.forName(className, false, annotatedClass.getClassLoader());
                    validateResourceClass(annotatedField, clazz);
                } catch (ClassNotFoundException ignore) {
                }
            }
        }
    }


    private void validateResourceProducer(Class annotatedClass, AnnotatedField annotatedField,
        List injectionResources) {
        Resource resourceAnnotation = annotatedField.getAnnotation(Resource.class);
        if (resourceAnnotation != null) {
            SimpleJndiName lookupName = getLookupName(annotatedClass, annotatedField, injectionResources);
            if (lookupName.toString().equals(JNDI_CTX_JAVA_COMPONENT + "BeanManager")) {
                validateResourceClass(annotatedField, BeanManager.class);
            } else {
                boolean done = false;
                for (InjectionCapable injectionCapable : injectionResources) {
                    for (com.sun.enterprise.deployment.InjectionTarget target : injectionCapable.getInjectionTargets()) {
                        if (target.isFieldInjectable()) { // make sure it's a field and not a method
                            if (annotatedClass.getName().equals(target.getClassName())
                                    && target.getFieldName().equals(annotatedField.getJavaMember().getName())) {
                                String type = injectionCapable.getInjectResourceType();
                                try {
                                    Class clazz = Class.forName(type, false, annotatedClass.getClassLoader());
                                    validateResourceClass(annotatedField, clazz);
                                } catch (ClassNotFoundException ignore) {
                                } finally {
                                    done = true;
                                }
                            }
                        }
                        if (done) {
                            break;
                        }
                    }
                }
            }
        }
    }

    private void validateResourceClass(AnnotatedField annotatedField, Class resourceClass) {
        if (!annotatedField.getJavaMember().getType().isAssignableFrom(resourceClass)) {
            throwProducerDefinitionExeption(annotatedField.getJavaMember().getName(),
                annotatedField.getJavaMember().getType().getName(), resourceClass.getName());
        }
    }

    private void throwProducerDefinitionExeption(String annotatedFieldName, String annotatedFieldType, String resourceClassName) {
        throw new DefinitionException(
            "The type of the injection point " + annotatedFieldName + " is " + annotatedFieldType
                + ".  The type of the physical resource is " + resourceClassName + " They are incompatible. ");
    }


    private SimpleJndiName getComponentEnvName(Class annotatedClass, String fieldName,
        List injectionResources) {
        for (InjectionCapable injectionCapable : injectionResources) {
            for (com.sun.enterprise.deployment.InjectionTarget target : injectionCapable.getInjectionTargets()) {
                if (target.isFieldInjectable()) { // make sure it's a field and not a method
                    if (annotatedClass.getName().equals(target.getClassName()) && target.getFieldName().equals(fieldName)) {
                        SimpleJndiName name = injectionCapable.getComponentEnvName();
                        if (!name.hasJavaPrefix()) {
                            name = new SimpleJndiName(JNDI_CTX_JAVA_COMPONENT_ENV + name);
                        }
                        return name;
                    }
                }
            }
        }
        return null;
    }


    private SimpleJndiName getLookupName(Class annotatedClass, AnnotatedField annotatedField,
        List injectionResources) {
        SimpleJndiName lookupName = null;
        if (annotatedField.isAnnotationPresent(Resource.class)) {
            Resource resource = annotatedField.getAnnotation(Resource.class);
            lookupName = getJndiName(resource.lookup(), resource.mappedName(), resource.name());
        } else if (annotatedField.isAnnotationPresent(EJB.class)) {
            EJB ejb = annotatedField.getAnnotation(EJB.class);
            lookupName = getJndiName(ejb.lookup(), ejb.mappedName(), ejb.name());
        } else if (getWsHandler().handles(annotatedField)) {
            lookupName = getWsHandler().getJndiName(annotatedField);
        } else if (annotatedField.isAnnotationPresent(PersistenceUnit.class)) {
            PersistenceUnit persistenceUnit = annotatedField.getAnnotation(PersistenceUnit.class);
            lookupName = getJndiName(persistenceUnit.unitName(), null, persistenceUnit.name());
        } else if (annotatedField.isAnnotationPresent(PersistenceContext.class)) {
            PersistenceContext persistenceContext = annotatedField.getAnnotation(PersistenceContext.class);
            lookupName = getJndiName(persistenceContext.unitName(), null, persistenceContext.name());
        }

        if (lookupName == null || lookupName.isEmpty()) {
            lookupName = getComponentEnvName(annotatedClass, annotatedField.getJavaMember().getName(), injectionResources);
        }
        return lookupName;
    }

    static SimpleJndiName getJndiName(String lookup, String mappedName, String name) {
        String jndiName = lookup;
        if (jndiName == null || jndiName.isEmpty()) {
            jndiName = mappedName;
            if (jndiName == null || jndiName.isEmpty()) {
                jndiName = name;
            }
        }
        return jndiName == null ? null : new SimpleJndiName(jndiName.trim());
    }

    private WsInjectionHandler getWsHandler() {
        if (wsHandler == null) {
            try {
                //TODO: define this properly so that the ServiceLocator can be used instead
                // and (optional) dependency on webservices-apis can be dropped
                wsHandler = (WsInjectionHandler) Class.forName("org.glassfish.weld.services.WsInjectionHandlerImpl")
                    .getConstructor().newInstance();
            } catch (ReflectiveOperationException | SecurityException t) {
                // not loaded due to missing jakarta.xml.ws packages => likely web profile
                // let's use noop handler
                wsHandler = WsInjectionHandler.NOOP;
            }
        }
        return wsHandler;
    }

    @Override
    public void cleanup() {

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy