org.apache.openejb.cdi.CdiEjbBean Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.openejb.cdi;
import org.apache.openejb.BeanContext;
import org.apache.openejb.BeanType;
import org.apache.openejb.OpenEJBRuntimeException;
import org.apache.openejb.assembler.classic.ProxyInterfaceResolver;
import org.apache.openejb.core.ivm.BaseEjbProxyHandler;
import org.apache.openejb.util.proxy.LocalBeanProxyFactory;
import org.apache.openejb.util.proxy.ProxyManager;
import org.apache.webbeans.component.BeanAttributesImpl;
import org.apache.webbeans.component.InterceptedMarker;
import org.apache.webbeans.component.creation.BeanAttributesBuilder;
import org.apache.webbeans.config.WebBeansContext;
import org.apache.webbeans.container.InjectionTargetFactoryImpl;
import org.apache.webbeans.context.creational.CreationalContextImpl;
import org.apache.webbeans.ejb.common.component.BaseEjbBean;
import org.apache.webbeans.portable.InjectionTargetImpl;
import javax.ejb.NoSuchEJBException;
import javax.ejb.Remove;
import javax.enterprise.context.Dependent;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.Typed;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.enterprise.inject.spi.InjectionTarget;
import javax.enterprise.inject.spi.SessionBeanType;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.UndeclaredThrowableException;
import java.rmi.NoSuchObjectException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
public class CdiEjbBean extends BaseEjbBean implements InterceptedMarker {
private final Map dependentSFSBToBeRemoved = new ConcurrentHashMap();
private final BeanContext beanContext;
private final boolean isDependentAndStateful;
// initialized a bit later in the lifecycle but could be final otherwise
private BeanContext.BusinessLocalBeanHome homeLocalBean;
private BeanContext.BusinessLocalHome home;
public CdiEjbBean(final BeanContext beanContext, final WebBeansContext webBeansContext, final AnnotatedType at) {
this(beanContext, webBeansContext, beanContext.getManagedClass(), at, new EjbInjectionTargetFactory(at, webBeansContext));
EjbInjectionTargetImpl.class.cast(getInjectionTarget()).setCdiEjbBean(this);
}
public CdiEjbBean(final BeanContext beanContext, final WebBeansContext webBeansContext, final Class beanClass, final AnnotatedType at, final InjectionTargetFactoryImpl factory) {
super(webBeansContext, toSessionType(beanContext.getComponentType()), at, new EJBBeanAttributesImpl(beanContext,
BeanAttributesBuilder.forContext(webBeansContext).newBeanAttibutes(at).build()), beanClass, factory);
this.beanContext = beanContext;
beanContext.set(Bean.class, this);
passivatingId = beanContext.getDeploymentID() + getReturnType().getName();
isDependentAndStateful = getScope().equals(Dependent.class) && BeanType.STATEFUL.equals(beanContext.getComponentType());
}
public BeanContext getBeanContext() {
return this.beanContext;
}
private static SessionBeanType toSessionType(final BeanType beanType) {
switch (beanType) {
case SINGLETON:
return SessionBeanType.SINGLETON;
case MESSAGE_DRIVEN: // OWB implementation test stateful or not so do we really care?
case STATELESS:
case MANAGED: // can't be stateful since it will prevent every integration using ManagedBean to get injections to work + it is never used
return SessionBeanType.STATELESS;
case STATEFUL:
return SessionBeanType.STATEFUL;
default:
throw new IllegalStateException("Unknown Session BeanType " + beanType);
}
}
public String getEjbName() {
return this.beanContext.getEjbName();
}
public boolean needsBeanLocalViewAddedToTypes() {
return beanContext.isLocalbean() && beanContext.getBeanClass().getAnnotation(Typed.class) == null;
}
@Override
public List> getBusinessLocalInterfaces() {
final List> classes = new ArrayList>();
for (final Type t : getTypes()) {
if (Class.class.isInstance(t)) {
classes.add(Class.class.cast(t));
}
}
return classes;
}
public void destroyComponentInstance(final T instance) {
if (getScope() == null || Dependent.class == getScope()) {
destroyStatefulSessionBeanInstance(instance, null);
} else {
destroyScopedStateful(instance, null);
}
}
@Override
protected void destroyStatefulSessionBeanInstance(final T proxyInstance, final Object unused) {
if (proxyInstance instanceof BeanContext.Removable) {
try {
((BeanContext.Removable) proxyInstance).$$remove();
} catch (final NoSuchEJBException nsee) {
// no-op
} catch (final UndeclaredThrowableException nsoe) {
if (!(nsoe.getCause() instanceof NoSuchObjectException)) {
throw nsoe;
}
} catch (final Exception e) {
if (!(e instanceof NoSuchObjectException)) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
}
throw new OpenEJBRuntimeException(e);
}
}
}
}
@Override
public List getRemoveMethods() {
// Should we delegate to super and merge both?
if (beanContext.isLocalbean()) {
return findRemove(beanContext.getBeanClass(), beanContext.getBeanClass());
}
return findRemove(beanContext.getBeanClass(), beanContext.getBusinessLocalInterface());
}
private List findRemove(final Class> beanClass, final Class> beanInterface) {
final List toReturn = new ArrayList();
// Get all the public methods of the bean class and super class
final Method[] methods = beanClass.getMethods();
// Search for methods annotated with @Remove
for (final Method method : methods) {
final Remove annotation = method.getAnnotation(Remove.class);
if (annotation != null) {
// Get the corresponding method into the bean interface
final Method interfaceMethod;
try {
interfaceMethod = beanInterface.getMethod(method.getName(), method.getParameterTypes());
toReturn.add(interfaceMethod);
} catch (final SecurityException e) {
e.printStackTrace();
} catch (final NoSuchMethodException e) {
// The method can not be into the interface in which case we
// don't wonder of
}
}
}
return toReturn;
}
protected T createEjb(final CreationalContext creationalContext) {
final CurrentCreationalContext currentCreationalContext = beanContext.get(CurrentCreationalContext.class);
final CreationalContext existing = currentCreationalContext.get();
currentCreationalContext.set(creationalContext);
try {
final T instance;
if (homeLocalBean != null) {
instance = (T) homeLocalBean.create();
} else {
instance = (T) home.create();
}
if (isDependentAndStateful) {
CreationalContextImpl.class.cast(creationalContext).addDependent(this, instance);
}
return instance;
} finally {
currentCreationalContext.set(existing);
}
}
private void destroyScopedStateful(final T instance, final CreationalContext cc) {
try {
instance.hashCode(); // force the instance to be created - otherwise we'll miss @PreDestroy for instance
} catch (final NoSuchEJBException e) {
InvocationHandler handler = null;
if (LocalBeanProxyFactory.isProxy(instance.getClass())) {
handler = LocalBeanProxyFactory.getInvocationHandler(instance);
} else if (ProxyManager.isProxyClass(instance.getClass())) {
handler = ProxyManager.getInvocationHandler(instance);
}
if (BaseEjbProxyHandler.class.isInstance(handler) && !BaseEjbProxyHandler.class.cast(handler).isValid()) {
return; // already destroyed
} // else log error
logger.log(Level.FINE, "The stateful instance " + instance + " can't be removed since it was invalidated", e);
return;
}
final Object ejbInstance = dependentSFSBToBeRemoved.remove(System.identityHashCode(instance));
if (ejbInstance != null) {
destroyStatefulSessionBeanInstance((T) ejbInstance, cc);
} else {
destroyStatefulSessionBeanInstance(instance, cc);
}
}
public void storeStatefulInstance(final Object proxy, final T instance) {
dependentSFSBToBeRemoved.put(System.identityHashCode(proxy), instance);
}
public void initInternals() {
final List classes = beanContext.getBusinessLocalInterfaces();
final boolean noLocalInterface = classes.isEmpty();
if (noLocalInterface && beanContext.isLocalbean()) {
homeLocalBean = beanContext.getBusinessLocalBeanHome();
home = null;
} else if (!noLocalInterface) {
final Class> mainInterface = classes.get(0);
final List interfaces = ProxyInterfaceResolver.getInterfaces(beanContext.getBeanClass(), mainInterface, classes);
home = beanContext.getBusinessLocalHome(interfaces, mainInterface);
homeLocalBean = null;
} // else remote
}
private static class EJBBeanAttributesImpl extends BeanAttributesImpl {
private final BeanContext beanContext;
private final Set ejbTypes;
public EJBBeanAttributesImpl(final BeanContext bc, final BeanAttributesImpl beanAttributes) {
super(beanAttributes, false);
this.beanContext = bc;
this.ejbTypes = new HashSet();
initTypes();
}
@Override
public Set getTypes() {
return ejbTypes;
}
public void initTypes() {
if (beanContext.isLocalbean()) {
addApiTypes(ejbTypes, beanContext.getBeanClass());
}
if (beanContext.getProxyClass() != null) {
addApiTypes(ejbTypes, beanContext.getProxyClass());
}
final List cl = beanContext.getBusinessLocalInterfaces();
if (cl != null && !cl.isEmpty()) {
for (final Class> c : cl) {
ejbTypes.add(c);
}
}
if (!ejbTypes.contains(Serializable.class)) {
ejbTypes.add(Serializable.class);
}
ejbTypes.add(Object.class);
}
private static void addApiTypes(final Collection clazzes, final Class> beanClass) {
final Typed typed = beanClass.getAnnotation(Typed.class);
if (typed == null || typed.value().length == 0) {
Class> current = beanClass;
while (current != null && !Object.class.equals(current)) {
clazzes.add(current);
current = current.getSuperclass();
}
} else {
Collections.addAll(clazzes, typed.value());
}
}
}
public static class EjbInjectionTargetFactory extends InjectionTargetFactoryImpl {
public EjbInjectionTargetFactory(final AnnotatedType annotatedType, final WebBeansContext webBeansContext) {
super(annotatedType, webBeansContext);
}
@Override
public InjectionTarget createInjectionTarget(final Bean bean) {
final EjbInjectionTargetImpl injectionTarget = new EjbInjectionTargetImpl(getAnnotatedType(), createInjectionPoints(bean), getWebBeansContext());
final InjectionTarget it = getWebBeansContext().getWebBeansUtil().fireProcessInjectionTargetEvent(injectionTarget, getAnnotatedType()).getInjectionTarget();
if (!EjbInjectionTargetImpl.class.isInstance(it)) {
return new EjbInjectionTargetImpl(injectionTarget, it);
}
return it;
}
protected Set createInjectionPoints(final Bean bean) {
final Set injectionPoints = new HashSet();
for (final InjectionPoint injectionPoint : getWebBeansContext().getInjectionPointFactory().buildInjectionPoints(bean, getAnnotatedType())) {
injectionPoints.add(injectionPoint);
}
return injectionPoints;
}
protected List> getPostConstructMethods() {
return Collections.emptyList();
}
protected List> getPreDestroyMethods() {
return Collections.emptyList();
}
}
public static class EjbInjectionTargetImpl extends InjectionTargetImpl {
private CdiEjbBean bean;
private InjectionTarget delegate;
public EjbInjectionTargetImpl(final AnnotatedType annotatedType, final Set points, final WebBeansContext webBeansContext) {
super(annotatedType, points, webBeansContext,
Collections.>emptyList(), Collections.>emptyList());
}
public EjbInjectionTargetImpl(final EjbInjectionTargetImpl original, final InjectionTarget delegate) {
super(original.annotatedType, original.getInjectionPoints(), original.webBeansContext, Collections.>emptyList(), Collections.>emptyList());
this.delegate = delegate;
}
public void setCdiEjbBean(final CdiEjbBean bean) {
this.bean = bean;
}
@Override
public T produce(final CreationalContext creationalContext) {
if (delegate == null) {
return bean.createEjb(creationalContext);
}
return delegate.produce(creationalContext);
}
@Override
public void dispose(final T instance) {
if (delegate == null) {
bean.destroyComponentInstance(instance);
} else {
delegate.dispose(instance);
}
}
@Override
public Set getInjectionPoints() {
if (delegate == null) {
return super.getInjectionPoints();
}
return delegate.getInjectionPoints();
}
@Override
public void inject(final T instance, final CreationalContext ctx) {
if (delegate == null) {
super.inject(instance, ctx);
} else {
delegate.inject(instance, ctx);
}
}
@Override
public void postConstruct(final T instance) {
if (delegate == null) {
super.postConstruct(instance);
} else {
delegate.postConstruct(instance);
}
}
@Override
public void preDestroy(final T instance) {
if (delegate == null) {
super.preDestroy(instance);
} else {
delegate.preDestroy(instance);
}
}
public T createNewPojo(final CreationalContext creationalContext) {
return (T) super.newInstance(CreationalContextImpl.class.cast(creationalContext));
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy