0001: /**
0002: *
0003: * Licensed to the Apache Software Foundation (ASF) under one or more
0004: * contributor license agreements. See the NOTICE file distributed with
0005: * this work for additional information regarding copyright ownership.
0006: * The ASF licenses this file to You under the Apache License, Version 2.0
0007: * (the "License"); you may not use this file except in compliance with
0008: * the License. You may obtain a copy of the License at
0009: *
0010: * http://www.apache.org/licenses/LICENSE-2.0
0011: *
0012: * Unless required by applicable law or agreed to in writing, software
0013: * distributed under the License is distributed on an "AS IS" BASIS,
0014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0015: * See the License for the specific language governing permissions and
0016: * limitations under the License.
0017: */package org.apache.openejb.core.cmp;
0018:
0019: import java.lang.reflect.Field;
0020: import java.lang.reflect.InvocationTargetException;
0021: import java.lang.reflect.Method;
0022: import java.rmi.NoSuchObjectException;
0023: import java.rmi.RemoteException;
0024: import java.util.Collection;
0025: import java.util.Enumeration;
0026: import java.util.HashMap;
0027: import java.util.List;
0028: import java.util.Map;
0029: import java.util.ArrayList;
0030: import java.util.LinkedHashSet;
0031: import java.util.Set;
0032: import javax.ejb.CreateException;
0033: import javax.ejb.EJBException;
0034: import javax.ejb.EJBHome;
0035: import javax.ejb.EJBLocalHome;
0036: import javax.ejb.EJBLocalObject;
0037: import javax.ejb.EJBObject;
0038: import javax.ejb.EntityBean;
0039: import javax.ejb.ObjectNotFoundException;
0040: import javax.ejb.RemoveException;
0041: import javax.ejb.Timer;
0042: import javax.ejb.FinderException;
0043: import javax.ejb.EJBAccessException;
0044: import javax.transaction.TransactionManager;
0045: import javax.transaction.TransactionSynchronizationRegistry;
0046: import javax.transaction.Synchronization;
0047:
0048: import org.apache.openejb.ApplicationException;
0049: import org.apache.openejb.DeploymentInfo;
0050: import org.apache.openejb.OpenEJBException;
0051: import org.apache.openejb.ProxyInfo;
0052: import org.apache.openejb.RpcContainer;
0053: import org.apache.openejb.ContainerType;
0054: import org.apache.openejb.loader.SystemInstance;
0055: import org.apache.openejb.core.CoreDeploymentInfo;
0056: import org.apache.openejb.core.Operation;
0057: import org.apache.openejb.core.ThreadContext;
0058: import org.apache.openejb.core.ExceptionType;
0059: import org.apache.openejb.core.timer.EjbTimerService;
0060: import org.apache.openejb.core.timer.EjbTimerServiceImpl;
0061: import org.apache.openejb.core.entity.EntityContext;
0062: import org.apache.openejb.core.entity.EntrancyTracker;
0063: import org.apache.openejb.core.transaction.TransactionContainer;
0064: import org.apache.openejb.core.transaction.TransactionContext;
0065: import org.apache.openejb.core.transaction.TransactionPolicy;
0066: import org.apache.openejb.spi.SecurityService;
0067: import org.apache.openejb.util.Enumerator;
0068:
0069: /**
0070: * @org.apache.xbean.XBean element="cmpContainer"
0071: */
0072: public class CmpContainer implements RpcContainer, TransactionContainer {
0073: protected final Object containerID;
0074: protected final TransactionManager transactionManager;
0075: protected final SecurityService securityService;
0076:
0077: /**
0078: * Index used for getDeployments() and getDeploymentInfo(deploymentId).
0079: */
0080: protected final Map<Object, DeploymentInfo> deploymentsById = new HashMap<Object, DeploymentInfo>();
0081:
0082: /**
0083: * When events are fired from the CMP engine only an entity bean instance is returned. The type of the bean is used
0084: * to find the deployment info. This means that when the same type is used multiple ejb deployments a random deployment
0085: * will be selected to handle the ejb callback.
0086: */
0087: protected final Map<Class, DeploymentInfo> deploymentsByClass = new HashMap<Class, DeploymentInfo>();
0088:
0089: /**
0090: * The CmpEngine which performs the actual persistence operations
0091: */
0092: protected final CmpEngine cmpEngine;
0093:
0094: /**
0095: * Tracks entity instances that have been "entered" so we can throw reentrancy exceptions.
0096: */
0097: protected EntrancyTracker entrancyTracker;
0098: protected TransactionSynchronizationRegistry synchronizationRegistry;
0099: private static final Object ENTITIES_TO_STORE = new Object() {
0100: public String toString() {
0101: return "EntitiesToStore";
0102: }
0103: };
0104:
0105: public CmpContainer(Object id,
0106: TransactionManager transactionManager,
0107: SecurityService securityService, String cmpEngineFactory,
0108: String engine, String connectorName)
0109: throws OpenEJBException {
0110: this .transactionManager = transactionManager;
0111: this .securityService = securityService;
0112: this .containerID = id;
0113: synchronizationRegistry = SystemInstance.get().getComponent(
0114: TransactionSynchronizationRegistry.class);
0115: entrancyTracker = new EntrancyTracker(synchronizationRegistry);
0116:
0117: // create the cmp engine instance
0118: ClassLoader classLoader = Thread.currentThread()
0119: .getContextClassLoader();
0120: if (classLoader == null)
0121: classLoader = getClass().getClassLoader();
0122:
0123: CmpEngineFactory factory;
0124: try {
0125: Class<?> cmpEngineFactoryClass = classLoader
0126: .loadClass(cmpEngineFactory);
0127: factory = (CmpEngineFactory) cmpEngineFactoryClass
0128: .newInstance();
0129: } catch (Exception e) {
0130: throw new OpenEJBException(
0131: "Unable to create cmp engine factory "
0132: + cmpEngineFactory, e);
0133: }
0134: factory.setTransactionManager(transactionManager);
0135: factory
0136: .setTransactionSynchronizationRegistry(synchronizationRegistry);
0137: factory.setConnectorName(connectorName);
0138: factory.setCmpCallback(new ContainerCmpCallback());
0139: factory.setEngine(engine);
0140: factory.setClassLoader(classLoader);
0141: cmpEngine = factory.create();
0142: }
0143:
0144: public Object getContainerID() {
0145: return containerID;
0146: }
0147:
0148: public ContainerType getContainerType() {
0149: return ContainerType.CMP_ENTITY;
0150: }
0151:
0152: public synchronized DeploymentInfo[] deployments() {
0153: return deploymentsById.values().toArray(
0154: new DeploymentInfo[deploymentsById.size()]);
0155: }
0156:
0157: public synchronized DeploymentInfo getDeploymentInfo(
0158: Object deploymentID) {
0159: return deploymentsById.get(deploymentID);
0160: }
0161:
0162: private DeploymentInfo getDeploymentInfoByClass(Class type) {
0163: DeploymentInfo deploymentInfo = null;
0164: while (type != null && deploymentInfo == null) {
0165: deploymentInfo = deploymentsByClass.get(type);
0166: type = type.getSuperclass();
0167: }
0168:
0169: return deploymentInfo;
0170: }
0171:
0172: public void deploy(DeploymentInfo deploymentInfo)
0173: throws OpenEJBException {
0174: deploy((CoreDeploymentInfo) deploymentInfo);
0175: }
0176:
0177: public void deploy(CoreDeploymentInfo deploymentInfo)
0178: throws OpenEJBException {
0179: synchronized (this ) {
0180: Object deploymentId = deploymentInfo.getDeploymentID();
0181:
0182: cmpEngine.deploy(deploymentInfo);
0183: deploymentInfo.setContainerData(cmpEngine);
0184:
0185: // try to set deploymentInfo static field on bean implementation class
0186: try {
0187: Field field = deploymentInfo.getCmpImplClass()
0188: .getField("deploymentInfo");
0189: field.set(null, deploymentInfo);
0190: } catch (Exception e) {
0191: // ignore
0192: }
0193:
0194: // add to indexes
0195: deploymentsById.put(deploymentId, deploymentInfo);
0196: deploymentsByClass.put(deploymentInfo.getCmpImplClass(),
0197: deploymentInfo);
0198: deploymentInfo.setContainer(this );
0199: }
0200:
0201: EjbTimerService timerService = deploymentInfo
0202: .getEjbTimerService();
0203: if (timerService != null) {
0204: timerService.start();
0205: }
0206: }
0207:
0208: public void undeploy(DeploymentInfo deploymentInfo)
0209: throws OpenEJBException {
0210: EjbTimerService timerService = deploymentInfo
0211: .getEjbTimerService();
0212: if (timerService != null) {
0213: timerService.stop();
0214: }
0215: undeploy((CoreDeploymentInfo) deploymentInfo);
0216: }
0217:
0218: public void undeploy(CoreDeploymentInfo deploymentInfo)
0219: throws OpenEJBException {
0220: synchronized (this ) {
0221: deploymentsById.remove(deploymentInfo.getDeploymentID());
0222: deploymentsByClass.remove(deploymentInfo.getCmpImplClass());
0223:
0224: try {
0225: Field field = deploymentInfo.getCmpImplClass()
0226: .getField("deploymentInfo");
0227: field.set(null, null);
0228: } catch (Exception e) {
0229: // ignore
0230: }
0231:
0232: deploymentInfo.setContainer(null);
0233: deploymentInfo.setContainerData(null);
0234: }
0235: }
0236:
0237: public Object getEjbInstance(CoreDeploymentInfo deployInfo,
0238: Object primaryKey) {
0239: ThreadContext callContext = new ThreadContext(deployInfo,
0240: primaryKey);
0241:
0242: ThreadContext oldCallContext = ThreadContext.enter(callContext);
0243: try {
0244: Object bean = cmpEngine.loadBean(callContext, primaryKey);
0245: return bean;
0246: } finally {
0247: ThreadContext.exit(oldCallContext);
0248: }
0249: }
0250:
0251: /**
0252: * @deprecated use invoke signature without 'securityIdentity' argument.
0253: */
0254: public Object invoke(Object deployID, Method callMethod,
0255: Object[] args, Object primKey, Object securityIdentity)
0256: throws OpenEJBException {
0257: return invoke(deployID, callMethod.getDeclaringClass(),
0258: callMethod, args, primKey);
0259: }
0260:
0261: public Object invoke(Object deployID, Class callInterface,
0262: Method callMethod, Object[] args, Object primKey)
0263: throws OpenEJBException {
0264: CoreDeploymentInfo deployInfo = (CoreDeploymentInfo) this
0265: .getDeploymentInfo(deployID);
0266: if (deployInfo == null)
0267: throw new OpenEJBException(
0268: "Deployment does not exist in this container. Deployment(id='"
0269: + deployID + "'), Container(id='"
0270: + containerID + "')");
0271: ThreadContext callContext = new ThreadContext(deployInfo,
0272: primKey);
0273:
0274: ThreadContext oldCallContext = ThreadContext.enter(callContext);
0275: try {
0276:
0277: boolean authorized = securityService.isCallerAuthorized(
0278: callMethod, deployInfo
0279: .getInterfaceType(callInterface));
0280: if (!authorized) {
0281: throw new ApplicationException(new EJBAccessException(
0282: "Unauthorized Access by Principal Denied"));
0283: }
0284:
0285: Class declaringClass = callMethod.getDeclaringClass();
0286: String methodName = callMethod.getName();
0287:
0288: if (EJBHome.class.isAssignableFrom(declaringClass)
0289: || EJBLocalHome.class
0290: .isAssignableFrom(declaringClass)) {
0291: if (declaringClass != EJBHome.class
0292: && declaringClass != EJBLocalHome.class) {
0293: if (methodName.startsWith("create")) {
0294: return createEJBObject(callMethod, args,
0295: callContext);
0296: } else if (methodName.equals("findByPrimaryKey")) {
0297: return findByPrimaryKey(callMethod, args,
0298: callContext);
0299: } else if (methodName.startsWith("find")) {
0300: return findEJBObject(callMethod, args,
0301: callContext);
0302: } else {
0303: return homeMethod(callMethod, args, callContext);
0304: }
0305: } else if (methodName.equals("remove")) {
0306: removeEJBObject(callMethod, callContext);
0307: return null;
0308: }
0309: } else if ((EJBObject.class == declaringClass || EJBLocalObject.class == declaringClass)
0310: && methodName.equals("remove")) {
0311: removeEJBObject(callMethod, callContext);
0312: return null;
0313: }
0314:
0315: // business method
0316: callContext.setCurrentOperation(Operation.BUSINESS);
0317: callContext.setCurrentAllowedStates(EntityContext
0318: .getStates());
0319: Method runMethod = deployInfo
0320: .getMatchingBeanMethod(callMethod);
0321:
0322: callContext.set(Method.class, runMethod);
0323:
0324: Object retValue = businessMethod(callMethod, runMethod,
0325: args, callContext);
0326:
0327: return retValue;
0328: } finally {
0329: ThreadContext.exit(oldCallContext);
0330: }
0331: }
0332:
0333: public void discardInstance(Object bean, ThreadContext threadContext) {
0334: }
0335:
0336: private EntityBean createNewInstance(ThreadContext callContext) {
0337: CoreDeploymentInfo deploymentInfo = callContext
0338: .getDeploymentInfo();
0339: try {
0340: EntityBean bean = (EntityBean) deploymentInfo
0341: .getCmpImplClass().newInstance();
0342: return bean;
0343: } catch (Exception e) {
0344: throw new EJBException(
0345: "Unable to create new entity bean instance "
0346: + deploymentInfo.getCmpImplClass(), e);
0347: }
0348: }
0349:
0350: private ThreadContext createThreadContext(EntityBean entityBean) {
0351: if (entityBean == null)
0352: throw new NullPointerException("entityBean is null");
0353:
0354: CoreDeploymentInfo deployInfo = (CoreDeploymentInfo) getDeploymentInfoByClass(entityBean
0355: .getClass());
0356: KeyGenerator keyGenerator = deployInfo.getKeyGenerator();
0357: Object primaryKey = keyGenerator.getPrimaryKey(entityBean);
0358:
0359: ThreadContext callContext = new ThreadContext(deployInfo,
0360: primaryKey);
0361: return callContext;
0362: }
0363:
0364: private void setEntityContext(EntityBean entityBean) {
0365: if (entityBean == null)
0366: throw new NullPointerException("entityBean is null");
0367:
0368: // activating entity doen't have a primary key
0369: CoreDeploymentInfo deployInfo = (CoreDeploymentInfo) getDeploymentInfoByClass(entityBean
0370: .getClass());
0371:
0372: ThreadContext callContext = new ThreadContext(deployInfo, null);
0373: callContext.setCurrentOperation(Operation.SET_CONTEXT);
0374: callContext.setCurrentAllowedStates(EntityContext.getStates());
0375:
0376: ThreadContext oldCallContext = ThreadContext.enter(callContext);
0377: try {
0378: entityBean.setEntityContext(new EntityContext(
0379: transactionManager, securityService));
0380: } catch (RemoteException e) {
0381: throw new EJBException(e);
0382: } finally {
0383: ThreadContext.exit(oldCallContext);
0384: }
0385: }
0386:
0387: private void unsetEntityContext(EntityBean entityBean) {
0388: if (entityBean == null)
0389: throw new NullPointerException("entityBean is null");
0390:
0391: ThreadContext callContext = createThreadContext(entityBean);
0392: callContext.setCurrentOperation(Operation.UNSET_CONTEXT);
0393: callContext.setCurrentAllowedStates(EntityContext.getStates());
0394:
0395: ThreadContext oldCallContext = ThreadContext.enter(callContext);
0396: try {
0397: entityBean.unsetEntityContext();
0398: } catch (RemoteException e) {
0399: throw new EJBException(e);
0400: } finally {
0401: ThreadContext.exit(oldCallContext);
0402: }
0403: }
0404:
0405: private void ejbLoad(EntityBean entityBean) {
0406: if (entityBean == null)
0407: throw new NullPointerException("entityBean is null");
0408:
0409: ThreadContext callContext = createThreadContext(entityBean);
0410: callContext.setCurrentOperation(Operation.LOAD);
0411: callContext.setCurrentAllowedStates(EntityContext.getStates());
0412:
0413: ThreadContext oldCallContext = ThreadContext.enter(callContext);
0414: try {
0415: entityBean.ejbLoad();
0416: } catch (RemoteException e) {
0417: throw new EJBException(e);
0418: } finally {
0419: ThreadContext.exit(oldCallContext);
0420: }
0421:
0422: // if we call load we must call store
0423: try {
0424: //noinspection unchecked
0425: Set<EntityBean> registeredEntities = (LinkedHashSet<EntityBean>) synchronizationRegistry
0426: .getResource(ENTITIES_TO_STORE);
0427: if (registeredEntities == null) {
0428: registeredEntities = new LinkedHashSet<EntityBean>();
0429: synchronizationRegistry.putResource(ENTITIES_TO_STORE,
0430: registeredEntities);
0431: synchronizationRegistry
0432: .registerInterposedSynchronization(new Synchronization() {
0433: public void beforeCompletion() {
0434: //noinspection unchecked
0435: Set<EntityBean> registeredEntities = (LinkedHashSet<EntityBean>) synchronizationRegistry
0436: .getResource(ENTITIES_TO_STORE);
0437: if (registeredEntities == null) {
0438: return;
0439: }
0440: for (EntityBean entityBean : registeredEntities) {
0441: ejbStore(entityBean);
0442: }
0443: }
0444:
0445: public void afterCompletion(int i) {
0446: }
0447: });
0448: }
0449: registeredEntities.add(entityBean);
0450: } catch (Exception e) {
0451: }
0452: }
0453:
0454: private void ejbStore(EntityBean entityBean) {
0455: if (entityBean == null)
0456: throw new NullPointerException("entityBean is null");
0457:
0458: ThreadContext callContext = createThreadContext(entityBean);
0459: callContext.setCurrentOperation(Operation.STORE);
0460: callContext.setCurrentAllowedStates(EntityContext.getStates());
0461:
0462: ThreadContext oldCallContext = ThreadContext.enter(callContext);
0463: try {
0464: entityBean.ejbStore();
0465: } catch (RemoteException e) {
0466: throw new EJBException(e);
0467: } finally {
0468: ThreadContext.exit(oldCallContext);
0469: }
0470: }
0471:
0472: private void ejbRemove(EntityBean entityBean)
0473: throws RemoveException {
0474: if (entityBean == null)
0475: throw new NullPointerException("entityBean is null");
0476: if (isDeleted(entityBean))
0477: return;
0478:
0479: ThreadContext callContext = createThreadContext(entityBean);
0480: callContext.setCurrentOperation(Operation.REMOVE);
0481: callContext.setCurrentAllowedStates(EntityContext.getStates());
0482:
0483: ThreadContext oldCallContext = ThreadContext.enter(callContext);
0484: try {
0485: entityBean.ejbRemove();
0486: } catch (RemoteException e) {
0487: throw new EJBException(e);
0488: } finally {
0489: // clear relationships
0490: // todo replace with interface call when CmpEntityBean interface is added
0491: try {
0492: entityBean.getClass().getMethod("OpenEJB_deleted")
0493: .invoke(entityBean);
0494: } catch (Exception ignored) {
0495: }
0496: cancelTimers(callContext);
0497: ThreadContext.exit(oldCallContext);
0498: }
0499: }
0500:
0501: private boolean isDeleted(EntityBean entityBean) {
0502: try {
0503: return (Boolean) entityBean.getClass().getMethod(
0504: "OpenEJB_isDeleted").invoke(entityBean);
0505: } catch (NoSuchMethodException e) {
0506: return false;
0507: } catch (Exception e) {
0508: throw new EJBException(e);
0509: }
0510: }
0511:
0512: private void ejbActivate(EntityBean entityBean) {
0513: if (entityBean == null)
0514: throw new NullPointerException("entityBean is null");
0515:
0516: ThreadContext callContext = createThreadContext(entityBean);
0517: callContext.setCurrentOperation(Operation.ACTIVATE);
0518: callContext.setCurrentAllowedStates(EntityContext.getStates());
0519:
0520: ThreadContext oldCallContext = ThreadContext.enter(callContext);
0521: try {
0522: entityBean.ejbActivate();
0523: } catch (RemoteException e) {
0524: throw new EJBException(e);
0525: } finally {
0526: ThreadContext.exit(oldCallContext);
0527: }
0528: }
0529:
0530: private void ejbPassivate(EntityBean entityBean) {
0531: if (entityBean == null)
0532: throw new NullPointerException("entityBean is null");
0533:
0534: ThreadContext callContext = createThreadContext(entityBean);
0535: callContext.setCurrentOperation(Operation.PASSIVATE);
0536: callContext.setCurrentAllowedStates(EntityContext.getStates());
0537:
0538: ThreadContext oldCallContext = ThreadContext.enter(callContext);
0539: try {
0540: entityBean.ejbPassivate();
0541: } catch (RemoteException e) {
0542: throw new EJBException(e);
0543: } finally {
0544: ThreadContext.exit(oldCallContext);
0545: }
0546: }
0547:
0548: private Object businessMethod(Method callMethod, Method runMethod,
0549: Object[] args, ThreadContext callContext)
0550: throws OpenEJBException {
0551: CoreDeploymentInfo deploymentInfo = callContext
0552: .getDeploymentInfo();
0553: TransactionPolicy txPolicy = deploymentInfo
0554: .getTransactionPolicy(callMethod);
0555: TransactionContext txContext = new TransactionContext(
0556: callContext, transactionManager);
0557:
0558: txPolicy.beforeInvoke(null, txContext);
0559:
0560: EntityBean bean = null;
0561: Object returnValue = null;
0562:
0563: entrancyTracker.enter(deploymentInfo, callContext
0564: .getPrimaryKey());
0565: try {
0566: bean = (EntityBean) cmpEngine.loadBean(callContext,
0567: callContext.getPrimaryKey());
0568: if (bean == null) {
0569: throw new NoSuchObjectException(deploymentInfo
0570: .getDeploymentID()
0571: + " : " + callContext.getPrimaryKey());
0572: }
0573:
0574: returnValue = runMethod.invoke(bean, args);
0575:
0576: // when there is not transaction, merge the data from the bean back into the cmp engine
0577: cmpEngine.storeBeanIfNoTx(callContext, bean);
0578: } catch (InvocationTargetException ite) {
0579: ExceptionType type = callContext.getDeploymentInfo()
0580: .getExceptionType(ite.getTargetException());
0581: if (type == ExceptionType.SYSTEM) {
0582: /* System Exception ****************************/
0583: txPolicy.handleSystemException(
0584: ite.getTargetException(), bean, txContext);
0585:
0586: } else {
0587: /* Application Exception ***********************/
0588: txPolicy.handleApplicationException(ite
0589: .getTargetException(),
0590: type == ExceptionType.APPLICATION_ROLLBACK,
0591: txContext);
0592: }
0593: } catch (NoSuchObjectException e) {
0594: txPolicy.handleApplicationException(e, false, txContext);
0595: } catch (Throwable e) {
0596: /* System Exception ****************************/
0597: txPolicy.handleSystemException(e, bean, txContext);
0598: } finally {
0599: entrancyTracker.exit(deploymentInfo, callContext
0600: .getPrimaryKey());
0601: txPolicy.afterInvoke(bean, txContext);
0602: }
0603:
0604: return returnValue;
0605: }
0606:
0607: private Object homeMethod(Method callMethod, Object[] args,
0608: ThreadContext callContext) throws OpenEJBException {
0609: CoreDeploymentInfo deploymentInfo = callContext
0610: .getDeploymentInfo();
0611: TransactionPolicy txPolicy = deploymentInfo
0612: .getTransactionPolicy(callMethod);
0613: TransactionContext txContext = new TransactionContext(
0614: callContext, transactionManager);
0615:
0616: txPolicy.beforeInvoke(null, txContext);
0617:
0618: EntityBean bean = null;
0619: Object returnValue = null;
0620: try {
0621: /*
0622: Obtain a bean instance from the method ready pool
0623: */
0624: bean = createNewInstance(callContext);
0625:
0626: // set the entity context
0627: setEntityContext(bean);
0628:
0629: try {
0630: callContext.setCurrentOperation(Operation.HOME);
0631: callContext.setCurrentAllowedStates(EntityContext
0632: .getStates());
0633:
0634: Method runMethod = deploymentInfo
0635: .getMatchingBeanMethod(callMethod);
0636:
0637: try {
0638: returnValue = runMethod.invoke(bean, args);
0639: } catch (IllegalArgumentException e) {
0640: System.out
0641: .println("********************************************************");
0642: System.out.println("callMethod = " + callMethod);
0643: System.out.println("runMethod = " + runMethod);
0644: System.out.println("bean = "
0645: + bean.getClass().getName());
0646:
0647: throw e;
0648: }
0649: } finally {
0650: unsetEntityContext(bean);
0651: }
0652:
0653: bean = null; // poof
0654:
0655: } catch (InvocationTargetException ite) {
0656: ExceptionType type = callContext.getDeploymentInfo()
0657: .getExceptionType(ite.getTargetException());
0658: if (type == ExceptionType.SYSTEM) {
0659: /* System Exception ****************************/
0660: txPolicy.handleSystemException(
0661: ite.getTargetException(), bean, txContext);
0662:
0663: } else {
0664: /* Application Exception ***********************/
0665: txPolicy.handleApplicationException(ite
0666: .getTargetException(),
0667: type == ExceptionType.APPLICATION_ROLLBACK,
0668: txContext);
0669: }
0670: } catch (Throwable e) {
0671: /* System Exception ****************************/
0672: txPolicy.handleSystemException(e, bean, txContext);
0673: } finally {
0674: txPolicy.afterInvoke(bean, txContext);
0675: }
0676:
0677: return returnValue;
0678: }
0679:
0680: private ProxyInfo createEJBObject(Method callMethod, Object[] args,
0681: ThreadContext callContext) throws OpenEJBException {
0682: CoreDeploymentInfo deploymentInfo = callContext
0683: .getDeploymentInfo();
0684:
0685: EntityBean bean = null;
0686: Object primaryKey = null;
0687:
0688: TransactionPolicy txPolicy = deploymentInfo
0689: .getTransactionPolicy(callMethod);
0690: TransactionContext txContext = new TransactionContext(
0691: callContext, transactionManager);
0692:
0693: txPolicy.beforeInvoke(bean, txContext);
0694:
0695: try {
0696: // Obtain a bean instance from the method ready pool
0697: bean = createNewInstance(callContext);
0698:
0699: // set the entity context
0700: setEntityContext(bean);
0701:
0702: // Obtain the proper ejbCreate() method
0703: Method ejbCreateMethod = deploymentInfo
0704: .getMatchingBeanMethod(callMethod);
0705:
0706: // Set current operation for allowed operations
0707: callContext.setCurrentOperation(Operation.CREATE);
0708: callContext.setCurrentAllowedStates(EntityContext
0709: .getStates());
0710:
0711: // Invoke the proper ejbCreate() method on the instance
0712: ejbCreateMethod.invoke(bean, args);
0713:
0714: // create the new bean
0715: primaryKey = cmpEngine.createBean(bean, callContext);
0716:
0717: // determine post create callback method
0718: Method ejbPostCreateMethod = deploymentInfo
0719: .getMatchingPostCreateMethod(ejbCreateMethod);
0720:
0721: // create a new context containing the pk for the post create call
0722: ThreadContext postCreateContext = new ThreadContext(
0723: deploymentInfo, primaryKey);
0724: postCreateContext
0725: .setCurrentOperation(Operation.POST_CREATE);
0726: postCreateContext.setCurrentAllowedStates(EntityContext
0727: .getStates());
0728:
0729: ThreadContext oldContext = ThreadContext
0730: .enter(postCreateContext);
0731: try {
0732: // Invoke the ejbPostCreate method on the bean instance
0733: ejbPostCreateMethod.invoke(bean, args);
0734:
0735: // According to section 9.1.5.1 of the EJB 1.1 specification, the "ejbPostCreate(...)
0736: // method executes in the same transaction context as the previous ejbCreate(...) method."
0737: //
0738: // The bean is first insterted using db.create( ) and then after ejbPostCreate( ) its
0739: // updated using db.update(). This protocol allows for visablity of the bean after ejbCreate
0740: // within the current trasnaction.
0741: } finally {
0742: ThreadContext.exit(oldContext);
0743: }
0744:
0745: // when there is not transaction, merge the data from the bean back into the cmp engine
0746: cmpEngine.storeBeanIfNoTx(callContext, bean);
0747: } catch (InvocationTargetException ite) {// handle enterprise bean exceptions
0748: ExceptionType type = callContext.getDeploymentInfo()
0749: .getExceptionType(ite.getTargetException());
0750: if (type == ExceptionType.SYSTEM) {
0751: /* System Exception ****************************/
0752: txPolicy.handleSystemException(
0753: ite.getTargetException(), bean, txContext);
0754: } else {
0755: /* Application Exception ***********************/
0756: txPolicy.handleApplicationException(ite
0757: .getTargetException(),
0758: type == ExceptionType.APPLICATION_ROLLBACK,
0759: txContext);
0760: }
0761: } catch (CreateException e) {
0762: txPolicy.handleSystemException(e, bean, txContext);
0763: } catch (Throwable e) {
0764: txPolicy.handleSystemException(e, bean, txContext);
0765: } finally {
0766: txPolicy.afterInvoke(bean, txContext);
0767: }
0768:
0769: return new ProxyInfo(deploymentInfo, primaryKey);
0770: }
0771:
0772: private Object findByPrimaryKey(Method callMethod, Object[] args,
0773: ThreadContext callContext) throws OpenEJBException {
0774: CoreDeploymentInfo deploymentInfo = callContext
0775: .getDeploymentInfo();
0776:
0777: // Get the transaction policy assigned to this method
0778: TransactionPolicy txPolicy = deploymentInfo
0779: .getTransactionPolicy(callMethod);
0780: TransactionContext txContext = new TransactionContext(
0781: callContext, transactionManager);
0782:
0783: txPolicy.beforeInvoke(null, txContext);
0784: try {
0785: EntityBean bean = (EntityBean) cmpEngine.loadBean(
0786: callContext, args[0]);
0787: if (bean == null) {
0788: throw new ObjectNotFoundException(deploymentInfo
0789: .getDeploymentID()
0790: + " : " + args[0]);
0791: }
0792:
0793: // rebuild the primary key
0794: KeyGenerator kg = deploymentInfo.getKeyGenerator();
0795: Object primaryKey = kg.getPrimaryKey(bean);
0796:
0797: // create a new ProxyInfo based on the deployment info and primary key
0798: return new ProxyInfo(deploymentInfo, primaryKey);
0799: } catch (javax.ejb.FinderException fe) {
0800: txPolicy.handleApplicationException(fe, false, txContext);
0801: } catch (Throwable e) {// handle reflection exception
0802: txPolicy.handleSystemException(e, null, txContext);
0803: } finally {
0804: txPolicy.afterInvoke(null, txContext);
0805: }
0806: throw new AssertionError("Should not get here");
0807: }
0808:
0809: private Object findEJBObject(Method callMethod, Object[] args,
0810: ThreadContext callContext) throws OpenEJBException {
0811: CoreDeploymentInfo deploymentInfo = callContext
0812: .getDeploymentInfo();
0813:
0814: // Get the transaction policy assigned to this method
0815: TransactionPolicy txPolicy = deploymentInfo
0816: .getTransactionPolicy(callMethod);
0817: TransactionContext txContext = new TransactionContext(
0818: callContext, transactionManager);
0819:
0820: txPolicy.beforeInvoke(null, txContext);
0821: try {
0822: List<Object> results = cmpEngine.queryBeans(callContext,
0823: callMethod, args);
0824:
0825: KeyGenerator kg = deploymentInfo.getKeyGenerator();
0826:
0827: // The following block of code is responsible for returning ProxyInfo object(s) for each
0828: // matching entity bean found by the query. If its a multi-value find operation a Vector
0829: // of ProxyInfo objects will be returned. If its a single-value find operation then a
0830: // single ProxyInfo object is returned.
0831: if (callMethod.getReturnType() == Collection.class
0832: || callMethod.getReturnType() == Enumeration.class) {
0833: List<ProxyInfo> proxies = new ArrayList<ProxyInfo>();
0834: for (Object value : results) {
0835: EntityBean bean = (EntityBean) value;
0836:
0837: if (value == null) {
0838: proxies.add(null);
0839: } else {
0840: // get the primary key
0841: Object primaryKey = kg.getPrimaryKey(bean);
0842:
0843: // create a new ProxyInfo based on the deployment info and primary key and add it to the vector
0844: proxies.add(new ProxyInfo(deploymentInfo,
0845: primaryKey));
0846: }
0847: }
0848: if (callMethod.getReturnType() == Enumeration.class) {
0849: return new Enumerator(proxies);
0850: } else {
0851: return proxies;
0852: }
0853: } else {
0854: if (results.size() != 1) {
0855: throw new ObjectNotFoundException(
0856: "A Enteprise bean with deployment_id = "
0857: + deploymentInfo.getDeploymentID()
0858: + " and primarykey = " + args[0]
0859: + " Does not exist");
0860: }
0861:
0862: // create a new ProxyInfo based on the deployment info and primary key
0863: EntityBean bean = (EntityBean) results.get(0);
0864: if (bean == null) {
0865: return null;
0866: } else {
0867: Object primaryKey = kg.getPrimaryKey(bean);
0868: return new ProxyInfo(deploymentInfo, primaryKey);
0869: }
0870: }
0871: } catch (javax.ejb.FinderException fe) {
0872: txPolicy.handleApplicationException(fe, false, txContext);
0873: } catch (Throwable e) {// handle reflection exception
0874: txPolicy.handleSystemException(e, null, txContext);
0875: } finally {
0876: txPolicy.afterInvoke(null, txContext);
0877: }
0878: throw new AssertionError("Should not get here");
0879: }
0880:
0881: public Object select(DeploymentInfo di, String methodSignature,
0882: String returnType, Object... args) throws FinderException {
0883: CoreDeploymentInfo deploymentInfo = (CoreDeploymentInfo) di;
0884: String signature = deploymentInfo.getAbstractSchemaName() + "."
0885: + methodSignature;
0886:
0887: try {
0888: // exectue the select query
0889: Collection<Object> results = cmpEngine.queryBeans(
0890: deploymentInfo, signature, args);
0891:
0892: //
0893: // process the results
0894: //
0895:
0896: // If we need to return a set...
0897: Collection<Object> proxies;
0898: if (returnType.equals("java.util.Set")) {
0899: // we collect values into a LinkedHashSet to preserve ordering
0900: proxies = new LinkedHashSet<Object>();
0901: } else {
0902: // otherwise use a simple array list
0903: proxies = new ArrayList<Object>();
0904: }
0905:
0906: boolean isSingleValued = !returnType
0907: .equals("java.util.Collection")
0908: && !returnType.equals("java.util.Set");
0909: ProxyFactory proxyFactory = null;
0910: for (Object value : results) {
0911: // if this is a single valued query and we already have results, throw FinderException
0912: if (isSingleValued && !proxies.isEmpty()) {
0913: throw new FinderException(
0914: "The single valued query "
0915: + methodSignature
0916: + "returned more than one item");
0917: }
0918:
0919: // if we have an EntityBean, we need to proxy it
0920: if (value instanceof EntityBean) {
0921: EntityBean entityBean = (EntityBean) value;
0922: if (proxyFactory == null) {
0923: CoreDeploymentInfo resultInfo = (CoreDeploymentInfo) getDeploymentInfoByClass(entityBean
0924: .getClass());
0925: if (resultInfo != null) {
0926: proxyFactory = new ProxyFactory(resultInfo);
0927: }
0928: }
0929:
0930: if (proxyFactory != null) {
0931: if (deploymentInfo
0932: .isRemoteQueryResults(methodSignature)) {
0933: value = proxyFactory.createRemoteProxy(
0934: entityBean, this );
0935: } else {
0936: value = proxyFactory.createLocalProxy(
0937: entityBean, this );
0938: }
0939: }
0940: }
0941: proxies.add(value);
0942: }
0943:
0944: // if not single valued, return the set
0945: if (!isSingleValued) {
0946: return proxies;
0947: }
0948:
0949: // single valued query that returned no rows, is an exception
0950: if (proxies.isEmpty()) {
0951: throw new ObjectNotFoundException();
0952: }
0953:
0954: // return the single item.... multpile return values was handled in for loop above
0955: Object returnValue = proxies.iterator().next();
0956: return returnValue;
0957: } catch (RuntimeException e) {
0958: throw new EJBException(e);
0959: }
0960: }
0961:
0962: public int update(DeploymentInfo di, String methodSignature,
0963: Object... args) throws FinderException {
0964: CoreDeploymentInfo deploymentInfo = (CoreDeploymentInfo) di;
0965: String signature = deploymentInfo.getAbstractSchemaName() + "."
0966: + methodSignature;
0967:
0968: // exectue the update query
0969: int result = cmpEngine.executeUpdateQuery(deploymentInfo,
0970: signature, args);
0971: return result;
0972: }
0973:
0974: private void removeEJBObject(Method callMethod,
0975: ThreadContext callContext) throws OpenEJBException {
0976: CoreDeploymentInfo deploymentInfo = callContext
0977: .getDeploymentInfo();
0978: TransactionContext txContext = new TransactionContext(
0979: callContext, transactionManager);
0980: TransactionPolicy txPolicy = deploymentInfo
0981: .getTransactionPolicy(callMethod);
0982:
0983: txPolicy.beforeInvoke(null, txContext);
0984: try {
0985: EntityBean entityBean = (EntityBean) cmpEngine.loadBean(
0986: callContext, callContext.getPrimaryKey());
0987: if (entityBean == null) {
0988: throw new NoSuchObjectException(callContext
0989: .getDeploymentInfo().getDeploymentID()
0990: + " " + callContext.getPrimaryKey());
0991: }
0992: ejbRemove(entityBean);
0993: cmpEngine.removeBean(callContext);
0994: } catch (NoSuchObjectException e) {
0995: txPolicy.handleApplicationException(e, false, txContext);
0996: } catch (Throwable e) {// handle reflection exception
0997: txPolicy.handleSystemException(e, null, txContext);
0998: } finally {
0999: txPolicy.afterInvoke(null, txContext);
1000: }
1001: }
1002:
1003: private void cancelTimers(ThreadContext threadContext) {
1004: CoreDeploymentInfo deploymentInfo = threadContext
1005: .getDeploymentInfo();
1006: Object primaryKey = threadContext.getPrimaryKey();
1007:
1008: // stop timers
1009: if (primaryKey != null
1010: && deploymentInfo.getEjbTimerService() != null) {
1011: EjbTimerService timerService = deploymentInfo
1012: .getEjbTimerService();
1013: if (timerService != null
1014: && timerService instanceof EjbTimerServiceImpl) {
1015: for (Timer timer : deploymentInfo.getEjbTimerService()
1016: .getTimers(primaryKey)) {
1017: timer.cancel();
1018: }
1019: }
1020: }
1021: }
1022:
1023: private class ContainerCmpCallback implements CmpCallback {
1024: public void setEntityContext(EntityBean entity) {
1025: CmpContainer.this .setEntityContext(entity);
1026: }
1027:
1028: public void unsetEntityContext(EntityBean entity) {
1029: CmpContainer.this .unsetEntityContext(entity);
1030: }
1031:
1032: public void ejbActivate(EntityBean entity) {
1033: CmpContainer.this .ejbActivate(entity);
1034: }
1035:
1036: public void ejbPassivate(EntityBean entity) {
1037: CmpContainer.this .ejbPassivate(entity);
1038: }
1039:
1040: public void ejbLoad(EntityBean entity) {
1041: CmpContainer.this .ejbLoad(entity);
1042: }
1043:
1044: public void ejbStore(EntityBean entity) {
1045: CmpContainer.this .ejbStore(entity);
1046: }
1047:
1048: public void ejbRemove(EntityBean entity) throws RemoveException {
1049: CmpContainer.this.ejbRemove(entity);
1050: }
1051: }
1052: }
|