Home » openejb-3.1.2-src » org.apache » openejb » core » cmp » [javadoc | source]

    1   /**
    2    *
    3    * Licensed to the Apache Software Foundation (ASF) under one or more
    4    * contributor license agreements.  See the NOTICE file distributed with
    5    * this work for additional information regarding copyright ownership.
    6    * The ASF licenses this file to You under the Apache License, Version 2.0
    7    * (the "License"); you may not use this file except in compliance with
    8    * the License.  You may obtain a copy of the License at
    9    *
   10    *     http://www.apache.org/licenses/LICENSE-2.0
   11    *
   12    *  Unless required by applicable law or agreed to in writing, software
   13    *  distributed under the License is distributed on an "AS IS" BASIS,
   14    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   15    *  See the License for the specific language governing permissions and
   16    *  limitations under the License.
   17    */
   18   package org.apache.openejb.core.cmp;
   19   
   20   import java.lang.reflect.Field;
   21   import java.lang.reflect.InvocationTargetException;
   22   import java.lang.reflect.Method;
   23   import java.rmi.NoSuchObjectException;
   24   import java.rmi.RemoteException;
   25   import java.util.Collection;
   26   import java.util.Enumeration;
   27   import java.util.HashMap;
   28   import java.util.List;
   29   import java.util.Map;
   30   import java.util.ArrayList;
   31   import java.util.LinkedHashSet;
   32   import java.util.Set;
   33   import javax.ejb.EJBException;
   34   import javax.ejb.EJBHome;
   35   import javax.ejb.EJBLocalHome;
   36   import javax.ejb.EJBLocalObject;
   37   import javax.ejb.EJBObject;
   38   import javax.ejb.EntityBean;
   39   import javax.ejb.ObjectNotFoundException;
   40   import javax.ejb.RemoveException;
   41   import javax.ejb.Timer;
   42   import javax.ejb.FinderException;
   43   import javax.ejb.EJBAccessException;
   44   import javax.transaction.TransactionManager;
   45   import javax.transaction.TransactionSynchronizationRegistry;
   46   import javax.transaction.Synchronization;
   47   
   48   import org.apache.openejb.ApplicationException;
   49   import org.apache.openejb.DeploymentInfo;
   50   import org.apache.openejb.OpenEJBException;
   51   import org.apache.openejb.ProxyInfo;
   52   import org.apache.openejb.RpcContainer;
   53   import org.apache.openejb.ContainerType;
   54   import org.apache.openejb.InterfaceType;
   55   import org.apache.openejb.loader.SystemInstance;
   56   import org.apache.openejb.core.CoreDeploymentInfo;
   57   import org.apache.openejb.core.Operation;
   58   import org.apache.openejb.core.ThreadContext;
   59   import org.apache.openejb.core.ExceptionType;
   60   import org.apache.openejb.core.timer.EjbTimerService;
   61   import org.apache.openejb.core.timer.EjbTimerServiceImpl;
   62   import org.apache.openejb.core.entity.EntityContext;
   63   import org.apache.openejb.core.entity.EntrancyTracker;
   64   import org.apache.openejb.core.transaction.TransactionPolicy;
   65   import static org.apache.openejb.core.transaction.EjbTransactionUtil.handleApplicationException;
   66   import static org.apache.openejb.core.transaction.EjbTransactionUtil.handleSystemException;
   67   import static org.apache.openejb.core.transaction.EjbTransactionUtil.afterInvoke;
   68   import static org.apache.openejb.core.transaction.EjbTransactionUtil.createTransactionPolicy;
   69   import org.apache.openejb.spi.SecurityService;
   70   import org.apache.openejb.util.Enumerator;
   71   
   72   /**
   73    * @org.apache.xbean.XBean element="cmpContainer"
   74    */
   75   public class CmpContainer implements RpcContainer {
   76       protected final Object containerID;
   77       protected final SecurityService securityService;
   78   
   79       /**
   80        * Index used for getDeployments() and getDeploymentInfo(deploymentId).
   81        */
   82       protected final Map<Object, DeploymentInfo> deploymentsById = new HashMap<Object, DeploymentInfo>();
   83   
   84       /**
   85        * When events are fired from the CMP engine only an entity bean instance is returned.  The type of the bean is used
   86        * to find the deployment info.  This means that when the same type is used multiple ejb deployments a random deployment
   87        * will be selected to handle the ejb callback.
   88        */
   89       protected final Map<Class, DeploymentInfo> deploymentsByClass = new HashMap<Class, DeploymentInfo>();
   90   
   91       /**
   92        * The CmpEngine which performs the actual persistence operations
   93        */
   94       protected final CmpEngine cmpEngine;
   95   
   96       /**
   97        * Tracks entity instances that have been "entered" so we can throw reentrancy exceptions.
   98        */
   99       protected EntrancyTracker entrancyTracker;
  100       protected TransactionSynchronizationRegistry synchronizationRegistry;
  101       private static final Object ENTITIES_TO_STORE = new Object() {
  102           public String toString() {
  103               return "EntitiesToStore";
  104           }
  105       };
  106   
  107       public CmpContainer(Object id, TransactionManager transactionManager, SecurityService securityService, String cmpEngineFactory) throws OpenEJBException {
  108           this.containerID = id;
  109           this.securityService = securityService;
  110           synchronizationRegistry = SystemInstance.get().getComponent(TransactionSynchronizationRegistry.class);
  111           entrancyTracker = new EntrancyTracker(synchronizationRegistry);
  112   
  113           // create the cmp engine instance
  114           ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  115           if (classLoader == null) classLoader = getClass().getClassLoader();
  116   
  117           CmpEngineFactory factory;
  118           try {
  119               Class<?> cmpEngineFactoryClass = classLoader.loadClass(cmpEngineFactory);
  120               factory = (CmpEngineFactory) cmpEngineFactoryClass.newInstance();
  121           } catch (Exception e) {
  122               throw new OpenEJBException("Unable to create cmp engine factory " + cmpEngineFactory, e);
  123           }
  124           factory.setTransactionManager(transactionManager);
  125           factory.setTransactionSynchronizationRegistry(synchronizationRegistry);
  126           factory.setCmpCallback(new ContainerCmpCallback());
  127           cmpEngine = factory.create();
  128       }
  129   
  130       public Object getContainerID() {
  131           return containerID;
  132       }
  133   
  134       public ContainerType getContainerType() {
  135           return ContainerType.CMP_ENTITY;
  136       }
  137   
  138       public synchronized DeploymentInfo[] deployments() {
  139           return deploymentsById.values().toArray(new DeploymentInfo[deploymentsById.size()]);
  140       }
  141   
  142       public synchronized DeploymentInfo getDeploymentInfo(Object deploymentID) {
  143           return deploymentsById.get(deploymentID);
  144       }
  145   
  146       private DeploymentInfo getDeploymentInfoByClass(Class type) {
  147           DeploymentInfo deploymentInfo = null;
  148           while (type != null && deploymentInfo == null) {
  149               deploymentInfo = deploymentsByClass.get(type);
  150               type = type.getSuperclass();
  151           }
  152   
  153           return deploymentInfo;
  154       }
  155   
  156       public void deploy(DeploymentInfo deploymentInfo) throws OpenEJBException {
  157           deploy((CoreDeploymentInfo) deploymentInfo);
  158       }
  159   
  160       public void deploy(CoreDeploymentInfo deploymentInfo) throws OpenEJBException {
  161           synchronized (this) {
  162               Object deploymentId = deploymentInfo.getDeploymentID();
  163   
  164               cmpEngine.deploy(deploymentInfo);
  165               deploymentInfo.setContainerData(cmpEngine);
  166   
  167               // try to set deploymentInfo static field on bean implementation class
  168               try {
  169                   Field field = deploymentInfo.getCmpImplClass().getField("deploymentInfo");
  170                   field.set(null, deploymentInfo);
  171               } catch (Exception e) {
  172                   // ignore
  173               }
  174   
  175               // add to indexes
  176               deploymentsById.put(deploymentId, deploymentInfo);
  177               deploymentsByClass.put(deploymentInfo.getCmpImplClass(), deploymentInfo);
  178               deploymentInfo.setContainer(this);
  179           }
  180   
  181           EjbTimerService timerService = deploymentInfo.getEjbTimerService();
  182           if (timerService != null) {
  183               timerService.start();
  184           }
  185       }
  186   
  187       public void undeploy(DeploymentInfo deploymentInfo) throws OpenEJBException {
  188           EjbTimerService timerService = deploymentInfo.getEjbTimerService();
  189           if (timerService != null) {
  190               timerService.stop();
  191           }
  192           undeploy((CoreDeploymentInfo)deploymentInfo);
  193       }
  194   
  195       public void undeploy(CoreDeploymentInfo deploymentInfo) throws OpenEJBException {
  196           synchronized (this) {
  197               deploymentsById.remove(deploymentInfo.getDeploymentID());
  198               deploymentsByClass.remove(deploymentInfo.getCmpImplClass());
  199   
  200               try {
  201                   Field field = deploymentInfo.getCmpImplClass().getField("deploymentInfo");
  202                   field.set(null, null);
  203               } catch (Exception e) {
  204                   // ignore
  205               }
  206   
  207               deploymentInfo.setContainer(null);
  208               deploymentInfo.setContainerData(null);
  209           }
  210       }
  211   
  212       public Object getEjbInstance(CoreDeploymentInfo deployInfo, Object primaryKey) {
  213           ThreadContext callContext = new ThreadContext(deployInfo, primaryKey);
  214   
  215           ThreadContext oldCallContext = ThreadContext.enter(callContext);
  216           try {
  217               Object bean = cmpEngine.loadBean(callContext, primaryKey);
  218               return bean;
  219           } finally {
  220               ThreadContext.exit(oldCallContext);
  221           }
  222       }
  223   
  224       /**
  225        * @deprecated use invoke signature without 'securityIdentity' argument.
  226        */
  227       public Object invoke(Object deployID, Method callMethod, Object[] args, Object primKey, Object securityIdentity) throws OpenEJBException {
  228           return invoke(deployID, null, callMethod.getDeclaringClass(), callMethod, args, primKey);
  229       }
  230   
  231       public Object invoke(Object deployID, Class callInterface, Method callMethod, Object[] args, Object primKey) throws OpenEJBException {
  232           return invoke(deployID, null, callInterface, callMethod, args, primKey);
  233       }
  234   
  235       public Object invoke(Object deployID, InterfaceType type, Class callInterface, Method callMethod, Object[] args, Object primKey) throws OpenEJBException {
  236           CoreDeploymentInfo deployInfo = (CoreDeploymentInfo) this.getDeploymentInfo(deployID);
  237   
  238           if (deployInfo == null) throw new OpenEJBException("Deployment does not exist in this container. Deployment(id='"+deployID+"'), Container(id='"+containerID+"')");
  239   
  240           // Use the backup way to determine call type if null was supplied.
  241           if (type == null) type = deployInfo.getInterfaceType(callInterface);
  242   
  243           ThreadContext callContext = new ThreadContext(deployInfo, primKey);
  244   
  245           ThreadContext oldCallContext = ThreadContext.enter(callContext);
  246           try {
  247   
  248               boolean authorized = securityService.isCallerAuthorized(callMethod, type);
  249               if (!authorized) {
  250                   throw new ApplicationException(new EJBAccessException("Unauthorized Access by Principal Denied"));
  251               }
  252   
  253               Class declaringClass = callMethod.getDeclaringClass();
  254               String methodName = callMethod.getName();
  255   
  256               if (EJBHome.class.isAssignableFrom(declaringClass) || EJBLocalHome.class.isAssignableFrom(declaringClass)) {
  257                   if (declaringClass != EJBHome.class && declaringClass != EJBLocalHome.class) {
  258                       if (methodName.startsWith("create")) {
  259                           return createEJBObject(callMethod, args, callContext);
  260                       } else if (methodName.equals("findByPrimaryKey")) {
  261                           return findByPrimaryKey(callMethod, args, callContext);
  262                       } else if (methodName.startsWith("find")) {
  263                           return findEJBObject(callMethod, args, callContext);
  264                       } else {
  265                           return homeMethod(callMethod, args, callContext);
  266                       }
  267                   } else if (methodName.equals("remove")) {
  268                       removeEJBObject(callMethod, callContext);
  269                       return null;
  270                   }
  271               } else if ((EJBObject.class == declaringClass || EJBLocalObject.class == declaringClass) && methodName.equals("remove")) {
  272                   removeEJBObject(callMethod, callContext);
  273                   return null;
  274               }
  275   
  276               // business method
  277               callContext.setCurrentOperation(Operation.BUSINESS);
  278               callContext.setCurrentAllowedStates(EntityContext.getStates());
  279               Method runMethod = deployInfo.getMatchingBeanMethod(callMethod);
  280   
  281               callContext.set(Method.class, runMethod);
  282   
  283               Object retValue = businessMethod(callMethod, runMethod, args, callContext);
  284   
  285               return retValue;
  286           } finally {
  287               ThreadContext.exit(oldCallContext);
  288           }
  289       }
  290   
  291       private EntityBean createNewInstance(ThreadContext callContext) {
  292           CoreDeploymentInfo deploymentInfo = callContext.getDeploymentInfo();
  293           try {
  294               EntityBean bean = (EntityBean) deploymentInfo.getCmpImplClass().newInstance();
  295               return bean;
  296           } catch (Exception e) {
  297               throw new EJBException("Unable to create new entity bean instance " + deploymentInfo.getCmpImplClass(), e);
  298           }
  299       }
  300   
  301       private ThreadContext createThreadContext(EntityBean entityBean) {
  302           if (entityBean == null) throw new NullPointerException("entityBean is null");
  303   
  304           CoreDeploymentInfo deployInfo = (CoreDeploymentInfo) getDeploymentInfoByClass(entityBean.getClass());
  305           KeyGenerator keyGenerator = deployInfo.getKeyGenerator();
  306           Object primaryKey = keyGenerator.getPrimaryKey(entityBean);
  307   
  308           ThreadContext callContext = new ThreadContext(deployInfo, primaryKey);
  309           return callContext;
  310       }
  311   
  312       private void setEntityContext(EntityBean entityBean) {
  313           if (entityBean == null) throw new NullPointerException("entityBean is null");
  314   
  315           // activating entity doen't have a primary key
  316           CoreDeploymentInfo deployInfo = (CoreDeploymentInfo) getDeploymentInfoByClass(entityBean.getClass());
  317   
  318           ThreadContext callContext = new ThreadContext(deployInfo, null);
  319           callContext.setCurrentOperation(Operation.SET_CONTEXT);
  320           callContext.setCurrentAllowedStates(EntityContext.getStates());
  321   
  322           ThreadContext oldCallContext = ThreadContext.enter(callContext);
  323           try {
  324               entityBean.setEntityContext(new EntityContext(securityService));
  325           } catch (RemoteException e) {
  326               throw new EJBException(e);
  327           } finally {
  328               ThreadContext.exit(oldCallContext);
  329           }
  330       }
  331   
  332       private void unsetEntityContext(EntityBean entityBean) {
  333           if (entityBean == null) throw new NullPointerException("entityBean is null");
  334   
  335           ThreadContext callContext = createThreadContext(entityBean);
  336           callContext.setCurrentOperation(Operation.UNSET_CONTEXT);
  337           callContext.setCurrentAllowedStates(EntityContext.getStates());
  338   
  339           ThreadContext oldCallContext = ThreadContext.enter(callContext);
  340           try {
  341               entityBean.unsetEntityContext();
  342           } catch (RemoteException e) {
  343               throw new EJBException(e);
  344           } finally {
  345               ThreadContext.exit(oldCallContext);
  346           }
  347       }
  348   
  349       private void ejbLoad(EntityBean entityBean) {
  350           if (entityBean == null) throw new NullPointerException("entityBean is null");
  351   
  352           ThreadContext callContext = createThreadContext(entityBean);
  353           callContext.setCurrentOperation(Operation.LOAD);
  354           callContext.setCurrentAllowedStates(EntityContext.getStates());
  355   
  356           ThreadContext oldCallContext = ThreadContext.enter(callContext);
  357           try {
  358               entityBean.ejbLoad();
  359           } catch (RemoteException e) {
  360               throw new EJBException(e);
  361           } finally {
  362               ThreadContext.exit(oldCallContext);
  363           }
  364   
  365           // if we call load we must call store
  366           try {
  367               //noinspection unchecked
  368               Set<EntityBean> registeredEntities = (LinkedHashSet<EntityBean>) synchronizationRegistry.getResource(ENTITIES_TO_STORE);
  369               if (registeredEntities == null) {
  370                   registeredEntities = new LinkedHashSet<EntityBean>();
  371                   synchronizationRegistry.putResource(ENTITIES_TO_STORE, registeredEntities);
  372                   synchronizationRegistry.registerInterposedSynchronization(new Synchronization() {
  373                       public void beforeCompletion() {
  374                           //noinspection unchecked
  375                           Set<EntityBean> registeredEntities = (LinkedHashSet<EntityBean>) synchronizationRegistry.getResource(ENTITIES_TO_STORE);
  376                           if (registeredEntities == null) {
  377                               return;
  378                           }
  379                           for (EntityBean entityBean : registeredEntities) {
  380                               ejbStore(entityBean);
  381                           }
  382                       }
  383                       public void afterCompletion(int i) {
  384                       }
  385                   });
  386               }
  387               registeredEntities.add(entityBean);
  388           } catch (Exception e) {
  389           }
  390       }
  391   
  392       private void ejbStore(EntityBean entityBean) {
  393           if (entityBean == null) throw new NullPointerException("entityBean is null");
  394   
  395           ThreadContext callContext = createThreadContext(entityBean);
  396           callContext.setCurrentOperation(Operation.STORE);
  397           callContext.setCurrentAllowedStates(EntityContext.getStates());
  398   
  399           ThreadContext oldCallContext = ThreadContext.enter(callContext);
  400           try {
  401               entityBean.ejbStore();
  402           } catch (RemoteException e) {
  403               throw new EJBException(e);
  404           } finally {
  405               ThreadContext.exit(oldCallContext);
  406           }
  407       }
  408   
  409       private void ejbRemove(EntityBean entityBean) throws RemoveException {
  410           if (entityBean == null) throw new NullPointerException("entityBean is null");
  411           if (isDeleted(entityBean)) return;
  412   
  413           ThreadContext callContext = createThreadContext(entityBean);
  414           callContext.setCurrentOperation(Operation.REMOVE);
  415           callContext.setCurrentAllowedStates(EntityContext.getStates());
  416   
  417           ThreadContext oldCallContext = ThreadContext.enter(callContext);
  418           try {
  419               entityBean.ejbRemove();
  420           } catch (RemoteException e) {
  421               throw new EJBException(e);
  422           } finally {
  423               // clear relationships
  424               // todo replace with interface call when CmpEntityBean interface is added
  425               try {
  426                   entityBean.getClass().getMethod("OpenEJB_deleted").invoke(entityBean);
  427               } catch (Exception ignored) {
  428               }
  429               cancelTimers(callContext);
  430               ThreadContext.exit(oldCallContext);
  431           }
  432       }
  433   
  434       private boolean isDeleted(EntityBean entityBean) {
  435           try {
  436               return (Boolean)entityBean.getClass().getMethod("OpenEJB_isDeleted").invoke(entityBean);
  437           } catch (NoSuchMethodException e) {
  438               return false;
  439           } catch (Exception e) {
  440               throw new EJBException(e);
  441           }
  442       }
  443   
  444       private void ejbActivate(EntityBean entityBean) {
  445           if (entityBean == null) throw new NullPointerException("entityBean is null");
  446   
  447           ThreadContext callContext = createThreadContext(entityBean);
  448           callContext.setCurrentOperation(Operation.ACTIVATE);
  449           callContext.setCurrentAllowedStates(EntityContext.getStates());
  450   
  451           ThreadContext oldCallContext = ThreadContext.enter(callContext);
  452           try {
  453               entityBean.ejbActivate();
  454           } catch (RemoteException e) {
  455               throw new EJBException(e);
  456           } finally {
  457               ThreadContext.exit(oldCallContext);
  458           }
  459       }
  460   
  461       private void ejbPassivate(EntityBean entityBean) {
  462           if (entityBean == null) throw new NullPointerException("entityBean is null");
  463   
  464           ThreadContext callContext = createThreadContext(entityBean);
  465           callContext.setCurrentOperation(Operation.PASSIVATE);
  466           callContext.setCurrentAllowedStates(EntityContext.getStates());
  467   
  468           ThreadContext oldCallContext = ThreadContext.enter(callContext);
  469           try {
  470               entityBean.ejbPassivate();
  471           } catch (RemoteException e) {
  472               throw new EJBException(e);
  473           } finally {
  474               ThreadContext.exit(oldCallContext);
  475           }
  476       }
  477   
  478       private Object businessMethod(Method callMethod, Method runMethod, Object[] args, ThreadContext callContext) throws OpenEJBException {
  479           CoreDeploymentInfo deploymentInfo = callContext.getDeploymentInfo();
  480   
  481           TransactionPolicy txPolicy = createTransactionPolicy(deploymentInfo.getTransactionType(callMethod), callContext);
  482   
  483           EntityBean bean;
  484           Object returnValue = null;
  485   
  486           entrancyTracker.enter(deploymentInfo, callContext.getPrimaryKey());
  487           try {
  488               bean = (EntityBean) cmpEngine.loadBean(callContext, callContext.getPrimaryKey());
  489               if (bean == null) {
  490                   throw new NoSuchObjectException(deploymentInfo.getDeploymentID() + " : " + callContext.getPrimaryKey());
  491               }
  492   
  493               returnValue = runMethod.invoke(bean, args);
  494   
  495               // when there is not transaction, merge the data from the bean back into the cmp engine
  496               cmpEngine.storeBeanIfNoTx(callContext, bean);
  497           } catch (NoSuchObjectException e) {
  498               handleApplicationException(txPolicy, e, false);
  499           } catch (Throwable e) {
  500               if (e instanceof InvocationTargetException) {
  501                   e = ((InvocationTargetException) e).getTargetException();
  502               }
  503   
  504               ExceptionType type = callContext.getDeploymentInfo().getExceptionType(e);
  505               if (type == ExceptionType.SYSTEM) {
  506                   /* System Exception ****************************/
  507                   handleSystemException(txPolicy, e, callContext);
  508               } else {
  509                   /* Application Exception ***********************/
  510                   handleApplicationException(txPolicy, e, type == ExceptionType.APPLICATION_ROLLBACK);
  511               }
  512           } finally {
  513               entrancyTracker.exit(deploymentInfo, callContext.getPrimaryKey());
  514               afterInvoke(txPolicy, callContext);
  515           }
  516   
  517           return returnValue;
  518       }
  519   
  520       private Object homeMethod(Method callMethod, Object[] args, ThreadContext callContext) throws OpenEJBException {
  521           CoreDeploymentInfo deploymentInfo = callContext.getDeploymentInfo();
  522   
  523           TransactionPolicy txPolicy = createTransactionPolicy(deploymentInfo.getTransactionType(callMethod), callContext);
  524   
  525           EntityBean bean;
  526           Object returnValue = null;
  527           try {
  528               /*
  529                 Obtain a bean instance from the method ready pool
  530               */
  531               bean = createNewInstance(callContext);
  532   
  533               // set the entity context
  534               setEntityContext(bean);
  535   
  536               try {
  537                   callContext.setCurrentOperation(Operation.HOME);
  538                   callContext.setCurrentAllowedStates(EntityContext.getStates());
  539   
  540                   Method runMethod = deploymentInfo.getMatchingBeanMethod(callMethod);
  541   
  542                   try {
  543                       returnValue = runMethod.invoke(bean, args);
  544                   } catch (IllegalArgumentException e) {
  545                       System.out.println("********************************************************");
  546                       System.out.println("callMethod = " + callMethod);
  547                       System.out.println("runMethod = " + runMethod);
  548                       System.out.println("bean = " + bean.getClass().getName());
  549   
  550                       throw e;
  551                   }
  552               } finally {
  553                   unsetEntityContext(bean);
  554               }
  555           } catch (Throwable e) {
  556               if (e instanceof InvocationTargetException) {
  557                   e = ((InvocationTargetException) e).getTargetException();
  558               }
  559   
  560               ExceptionType type = callContext.getDeploymentInfo().getExceptionType(e);
  561               if (type == ExceptionType.SYSTEM) {
  562                   /* System Exception ****************************/
  563                   handleSystemException(txPolicy, e, callContext);
  564   
  565               } else {
  566                   /* Application Exception ***********************/
  567                   handleApplicationException(txPolicy, e, type == ExceptionType.APPLICATION_ROLLBACK);
  568               }
  569           } finally {
  570               afterInvoke(txPolicy, callContext);
  571           }
  572   
  573           return returnValue;
  574       }
  575   
  576       private ProxyInfo createEJBObject(Method callMethod, Object[] args, ThreadContext callContext) throws OpenEJBException {
  577           CoreDeploymentInfo deploymentInfo = callContext.getDeploymentInfo();
  578   
  579           TransactionPolicy txPolicy = createTransactionPolicy(deploymentInfo.getTransactionType(callMethod), callContext);
  580   
  581           EntityBean bean;
  582           Object primaryKey = null;
  583   
  584           try {
  585               // Obtain a bean instance from the method ready pool
  586               bean = createNewInstance(callContext);
  587   
  588               // set the entity context
  589               setEntityContext(bean);
  590   
  591               // Obtain the proper ejbCreate() method
  592               Method ejbCreateMethod = deploymentInfo.getMatchingBeanMethod(callMethod);
  593   
  594               // Set current operation for allowed operations
  595               callContext.setCurrentOperation(Operation.CREATE);
  596               callContext.setCurrentAllowedStates(EntityContext.getStates());
  597   
  598               // Invoke the proper ejbCreate() method on the instance
  599               ejbCreateMethod.invoke(bean, args);
  600   
  601               // create the new bean
  602               primaryKey = cmpEngine.createBean(bean, callContext);
  603   
  604               // determine post create callback method
  605               Method ejbPostCreateMethod = deploymentInfo.getMatchingPostCreateMethod(ejbCreateMethod);
  606   
  607               // create a new context containing the pk for the post create call
  608               ThreadContext postCreateContext = new ThreadContext(deploymentInfo, primaryKey);
  609               postCreateContext.setCurrentOperation(Operation.POST_CREATE);
  610               postCreateContext.setCurrentAllowedStates(EntityContext.getStates());
  611   
  612               ThreadContext oldContext = ThreadContext.enter(postCreateContext);
  613               try {
  614                   // Invoke the ejbPostCreate method on the bean instance
  615                   ejbPostCreateMethod.invoke(bean, args);
  616   
  617                   // According to section 9.1.5.1 of the EJB 1.1 specification, the "ejbPostCreate(...)
  618                   // method executes in the same transaction context as the previous ejbCreate(...) method."
  619                   //
  620                   // The bean is first insterted using db.create( ) and then after ejbPostCreate( ) its
  621                   // updated using db.update(). This protocol allows for visablity of the bean after ejbCreate
  622                   // within the current trasnaction.
  623               } finally {
  624                   ThreadContext.exit(oldContext);
  625               }
  626   
  627               // when there is not transaction, merge the data from the bean back into the cmp engine
  628               cmpEngine.storeBeanIfNoTx(callContext, bean);
  629           } catch (Throwable e) {
  630               if (e instanceof InvocationTargetException) {
  631                   e = ((InvocationTargetException) e).getTargetException();
  632               }
  633   
  634               ExceptionType type = callContext.getDeploymentInfo().getExceptionType(e);
  635               if (type == ExceptionType.SYSTEM) {
  636                   /* System Exception ****************************/
  637                   handleSystemException(txPolicy, e, callContext);
  638               } else {
  639                   /* Application Exception ***********************/
  640                   handleApplicationException(txPolicy, e, type == ExceptionType.APPLICATION_ROLLBACK);
  641               }
  642           } finally {
  643               afterInvoke(txPolicy, callContext);
  644           }
  645   
  646           return new ProxyInfo(deploymentInfo, primaryKey);
  647       }
  648   
  649       private Object findByPrimaryKey(Method callMethod, Object[] args, ThreadContext callContext) throws OpenEJBException {
  650           CoreDeploymentInfo deploymentInfo = callContext.getDeploymentInfo();
  651   
  652           TransactionPolicy txPolicy = createTransactionPolicy(deploymentInfo.getTransactionType(callMethod), callContext);
  653   
  654           try {
  655               EntityBean bean = (EntityBean) cmpEngine.loadBean(callContext, args[0]);
  656               if (bean == null) {
  657                   throw new ObjectNotFoundException(deploymentInfo.getDeploymentID() + " : " + args[0]);
  658               }
  659   
  660               // rebuild the primary key
  661               KeyGenerator kg = deploymentInfo.getKeyGenerator();
  662               Object primaryKey = kg.getPrimaryKey(bean);
  663   
  664               // create a new ProxyInfo based on the deployment info and primary key
  665               return new ProxyInfo(deploymentInfo, primaryKey);
  666           } catch (javax.ejb.FinderException fe) {
  667               handleApplicationException(txPolicy, fe, false);
  668           } catch (Throwable e) {// handle reflection exception
  669               handleSystemException(txPolicy, e, callContext);
  670           } finally {
  671               afterInvoke(txPolicy, callContext);
  672           }
  673           throw new AssertionError("Should not get here");
  674       }
  675   
  676       private Object findEJBObject(Method callMethod, Object[] args, ThreadContext callContext) throws OpenEJBException {
  677           CoreDeploymentInfo deploymentInfo = callContext.getDeploymentInfo();
  678   
  679           TransactionPolicy txPolicy = createTransactionPolicy(deploymentInfo.getTransactionType(callMethod), callContext);
  680   
  681           try {
  682               List<Object> results = cmpEngine.queryBeans(callContext, callMethod, args);
  683   
  684               KeyGenerator kg = deploymentInfo.getKeyGenerator();
  685   
  686               // The following block of code is responsible for returning ProxyInfo object(s) for each
  687               // matching entity bean found by the query.  If its a multi-value find operation a Vector
  688               // of ProxyInfo objects will be returned. If its a single-value find operation then a
  689               // single ProxyInfo object is returned.
  690               if (callMethod.getReturnType() == Collection.class || callMethod.getReturnType() == Enumeration.class) {
  691                   List<ProxyInfo> proxies = new ArrayList<ProxyInfo>();
  692                   for (Object value : results) {
  693                       EntityBean bean = (EntityBean) value;
  694   
  695                       if (value == null) {
  696                           proxies.add(null);
  697                       } else {
  698                           // get the primary key
  699                           Object primaryKey = kg.getPrimaryKey(bean);
  700   
  701                           // create a new ProxyInfo based on the deployment info and primary key and add it to the vector
  702                           proxies.add(new ProxyInfo(deploymentInfo, primaryKey));
  703                       }
  704                   }
  705                   if (callMethod.getReturnType() == Enumeration.class) {
  706                       return new Enumerator(proxies);
  707                   } else {
  708                       return proxies;
  709                   }
  710               } else {
  711                   if (results.size() != 1) {
  712                       throw new ObjectNotFoundException("A Enteprise bean with deployment_id = " + deploymentInfo.getDeploymentID() + " and primarykey = " + args[0] + " Does not exist");
  713                   }
  714   
  715                   // create a new ProxyInfo based on the deployment info and primary key
  716                   EntityBean bean = (EntityBean) results.get(0);
  717                   if (bean == null) {
  718                       return null;
  719                   } else {
  720                       Object primaryKey = kg.getPrimaryKey(bean);
  721                       return new ProxyInfo(deploymentInfo, primaryKey);
  722                   }
  723               }
  724           } catch (javax.ejb.FinderException fe) {
  725               handleApplicationException(txPolicy, fe, false);
  726           } catch (Throwable e) {// handle reflection exception
  727               handleSystemException(txPolicy, e, callContext);
  728           } finally {
  729               afterInvoke(txPolicy, callContext);
  730           }
  731           throw new AssertionError("Should not get here");
  732       }
  733   
  734       public Object select(DeploymentInfo di, String methodSignature, String returnType, Object... args) throws FinderException {
  735           CoreDeploymentInfo deploymentInfo = (CoreDeploymentInfo) di;
  736           String signature = deploymentInfo.getAbstractSchemaName() + "." + methodSignature;
  737   
  738           try {
  739               // execute the select query
  740               Collection<Object> results = cmpEngine.queryBeans(deploymentInfo, signature, args);
  741   
  742               //
  743               // process the results
  744               //
  745   
  746               // If we need to return a set...
  747               Collection<Object> proxies;
  748               if (returnType.equals("java.util.Set")) {
  749                   // we collect values into a LinkedHashSet to preserve ordering
  750                   proxies = new LinkedHashSet<Object>();
  751               } else {
  752                   // otherwise use a simple array list
  753                   proxies = new ArrayList<Object>();
  754               }
  755   
  756               boolean isSingleValued = !returnType.equals("java.util.Collection") && !returnType.equals("java.util.Set");
  757               ProxyFactory proxyFactory = null;
  758               for (Object value : results) {
  759                   // if this is a single valued query and we already have results, throw FinderException
  760                   if (isSingleValued && !proxies.isEmpty()) {
  761                       throw new FinderException("The single valued query " + methodSignature + "returned more than one item");
  762                   }
  763   
  764                   // if we have an EntityBean, we need to proxy it
  765                   if (value instanceof EntityBean) {
  766                       EntityBean entityBean = (EntityBean) value;
  767                       if (proxyFactory == null) {
  768                           CoreDeploymentInfo resultInfo = (CoreDeploymentInfo) getDeploymentInfoByClass(entityBean.getClass());
  769                           if (resultInfo != null) {
  770                               proxyFactory = new ProxyFactory(resultInfo);
  771                           }
  772                       }
  773   
  774                       if (proxyFactory != null) {
  775                           if (deploymentInfo.isRemoteQueryResults(methodSignature)) {
  776                               value = proxyFactory.createRemoteProxy(entityBean, this);
  777                           } else {
  778                               value = proxyFactory.createLocalProxy(entityBean, this);
  779                           }
  780                       }
  781                   }
  782                   proxies.add(value);
  783               }
  784   
  785               // if not single valued, return the set
  786               if (!isSingleValued) {
  787                   return proxies;
  788               }
  789   
  790               // single valued query that returned no rows, is an exception
  791               if (proxies.isEmpty()) {
  792                   throw new ObjectNotFoundException();
  793               }
  794   
  795               // return the single item.... multiple return values was handled in for loop above
  796               Object returnValue = proxies.iterator().next();
  797               return returnValue;
  798           } catch (RuntimeException e) {
  799               throw new EJBException(e);
  800           }
  801       }
  802   
  803       public int update(DeploymentInfo di, String methodSignature, Object... args) throws FinderException {
  804           CoreDeploymentInfo deploymentInfo = (CoreDeploymentInfo) di;
  805           String signature = deploymentInfo.getAbstractSchemaName() + "." + methodSignature;
  806   
  807           // exectue the update query
  808           int result = cmpEngine.executeUpdateQuery(deploymentInfo, signature, args);
  809           return result;
  810       }
  811   
  812       private void removeEJBObject(Method callMethod, ThreadContext callContext) throws OpenEJBException {
  813           CoreDeploymentInfo deploymentInfo = callContext.getDeploymentInfo();
  814   
  815           TransactionPolicy txPolicy = createTransactionPolicy(deploymentInfo.getTransactionType(callMethod), callContext);
  816   
  817           try {
  818               EntityBean entityBean = (EntityBean) cmpEngine.loadBean(callContext, callContext.getPrimaryKey());
  819               if (entityBean == null) {
  820                   throw new NoSuchObjectException(callContext.getDeploymentInfo().getDeploymentID() + " " + callContext.getPrimaryKey());
  821               }
  822               ejbRemove(entityBean);
  823               cmpEngine.removeBean(callContext);
  824           } catch (NoSuchObjectException e) {
  825               handleApplicationException(txPolicy, e, false);
  826           } catch (Throwable e) {// handle reflection exception
  827               handleSystemException(txPolicy, e, callContext);
  828           } finally {
  829               afterInvoke(txPolicy, callContext);
  830           }
  831       }
  832   
  833       private void cancelTimers(ThreadContext threadContext) {
  834           CoreDeploymentInfo deploymentInfo = threadContext.getDeploymentInfo();
  835           Object primaryKey = threadContext.getPrimaryKey();
  836   
  837           // stop timers
  838           if (primaryKey != null && deploymentInfo.getEjbTimerService() != null) {
  839               EjbTimerService timerService = deploymentInfo.getEjbTimerService();
  840               if (timerService != null && timerService instanceof EjbTimerServiceImpl) {
  841                   for (Timer timer : deploymentInfo.getEjbTimerService().getTimers(primaryKey)) {
  842                       timer.cancel();
  843                   }
  844               }
  845           }
  846       }
  847   
  848       private class ContainerCmpCallback implements CmpCallback {
  849           public void setEntityContext(EntityBean entity) {
  850               CmpContainer.this.setEntityContext(entity);
  851           }
  852   
  853           public void unsetEntityContext(EntityBean entity) {
  854               CmpContainer.this.unsetEntityContext(entity);
  855           }
  856   
  857           public void ejbActivate(EntityBean entity) {
  858               CmpContainer.this.ejbActivate(entity);
  859           }
  860   
  861           public void ejbPassivate(EntityBean entity) {
  862               CmpContainer.this.ejbPassivate(entity);
  863           }
  864   
  865           public void ejbLoad(EntityBean entity) {
  866               CmpContainer.this.ejbLoad(entity);
  867           }
  868   
  869           public void ejbStore(EntityBean entity) {
  870               CmpContainer.this.ejbStore(entity);
  871           }
  872   
  873           public void ejbRemove(EntityBean entity) throws RemoveException {
  874               CmpContainer.this.ejbRemove(entity);
  875           }
  876       }
  877   }

Home » openejb-3.1.2-src » org.apache » openejb » core » cmp » [javadoc | source]