/* * JBoss, Home of Professional Open Source * Copyright 2012, Red Hat, Inc., and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.weld.module.ejb; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.List; import java.util.Set; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.Decorator; import javax.enterprise.inject.spi.InjectionPoint; import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedConstructor; import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedType; import org.jboss.weld.bean.SessionBean; import org.jboss.weld.bean.proxy.CombinedInterceptorAndDecoratorStackMethodHandler; import org.jboss.weld.bean.proxy.MethodHandler; import org.jboss.weld.bean.proxy.ProxyObject; import org.jboss.weld.injection.producer.AbstractInstantiator; import org.jboss.weld.injection.producer.BeanInjectionTarget; import org.jboss.weld.injection.producer.DefaultInjector; import org.jboss.weld.injection.producer.DefaultInstantiator; import org.jboss.weld.injection.producer.DefaultLifecycleCallbackInvoker; import org.jboss.weld.injection.producer.Injector; import org.jboss.weld.injection.producer.Instantiator; import org.jboss.weld.injection.producer.InterceptionModelInitializer; import org.jboss.weld.injection.producer.LifecycleCallbackInvoker; import org.jboss.weld.injection.producer.SubclassDecoratorApplyingInstantiator; import org.jboss.weld.injection.producer.SubclassedComponentInstantiator; import org.jboss.weld.manager.BeanManagerImpl; import org.jboss.weld.util.Types; class SessionBeanInjectionTarget<T> extends BeanInjectionTarget<T> { public static <T> SessionBeanInjectionTarget<T> of(EnhancedAnnotatedType<T> type, SessionBean<T> bean, BeanManagerImpl beanManager) { LifecycleCallbackInvoker<T> invoker = DefaultLifecycleCallbackInvoker.of(type); Injector<T> injector; if (bean.getEjbDescriptor().isStateless() || bean.getEjbDescriptor().isSingleton()) { injector = new DynamicInjectionPointInjector<T>(type, bean, beanManager); } else { injector = new DefaultInjector<T>(type, bean, beanManager); } return new SessionBeanInjectionTarget<T>(type, bean, beanManager, injector, invoker); } private final SessionBean<T> bean; private SessionBeanInjectionTarget(EnhancedAnnotatedType<T> type, SessionBean<T> bean, BeanManagerImpl beanManager, Injector<T> injector, LifecycleCallbackInvoker<T> invoker) { super(type, bean, beanManager, injector, invoker); this.bean = bean; } @Override public SessionBean<T> getBean() { return bean; } @Override protected Instantiator<T> initInstantiator(EnhancedAnnotatedType<T> type, Bean<T> bean, BeanManagerImpl beanManager, Set<InjectionPoint> injectionPoints) { if (bean instanceof SessionBean<?>) { EnhancedAnnotatedType<T> implementationClass = SessionBeans.getEjbImplementationClass((SessionBean<T>) bean); AbstractInstantiator<T> instantiator = null; if (type.equals(implementationClass)) { instantiator = new DefaultInstantiator<T>(type, bean, beanManager); } else { // Session bean subclassed by the EJB container instantiator = SubclassedComponentInstantiator.forSubclassedEjb(type, implementationClass, bean, beanManager); } injectionPoints.addAll(instantiator.getConstructorInjectionPoint().getParameterInjectionPoints()); return instantiator; } else { throw new IllegalArgumentException("Cannot create SessionBeanInjectionTarget for " + bean); } } @Override public void initializeAfterBeanDiscovery(EnhancedAnnotatedType<T> annotatedType) { initializeInterceptionModel(annotatedType); List<Decorator<?>> decorators = beanManager.resolveDecorators(getBean().getTypes(), getBean().getQualifiers()); if (!decorators.isEmpty()) { Instantiator<T> instantiator = getInstantiator(); EnhancedAnnotatedType<T> implementationClass = SessionBeans.getEjbImplementationClass(getBean()); instantiator = SubclassedComponentInstantiator.forInterceptedDecoratedBean(implementationClass, getBean(), (AbstractInstantiator<T>) instantiator, beanManager); instantiator = new SubclassDecoratorApplyingInstantiator<T>(getBeanManager().getContextId(), instantiator, getBean(), decorators, implementationClass.getJavaClass()); setInstantiator(instantiator); } /* * We only take care of @AroundConstructor interception. The EJB container deals with the other types of interception. */ setupConstructorInterceptionInstantiator(beanManager.getInterceptorModelRegistry().get(getType())); } @Override protected void buildInterceptionModel(EnhancedAnnotatedType<T> annotatedType, AbstractInstantiator<T> instantiator) { /* * instantiator.getConstructorInjectionPoint() may represent the constructor of the SessionBean subclass which may not have annotations applied * Therefore, use the component class constructor instead of the one from subclass. */ EnhancedAnnotatedConstructor<T> constructor = annotatedType.getDeclaredEnhancedConstructor(instantiator.getConstructorInjectionPoint().getSignature()); new InterceptionModelInitializer<T>(beanManager, annotatedType, constructor, getBean()).init(); } @Override public T produce(CreationalContext<T> ctx) { T result = super.produce(ctx); if (result instanceof ProxyObject) { // if decorators are applied, use SessionBeanViewMethodHandler ProxyObject proxy = (ProxyObject) result; proxy.setHandler(new SessionBeanViewMethodHandler(bean.getTypes(), (CombinedInterceptorAndDecoratorStackMethodHandler) proxy.getHandler())); } return result; } @Override public void inject(T instance, CreationalContext<T> ctx) { // explicitly use bean's AnnotatedType, not InjectionPoint's as this.getAnnotated() // may represent the annotated type for the EJB-container subclass (see SubclassedComponentDescriptor) getInjector().inject(instance, ctx, beanManager, bean.getAnnotated(), this); } /** * This {@link MethodHandler} assures that any method invoked on a decorated {@link SessionBean} is a method that belongs to * a bean type of the bean. If the methods belongs to the bean implementation and the bean implementation is not a bean type * the handler tries to replace the method with the equivalent method defined on a bean type. * * @author Jozef Hartinger * */ private static class SessionBeanViewMethodHandler extends CombinedInterceptorAndDecoratorStackMethodHandler { private static final long serialVersionUID = -8038819529432133787L; private final Set<Class<?>> beanTypes; public SessionBeanViewMethodHandler(Set<Type> types, CombinedInterceptorAndDecoratorStackMethodHandler delegate) { this.beanTypes = Types.getRawTypes(types); setOuterDecorator(delegate.getOuterDecorator()); setInterceptorMethodHandler(delegate.getInterceptorMethodHandler()); } @Override public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable { if (beanTypes.contains(thisMethod.getDeclaringClass())) { return super.invoke(self, thisMethod, proceed, args); } else { Method decoratedTypeMethod = getBeanTypeMethod(thisMethod); return super.invoke(self, decoratedTypeMethod, proceed, args); } } private Method getBeanTypeMethod(Method method) { for (Class<?> c : beanTypes) { try { return c.getMethod(method.getName(), method.getParameterTypes()); } catch (NoSuchMethodException e) { continue; } } return method; } } }