org.glassfish.weld.services.JCDIServiceImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of payara-micro Show documentation
Show all versions of payara-micro Show documentation
Micro Distribution of the Payara Project
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2009-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-2017] [Payara Foundation and/or its affiliates]
package org.glassfish.weld.services;
import com.sun.enterprise.container.common.spi.JCDIService;
import com.sun.enterprise.container.common.spi.util.ComponentEnvManager;
import com.sun.enterprise.deployment.BundleDescriptor;
import com.sun.enterprise.deployment.EjbDescriptor;
import com.sun.enterprise.deployment.JndiNameEnvironment;
import org.glassfish.api.invocation.ComponentInvocation;
import org.glassfish.api.invocation.InvocationManager;
import org.glassfish.cdi.CDILoggerInfo;
import org.glassfish.hk2.api.Rank;
import org.glassfish.weld.BeanDeploymentArchiveImpl;
import org.glassfish.weld.WeldDeployer;
import org.glassfish.weld.connector.WeldUtils;
import org.jboss.weld.bootstrap.WeldBootstrap;
import org.jboss.weld.bootstrap.spi.BeanDeploymentArchive;
import org.jboss.weld.manager.api.WeldManager;
import org.jboss.weld.manager.InjectionTargetFactoryImpl;
import org.jvnet.hk2.annotations.Service;
import org.jboss.weld.resources.ClassTransformer;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.ConversationScoped;
import javax.enterprise.context.Dependent;
import javax.enterprise.context.NormalScope;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.AnnotatedConstructor;
import javax.enterprise.inject.spi.AnnotatedField;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.InjectionTarget;
import javax.inject.Inject;
import javax.inject.Scope;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.inject.spi.BeanAttributes;
import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedType;
import org.jboss.weld.bean.InterceptorImpl;
import org.jboss.weld.bean.attributes.BeanAttributesFactory;
import org.jboss.weld.context.CreationalContextImpl;
import org.jboss.weld.manager.BeanManagerImpl;
import static org.jboss.weld.util.reflection.Reflections.cast;
@Service
@Rank(10)
public class JCDIServiceImpl implements JCDIService {
private static final HashSet validScopes = new HashSet();
static {
validScopes.add(Scope.class.getName());
validScopes.add(NormalScope.class.getName());
validScopes.add(RequestScoped.class.getName());
validScopes.add(SessionScoped.class.getName());
validScopes.add(ApplicationScoped.class.getName());
validScopes.add(ConversationScoped.class.getName());
}
private static final HashSet excludedScopes = new HashSet();
static {
excludedScopes.add(Dependent.class.getName());
}
@Inject
private WeldDeployer weldDeployer;
@Inject
private ComponentEnvManager compEnvManager;
@Inject
private InvocationManager invocationManager;
private Logger logger = Logger.getLogger(JCDIServiceImpl.class.getName());
@Override
public boolean isCurrentModuleJCDIEnabled() {
BundleDescriptor bundle = null;
ComponentInvocation inv = invocationManager.getCurrentInvocation();
if( inv == null ) {
return false;
}
JndiNameEnvironment componentEnv =
compEnvManager.getJndiNameEnvironment(inv.getComponentId());
if( componentEnv != null ) {
if( componentEnv instanceof BundleDescriptor ) {
bundle = (BundleDescriptor) componentEnv;
} else if( componentEnv instanceof EjbDescriptor ) {
bundle = ((EjbDescriptor) componentEnv).getEjbBundleDescriptor();
}
}
return (bundle != null) ? isJCDIEnabled(bundle) : false;
}
@Override
public boolean isJCDIEnabled(BundleDescriptor bundle) {
// Get the top-level bundle descriptor from the given bundle.
// E.g. allows EjbBundleDescriptor from a .war to be handled correctly.
BundleDescriptor topLevelBundleDesc = (BundleDescriptor) bundle.getModuleDescriptor().getDescriptor();
return weldDeployer.is299Enabled(topLevelBundleDesc);
}
@Override
public boolean isCDIScoped(Class clazz) {
// Check all the annotations on the specified Class to determine if the class is annotated
// with a supported CDI scope
return WeldUtils.hasValidAnnotation(clazz, validScopes, excludedScopes);
}
@Override
public void setELResolver(ServletContext servletContext) throws NamingException {
InitialContext context = new InitialContext();
BeanManager beanManager = (BeanManager)
context.lookup("java:comp/BeanManager");
if (beanManager != null) {
servletContext.setAttribute(
"org.glassfish.jsp.beanManagerELResolver",
beanManager.getELResolver());
}
}
@Override
public JCDIInjectionContext createJCDIInjectionContext(EjbDescriptor ejb, T instance) {
return _createJCDIInjectionContext(ejb, instance);
}
@Override
public JCDIInjectionContext createJCDIInjectionContext(EjbDescriptor ejb) {
return _createJCDIInjectionContext(ejb, null);
}
// instance could be null. If null, create a new one
@SuppressWarnings({ "rawtypes", "unchecked" })
private JCDIInjectionContext _createJCDIInjectionContext(EjbDescriptor ejb, T instance) {
BundleDescriptor topLevelBundleDesc = (BundleDescriptor)
ejb.getEjbBundleDescriptor().getModuleDescriptor().getDescriptor();
// First get BeanDeploymentArchive for this ejb
BeanDeploymentArchive bda = getBDAForBeanClass(topLevelBundleDesc, ejb.getEjbClassName());
WeldBootstrap bootstrap = weldDeployer.getBootstrapForApp(ejb.getEjbBundleDescriptor().getApplication());
WeldManager weldManager = bootstrap.getManager(bda);
org.jboss.weld.ejb.spi.EjbDescriptor ejbDesc = weldManager.getEjbDescriptor(ejb.getName());
if(ejbDesc == null) {
return null;
}
// Get an the Bean object
Bean bean = weldManager.getBean(ejbDesc);
// Create the injection target
InjectionTarget it = weldManager.createInjectionTarget(ejbDesc);
// Per instance required, create the creational context
CreationalContext cc = weldManager.createCreationalContext(bean);
Object beanInstance = instance;
if( beanInstance == null ) {
// Create instance , perform constructor injection.
beanInstance = it.produce(cc);
}
// Injection is not performed yet. Separate injectEJBInstance() call is required.
return new JCDIInjectionContextImpl(it, cc, beanInstance);
}
private BeanDeploymentArchive getBDAForBeanClass(BundleDescriptor bundleDesc, String beanClassName){
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
CDILoggerInfo.GET_BDA_FOR_BEAN_CLASS_SEARCH,
new Object [] {bundleDesc.getModuleName(), beanClassName});
}
BeanDeploymentArchive topLevelBDA = weldDeployer.getBeanDeploymentArchiveForBundle(bundleDesc);
if (topLevelBDA.getBeanClasses().contains(beanClassName)){
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
CDILoggerInfo.TOP_LEVEL_BDA_CONTAINS_BEAN_CLASS_NAME,
new Object[]{ topLevelBDA.getId(), beanClassName});
}
return topLevelBDA;
}
//for all sub-BDAs
for (BeanDeploymentArchive bda: topLevelBDA.getBeanDeploymentArchives()){
if (bda.getBeanClasses().contains(beanClassName)){
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
CDILoggerInfo.SUB_BDA_CONTAINS_BEAN_CLASS_NAME,
new Object[]{bda.getId(), beanClassName});
}
return bda;
}
}
//If not found in any BDA's subclasses, return topLevel BDA
return topLevelBDA;
}
@SuppressWarnings("unchecked")
@Override
public void injectEJBInstance(JCDIInjectionContext injectionCtx) {
JCDIInjectionContextImpl injectionCtxImpl = (JCDIInjectionContextImpl) injectionCtx;
// Perform injection and call initializers
injectionCtxImpl.it.inject(injectionCtxImpl.instance, injectionCtxImpl.cc);
// NOTE : PostConstruct is handled by ejb container
}
@Override
public JCDIInjectionContext createManagedObject(Class managedClass, BundleDescriptor bundle) {
return createManagedObject(managedClass, bundle, true);
}
/**
* Perform 299 style injection on the managedObject
argument.
* @param managedObject the managed object
* @param bundle the bundle descriptor
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public void injectManagedObject(Object managedObject, BundleDescriptor bundle) {
BundleDescriptor topLevelBundleDesc = (BundleDescriptor) bundle.getModuleDescriptor().getDescriptor();
// First get BeanDeploymentArchive for this ejb
BeanDeploymentArchive bda = weldDeployer.getBeanDeploymentArchiveForBundle(topLevelBundleDesc);
//BeanDeploymentArchive bda = getBDAForBeanClass(topLevelBundleDesc, managedObject.getClass().getName());
WeldBootstrap bootstrap = weldDeployer.getBootstrapForApp(bundle.getApplication());
BeanManager beanManager = bootstrap.getManager(bda);
AnnotatedType annotatedType = beanManager.createAnnotatedType(managedObject.getClass());
InjectionTarget it = beanManager.createInjectionTarget(annotatedType);
CreationalContext cc = beanManager.createCreationalContext(null);
it.inject(managedObject, cc);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public T createInterceptorInstance(Class interceptorClass, EjbDescriptor ejbDesc) {
BundleDescriptor bundle = ejbDesc.getEjbBundleDescriptor();
BundleDescriptor topLevelBundleDesc = (BundleDescriptor) bundle.getModuleDescriptor().getDescriptor();
// First get BeanDeploymentArchive for this ejb
BeanDeploymentArchive bda = weldDeployer.getBeanDeploymentArchiveForBundle(topLevelBundleDesc);
WeldBootstrap bootstrap = weldDeployer.getBootstrapForApp(bundle.getApplication());
BeanManagerImpl beanManager = bootstrap.getManager(bda);
WeldManager weldManager = beanManager;
AnnotatedType annotatedType = beanManager.createAnnotatedType(interceptorClass);
EnhancedAnnotatedType type = ((ClassTransformer) beanManager.getServices().get(ClassTransformer.class)).getEnhancedAnnotatedType(annotatedType, beanManager.getId());
// Get an the Bean object
BeanAttributes attributes = BeanAttributesFactory.forBean(type, beanManager);
InterceptorImpl interceptor = InterceptorImpl.of(attributes, type, beanManager);
// Create the creational context
CreationalContext ctx;
org.jboss.weld.ejb.spi.EjbDescriptor ejbWeldDesc = weldManager.getEjbDescriptor(ejbDesc.getName());
if (ejbWeldDesc == null) {
ctx = beanManager.createCreationalContext(null);
} else {
Bean sessionBean = weldManager.getBean(ejbWeldDesc);
ctx = beanManager.createCreationalContext(sessionBean);
}
T interceptorInstance = cast(beanManager.getReference(interceptor, interceptor.getBeanClass(), ctx));
return interceptorInstance;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public JCDIInjectionContext createManagedObject(Class managedClass, BundleDescriptor bundle,
boolean invokePostConstruct) {
Object managedObject = null;
BundleDescriptor topLevelBundleDesc = (BundleDescriptor) bundle.getModuleDescriptor().getDescriptor();
// First get BeanDeploymentArchive for this ejb
BeanDeploymentArchive bda = weldDeployer.getBeanDeploymentArchiveForBundle(topLevelBundleDesc);
WeldBootstrap bootstrap = weldDeployer.getBootstrapForApp(bundle.getApplication());
BeanManager beanManager = bootstrap.getManager(bda);
AnnotatedType annotatedType = beanManager.createAnnotatedType(managedClass);
if (!invokePostConstruct) {
annotatedType = new NoPostConstructPreDestroyAnnotatedType(annotatedType);
}
InjectionTarget it = ((BeanDeploymentArchiveImpl)bda).getInjectionTarget(annotatedType);
if (it == null) {
it = beanManager.createInjectionTarget(annotatedType);
}
CreationalContext cc = beanManager.createCreationalContext(null);
managedObject = it.produce(cc);
it.inject(managedObject, cc);
if( invokePostConstruct ) {
it.postConstruct(managedObject);
}
return new JCDIInjectionContextImpl(it, cc, managedObject);
}
/**
* This class is here to exclude the post-construct and pre-destroy methods from the AnnotatedType.
* This is done in cases where Weld will not be calling those methods and we therefore do NOT want
* Weld to validate them, as they may be of the form required for interceptors rather than
* Managed objects
*
* @author jwells
*
* @param
*/
private static class NoPostConstructPreDestroyAnnotatedType implements AnnotatedType {
private final AnnotatedType delegate;
private NoPostConstructPreDestroyAnnotatedType(AnnotatedType delegate) {
this.delegate = delegate;
}
@Override
public Type getBaseType() {
return delegate.getBaseType();
}
@Override
public Set getTypeClosure() {
return delegate.getTypeClosure();
}
@Override
public T getAnnotation(Class annotationType) {
return delegate.getAnnotation(annotationType);
}
@Override
public Set getAnnotations() {
return delegate.getAnnotations();
}
@Override
public boolean isAnnotationPresent(
Class annotationType) {
return delegate.isAnnotationPresent(annotationType);
}
@Override
public Class getJavaClass() {
return delegate.getJavaClass();
}
@Override
public Set> getConstructors() {
return delegate.getConstructors();
}
@Override
public Set> getMethods() {
HashSet> retVal = new HashSet>();
for (AnnotatedMethod m : delegate.getMethods()) {
if (m.isAnnotationPresent(PostConstruct.class) ||
m.isAnnotationPresent(PreDestroy.class)) {
// Do not include the post-construct or pre-destroy
continue;
}
retVal.add(m);
}
return retVal;
}
@Override
public Set> getFields() {
return delegate.getFields();
}
}
@SuppressWarnings("rawtypes")
private static class JCDIInjectionContextImpl implements JCDIInjectionContext {
InjectionTarget it;
CreationalContext cc;
T instance;
JCDIInjectionContextImpl(InjectionTarget it, CreationalContext cc, T i) {
this.it = it;
this.cc = cc;
this.instance = i;
}
@Override
public T getInstance() {
return instance;
}
@SuppressWarnings("unchecked")
@Override
public void cleanup(boolean callPreDestroy) {
if( callPreDestroy ) {
it.preDestroy(instance);
}
it.dispose(instance);
cc.release();
}
}
}