blob: 69fb1d495023c7c74a56eba9703c82dc5c9563c8 [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.core.cmp;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.rmi.NoSuchObjectException;
import java.rmi.RemoteException;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.ejb.EJBContext;
import javax.ejb.EJBException;
import javax.ejb.EJBHome;
import javax.ejb.EJBLocalHome;
import javax.ejb.EJBLocalObject;
import javax.ejb.EJBObject;
import javax.ejb.EntityBean;
import javax.ejb.ObjectNotFoundException;
import javax.ejb.RemoveException;
import javax.ejb.Timer;
import javax.ejb.FinderException;
import javax.ejb.EJBAccessException;
import javax.transaction.TransactionManager;
import javax.transaction.TransactionSynchronizationRegistry;
import javax.transaction.Synchronization;
import org.apache.openejb.ApplicationException;
import org.apache.openejb.BeanContext;
import org.apache.openejb.OpenEJBException;
import org.apache.openejb.ProxyInfo;
import org.apache.openejb.RpcContainer;
import org.apache.openejb.ContainerType;
import org.apache.openejb.InterfaceType;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.core.Operation;
import org.apache.openejb.core.ThreadContext;
import org.apache.openejb.core.ExceptionType;
import org.apache.openejb.core.timer.EjbTimerService;
import org.apache.openejb.core.timer.EjbTimerServiceImpl;
import org.apache.openejb.core.entity.EntityContext;
import org.apache.openejb.core.entity.EntrancyTracker;
import org.apache.openejb.core.transaction.TransactionPolicy;
import static org.apache.openejb.core.transaction.EjbTransactionUtil.handleApplicationException;
import static org.apache.openejb.core.transaction.EjbTransactionUtil.handleSystemException;
import static org.apache.openejb.core.transaction.EjbTransactionUtil.afterInvoke;
import static org.apache.openejb.core.transaction.EjbTransactionUtil.createTransactionPolicy;
import org.apache.openejb.spi.SecurityService;
import org.apache.openejb.util.Enumerator;
/**
* @org.apache.xbean.XBean element="cmpContainer"
*/
public class CmpContainer implements RpcContainer {
protected final Object containerID;
protected final SecurityService securityService;
/**
* Index used for getDeployments() and getDeploymentInfo(deploymentId).
*/
protected final Map<Object, BeanContext> deploymentsById = new HashMap<Object, BeanContext>();
/**
* When events are fired from the CMP engine only an entity bean instance is returned. The type of the bean is used
* to find the deployment info. This means that when the same type is used multiple ejb deployments a random deployment
* will be selected to handle the ejb callback.
*/
protected final Map<Class, BeanContext> beansByClass = new HashMap<Class, BeanContext>();
/**
* The CmpEngine which performs the actual persistence operations
*/
protected final CmpEngine cmpEngine;
/**
* Tracks entity instances that have been "entered" so we can throw reentrancy exceptions.
*/
protected EntrancyTracker entrancyTracker;
protected TransactionSynchronizationRegistry synchronizationRegistry;
private static final Object ENTITIES_TO_STORE = new Object() {
public String toString() {
return "EntitiesToStore";
}
};
public CmpContainer(Object id, TransactionManager transactionManager, SecurityService securityService, String cmpEngineFactory) throws OpenEJBException {
this.containerID = id;
this.securityService = securityService;
synchronizationRegistry = SystemInstance.get().getComponent(TransactionSynchronizationRegistry.class);
entrancyTracker = new EntrancyTracker(synchronizationRegistry);
// create the cmp engine instance
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) classLoader = getClass().getClassLoader();
CmpEngineFactory factory;
try {
Class<?> cmpEngineFactoryClass = classLoader.loadClass(cmpEngineFactory);
factory = (CmpEngineFactory) cmpEngineFactoryClass.newInstance();
} catch (Exception e) {
throw new OpenEJBException("Unable to create cmp engine factory " + cmpEngineFactory, e);
}
factory.setTransactionManager(transactionManager);
factory.setTransactionSynchronizationRegistry(synchronizationRegistry);
factory.setCmpCallback(new ContainerCmpCallback());
cmpEngine = factory.create();
}
public Object getContainerID() {
return containerID;
}
public ContainerType getContainerType() {
return ContainerType.CMP_ENTITY;
}
public synchronized BeanContext[] getBeanContexts() {
return deploymentsById.values().toArray(new BeanContext[deploymentsById.size()]);
}
public synchronized BeanContext getBeanContext(Object deploymentID) {
return deploymentsById.get(deploymentID);
}
private BeanContext getBeanContextByClass(Class type) {
BeanContext beanContext = null;
while (type != null && beanContext == null) {
beanContext = beansByClass.get(type);
type = type.getSuperclass();
}
return beanContext;
}
public void deploy(BeanContext beanContext) throws OpenEJBException {
synchronized (this) {
Object deploymentId = beanContext.getDeploymentID();
cmpEngine.deploy(beanContext);
beanContext.setContainerData(cmpEngine);
beanContext.set(EJBContext.class, new EntityContext(securityService));
// try to set deploymentInfo static field on bean implementation class
try {
Field field = beanContext.getCmpImplClass().getField("deploymentInfo");
field.set(null, beanContext);
} catch (Exception e) {
// ignore
}
// add to indexes
deploymentsById.put(deploymentId, beanContext);
beansByClass.put(beanContext.getCmpImplClass(), beanContext);
beanContext.setContainer(this);
}
EjbTimerService timerService = beanContext.getEjbTimerService();
if (timerService != null) {
timerService.start();
}
}
public void start(BeanContext beanContext) throws OpenEJBException {
}
public void stop(BeanContext beanContext) throws OpenEJBException {
}
public void undeploy(BeanContext beanContext) throws OpenEJBException {
EjbTimerService timerService = beanContext.getEjbTimerService();
if (timerService != null) {
timerService.stop();
}
synchronized (this) {
deploymentsById.remove(beanContext.getDeploymentID());
beansByClass.remove(beanContext.getCmpImplClass());
try {
Field field = beanContext.getCmpImplClass().getField("deploymentInfo");
field.set(null, null);
} catch (Exception e) {
// ignore
}
beanContext.setContainer(null);
beanContext.setContainerData(null);
}
}
public Object getEjbInstance(BeanContext beanContext, Object primaryKey) {
ThreadContext callContext = new ThreadContext(beanContext, primaryKey);
ThreadContext oldCallContext = ThreadContext.enter(callContext);
try {
Object bean = cmpEngine.loadBean(callContext, primaryKey);
return bean;
} finally {
ThreadContext.exit(oldCallContext);
}
}
/**
* @deprecated use invoke signature without 'securityIdentity' argument.
*/
public Object invoke(Object deployID, Method callMethod, Object[] args, Object primKey, Object securityIdentity) throws OpenEJBException {
return invoke(deployID, null, callMethod.getDeclaringClass(), callMethod, args, primKey);
}
public Object invoke(Object deployID, Class callInterface, Method callMethod, Object[] args, Object primKey) throws OpenEJBException {
return invoke(deployID, null, callInterface, callMethod, args, primKey);
}
public Object invoke(Object deployID, InterfaceType type, Class callInterface, Method callMethod, Object[] args, Object primKey) throws OpenEJBException {
BeanContext beanContext = this.getBeanContext(deployID);
if (beanContext == null) throw new OpenEJBException("Deployment does not exist in this container. Deployment(id='"+deployID+"'), Container(id='"+containerID+"')");
// Use the backup way to determine call type if null was supplied.
if (type == null) type = beanContext.getInterfaceType(callInterface);
ThreadContext callContext = new ThreadContext(beanContext, primKey);
ThreadContext oldCallContext = ThreadContext.enter(callContext);
try {
boolean authorized = securityService.isCallerAuthorized(callMethod, type);
if (!authorized) {
throw new ApplicationException(new EJBAccessException("Unauthorized Access by Principal Denied"));
}
Class declaringClass = callMethod.getDeclaringClass();
String methodName = callMethod.getName();
if (EJBHome.class.isAssignableFrom(declaringClass) || EJBLocalHome.class.isAssignableFrom(declaringClass)) {
if (declaringClass != EJBHome.class && declaringClass != EJBLocalHome.class) {
if (methodName.startsWith("create")) {
return createEJBObject(callMethod, args, callContext, type);
} else if (methodName.equals("findByPrimaryKey")) {
return findByPrimaryKey(callMethod, args, callContext, type);
} else if (methodName.startsWith("find")) {
return findEJBObject(callMethod, args, callContext, type);
} else {
return homeMethod(callMethod, args, callContext, type);
}
} else if (methodName.equals("remove")) {
removeEJBObject(callMethod, callContext, type);
return null;
}
} else if ((EJBObject.class == declaringClass || EJBLocalObject.class == declaringClass) && methodName.equals("remove")) {
removeEJBObject(callMethod, callContext, type);
return null;
}
// business method
callContext.setCurrentOperation(Operation.BUSINESS);
Method runMethod = beanContext.getMatchingBeanMethod(callMethod);
callContext.set(Method.class, runMethod);
Object retValue = businessMethod(callMethod, runMethod, args, callContext, type);
return retValue;
} finally {
ThreadContext.exit(oldCallContext);
}
}
private EntityBean createNewInstance(ThreadContext callContext) {
BeanContext beanContext = callContext.getBeanContext();
try {
EntityBean bean = (EntityBean) beanContext.getCmpImplClass().newInstance();
return bean;
} catch (Exception e) {
throw new EJBException("Unable to create new entity bean instance " + beanContext.getCmpImplClass(), e);
}
}
private ThreadContext createThreadContext(EntityBean entityBean) {
if (entityBean == null) throw new NullPointerException("entityBean is null");
BeanContext beanContext = getBeanContextByClass(entityBean.getClass());
KeyGenerator keyGenerator = beanContext.getKeyGenerator();
Object primaryKey = keyGenerator.getPrimaryKey(entityBean);
ThreadContext callContext = new ThreadContext(beanContext, primaryKey);
return callContext;
}
private void setEntityContext(EntityBean entityBean) {
if (entityBean == null) throw new NullPointerException("entityBean is null");
// activating entity doen't have a primary key
BeanContext beanContext = getBeanContextByClass(entityBean.getClass());
ThreadContext callContext = new ThreadContext(beanContext, null);
callContext.setCurrentOperation(Operation.SET_CONTEXT);
ThreadContext oldCallContext = ThreadContext.enter(callContext);
try {
entityBean.setEntityContext(new EntityContext(securityService));
} catch (RemoteException e) {
throw new EJBException(e);
} finally {
ThreadContext.exit(oldCallContext);
}
}
private void unsetEntityContext(EntityBean entityBean) {
if (entityBean == null) throw new NullPointerException("entityBean is null");
ThreadContext callContext = createThreadContext(entityBean);
callContext.setCurrentOperation(Operation.UNSET_CONTEXT);
ThreadContext oldCallContext = ThreadContext.enter(callContext);
try {
entityBean.unsetEntityContext();
} catch (RemoteException e) {
throw new EJBException(e);
} finally {
ThreadContext.exit(oldCallContext);
}
}
private void ejbLoad(EntityBean entityBean) {
if (entityBean == null) throw new NullPointerException("entityBean is null");
ThreadContext callContext = createThreadContext(entityBean);
callContext.setCurrentOperation(Operation.LOAD);
ThreadContext oldCallContext = ThreadContext.enter(callContext);
try {
entityBean.ejbLoad();
} catch (RemoteException e) {
throw new EJBException(e);
} finally {
ThreadContext.exit(oldCallContext);
}
// if we call load we must call store
try {
//noinspection unchecked
Set<EntityBean> registeredEntities = (LinkedHashSet<EntityBean>) synchronizationRegistry.getResource(ENTITIES_TO_STORE);
if (registeredEntities == null) {
registeredEntities = new LinkedHashSet<EntityBean>();
synchronizationRegistry.putResource(ENTITIES_TO_STORE, registeredEntities);
synchronizationRegistry.registerInterposedSynchronization(new Synchronization() {
public void beforeCompletion() {
//noinspection unchecked
Set<EntityBean> registeredEntities = (LinkedHashSet<EntityBean>) synchronizationRegistry.getResource(ENTITIES_TO_STORE);
if (registeredEntities == null) {
return;
}
for (EntityBean entityBean : registeredEntities) {
ejbStore(entityBean);
}
}
public void afterCompletion(int i) {
}
});
}
registeredEntities.add(entityBean);
} catch (Exception e) {
}
}
private void ejbStore(EntityBean entityBean) {
if (entityBean == null) throw new NullPointerException("entityBean is null");
ThreadContext callContext = createThreadContext(entityBean);
callContext.setCurrentOperation(Operation.STORE);
ThreadContext oldCallContext = ThreadContext.enter(callContext);
try {
entityBean.ejbStore();
} catch (RemoteException e) {
throw new EJBException(e);
} finally {
ThreadContext.exit(oldCallContext);
}
}
private void ejbRemove(EntityBean entityBean) throws RemoveException {
if (entityBean == null) throw new NullPointerException("entityBean is null");
if (isDeleted(entityBean)) return;
ThreadContext callContext = createThreadContext(entityBean);
callContext.setCurrentOperation(Operation.REMOVE);
ThreadContext oldCallContext = ThreadContext.enter(callContext);
try {
entityBean.ejbRemove();
} catch (RemoteException e) {
throw new EJBException(e);
} finally {
// clear relationships
// todo replace with interface call when CmpEntityBean interface is added
try {
entityBean.getClass().getMethod("OpenEJB_deleted").invoke(entityBean);
} catch (Exception ignored) {
}
cancelTimers(callContext);
ThreadContext.exit(oldCallContext);
}
}
private boolean isDeleted(EntityBean entityBean) {
try {
return (Boolean)entityBean.getClass().getMethod("OpenEJB_isDeleted").invoke(entityBean);
} catch (NoSuchMethodException e) {
return false;
} catch (Exception e) {
throw new EJBException(e);
}
}
private void ejbActivate(EntityBean entityBean) {
if (entityBean == null) throw new NullPointerException("entityBean is null");
ThreadContext callContext = createThreadContext(entityBean);
callContext.setCurrentOperation(Operation.ACTIVATE);
ThreadContext oldCallContext = ThreadContext.enter(callContext);
try {
entityBean.ejbActivate();
} catch (RemoteException e) {
throw new EJBException(e);
} finally {
ThreadContext.exit(oldCallContext);
}
}
private void ejbPassivate(EntityBean entityBean) {
if (entityBean == null) throw new NullPointerException("entityBean is null");
ThreadContext callContext = createThreadContext(entityBean);
callContext.setCurrentOperation(Operation.PASSIVATE);
ThreadContext oldCallContext = ThreadContext.enter(callContext);
try {
entityBean.ejbPassivate();
} catch (RemoteException e) {
throw new EJBException(e);
} finally {
ThreadContext.exit(oldCallContext);
}
}
private Object businessMethod(Method callMethod, Method runMethod, Object[] args, ThreadContext callContext, InterfaceType interfaceType) throws OpenEJBException {
BeanContext beanContext = callContext.getBeanContext();
TransactionPolicy txPolicy = createTransactionPolicy(beanContext.getTransactionType(callMethod, interfaceType), callContext);
EntityBean bean;
Object returnValue = null;
entrancyTracker.enter(beanContext, callContext.getPrimaryKey());
try {
bean = (EntityBean) cmpEngine.loadBean(callContext, callContext.getPrimaryKey());
if (bean == null) {
throw new NoSuchObjectException(beanContext.getDeploymentID() + " : " + callContext.getPrimaryKey());
}
returnValue = runMethod.invoke(bean, args);
// when there is not transaction, merge the data from the bean back into the cmp engine
cmpEngine.storeBeanIfNoTx(callContext, bean);
} catch (NoSuchObjectException e) {
handleApplicationException(txPolicy, e, false);
} catch (Throwable e) {
if (e instanceof InvocationTargetException) {
e = ((InvocationTargetException) e).getTargetException();
}
ExceptionType type = callContext.getBeanContext().getExceptionType(e);
if (type == ExceptionType.SYSTEM) {
/* System Exception ****************************/
handleSystemException(txPolicy, e, callContext);
} else {
/* Application Exception ***********************/
handleApplicationException(txPolicy, e, type == ExceptionType.APPLICATION_ROLLBACK);
}
} finally {
entrancyTracker.exit(beanContext, callContext.getPrimaryKey());
afterInvoke(txPolicy, callContext);
}
return returnValue;
}
private Object homeMethod(Method callMethod, Object[] args, ThreadContext callContext, InterfaceType interfaceType) throws OpenEJBException {
BeanContext beanContext = callContext.getBeanContext();
TransactionPolicy txPolicy = createTransactionPolicy(beanContext.getTransactionType(callMethod, interfaceType), callContext);
EntityBean bean;
Object returnValue = null;
try {
/*
Obtain a bean instance from the method ready pool
*/
bean = createNewInstance(callContext);
// set the entity context
setEntityContext(bean);
try {
callContext.setCurrentOperation(Operation.HOME);
Method runMethod = beanContext.getMatchingBeanMethod(callMethod);
try {
returnValue = runMethod.invoke(bean, args);
} catch (IllegalArgumentException e) {
System.out.println("********************************************************");
System.out.println("callMethod = " + callMethod);
System.out.println("runMethod = " + runMethod);
System.out.println("bean = " + bean.getClass().getName());
throw e;
}
} finally {
unsetEntityContext(bean);
}
} catch (Throwable e) {
if (e instanceof InvocationTargetException) {
e = ((InvocationTargetException) e).getTargetException();
}
ExceptionType type = callContext.getBeanContext().getExceptionType(e);
if (type == ExceptionType.SYSTEM) {
/* System Exception ****************************/
handleSystemException(txPolicy, e, callContext);
} else {
/* Application Exception ***********************/
handleApplicationException(txPolicy, e, type == ExceptionType.APPLICATION_ROLLBACK);
}
} finally {
afterInvoke(txPolicy, callContext);
}
return returnValue;
}
private ProxyInfo createEJBObject(Method callMethod, Object[] args, ThreadContext callContext, InterfaceType interfaceType) throws OpenEJBException {
BeanContext beanContext = callContext.getBeanContext();
TransactionPolicy txPolicy = createTransactionPolicy(beanContext.getTransactionType(callMethod, interfaceType), callContext);
EntityBean bean;
Object primaryKey = null;
try {
// Obtain a bean instance from the method ready pool
bean = createNewInstance(callContext);
// set the entity context
setEntityContext(bean);
// Obtain the proper ejbCreate() method
Method ejbCreateMethod = beanContext.getMatchingBeanMethod(callMethod);
// Set current operation for allowed operations
callContext.setCurrentOperation(Operation.CREATE);
// Invoke the proper ejbCreate() method on the instance
ejbCreateMethod.invoke(bean, args);
// create the new bean
primaryKey = cmpEngine.createBean(bean, callContext);
// determine post create callback method
Method ejbPostCreateMethod = beanContext.getMatchingPostCreateMethod(ejbCreateMethod);
// create a new context containing the pk for the post create call
ThreadContext postCreateContext = new ThreadContext(beanContext, primaryKey);
postCreateContext.setCurrentOperation(Operation.POST_CREATE);
ThreadContext oldContext = ThreadContext.enter(postCreateContext);
try {
// Invoke the ejbPostCreate method on the bean instance
ejbPostCreateMethod.invoke(bean, args);
// According to section 9.1.5.1 of the EJB 1.1 specification, the "ejbPostCreate(...)
// method executes in the same transaction context as the previous ejbCreate(...) method."
//
// The bean is first insterted using db.create( ) and then after ejbPostCreate( ) its
// updated using db.update(). This protocol allows for visablity of the bean after ejbCreate
// within the current trasnaction.
} finally {
ThreadContext.exit(oldContext);
}
// when there is not transaction, merge the data from the bean back into the cmp engine
cmpEngine.storeBeanIfNoTx(callContext, bean);
} catch (Throwable e) {
if (e instanceof InvocationTargetException) {
e = ((InvocationTargetException) e).getTargetException();
}
ExceptionType type = callContext.getBeanContext().getExceptionType(e);
if (type == ExceptionType.SYSTEM) {
/* System Exception ****************************/
handleSystemException(txPolicy, e, callContext);
} else {
/* Application Exception ***********************/
handleApplicationException(txPolicy, e, type == ExceptionType.APPLICATION_ROLLBACK);
}
} finally {
afterInvoke(txPolicy, callContext);
}
return new ProxyInfo(beanContext, primaryKey);
}
private Object findByPrimaryKey(Method callMethod, Object[] args, ThreadContext callContext, InterfaceType interfaceType) throws OpenEJBException {
BeanContext beanContext = callContext.getBeanContext();
TransactionPolicy txPolicy = createTransactionPolicy(beanContext.getTransactionType(callMethod, interfaceType), callContext);
try {
EntityBean bean = (EntityBean) cmpEngine.loadBean(callContext, args[0]);
if (bean == null) {
throw new ObjectNotFoundException(beanContext.getDeploymentID() + " : " + args[0]);
}
// rebuild the primary key
KeyGenerator kg = beanContext.getKeyGenerator();
Object primaryKey = kg.getPrimaryKey(bean);
// create a new ProxyInfo based on the deployment info and primary key
return new ProxyInfo(beanContext, primaryKey);
} catch (javax.ejb.FinderException fe) {
handleApplicationException(txPolicy, fe, false);
} catch (Throwable e) {// handle reflection exception
handleSystemException(txPolicy, e, callContext);
} finally {
afterInvoke(txPolicy, callContext);
}
throw new AssertionError("Should not get here");
}
private Object findEJBObject(Method callMethod, Object[] args, ThreadContext callContext, InterfaceType interfaceType) throws OpenEJBException {
BeanContext beanContext = callContext.getBeanContext();
TransactionPolicy txPolicy = createTransactionPolicy(beanContext.getTransactionType(callMethod, interfaceType), callContext);
try {
List<Object> results = cmpEngine.queryBeans(callContext, callMethod, args);
KeyGenerator kg = beanContext.getKeyGenerator();
// The following block of code is responsible for returning ProxyInfo object(s) for each
// matching entity bean found by the query. If its a multi-value find operation a Vector
// of ProxyInfo objects will be returned. If its a single-value find operation then a
// single ProxyInfo object is returned.
if (callMethod.getReturnType() == Collection.class || callMethod.getReturnType() == Enumeration.class) {
List<ProxyInfo> proxies = new ArrayList<ProxyInfo>();
for (Object value : results) {
EntityBean bean = (EntityBean) value;
if (value == null) {
proxies.add(null);
} else {
// get the primary key
Object primaryKey = kg.getPrimaryKey(bean);
// create a new ProxyInfo based on the deployment info and primary key and add it to the vector
proxies.add(new ProxyInfo(beanContext, primaryKey));
}
}
if (callMethod.getReturnType() == Enumeration.class) {
return new Enumerator(proxies);
} else {
return proxies;
}
} else {
if (results.size() != 1) {
throw new ObjectNotFoundException("A Enteprise bean with deployment_id = " + beanContext.getDeploymentID() + " and primarykey = " + args[0] + " Does not exist");
}
// create a new ProxyInfo based on the deployment info and primary key
EntityBean bean = (EntityBean) results.get(0);
if (bean == null) {
return null;
} else {
Object primaryKey = kg.getPrimaryKey(bean);
return new ProxyInfo(beanContext, primaryKey);
}
}
} catch (javax.ejb.FinderException fe) {
handleApplicationException(txPolicy, fe, false);
} catch (Throwable e) {// handle reflection exception
handleSystemException(txPolicy, e, callContext);
} finally {
afterInvoke(txPolicy, callContext);
}
throw new AssertionError("Should not get here");
}
public Object select(BeanContext beanContext, String methodSignature, String returnType, Object... args) throws FinderException {
String signature = beanContext.getAbstractSchemaName() + "." + methodSignature;
try {
// execute the select query
Collection<Object> results = cmpEngine.queryBeans(beanContext, signature, args);
//
// process the results
//
// If we need to return a set...
Collection<Object> proxies;
if (returnType.equals("java.util.Set")) {
// we collect values into a LinkedHashSet to preserve ordering
proxies = new LinkedHashSet<Object>();
} else {
// otherwise use a simple array list
proxies = new ArrayList<Object>();
}
boolean isSingleValued = !returnType.equals("java.util.Collection") && !returnType.equals("java.util.Set");
ProxyFactory proxyFactory = null;
for (Object value : results) {
// if this is a single valued query and we already have results, throw FinderException
if (isSingleValued && !proxies.isEmpty()) {
throw new FinderException("The single valued query " + methodSignature + "returned more than one item");
}
// if we have an EntityBean, we need to proxy it
if (value instanceof EntityBean) {
EntityBean entityBean = (EntityBean) value;
if (proxyFactory == null) {
BeanContext result = getBeanContextByClass(entityBean.getClass());
if (result != null) {
proxyFactory = new ProxyFactory(result);
}
}
if (proxyFactory != null) {
if (beanContext.isRemoteQueryResults(methodSignature)) {
value = proxyFactory.createRemoteProxy(entityBean, this);
} else {
value = proxyFactory.createLocalProxy(entityBean, this);
}
}
}
proxies.add(value);
}
// if not single valued, return the set
if (!isSingleValued) {
return proxies;
}
// single valued query that returned no rows, is an exception
if (proxies.isEmpty()) {
throw new ObjectNotFoundException();
}
// return the single item.... multiple return values was handled in for loop above
Object returnValue = proxies.iterator().next();
return returnValue;
} catch (RuntimeException e) {
throw new EJBException(e);
}
}
public int update(BeanContext beanContext, String methodSignature, Object... args) throws FinderException {
String signature = beanContext.getAbstractSchemaName() + "." + methodSignature;
// exectue the update query
int result = cmpEngine.executeUpdateQuery(beanContext, signature, args);
return result;
}
private void removeEJBObject(Method callMethod, ThreadContext callContext, InterfaceType interfaceType) throws OpenEJBException {
BeanContext beanContext = callContext.getBeanContext();
TransactionPolicy txPolicy = createTransactionPolicy(beanContext.getTransactionType(callMethod, interfaceType), callContext);
try {
EntityBean entityBean = (EntityBean) cmpEngine.loadBean(callContext, callContext.getPrimaryKey());
if (entityBean == null) {
throw new NoSuchObjectException(callContext.getBeanContext().getDeploymentID() + " " + callContext.getPrimaryKey());
}
ejbRemove(entityBean);
cmpEngine.removeBean(callContext);
} catch (NoSuchObjectException e) {
handleApplicationException(txPolicy, e, false);
} catch (Throwable e) {// handle reflection exception
handleSystemException(txPolicy, e, callContext);
} finally {
afterInvoke(txPolicy, callContext);
}
}
private void cancelTimers(ThreadContext threadContext) {
BeanContext beanContext = threadContext.getBeanContext();
Object primaryKey = threadContext.getPrimaryKey();
// stop timers
if (primaryKey != null && beanContext.getEjbTimerService() != null) {
EjbTimerService timerService = beanContext.getEjbTimerService();
if (timerService != null && timerService instanceof EjbTimerServiceImpl) {
for (Timer timer : beanContext.getEjbTimerService().getTimers(primaryKey)) {
timer.cancel();
}
}
}
}
private class ContainerCmpCallback implements CmpCallback {
public void setEntityContext(EntityBean entity) {
CmpContainer.this.setEntityContext(entity);
}
public void unsetEntityContext(EntityBean entity) {
CmpContainer.this.unsetEntityContext(entity);
}
public void ejbActivate(EntityBean entity) {
CmpContainer.this.ejbActivate(entity);
}
public void ejbPassivate(EntityBean entity) {
CmpContainer.this.ejbPassivate(entity);
}
public void ejbLoad(EntityBean entity) {
CmpContainer.this.ejbLoad(entity);
}
public void ejbStore(EntityBean entity) {
CmpContainer.this.ejbStore(entity);
}
public void ejbRemove(EntityBean entity) throws RemoveException {
CmpContainer.this.ejbRemove(entity);
}
}
}