blob: 4a7a371b21113dac0c8c3352c6f5ae14f017ecf2 [file] [log] [blame]
/*
* 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;
import org.apache.openejb.assembler.classic.ProxyInterfaceResolver;
import org.apache.openejb.cdi.CdiEjbBean;
import org.apache.openejb.cdi.ConstructorInjectionBean;
import org.apache.openejb.cdi.CurrentCreationalContext;
import org.apache.openejb.cdi.OWBInjector;
import org.apache.openejb.core.ExceptionType;
import org.apache.openejb.core.InstanceContext;
import org.apache.openejb.core.Operation;
import org.apache.openejb.core.ThreadContext;
import org.apache.openejb.core.cmp.KeyGenerator;
import org.apache.openejb.core.interceptor.InterceptorData;
import org.apache.openejb.core.interceptor.InterceptorInstance;
import org.apache.openejb.core.interceptor.InterceptorStack;
import org.apache.openejb.core.ivm.EjbHomeProxyHandler;
import org.apache.openejb.core.timer.EjbTimerService;
import org.apache.openejb.core.transaction.EjbTransactionUtil;
import org.apache.openejb.core.transaction.TransactionPolicy;
import org.apache.openejb.core.transaction.TransactionPolicyFactory;
import org.apache.openejb.core.transaction.TransactionType;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.util.Duration;
import org.apache.openejb.util.Index;
import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.Logger;
import org.apache.openejb.util.proxy.DynamicProxyImplFactory;
import org.apache.openejb.util.proxy.QueryProxy;
import org.apache.webbeans.component.AbstractInjectionTargetBean;
import org.apache.webbeans.component.InjectionTargetBean;
import org.apache.webbeans.config.WebBeansContext;
import org.apache.webbeans.context.creational.CreationalContextImpl;
import org.apache.webbeans.inject.AbstractInjectable;
import org.apache.xbean.recipe.ConstructionException;
import javax.ejb.EJBHome;
import javax.ejb.EJBLocalHome;
import javax.ejb.EJBLocalObject;
import javax.ejb.EJBObject;
import javax.ejb.LockType;
import javax.ejb.MessageDrivenBean;
import javax.ejb.TimedObject;
import javax.ejb.Timer;
import javax.enterprise.context.spi.Contextual;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.naming.Context;
import javax.persistence.EntityManagerFactory;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.Future;
public class BeanContext extends DeploymentContext {
private Logger logger = Logger.getInstance(LogCategory.OPENEJB, BeanContext.class);
public static final String USER_INTERCEPTOR_KEY = "org.apache.openejb.default.system.interceptors";
public static final String USER_INTERCEPTOR_SEPARATOR = ",| |;";
public boolean isDynamicallyImplemented() {
return getBeanClass().equals(getLocalInterface());
}
public interface BusinessLocalHome extends javax.ejb.EJBLocalHome {
Object create();
}
public interface BusinessLocalBeanHome extends javax.ejb.EJBLocalHome {
Object create();
}
public interface BusinessRemoteHome extends javax.ejb.EJBHome {
Object create();
}
public interface Removable {
void $$remove();
}
public interface ServiceEndpoint {
}
public interface Timeout {
}
/**
* This ManagedBean is added to all EjbModules to effectively
* create a sharable "comp" namespace which can be used in
* for components with undefined namespace such as CDI
*/
public static class Comp {
public static String openejbCompName(String module) {
return module + "." + Comp.class.getSimpleName();
}
}
private final ModuleContext moduleContext;
private final Context jndiContext;
private Object containerData;
private boolean destroyed;
private Class homeInterface;
private Class remoteInterface;
private Class localHomeInterface;
private Class localInterface;
private Class beanClass;
private Class pkClass;
private final List<Class> businessLocals = new ArrayList<Class>();
private final List<Class> businessRemotes = new ArrayList<Class>();
private Class mdbInterface;
private Class serviceEndpointInterface;
private final List<Method> removeMethods = new ArrayList<Method>();
private final Set<String> dependsOn = new LinkedHashSet<String>();
private Method ejbTimeout;
private EjbTimerService ejbTimerService;
private boolean isBeanManagedTransaction;
private boolean isBeanManagedConcurrency;
private boolean isReentrant;
private Container container;
private EJBHome ejbHomeRef;
private EJBLocalHome ejbLocalHomeRef;
private String destinationId;
private String ejbName;
private String runAs;
private Method createMethod = null;
private final BeanType componentType;
private boolean hidden = false;
private final Map<Method, Method> postCreateMethodMap = new HashMap<Method, Method>();
private final Map<Method, TransactionType> methodTransactionType = new HashMap<Method, TransactionType>();
private final Map<Method, Method> methodMap = new HashMap<Method, Method>();
private final Map<Method, MethodContext> methodContextMap = new HashMap<Method, MethodContext>();
private final Map<String, ViewContext> viewContextMap = new HashMap<String, ViewContext>();
private Index<EntityManagerFactory,Map> extendedEntityManagerFactories;
private TransactionPolicyFactory transactionPolicyFactory;
private final List<InterceptorData> callbackInterceptors = new ArrayList<InterceptorData>();
private final Set<InterceptorData> instanceScopedInterceptors = new HashSet<InterceptorData>();
private final List<InterceptorInstance> systemInterceptors = new ArrayList<InterceptorInstance>();
private final List<InterceptorInstance> userInterceptors = new ArrayList<InterceptorInstance>();
private final Map<String, String> activationProperties = new HashMap<String, String>();
private final List<Injection> injections = new ArrayList<Injection>();
private final Map<Class, InterfaceType> interfaces = new HashMap<Class, InterfaceType>();
private final Map<Class, ExceptionType> exceptions = new HashMap<Class, ExceptionType>();
private boolean loadOnStartup;
private final boolean localbean;
private Duration accessTimeout;
private Duration statefulTimeout;
private Set<Class<?>> asynchronousClasses = new HashSet<Class<?>>();
private Set<String> asynchronousMethodSignatures = new HashSet<String>();
private Class<?> proxyClass;
public Class getInterface(InterfaceType interfaceType) {
switch(interfaceType){
case EJB_HOME: return getHomeInterface();
case EJB_OBJECT: return getRemoteInterface();
case EJB_LOCAL_HOME: return getLocalHomeInterface();
case EJB_LOCAL: return getLocalInterface();
case BUSINESS_LOCAL: return getBusinessLocalInterface();
case BUSINESS_REMOTE: return getBusinessRemoteInterface();
case TIMEOUT : return BeanContext.Timeout.class;
case BUSINESS_REMOTE_HOME: return BeanContext.BusinessRemoteHome.class;
case BUSINESS_LOCAL_HOME: return BeanContext.BusinessLocalHome.class;
case SERVICE_ENDPOINT: return getServiceEndpointInterface();
case LOCALBEAN: return getBeanClass();
case BUSINESS_LOCALBEAN_HOME: return BeanContext.BusinessLocalBeanHome.class;
default: throw new IllegalStateException("Unexpected enum constant: " + interfaceType);
}
}
public List<Class> getInterfaces(InterfaceType interfaceType) {
switch(interfaceType){
case BUSINESS_REMOTE: return getBusinessRemoteInterfaces();
case BUSINESS_LOCAL: return getBusinessLocalInterfaces();
default:
List<Class> interfaces = new ArrayList<Class>();
interfaces.add(getInterface(interfaceType));
return interfaces;
}
}
public InterfaceType getInterfaceType(Class clazz) {
InterfaceType type = interfaces.get(clazz);
if (type != null) return type;
if (javax.ejb.EJBLocalHome.class.isAssignableFrom(clazz)) return InterfaceType.EJB_LOCAL_HOME;
if (javax.ejb.EJBLocalObject.class.isAssignableFrom(clazz)) return InterfaceType.EJB_LOCAL;
if (javax.ejb.EJBHome.class.isAssignableFrom(clazz)) return InterfaceType.EJB_HOME;
if (javax.ejb.EJBObject.class.isAssignableFrom(clazz)) return InterfaceType.EJB_OBJECT;
return null;
}
/**
* load default interceptors configured in properties.
*/
private BeanContext(String id, Context jndiContext, ModuleContext moduleContext, BeanType componentType, boolean localBean) {
super(id, moduleContext.getOptions());
this.moduleContext = moduleContext;
this.jndiContext = jndiContext;
this.localbean = localBean;
this.componentType = componentType;
String interceptors = SystemInstance.get().getProperties().getProperty(USER_INTERCEPTOR_KEY);
if (interceptors != null) {
String[] interceptorArray = interceptors.split(USER_INTERCEPTOR_SEPARATOR);
ClassLoader classLoader = moduleContext.getClassLoader();
for (String interceptor : interceptorArray) {
if (interceptor != null && !interceptor.isEmpty()) {
Object interceptorObject;
try {
Class<?> clazz = classLoader.loadClass(interceptor);
interceptorObject = clazz.newInstance();
} catch (Exception e) {
logger.warning("interceptor " + interceptor + " not found, are you sure the container can load it?");
continue;
}
addUserInterceptor(interceptorObject);
}
}
}
}
public BeanContext(String id, Context jndiContext, ModuleContext moduleContext,
Class beanClass, Class homeInterface,
Class remoteInterface,
Class localHomeInterface,
Class localInterface,
Class proxy,
Class serviceEndpointInterface, List<Class> businessLocals, List<Class> businessRemotes, Class pkClass,
BeanType componentType,
boolean localBean) throws SystemException {
this(id, jndiContext, moduleContext, componentType, localBean);
if (beanClass == null) throw new NullPointerException("beanClass input parameter is null");
this.pkClass = pkClass;
proxyClass = proxy;
this.homeInterface = homeInterface;
this.remoteInterface = remoteInterface;
this.localInterface = localInterface;
this.localHomeInterface = localHomeInterface;
if (businessLocals != null){
this.businessLocals.addAll(businessLocals);
}
if (businessRemotes != null) {
this.businessRemotes.addAll(businessRemotes);
}
this.remoteInterface = remoteInterface;
this.beanClass = beanClass;
this.pkClass = pkClass;
this.serviceEndpointInterface = serviceEndpointInterface;
// if (businessLocal != null && localHomeInterface == null){
// this.localHomeInterface = BusinessLocalHome.class;
// }
//
// if (businessRemote != null && homeInterface == null){
// this.homeInterface = BusinessRemoteHome.class;
// }
// createMethodMap();
if (TimedObject.class.isAssignableFrom(beanClass)) {
try {
this.ejbTimeout = beanClass.getMethod("ejbTimeout", Timer.class);
} catch (NoSuchMethodException e) {
throw new IllegalStateException(e);
}
}
addInterface(getServiceEndpointInterface(), InterfaceType.SERVICE_ENDPOINT);
addInterface(javax.ejb.EJBHome.class, InterfaceType.EJB_HOME);
addInterface(javax.ejb.EJBObject.class, InterfaceType.EJB_OBJECT);
addInterface(javax.ejb.EJBLocalHome.class, InterfaceType.EJB_LOCAL_HOME);
addInterface(javax.ejb.EJBLocalObject.class, InterfaceType.EJB_LOCAL);
addInterface(getHomeInterface(), InterfaceType.EJB_HOME);
addInterface(getRemoteInterface(), InterfaceType.EJB_OBJECT);
addInterface(getLocalHomeInterface(), InterfaceType.EJB_LOCAL_HOME);
addInterface(getLocalInterface(), InterfaceType.EJB_LOCAL);
addInterface(BeanContext.BusinessRemoteHome.class, InterfaceType.BUSINESS_REMOTE_HOME);
for (Class businessRemote : this.businessRemotes) {
addInterface(businessRemote, InterfaceType.BUSINESS_REMOTE);
}
addInterface(BeanContext.BusinessLocalHome.class, InterfaceType.BUSINESS_LOCAL_HOME);
for (Class businessLocal : this.businessLocals) {
addInterface(businessLocal, InterfaceType.BUSINESS_LOCAL);
}
if (localBean) {
addInterface(beanClass, InterfaceType.LOCALBEAN);
}
}
/**
* DMB: This is a not so reliable way to determine the proxy type
* The proxy type really should come with the call in the invoke.
*
* @param interfce
* @param type
*/
private void addInterface(Class interfce, InterfaceType type){
if (interfce == null) return;
interfaces.put(interfce, type);
for (Class clazz : interfce.getInterfaces()) {
addInterface(clazz, type);
}
}
public void addApplicationException(Class exception, boolean rollback, boolean inherited) {
if (inherited) {
if (rollback) {
exceptions.put(exception, ExceptionType.APPLICATION_ROLLBACK);
} else {
exceptions.put(exception, ExceptionType.APPLICATION);
}
} else {
if (rollback) {
exceptions.put(exception, ExceptionType.APPLICATION_ROLLBACK_NOT_INHERITED);
} else {
exceptions.put(exception, ExceptionType.APPLICATION_NOT_INHERITED);
}
}
}
public ExceptionType getExceptionType(Throwable e) {
// Errors are always system exceptions
if (!(e instanceof Exception)) {
return ExceptionType.SYSTEM;
}
// check the registered app exceptions
Class<?> exceptionClass = e.getClass();
boolean inherited = false;
while (exceptionClass != Object.class) {
ExceptionType type = exceptions.get(exceptionClass);
if (type == ExceptionType.APPLICATION || type == ExceptionType.APPLICATION_ROLLBACK) {
return type;
}
if (type != null) {
if (inherited) {
return ExceptionType.SYSTEM;
}
if (type == ExceptionType.APPLICATION_NOT_INHERITED) {
return ExceptionType.APPLICATION;
}
return ExceptionType.APPLICATION_ROLLBACK;
}
exceptionClass = exceptionClass.getSuperclass();
inherited = true;
}
// Unregistered - runtime exceptions are system exception and the rest are application exceptions
if (e instanceof RuntimeException) {
return ExceptionType.SYSTEM;
} else {
return ExceptionType.APPLICATION;
}
}
public BeanContext(String id, Context jndiContext, ModuleContext moduleContext, Class beanClass, Class mdbInterface, Map<String, String> activationProperties) throws SystemException {
this(id, jndiContext, moduleContext, BeanType.MESSAGE_DRIVEN, false);
this.beanClass = beanClass;
this.mdbInterface = mdbInterface;
this.activationProperties.putAll(activationProperties);
if (TimedObject.class.isAssignableFrom(beanClass)) {
try {
this.ejbTimeout = beanClass.getMethod("ejbTimeout", Timer.class);
} catch (NoSuchMethodException e) {
throw new IllegalStateException(e);
}
}
createMethodMap();
}
public Object getContainerData() {
return containerData;
}
public void setContainerData(Object containerData) {
this.containerData = containerData;
}
public ClassLoader getClassLoader() {
return moduleContext.getClassLoader();
}
public Context getJndiContext() {
return jndiContext;
}
public ModuleContext getModuleContext() {
return moduleContext;
}
public boolean isDestroyed() {
return destroyed;
}
public void setDestroyed(boolean destroyed) {
this.destroyed = destroyed;
}
public List<Injection> getInjections() {
return injections;
}
public Index<EntityManagerFactory,Map> getExtendedEntityManagerFactories() {
return extendedEntityManagerFactories;
}
public void setExtendedEntityManagerFactories(Index<EntityManagerFactory, Map> extendedEntityManagerFactories) {
this.extendedEntityManagerFactories = extendedEntityManagerFactories;
}
public void setContainer(Container container) {
this.container = container;
}
public BeanType getComponentType() {
return componentType;
}
public LockType getConcurrencyAttribute(Method beanMethod) {
return getMethodContext(beanMethod).getLockType();
}
public LockType getLockType() {
return LockType.WRITE;
}
public TransactionType getTransactionType(Method method) {
return getTransactionType(method, null);
}
public TransactionType getTransactionType(Method method, InterfaceType interfaceType) {
MethodContext methodContext = null;
if (interfaceType != null) {
methodContext = getViewMethodContext(method, interfaceType.getSpecName());
}
if (methodContext == null) methodContext = methodContextMap.get(method);
if (methodContext == null) {
final Method beanMethod = getMatchingBeanMethod(method);
methodContext = getMethodContext(beanMethod);
}
return methodContext.getTransactionType();
//
// // Check the cache
// TransactionType type = methodTransactionType.get(method);
// if (type != null) {
// return type;
// }
//
// // Bean managed EJBs always get the BeanManaged policy
// if (isBeanManagedTransaction) {
// return TransactionType.BeanManaged;
// }
//
// // Check the matching bean method for the supplied method
// Method beanMethod = getMatchingBeanMethod(method);
// if (beanMethod != null){
// type = methodTransactionType.get(beanMethod);
// if (type != null) {
// return type;
// }
// }
//
// // All transaction attributes should have been set during deployment, so log a message
// Logger log = Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources");
// log.debug("The following method doesn't have a transaction policy assigned: " + method);
//
// // default transaction policy is required
// type = getTransactionType();
//
// // cache this default to avoid extra log messages
// methodTransactionType.put(method, type);
// return type;
}
public TransactionType getTransactionType() {
return (isBeanManagedTransaction) ? TransactionType.BeanManaged : TransactionType.Required;
}
public TransactionPolicyFactory getTransactionPolicyFactory() {
return transactionPolicyFactory;
}
public void setTransactionPolicyFactory(TransactionPolicyFactory transactionPolicyFactory) {
this.transactionPolicyFactory = transactionPolicyFactory;
}
public Container getContainer() {
return container;
}
public Object getDeploymentID() {
return getId();
}
public boolean isBeanManagedTransaction() {
return isBeanManagedTransaction;
}
public boolean isBeanManagedConcurrency() {
return isBeanManagedConcurrency;
}
public Class getHomeInterface() {
return homeInterface;
}
public Class getRemoteInterface() {
return remoteInterface;
}
public Class getLocalHomeInterface() {
return localHomeInterface;
}
public Class getLocalInterface() {
return localInterface;
}
public Class getBeanClass() {
return beanClass;
}
public Class getBusinessLocalInterface() {
return businessLocals.size() > 0 ? businessLocals.get(0) : null;
}
public Class getBusinessRemoteInterface() {
return businessRemotes.size() > 0 ? businessRemotes.get(0) : null;
}
public List<Class> getBusinessLocalInterfaces() {
return businessLocals;
}
public List<Class> getBusinessRemoteInterfaces() {
return businessRemotes;
}
public Class getMdbInterface() {
return mdbInterface;
}
public Class getServiceEndpointInterface() {
return serviceEndpointInterface;
}
public Map<String, String> getActivationProperties() {
return activationProperties;
}
public Class getPrimaryKeyClass() {
return pkClass;
}
public EJBHome getEJBHome() {
if (getHomeInterface() == null) {
throw new IllegalStateException("This component has no home interface: " + getDeploymentID());
}
if (ejbHomeRef == null) {
ejbHomeRef = (EJBHome) EjbHomeProxyHandler.createHomeProxy(this, InterfaceType.EJB_HOME);
}
return ejbHomeRef;
}
public EJBLocalHome getEJBLocalHome() {
if (getLocalHomeInterface() == null) {
throw new IllegalStateException("This component has no local home interface: " + getDeploymentID());
}
if (ejbLocalHomeRef == null) {
ejbLocalHomeRef = (EJBLocalHome) EjbHomeProxyHandler.createHomeProxy(this, InterfaceType.EJB_LOCAL_HOME);
}
return ejbLocalHomeRef;
}
//unused
public BusinessLocalHome getBusinessLocalHome() {
return getBusinessLocalHome(getBusinessLocalInterfaces(), null);
}
public BusinessLocalBeanHome getBusinessLocalBeanHome() {
List<Class> interfaces = new ArrayList<Class>();
interfaces.add(this.beanClass);
return (BusinessLocalBeanHome) EjbHomeProxyHandler.createHomeProxy(this, InterfaceType.BUSINESS_LOCALBEAN_HOME, interfaces, this.beanClass);
}
public BusinessLocalHome getBusinessLocalHome(Class mainInterface) {
List<Class> localInterfaces = this.getBusinessLocalInterfaces();
List<Class> interfaces = ProxyInterfaceResolver.getInterfaces(this.getBeanClass(), mainInterface, localInterfaces);
return this.getBusinessLocalHome(interfaces, mainInterface);
}
public BusinessLocalHome getBusinessLocalHome(List<Class> interfaces, Class mainInterface) {
if (getBusinessLocalInterfaces().size() == 0){
throw new IllegalStateException("This component has no business local interfaces: " + getDeploymentID());
}
if (interfaces.size() == 0){
throw new IllegalArgumentException("No interface classes were specified");
}
for (Class clazz : interfaces) {
if (!getBusinessLocalInterfaces().contains(clazz)){
throw new IllegalArgumentException("Not a business interface of this bean:" + clazz.getName());
}
}
return (BusinessLocalHome) EjbHomeProxyHandler.createHomeProxy(this, InterfaceType.BUSINESS_LOCAL_HOME, interfaces, mainInterface);
}
//unused
public BusinessRemoteHome getBusinessRemoteHome() {
return getBusinessRemoteHome(getBusinessRemoteInterfaces(), null);
}
public BusinessRemoteHome getBusinessRemoteHome(Class mainInterface) {
List<Class> remoteInterfaces = this.getBusinessRemoteInterfaces();
List<Class> interfaces = ProxyInterfaceResolver.getInterfaces(this.getBeanClass(), mainInterface, remoteInterfaces);
return this.getBusinessRemoteHome(interfaces, mainInterface);
}
public BusinessRemoteHome getBusinessRemoteHome(List<Class> interfaces, Class mainInterface) {
if (getBusinessRemoteInterfaces().size() == 0){
throw new IllegalStateException("This component has no business remote interfaces: " + getDeploymentID());
}
if (interfaces.size() == 0){
throw new IllegalArgumentException("No interface classes were specified");
}
for (Class clazz : interfaces) {
if (!getBusinessRemoteInterfaces().contains(clazz)){
throw new IllegalArgumentException("Not a business interface of this bean:" + clazz.getName());
}
}
return (BusinessRemoteHome) EjbHomeProxyHandler.createHomeProxy(this, InterfaceType.BUSINESS_REMOTE_HOME, interfaces, mainInterface);
}
public String getDestinationId() {
return destinationId;
}
public void setDestinationId(String destinationId) {
this.destinationId = destinationId;
}
public void setBeanManagedTransaction(boolean value) {
isBeanManagedTransaction = value;
}
public void setBeanManagedConcurrency(boolean beanManagedConcurrency) {
isBeanManagedConcurrency = beanManagedConcurrency;
}
public Context getJndiEnc() {
return jndiContext;
}
public boolean isReentrant() {
return isReentrant;
}
public void setIsReentrant(boolean reentrant) {
isReentrant = reentrant;
}
public Method getMatchingBeanMethod(Method interfaceMethod) {
Method method = methodMap.get(interfaceMethod);
return (method == null) ? interfaceMethod : method;
}
public MethodContext getMethodContext(Method method) {
MethodContext methodContext = methodContextMap.get(method);
if (methodContext == null) {
methodContext = new MethodContext(this, method);
methodContextMap.put(method, methodContext);
}
return methodContext;
}
// TODO The MethodContext object has Method as a variable, so we could change this
// to simply return methodContextMap.values() which would be cleaner
public Iterator<Entry<Method, MethodContext>> iteratorMethodContext() {
return methodContextMap.entrySet().iterator();
}
public void setMethodConcurrencyAttribute(Method method, LockType concurrencyAttribute) {
getMethodContext(method).setLockType(concurrencyAttribute);
}
/**
* TODO: Move to MethodContext
*/
public void setMethodTransactionAttribute(Method method, TransactionType transactionType) throws OpenEJBException {
setMethodTransactionAttribute(method, transactionType, null);
}
/**
* TODO: Move to MethodContext
*/
public void setMethodTransactionAttribute(Method method, TransactionType transactionType, String view) throws OpenEJBException {
// method = getMatchingBeanMethod(method);
if (view == null) {
getMethodContext(method).setTransactionType(transactionType);
} else {
initViewMethodContext(method, view).setTransactionType(transactionType);
}
return;
// // Only the NOT_SUPPORTED and REQUIRED transaction attributes may be used for message-driven
// // bean message listener methods. The use of the other transaction attributes is not meaningful
// // for message-driven bean message listener methods because there is no pre-existing client transaction
// // context(REQUIRES_NEW, SUPPORTS) and no client to handle exceptions (MANDATORY, NEVER).
// if (componentType.isMessageDriven() && !isBeanManagedTransaction) {
// if (transactionType != TransactionType.NotSupported && transactionType != TransactionType.Required) {
//
// if ((method.equals(this.ejbTimeout) || methodContextMap.get(method).isAsynchronous()) && transactionType == TransactionType.RequiresNew) {
// // do nothing. This is allowed as the timer callback method for a message driven bean
// // can also have a transaction policy of RequiresNew Sec 5.4.12 of Ejb 3.0 Core Spec
// } else {
// throw new OpenEJBException("The transaction attribute " + transactionType + " is not supported for the method "
// + method.getName() + " of the Message Driven Bean " + beanClass.getName());
// }
// }
// }
// methodTransactionType.put(method, transactionType);
}
public List<Method> getRemoveMethods() {
return removeMethods;
}
/**
* TODO: Move to MethodContext
*/
private final Map<Method, Boolean> removeExceptionPolicy = new HashMap<Method,Boolean>();
/**
* TODO: Move to MethodContext
*/
public void setRetainIfExeption(Method removeMethod, boolean retain){
if (getRemoveMethods().contains(removeMethod)){
removeExceptionPolicy.put(removeMethod, retain);
}
}
/**
* TODO: Move to MethodContext
*/
public boolean retainIfExeption(Method removeMethod){
Boolean retain = removeExceptionPolicy.get(removeMethod);
return retain != null && retain;
}
/**
* When an instance of an EJB is instantiated, everything in this list
* is also instatiated and tied to the bean instance. Per spec, interceptors
* are supposed to have the same lifecycle as the bean they wrap.
*
* OpenEJB has the concept of interceptors which do not share the same lifecycle
* as the bean instance -- they may be instantiated elsewhere and simply applied
* to the bean. The impact is that these interceptors must be multithreaded.
* It also means we do not add these interceptors to this list and expose them
* via different means.
*
* @return standard interceptors sharing the bean lifecycle
*/
public Set<InterceptorData> getInstanceScopedInterceptors() {
return instanceScopedInterceptors;
}
public void addSystemInterceptor(Object interceptor) {
systemInterceptors.add(new InterceptorInstance(interceptor));
}
public void addUserInterceptor(Object interceptor) {
userInterceptors.add(new InterceptorInstance(interceptor));
}
public List<InterceptorInstance> getUserAndSystemInterceptors() {
List<InterceptorInstance> interceptors = new ArrayList<InterceptorInstance>(systemInterceptors);
interceptors.addAll(userInterceptors);
return interceptors;
}
private final Set<InterceptorData> cdiInterceptors = new LinkedHashSet<InterceptorData>();
public List<InterceptorData> getCallbackInterceptors() {
List<InterceptorData> datas = getInterceptorData();
datas.addAll(callbackInterceptors);
datas.addAll(cdiInterceptors);
return datas;
}
public void setCallbackInterceptors(List<InterceptorData> callbackInterceptors) {
//TODO shouldn't we remove the old callbackInterceptors from instanceScopedInterceptors before adding the new ones?
this.callbackInterceptors.clear();
this.callbackInterceptors.addAll(callbackInterceptors);
this.instanceScopedInterceptors.addAll(callbackInterceptors);
}
public List<InterceptorData> getCdiInterceptors() {
return new ArrayList<InterceptorData>(cdiInterceptors);
}
public void setCdiInterceptors(List<InterceptorData> cdiInterceptors) {
this.cdiInterceptors.clear();
this.cdiInterceptors.addAll(cdiInterceptors);
this.instanceScopedInterceptors.addAll(cdiInterceptors);
}
public List<InterceptorData> getMethodInterceptors(Method method) {
return getMethodContext(method).getInterceptors();
}
public List<InterceptorData> getInterceptorData() {
List<InterceptorData> datas = new ArrayList<InterceptorData>();
for (InterceptorInstance instance : getUserAndSystemInterceptors()) {
datas.add(instance.getData());
}
return datas;
}
public void setMethodInterceptors(Method method, List<InterceptorData> interceptors) {
getMethodContext(method).setInterceptors(interceptors);
this.instanceScopedInterceptors.addAll(interceptors);
}
public void createMethodMap() throws org.apache.openejb.SystemException {
if (remoteInterface != null) {
mapObjectInterface(remoteInterface);
mapHomeInterface(homeInterface);
}
if (localInterface != null) {
mapObjectInterface(localInterface);
}
if (localHomeInterface != null) {
mapHomeInterface(localHomeInterface);
}
if (serviceEndpointInterface != null) {
mapObjectInterface(serviceEndpointInterface);
}
for (Class businessLocal : businessLocals) {
mapObjectInterface(businessLocal);
}
for (Class businessRemote : businessRemotes) {
mapObjectInterface(businessRemote);
}
if (componentType == BeanType.MESSAGE_DRIVEN && MessageDrivenBean.class.isAssignableFrom(beanClass)) {
try {
createMethod = beanClass.getMethod("ejbCreate");
} catch (NoSuchMethodException e) {
// if there isn't an ejbCreate method that is fine
}
}
try {
// map the remove methods
if (componentType == BeanType.STATEFUL || componentType == BeanType.MANAGED) {
Method beanMethod = null;
if (javax.ejb.SessionBean.class.isAssignableFrom(beanClass)) {
beanMethod = javax.ejb.SessionBean.class.getDeclaredMethod("ejbRemove");
} else {
for (Method method : getRemoveMethods()) {
if (method.getParameterTypes().length == 0){
beanMethod = method;
break;
}
}
if (beanMethod == null && (homeInterface != null || localHomeInterface != null)){
throw new IllegalStateException("Bean class has no @Remove methods to match EJBObject.remove() or EJBLocalObject.remove(). A no-arg remove method must be added: beanClass="+beanClass.getName());
}
}
Method clientMethod = EJBHome.class.getDeclaredMethod("remove", javax.ejb.Handle.class);
mapMethods(clientMethod, beanMethod);
clientMethod = EJBHome.class.getDeclaredMethod("remove", java.lang.Object.class);
mapMethods(clientMethod, beanMethod);
clientMethod = javax.ejb.EJBObject.class.getDeclaredMethod("remove");
mapMethods(clientMethod, beanMethod);
clientMethod = javax.ejb.EJBLocalObject.class.getDeclaredMethod("remove");
mapMethods(clientMethod, beanMethod);
} else if (componentType == BeanType.BMP_ENTITY || componentType == BeanType.CMP_ENTITY) {
Method beanMethod = javax.ejb.EntityBean.class.getDeclaredMethod("ejbRemove");
Method clientMethod = EJBHome.class.getDeclaredMethod("remove", javax.ejb.Handle.class);
mapMethods(clientMethod, beanMethod);
clientMethod = EJBHome.class.getDeclaredMethod("remove", java.lang.Object.class);
mapMethods(clientMethod, beanMethod);
clientMethod = javax.ejb.EJBObject.class.getDeclaredMethod("remove");
mapMethods(clientMethod, beanMethod);
clientMethod = javax.ejb.EJBLocalObject.class.getDeclaredMethod("remove");
mapMethods(clientMethod, beanMethod);
}
} catch (java.lang.NoSuchMethodException nsme) {
throw new org.apache.openejb.SystemException(nsme);
}
if (mdbInterface != null) {
mapObjectInterface(mdbInterface);
}
}
private void mapHomeInterface(Class intrface) {
Method [] homeMethods = intrface.getMethods();
for (Method method : homeMethods) {
Class owner = method.getDeclaringClass();
if (owner == EJBHome.class || owner == EJBLocalHome.class) {
continue;
}
try {
Method beanMethod = null;
if (method.getName().startsWith("create")) {
StringBuilder ejbCreateName = new StringBuilder(method.getName());
ejbCreateName.replace(0, 1, "ejbC");
beanMethod = beanClass.getMethod(ejbCreateName.toString(), method.getParameterTypes());
createMethod = beanMethod;
/*
Entity beans have a ejbCreate and ejbPostCreate methods with matching
parameters. This code maps that relationship.
*/
if (this.componentType == BeanType.BMP_ENTITY || this.componentType == BeanType.CMP_ENTITY) {
ejbCreateName.insert(3, "Post");
Class clazz = beanClass;
if (cmpImplClass != null) clazz = cmpImplClass;
Method postCreateMethod = clazz.getMethod(ejbCreateName.toString(), method.getParameterTypes());
postCreateMethodMap.put(createMethod, postCreateMethod);
}
/*
* Stateless session beans only have one create method. The getCreateMethod is
* used by instance manager of the core.stateless.StatelessContainer as a convenience
* method for obtaining the ejbCreate method.
*/
} else if (method.getName().startsWith("find")) {
if (this.componentType == BeanType.BMP_ENTITY) {
String beanMethodName = "ejbF" + method.getName().substring(1);
beanMethod = beanClass.getMethod(beanMethodName, method.getParameterTypes());
}
} else {
String beanMethodName = "ejbHome" + method.getName().substring(0, 1).toUpperCase() + method.getName().substring(1);
beanMethod = beanClass.getMethod(beanMethodName, method.getParameterTypes());
}
if (beanMethod != null) {
mapMethods(method, beanMethod);
}
} catch (NoSuchMethodException nsme) {
// throw new RuntimeException("Invalid method [" + method + "] Not declared by " + beanClass.getName() + " class");
}
}
}
public void mapMethods(Method interfaceMethod, Method beanMethod){
methodMap.put(interfaceMethod, beanMethod);
}
private void mapObjectInterface(Class intrface) {
if (intrface == BusinessLocalHome.class || intrface == BusinessRemoteHome.class || intrface == ServiceEndpoint.class){
return;
}
Method [] interfaceMethods = intrface.getMethods();
for (Method method : interfaceMethods) {
Class declaringClass = method.getDeclaringClass();
if (declaringClass == EJBObject.class || declaringClass == EJBLocalObject.class) {
continue;
}
try {
Method beanMethod = beanClass.getMethod(method.getName(), method.getParameterTypes());
mapMethods(method, beanMethod);
} catch (NoSuchMethodException nsme) {
throw new RuntimeException("Invalid method [" + method + "]. Not declared by " + beanClass.getName() + " class");
}
}
}
public List<Class> getObjectInterface(Class homeInterface){
if (BusinessLocalHome.class.isAssignableFrom(homeInterface)){
return getBusinessLocalInterfaces();
} else if (BusinessRemoteHome.class.isAssignableFrom(homeInterface)){
return getBusinessRemoteInterfaces();
} else if (EJBLocalHome.class.isAssignableFrom(homeInterface)){
List<Class> classes = new ArrayList<Class>();
classes.add(getLocalInterface());
return classes;
} else if (EJBHome.class.isAssignableFrom(homeInterface)){
List<Class> classes = new ArrayList<Class>();
classes.add(getRemoteInterface());
return classes;
} else {
throw new IllegalArgumentException("Cannot determine object interface for "+homeInterface);
}
}
public Method getCreateMethod() {
return createMethod;
}
public Method getMatchingPostCreateMethod(Method createMethod) {
return this.postCreateMethodMap.get(createMethod);
}
public boolean isAsynchronous(Method method) {
Method matchingBeanMethod = getMatchingBeanMethod(method);
Class<?> returnType = matchingBeanMethod.getReturnType();
if (returnType != void.class && returnType != Future.class) {
return false;
}
if (asynchronousClasses.contains(matchingBeanMethod.getDeclaringClass())) {
return true;
}
MethodContext methodContext = methodContextMap.get(matchingBeanMethod);
return methodContext == null ? false : methodContext.isAsynchronous();
}
//
// CMP specific data
//
private boolean cmp2;
private KeyGenerator keyGenerator;
private String primaryKeyField;
private Class cmpImplClass;
private String abstractSchemaName;
private Set<String> remoteQueryResults = new TreeSet<String>();
public boolean isCmp2() {
return cmp2;
}
public void setCmp2(boolean cmp2) {
this.cmp2 = cmp2;
}
public String getPrimaryKeyField() {
return primaryKeyField;
}
public void setPrimaryKeyField(String primaryKeyField) {
this.primaryKeyField = primaryKeyField;
}
public KeyGenerator getKeyGenerator() {
return keyGenerator;
}
public void setKeyGenerator(KeyGenerator keyGenerator) {
this.keyGenerator = keyGenerator;
}
public void setRemoteQueryResults(String methodSignature) {
remoteQueryResults.add(methodSignature);
}
public boolean isRemoteQueryResults(String methodSignature) {
return remoteQueryResults.contains(methodSignature);
}
public Class getCmpImplClass() {
return cmpImplClass;
}
public void setCmpImplClass(Class cmpImplClass) {
this.cmpImplClass = cmpImplClass;
}
public String getAbstractSchemaName() {
return abstractSchemaName;
}
public void setAbstractSchemaName(String abstractSchemaName) {
this.abstractSchemaName = abstractSchemaName;
}
public Method getEjbTimeout() {
return ejbTimeout;
}
public void setEjbTimeout(Method ejbTimeout) {
this.ejbTimeout = ejbTimeout;
}
public EjbTimerService getEjbTimerService() {
return ejbTimerService;
}
public void setEjbTimerService(EjbTimerService ejbTimerService) {
this.ejbTimerService = ejbTimerService;
}
public String getEjbName() {
return ejbName;
}
public String getModuleID() {
return getModuleContext().getModuleURI().toString();
}
public String getModuleName() {
return getModuleContext().getId();
}
public String getRunAs() {
return runAs;
}
public void setEjbName(String ejbName) {
this.ejbName = ejbName;
}
public void setRunAs(String runAs) {
this.runAs = runAs;
}
public String toString() {
return "BeanContext(id="+getDeploymentID()+")";
}
public boolean isLoadOnStartup() {
return loadOnStartup;
}
public void setLoadOnStartup(boolean loadOnStartup) {
this.loadOnStartup = loadOnStartup;
}
public Set<String> getDependsOn() {
return dependsOn;
}
public boolean isSessionSynchronized() {
return !isBeanManagedTransaction();
}
public boolean isLocalbean() {
return localbean;
}
public Class getBusinessLocalBeanInterface() {
if (this.isLocalbean()) {
return this.beanClass;
}
return null;
}
public Duration getAccessTimeout(Method beanMethod) {
return getMethodContext(beanMethod).getAccessTimeout();
}
public Duration getAccessTimeout() {
return accessTimeout;
}
public void setAccessTimeout(Duration accessTimeout) {
this.accessTimeout = accessTimeout;
}
public Duration getStatefulTimeout() {
return statefulTimeout;
}
public void setStatefulTimeout(Duration statefulTimeout) {
this.statefulTimeout = statefulTimeout;
}
public Class<Object> getManagedClass() {
if (isDynamicallyImplemented()) {
return (Class<Object>) getProxyClass();
}
return beanClass;
}
public InstanceContext newInstance() throws Exception {
ThreadContext callContext = new ThreadContext(this, null, Operation.INJECTION);
ThreadContext oldContext = ThreadContext.enter(callContext);
WebBeansContext webBeansContext = null;
AbstractInjectionTargetBean<Object> beanDefinition = null;
webBeansContext = getModuleContext().getAppContext().getWebBeansContext();
beanDefinition = get(CdiEjbBean.class);
if (isDynamicallyImplemented()) {
if (!InvocationHandler.class.isAssignableFrom(getProxyClass())) {
throw new OpenEJBException("proxy class can only be InvocationHandler");
}
}
ConstructorInjectionBean<Object> beanConstructor = new ConstructorInjectionBean<Object>(webBeansContext, getManagedClass());
if (beanDefinition == null) {
beanDefinition = beanConstructor;
}
try {
final Context ctx = this.getJndiEnc();
final Class beanClass = this.getBeanClass();
CurrentCreationalContext<Object> currentCreationalContext = get(CurrentCreationalContext.class);
CreationalContext<Object> creationalContext = (currentCreationalContext != null) ? currentCreationalContext.get() : null;
if (creationalContext == null) {
creationalContext = webBeansContext.getBeanManagerImpl().createCreationalContext(beanDefinition);
}
// Create bean instance
final Object beanInstance;
final InjectionProcessor injectionProcessor = new InjectionProcessor(beanConstructor.create(creationalContext), this.getInjections(), InjectionProcessor.unwrap(ctx));
if (!isDynamicallyImplemented()) {
beanInstance = injectionProcessor.createInstance();
inject(beanInstance, creationalContext);
} else {
InvocationHandler handler = (InvocationHandler) injectionProcessor.createInstance();
beanInstance = DynamicProxyImplFactory.newProxy(this, handler);
inject(handler, creationalContext);
}
// Create interceptors
final HashMap<String, Object> interceptorInstances = new HashMap<String, Object>();
// Add the stats interceptor instance and other already created interceptor instances
for (InterceptorInstance interceptorInstance : this.getUserAndSystemInterceptors()) {
final Class clazz = interceptorInstance.getData().getInterceptorClass();
interceptorInstances.put(clazz.getName(), interceptorInstance.getInterceptor());
}
for (InterceptorData interceptorData : this.getInstanceScopedInterceptors()) {
if (interceptorData.getInterceptorClass().equals(beanClass)) {
continue;
}
final Class clazz = interceptorData.getInterceptorClass();
final ConstructorInjectionBean interceptorConstructor = new ConstructorInjectionBean(webBeansContext, clazz);
final InjectionProcessor interceptorInjector = new InjectionProcessor(interceptorConstructor.create(creationalContext), this.getInjections(), org.apache.openejb.InjectionProcessor.unwrap(ctx));
try {
final Object interceptorInstance = interceptorInjector.createInstance();
// TODO we likely don't want to create a new one each time -- investigate the destroy() method
try {
OWBInjector interceptorCdiInjector = new OWBInjector(webBeansContext);
interceptorCdiInjector.inject(interceptorInstance, creationalContext);
} catch (Throwable t) {
// TODO handle this differently
// this is temporary till the injector can be rewritten
}
interceptorInstances.put(clazz.getName(), interceptorInstance);
} catch (ConstructionException e) {
throw new Exception("Failed to create interceptor: " + clazz.getName(), e);
}
}
interceptorInstances.put(beanClass.getName(), beanInstance);
// Invoke post construct method
callContext.setCurrentOperation(Operation.POST_CONSTRUCT);
final List<InterceptorData> callbackInterceptors = this.getCallbackInterceptors();
final InterceptorStack postConstruct = new InterceptorStack(beanInstance, null, Operation.POST_CONSTRUCT, callbackInterceptors, interceptorInstances);
//Transaction Demarcation for Singleton PostConstruct method
TransactionType transactionType;
if (getComponentType() == BeanType.SINGLETON) {
Set<Method> callbacks = callbackInterceptors.get(callbackInterceptors.size() -1).getPostConstruct();
if (callbacks.isEmpty()) {
transactionType = TransactionType.RequiresNew;
} else {
transactionType = getTransactionType(callbacks.iterator().next());
if (transactionType == TransactionType.Required) {
transactionType = TransactionType.RequiresNew;
}
}
} else {
transactionType = isBeanManagedTransaction()? TransactionType.BeanManaged: TransactionType.NotSupported;
}
TransactionPolicy transactionPolicy = EjbTransactionUtil.createTransactionPolicy(transactionType, callContext);
try{
//Call the chain
postConstruct.invoke();
} catch(Throwable e) {
//RollBack Transaction
EjbTransactionUtil.handleSystemException(transactionPolicy, e, callContext);
}
finally{
EjbTransactionUtil.afterInvoke(transactionPolicy, callContext);
}
return new InstanceContext(this, beanInstance, interceptorInstances, creationalContext);
} finally {
ThreadContext.exit(oldContext);
}
}
protected <X> X getBean(Class<X> clazz, Bean<?> bean) {
return clazz.cast(bean);
}
public <T> void inject(T instance, CreationalContext<T> ctx) {
WebBeansContext webBeansContext = getModuleContext().getAppContext().getWebBeansContext();
AbstractInjectionTargetBean<Object> beanDefinition = get(CdiEjbBean.class);
final ConstructorInjectionBean<Object> beanConstructor = new ConstructorInjectionBean<Object>(webBeansContext, getManagedClass());
if (beanDefinition == null) {
beanDefinition = beanConstructor;
}
if (!(ctx instanceof CreationalContextImpl)) {
ctx = webBeansContext.getCreationalContextFactory().wrappedCreationalContext(ctx, beanDefinition);
}
Object oldInstanceUnderInjection = AbstractInjectable.instanceUnderInjection.get();
boolean isInjectionToAnotherBean = false;
try {
Contextual<?> contextual = null;
if (ctx instanceof CreationalContextImpl) {
contextual = ((CreationalContextImpl) ctx).getBean();
isInjectionToAnotherBean = contextual == getBean(InjectionTargetBean.class, beanDefinition) ? false : true;
}
if (!isInjectionToAnotherBean) {
AbstractInjectable.instanceUnderInjection.set(instance);
}
InjectionTargetBean<T> bean = getBean(InjectionTargetBean.class, beanDefinition);
bean.injectResources(instance, ctx);
bean.injectSuperFields(instance, ctx);
bean.injectSuperMethods(instance, ctx);
bean.injectFields(instance, ctx);
bean.injectMethods(instance, ctx);
} finally {
if (oldInstanceUnderInjection != null) {
AbstractInjectable.instanceUnderInjection.set(oldInstanceUnderInjection);
} else {
AbstractInjectable.instanceUnderInjection.set(null);
AbstractInjectable.instanceUnderInjection.remove();
}
}
}
public Set<Class<?>> getAsynchronousClasses() {
return asynchronousClasses;
}
public Set<String> getAsynchronousMethodSignatures() {
return asynchronousMethodSignatures;
}
public void createAsynchronousMethodSet(){
for(Map.Entry<Method, MethodContext> entry : methodContextMap.entrySet()) {
if(entry.getValue().isAsynchronous()) {
asynchronousMethodSignatures.add(generateMethodSignature(entry.getKey()));
}
}
for(Class<?> cls : asynchronousClasses) {
for(Method method : cls.getDeclaredMethods()) {
if(Modifier.isPublic(method.getModifiers())) {
asynchronousMethodSignatures.add(generateMethodSignature(method));
}
}
}
}
private String generateMethodSignature(Method method) {
StringBuilder buffer = new StringBuilder(method.getName());
for(Class<?> parameterType : method.getParameterTypes()) {
buffer.append(parameterType.getName());
}
return buffer.toString();
}
private MethodContext getViewMethodContext(Method method, String view) {
ViewContext viewContext = this.viewContextMap.get(view);
return (viewContext == null) ? null : viewContext.getMethodContext(method);
}
private MethodContext initViewMethodContext(Method method, String view) {
ViewContext viewContext = this.viewContextMap.get(view);
if (viewContext == null) {
viewContext = new ViewContext();
viewContextMap.put(view, viewContext);
}
return viewContext.initMethodContext(method);
}
public Class<?> getProxyClass() {
if (isDynamicallyImplemented() && proxyClass == null) {
return QueryProxy.class;
}
return proxyClass;
}
public class ViewContext {
private final Map<Method, MethodContext> methodContextMap = new HashMap<Method, MethodContext>();
public MethodContext getMethodContext(Method method) {
return methodContextMap.get(method);
}
public MethodContext initMethodContext(Method method) {
MethodContext methodContext = methodContextMap.get(method);
if (methodContext != null) return methodContext;
methodContext = new MethodContext(BeanContext.this, method);
methodContextMap.put(method, methodContext);
return methodContext;
}
}
public boolean isHidden() {
return hidden;
}
public void setHidden(boolean hidden) {
this.hidden = hidden;
}
}