Save This Page
Home » jboss-5.0.0.CR1-src » org » jboss » ejb » [javadoc | source]
    1   /*
    2   * JBoss, Home of Professional Open Source
    3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
    4   * by the @authors tag. See the copyright.txt in the distribution for a
    5   * full listing of individual contributors.
    6   *
    7   * This is free software; you can redistribute it and/or modify it
    8   * under the terms of the GNU Lesser General Public License as
    9   * published by the Free Software Foundation; either version 2.1 of
   10   * the License, or (at your option) any later version.
   11   *
   12   * This software is distributed in the hope that it will be useful,
   13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   15   * Lesser General Public License for more details.
   16   *
   17   * You should have received a copy of the GNU Lesser General Public
   18   * License along with this software; if not, write to the Free
   19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   21   */
   22   package org.jboss.ejb;
   23   
   24   import java.lang.reflect.Method;
   25   import java.rmi.RemoteException;
   26   import java.util.Collection;
   27   import java.util.Enumeration;
   28   import java.util.HashMap;
   29   import java.util.Hashtable;
   30   import java.util.Iterator;
   31   import java.util.Map;
   32   
   33   import javax.ejb.EJBException;
   34   import javax.ejb.EJBHome;
   35   import javax.ejb.EJBLocalHome;
   36   import javax.ejb.EJBLocalObject;
   37   import javax.ejb.EJBMetaData;
   38   import javax.ejb.EJBObject;
   39   import javax.ejb.Handle;
   40   import javax.ejb.HomeHandle;
   41   import javax.ejb.RemoveException;
   42   import javax.ejb.TimedObject;
   43   import javax.ejb.Timer;
   44   import javax.management.ObjectName;
   45   import javax.transaction.Transaction;
   46   
   47   import org.jboss.invocation.Invocation;
   48   import org.jboss.invocation.InvocationType;
   49   import org.jboss.invocation.MarshalledInvocation;
   50   import org.jboss.metadata.ConfigurationMetaData;
   51   import org.jboss.metadata.EntityMetaData;
   52   import org.jboss.monitor.StatisticsProvider;
   53   import org.jboss.util.collection.SerializableEnumeration;
   54   
   55   /**
   56    * This is a Container for EntityBeans (both BMP and CMP).
   57    *
   58    * @see Container
   59    * @see EntityEnterpriseContext
   60    *
   61    * @author <a href="mailto:rickard.oberg@telkel.com">Rickard Oberg</a>
   62    * @author <a href="mailto:marc.fleury@telkel.com">Marc Fleury</a>
   63    * @author <a href="mailto:sebastien.alborini@m4x.org">Sebastien Alborini</a>
   64    * @author <a href="mailto:docodan@mvcsoft.com">Daniel OConnor</a>
   65    * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
   66    * @author <a href="mailto:andreas.schaefer@madplanet.com">Andreas Schaefer</a>
   67    * @author <a href="mailto:dain@daingroup.com">Dain Sundstrom</a>
   68    * @author <a href="mailto:anil.saldhana@redhat.com">Anil Saldhana</a>
   69    * @version $Revision: 66439 $
   70    *
   71    * @jmx.mbean extends="org.jboss.ejb.ContainerMBean"
   72    */
   73   public class EntityContainer
   74      extends Container
   75      implements EJBProxyFactoryContainer, InstancePoolContainer,
   76         EntityContainerMBean
   77   {
   78      /**
   79       * These are the mappings between the home interface methods and the
   80       * container methods.
   81       */
   82      protected Map homeMapping = new HashMap();
   83   
   84      /**
   85       * These are the mappings between the remote/local interface methods and the
   86       * bean methods.
   87       */
   88      protected Map beanMapping = new HashMap();
   89   
   90      /** This is the persistence manager for this container */
   91      protected EntityPersistenceManager persistenceManager;
   92   
   93      /** This is the instance cache for this container */
   94      protected InstanceCache instanceCache;
   95   
   96      /** This is the instancepool that is to be used */
   97      protected InstancePool instancePool;
   98   
   99      /**
  100       * This is the first interceptor in the chain. The last interceptor must
  101       * be provided by the container itself.
  102       */
  103      protected Interceptor interceptor;
  104   
  105      /**
  106       * <code>readOnly</code> determines if state can be written to resource manager.
  107       */
  108      protected boolean readOnly = false;
  109   
  110      /**
  111       * This provides a way to find the entities that are part of a given
  112       * transaction EntitySynchronizationInterceptor and InstanceSynchronization
  113       * manage this instance.
  114       */
  115      protected static GlobalTxEntityMap globalTxEntityMap = new GlobalTxEntityMap();
  116      
  117      public static GlobalTxEntityMap getGlobalTxEntityMap()
  118      {
  119         return globalTxEntityMap;
  120      }
  121   
  122      /**
  123       * Stores all of the entities associated with the specified transaction.
  124       * As per the spec 9.6.4, entities must be synchronized with the datastore
  125       * when an ejbFind<METHOD> is called.
  126       * Also, all entities within entire transaction should be synchronized before
  127       * a remove, otherwise there may be problems with 'cascade delete'.
  128       *
  129       * @param tx the transaction that associated entites will be stored
  130       */
  131      public static void synchronizeEntitiesWithinTransaction(Transaction tx)
  132      {
  133         // If there is no transaction, there is nothing to synchronize.
  134         if(tx != null)
  135         {
  136            getGlobalTxEntityMap().synchronizeEntities(tx);
  137         }
  138      }
  139   
  140      // Public --------------------------------------------------------
  141   
  142      public boolean isReadOnly()
  143      {
  144         return readOnly;
  145      }
  146   
  147      public LocalProxyFactory getLocalProxyFactory()
  148      {
  149         return localProxyFactory;
  150      }
  151   
  152      public void setInstancePool(InstancePool ip)
  153      {
  154         if (ip == null)
  155            throw new IllegalArgumentException("Null pool");
  156   
  157         this.instancePool = ip;
  158         ip.setContainer(this);
  159      }
  160   
  161      public InstancePool getInstancePool()
  162      {
  163         return instancePool;
  164      }
  165   
  166      public void setInstanceCache(InstanceCache ic)
  167      {
  168         if (ic == null)
  169            throw new IllegalArgumentException("Null cache");
  170   
  171         this.instanceCache = ic;
  172         ic.setContainer(this);
  173      }
  174   
  175      public InstanceCache getInstanceCache()
  176      {
  177         return instanceCache;
  178      }
  179   
  180      public EntityPersistenceManager getPersistenceManager()
  181      {
  182         return persistenceManager;
  183      }
  184   
  185      public void setPersistenceManager(EntityPersistenceManager pm)
  186      {
  187         if (pm == null)
  188            throw new IllegalArgumentException("Null persistence manager");
  189   
  190         persistenceManager = pm;
  191         pm.setContainer(this);
  192      }
  193   
  194      public void addInterceptor(Interceptor in)
  195      {
  196         if (interceptor == null)
  197         {
  198            interceptor = in;
  199         }
  200         else
  201         {
  202            Interceptor current = interceptor;
  203            while (current.getNext() != null)
  204            {
  205               current = current.getNext();
  206            }
  207   
  208            current.setNext(in);
  209         }
  210      }
  211   
  212      public Interceptor getInterceptor()
  213      {
  214         return interceptor;
  215      }
  216   
  217      public Class getHomeClass()
  218      {
  219         return homeInterface;
  220      }
  221   
  222      public Class getRemoteClass()
  223      {
  224         return remoteInterface;
  225      }
  226   
  227      /**
  228       * Returns a new instance of the bean class or a subclass of the bean class.
  229       * If this is 1.x cmp, simply return a new instance of the bean class.
  230       * If this is 2.x cmp, return a subclass that provides an implementation
  231       * of the abstract accessors.
  232       *
  233       * @see java.lang.Class#newInstance
  234       *
  235       * @return   The new instance.
  236       */
  237      public Object createBeanClassInstance() throws Exception {
  238         return persistenceManager.createBeanClassInstance();
  239      }
  240   
  241      // Container implementation --------------------------------------
  242   
  243      protected void createService() throws Exception
  244      {
  245         // Associate thread with classloader
  246         ClassLoader oldCl = SecurityActions.getContextClassLoader();
  247         SecurityActions.setContextClassLoader(getClassLoader());
  248         pushENC();
  249         try
  250         {
  251            // Acquire classes from CL
  252            if (metaData.getHome() != null)
  253               homeInterface = classLoader.loadClass(metaData.getHome());
  254            if (metaData.getRemote() != null)
  255               remoteInterface = classLoader.loadClass(metaData.getRemote());
  256   
  257            // Call default init
  258            super.createService();
  259   
  260            // Make some additional validity checks with regards to the container configuration
  261            checkCoherency ();
  262   
  263            // Map the bean methods
  264            setupBeanMapping();
  265   
  266            // Map the home methods
  267            setupHomeMapping();
  268   
  269            // Map the interfaces to Long
  270            setupMarshalledInvocationMapping();
  271   
  272            // Try to register the instance pool as an MBean
  273            try
  274            {
  275               ObjectName containerName = super.getJmxName();
  276               Hashtable props = containerName.getKeyPropertyList();
  277               props.put("plugin", "pool");
  278               ObjectName poolName = new ObjectName(containerName.getDomain(), props);
  279               server.registerMBean(instancePool, poolName);
  280            }
  281            catch(Throwable t)
  282            {
  283               log.debug("Failed to register cache as mbean", t);
  284            }
  285            // Initialize pool
  286            instancePool.create();
  287   
  288            for (Iterator it = proxyFactories.keySet().iterator(); it.hasNext(); )
  289            {
  290               String invokerBinding = (String)it.next();
  291               EJBProxyFactory ci = (EJBProxyFactory)proxyFactories.get(invokerBinding);
  292               ci.create();
  293            }
  294   
  295            // Try to register the instance cache as an MBean
  296            try
  297            {
  298               ObjectName containerName = super.getJmxName();
  299               Hashtable props = containerName.getKeyPropertyList();
  300               props.put("plugin", "cache");
  301               ObjectName cacheName = new ObjectName(containerName.getDomain(), props);
  302               server.registerMBean(instanceCache, cacheName);
  303            }
  304            catch(Throwable t)
  305            {
  306               log.debug("Failed to register cache as mbean", t);
  307            }
  308            // Init instance cache
  309            instanceCache.create();
  310   
  311            // Init persistence
  312            persistenceManager.create();
  313   
  314            // Initialize the interceptor by calling the chain
  315            Interceptor in = interceptor;
  316            while (in != null)
  317            {
  318               in.setContainer(this);
  319               in.create();
  320               in = in.getNext();
  321            }
  322            readOnly = ((EntityMetaData)metaData).isReadOnly();
  323         }
  324         finally
  325         {
  326            popENC();
  327            // Reset classloader
  328            SecurityActions.setContextClassLoader(oldCl);
  329         }
  330      }
  331   
  332      protected void startService() throws Exception
  333      {
  334         // Associate thread with classloader
  335         ClassLoader oldCl = SecurityActions.getContextClassLoader();
  336         SecurityActions.setContextClassLoader(getClassLoader());
  337         pushENC();
  338         try
  339         {
  340            // Call default start
  341            super.startService();
  342   
  343            // Start container invokers
  344            for (Iterator it = proxyFactories.keySet().iterator(); it.hasNext(); )
  345            {
  346               String invokerBinding = (String)it.next();
  347               EJBProxyFactory ci = (EJBProxyFactory)proxyFactories.get(invokerBinding);
  348               ci.start();
  349            }
  350   
  351            // Start instance cache
  352            instanceCache.start();
  353   
  354            // Start the instance pool
  355            instancePool.start();
  356   
  357            Interceptor i = interceptor;
  358            while(i != null)
  359            {
  360               i.start();
  361               i = i.getNext();
  362            }
  363   
  364            // Restore persisted ejb timers
  365            restoreTimers();
  366         }
  367         finally
  368         {
  369            popENC();
  370            // Reset classloader
  371            SecurityActions.setContextClassLoader(oldCl);
  372         }
  373      }
  374   
  375      protected void stopService() throws Exception
  376      {
  377         // Associate thread with classloader
  378         ClassLoader oldCl = SecurityActions.getContextClassLoader();
  379         SecurityActions.setContextClassLoader(getClassLoader());
  380         pushENC();
  381         try
  382         {
  383            //Stop items in reverse order from start
  384            //This assures that CachedConnectionInterceptor will get removed
  385            //from in between this and the pm before the pm is stopped.
  386            // Stop all interceptors in the chain
  387            Interceptor in = interceptor;
  388            while (in != null)
  389            {
  390               in.stop();
  391               in = in.getNext();
  392            }
  393   
  394            // Stop the instance pool
  395            instancePool.stop();
  396   
  397   
  398            // Stop persistence
  399            persistenceManager.stop();
  400   
  401            // Stop instance cache
  402            instanceCache.stop();
  403   
  404            // Stop container invoker
  405            for (Iterator it = proxyFactories.keySet().iterator(); it.hasNext(); )
  406            {
  407               String invokerBinding = (String)it.next();
  408               EJBProxyFactory ci = (EJBProxyFactory)proxyFactories.get(invokerBinding);
  409               ci.stop();
  410            }
  411   
  412            // Call default stop
  413            super.stopService();
  414         }
  415         finally
  416         {
  417            popENC();
  418            // Reset classloader
  419            SecurityActions.setContextClassLoader(oldCl);
  420         }
  421      }
  422   
  423      protected void destroyService() throws Exception
  424      {
  425         // Associate thread with classloader
  426         ClassLoader oldCl = SecurityActions.getContextClassLoader();
  427         SecurityActions.setContextClassLoader(getClassLoader());
  428         pushENC();
  429         try
  430         {
  431            // Destroy container invoker
  432            for (Iterator it = proxyFactories.keySet().iterator(); it.hasNext(); )
  433            {
  434               String invokerBinding = (String)it.next();
  435               EJBProxyFactory ci = (EJBProxyFactory)proxyFactories.get(invokerBinding);
  436               ci.destroy();
  437            }
  438   
  439            // Destroy instance cache
  440            instanceCache.destroy();
  441            instanceCache.setContainer(null);
  442            try
  443            {
  444               ObjectName containerName = super.getJmxName();
  445               Hashtable props = containerName.getKeyPropertyList();
  446               props.put("plugin", "cache");
  447               ObjectName cacheName = new ObjectName(containerName.getDomain(), props);
  448               server.unregisterMBean(cacheName);
  449            }
  450            catch(Throwable ignore)
  451            {
  452            }
  453   
  454            // Destroy persistence
  455            persistenceManager.destroy();
  456            persistenceManager.setContainer(null);
  457   
  458            // Destroy the pool
  459            instancePool.destroy();
  460            instancePool.setContainer(null);
  461            try
  462            {
  463               ObjectName containerName = super.getJmxName();
  464               Hashtable props = containerName.getKeyPropertyList();
  465               props.put("plugin", "pool");
  466               ObjectName poolName = new ObjectName(containerName.getDomain(), props);
  467               server.unregisterMBean(poolName);
  468            }
  469            catch(Throwable ignore)
  470            {
  471            }
  472   
  473            // Destroy all the interceptors in the chain
  474            Interceptor in = interceptor;
  475            while (in != null)
  476            {
  477               in.destroy();
  478               in.setContainer(null);
  479               in = in.getNext();
  480            }
  481   
  482            MarshalledInvocation.removeHashes(homeInterface);
  483            MarshalledInvocation.removeHashes(remoteInterface);
  484   
  485            // Call default destroy
  486            super.destroyService();
  487         }
  488         finally
  489         {
  490            popENC();
  491            // Reset classloader
  492            SecurityActions.setContextClassLoader(oldCl);
  493         }
  494      }
  495   
  496      public Object internalInvokeHome(Invocation mi) throws Exception
  497      {
  498         Method method = mi.getMethod();
  499         if (method != null && method.getName().equals("remove"))
  500         {
  501            // Map to EJBHome.remove(Object) to EJBObject.remove()
  502            InvocationType type = mi.getType(); 
  503            if (type == InvocationType.HOME)
  504               mi.setType(InvocationType.REMOTE);
  505            else if (type == InvocationType.LOCALHOME)
  506               mi.setType(InvocationType.LOCAL);
  507            mi.setMethod(EJBOBJECT_REMOVE);
  508   
  509            // Handle or primary key?
  510            Object arg = mi.getArguments()[0];
  511            if (arg instanceof Handle)
  512            {
  513               if (arg == null)
  514                  throw new RemoteException("Null handle");
  515               Handle handle = (Handle) arg;
  516               EJBObject ejbObject = handle.getEJBObject();
  517               mi.setId(ejbObject.getPrimaryKey());
  518            }
  519            else
  520               mi.setId(arg);
  521   
  522            mi.setArguments(new Object[0]);
  523            return getInterceptor().invoke(mi);
  524         }
  525         // Invoke through interceptors
  526         return getInterceptor().invokeHome(mi);
  527      }
  528   
  529      public Object internalInvoke(Invocation mi) throws Exception
  530      {
  531         // Invoke through interceptors
  532         return getInterceptor().invoke(mi);
  533      }
  534   
  535      // EJBObject implementation --------------------------------------
  536   
  537      public void remove(Invocation mi)
  538         throws RemoteException, RemoveException
  539      {
  540         // synchronize entities with the datastore before the bean is removed
  541         // this will write queued updates so datastore will be consistent before removal
  542         Transaction tx = mi.getTransaction();
  543         if (!getBeanMetaData().getContainerConfiguration().getSyncOnCommitOnly())
  544            synchronizeEntitiesWithinTransaction(tx);
  545   
  546         // Get the persistence manager to do the dirty work
  547         EntityEnterpriseContext ctx = (EntityEnterpriseContext)mi.getEnterpriseContext();
  548         getPersistenceManager().removeEntity(ctx);
  549   
  550         Object pk = ctx.getId();
  551         removeTimerService(pk);
  552   
  553         // We signify "removed" with a null id
  554         // There is no need to synchronize on the context since all the threads reaching here have
  555         // gone through the InstanceInterceptor so the instance is locked and we only have one thread
  556         // the case of reentrant threads is unclear (would you want to delete an instance in reentrancy)
  557         ctx.setId(null);
  558         removeCount++;
  559      }
  560   
  561      /**
  562       * @throws Error    Not yet implemented.
  563       */
  564      public Handle getHandle(Invocation mi)
  565         throws RemoteException
  566      {
  567         // TODO
  568         throw new Error("Not yet implemented");
  569      }
  570   
  571      public Object getPrimaryKey(Invocation mi)
  572         throws RemoteException
  573      {
  574         return mi.getId();
  575      }
  576   
  577      /**
  578       * @throws IllegalStateException     If container invoker is null.
  579       */
  580      public EJBHome getEJBHome(Invocation mi)
  581         throws RemoteException
  582      {
  583         EJBProxyFactory ci = getProxyFactory();
  584         if (ci == null)
  585         {
  586            String msg = "No ProxyFactory, check for ProxyFactoryFinderInterceptor";
  587            throw new IllegalStateException(msg);
  588         }
  589         return (EJBHome) ci.getEJBHome();
  590      }
  591   
  592      public boolean isIdentical(Invocation mi)
  593         throws RemoteException
  594      {
  595         EJBProxyFactory ci = getProxyFactory();
  596         if (ci == null)
  597         {
  598            String msg = "No ProxyFactory, check for ProxyFactoryFinderInterceptor";
  599            throw new IllegalStateException(msg);
  600         }
  601   
  602         return ci.isIdentical(this, mi);
  603      }
  604   
  605      /**
  606       * MF FIXME these are implemented on the client
  607       */
  608      public EJBLocalHome getEJBLocalHome(Invocation mi)
  609      {
  610         return localProxyFactory.getEJBLocalHome();
  611      }
  612   
  613      /**
  614       * @throws Error    Not yet implemented.
  615       */
  616      public void removeLocalHome(Invocation mi)
  617         throws RemoteException, RemoveException
  618      {
  619         throw new Error("Not Yet Implemented");
  620      }
  621   
  622      /**
  623       * Local home interface implementation
  624       */
  625      public EJBLocalObject createLocalHome(Invocation mi)
  626         throws Exception
  627      {
  628         // The persistence manager takes care of the wiring and creating the EJBLocalObject
  629         final EntityEnterpriseContext ctx = (EntityEnterpriseContext)mi.getEnterpriseContext();
  630         getPersistenceManager().createEntity(mi.getMethod(), mi.getArguments(), ctx);
  631   
  632         // The context implicitely carries the EJBObject
  633         createCount++;
  634         return localProxyFactory.getEntityEJBLocalObject(ctx.getId(), true);
  635      }
  636   
  637      /**
  638       * Delegates to the persistence manager postCreateEntityMethod.
  639       */
  640      public void postCreateLocalHome(Invocation mi) throws Exception
  641      {
  642         // The persistence manager takes care of the post create step
  643         getPersistenceManager().postCreateEntity(mi.getMethod(),mi.getArguments(),
  644            (EntityEnterpriseContext) mi.getEnterpriseContext());
  645      }
  646   
  647      public Object findLocal(Invocation mi)
  648         throws Exception
  649      {
  650         Method method = mi.getMethod();
  651         Object[] args = mi.getArguments();
  652         EntityEnterpriseContext instance = (EntityEnterpriseContext)mi.getEnterpriseContext();
  653   
  654         boolean syncOnCommitOnly = metaData.getContainerConfiguration().getSyncOnCommitOnly();
  655         Transaction tx = mi.getTransaction();
  656   
  657         Class returnType = method.getReturnType();
  658         if (Collection.class.isAssignableFrom(returnType) || returnType == Enumeration.class)
  659         {
  660            // as per the spec 9.6.4, entities must be synchronized with the datastore when an ejbFind<METHOD> is called.
  661            if (!syncOnCommitOnly)
  662            {
  663               synchronizeEntitiesWithinTransaction(tx);
  664            }
  665   
  666            // Iterator finder
  667            Collection c = getPersistenceManager().findEntities(method, args, instance, localProxyFactory);
  668   
  669            // BMP entity finder methods are allowed to return java.util.Enumeration.
  670            if (returnType == Enumeration.class)
  671            {
  672               return java.util.Collections.enumeration(c);
  673            }
  674            else
  675            {
  676               return c;
  677            }
  678         }
  679         else
  680         {
  681            return findSingleObject(tx, method, args, instance, localProxyFactory);
  682         }
  683      }
  684   
  685      // Home interface implementation ---------------------------------
  686   
  687      /**
  688       * This methods finds the target instances by delegating to the persistence
  689       * manager It then manufactures EJBObject for all the involved instances
  690       * found.
  691       */
  692      public Object find(Invocation mi) throws Exception
  693      {
  694         EJBProxyFactory ci = getProxyFactory();
  695         if (ci == null)
  696         {
  697            String msg = "No ProxyFactory, check for ProxyFactoryFinderInterceptor";
  698            throw new IllegalStateException(msg);
  699         }
  700   
  701         Method method = mi.getMethod();
  702         Object[] args = mi.getArguments();
  703         EntityEnterpriseContext instance = (EntityEnterpriseContext)mi.getEnterpriseContext();
  704   
  705         boolean syncOnCommitOnly = metaData.getContainerConfiguration().getSyncOnCommitOnly();
  706         Transaction tx = mi.getTransaction();
  707   
  708         Class returnType = method.getReturnType();
  709         if (Collection.class.isAssignableFrom(returnType) || returnType == Enumeration.class)
  710         {
  711            // as per the spec 9.6.4, entities must be synchronized with the datastore when an ejbFind<METHOD> is called.
  712            if (!syncOnCommitOnly)
  713            {
  714               synchronizeEntitiesWithinTransaction(tx);
  715            }
  716   
  717            // Iterator finder
  718            Collection c = getPersistenceManager().findEntities(method, args, instance, ci);
  719   
  720            // BMP entity finder methods are allowed to return java.util.Enumeration.
  721            // We need a serializable Enumeration, so we can't use Collections.enumeration()
  722            if (returnType == Enumeration.class)
  723            {
  724               return new SerializableEnumeration(c);
  725            }
  726            else
  727            {
  728               return c;
  729            }
  730         }
  731         else
  732         {
  733            return findSingleObject(tx, method, args, instance, ci);
  734         }
  735      }
  736   
  737      /**
  738       * Invokes ejbStore method on the instance
  739       * @param ctx  the instance to invoke ejbStore on
  740       * @throws Exception
  741       */
  742      public void invokeEjbStore(EntityEnterpriseContext ctx) throws Exception
  743      {
  744         if (ctx.getId() != null)
  745         {
  746            final EntityPersistenceManager pm = getPersistenceManager();
  747            pm.invokeEjbStore(ctx);
  748         }
  749      }
  750   
  751      /**
  752       * For CMP actually stores the instance
  753       */
  754      public void storeEntity(EntityEnterpriseContext ctx) throws Exception
  755      {
  756         if (ctx.getId() != null)
  757         {
  758            final EntityPersistenceManager pm = getPersistenceManager();
  759            if(pm.isStoreRequired(ctx))
  760            {
  761               pm.storeEntity(ctx);
  762            }
  763         }
  764      }
  765   
  766      /**
  767       * Delegates to the persistence manager postCreateEntityMethod.
  768       */
  769      public void postCreateHome(Invocation mi) throws Exception
  770      {
  771         // The persistence manager takes care of the post create step
  772         getPersistenceManager().postCreateEntity(mi.getMethod(),mi.getArguments(),
  773            (EntityEnterpriseContext) mi.getEnterpriseContext());
  774      }
  775   
  776      /**
  777       * This method takes care of the wiring of the "EJBObject" trio
  778       * (target, context, proxy).  It delegates to the persistence manager.
  779       */
  780      public EJBObject createHome(Invocation mi)
  781         throws Exception
  782      {
  783         // The persistence manager takes care of the wiring and creating the EJBObject
  784         getPersistenceManager().createEntity(mi.getMethod(),mi.getArguments(),
  785            (EntityEnterpriseContext) mi.getEnterpriseContext());
  786   
  787         // The context implicitely carries the EJBObject
  788         createCount++;
  789         return ((EntityEnterpriseContext)mi.getEnterpriseContext()).getEJBObject();
  790      }
  791   
  792      /**
  793       * A method for the getEJBObject from the handle
  794       */
  795      public EJBObject getEJBObject(Invocation mi)
  796         throws RemoteException
  797      {
  798         EJBProxyFactory ci = getProxyFactory();
  799         if (ci == null)
  800         {
  801            String msg = "No ProxyFactory, check for ProxyFactoryFinderInterceptor";
  802            throw new IllegalStateException(msg);
  803         }
  804         // All we need is an EJBObject for this Id;
  805         return (EJBObject)ci.getEntityEJBObject(((EntityCache) instanceCache).createCacheKey(mi.getId()));
  806      }
  807   
  808      // EJBHome implementation ----------------------------------------
  809   
  810      /**
  811       * @throws Error    Not yet implemented.
  812       */
  813      public void removeHome(Invocation mi)
  814         throws RemoteException, RemoveException
  815      {
  816         throw new Error("Not yet implemented");
  817      }
  818   
  819      public EJBMetaData getEJBMetaDataHome(Invocation mi)
  820         throws RemoteException
  821      {
  822         EJBProxyFactory ci = getProxyFactory();
  823         if (ci == null)
  824         {
  825            String msg = "No ProxyFactory, check for ProxyFactoryFinderInterceptor";
  826            throw new IllegalStateException(msg);
  827         }
  828         return ci.getEJBMetaData();
  829      }
  830   
  831      /**
  832       * @throws Error    Not yet implemented.
  833       */
  834      public HomeHandle getHomeHandleHome(Invocation mi)
  835         throws RemoteException
  836      {
  837         // TODO
  838         throw new Error("Not yet implemented");
  839      }
  840   
  841      /**
  842       * @jmx.managed-attribute
  843       * @return the current cache size
  844       */
  845      public long getCacheSize()
  846      {
  847         return instanceCache.getCacheSize();
  848      }
  849   
  850      /** Flush the cache
  851       * @jmx.managed-operation
  852       */
  853      public void flushCache()
  854      {
  855         instanceCache.flush();
  856      }
  857   
  858      // StatisticsProvider implementation ------------------------------------
  859   
  860      public Map retrieveStatistic()
  861      {
  862         // Loop through all Interceptors and add statistics
  863         Map lStatistics = new HashMap();
  864         StatisticsProvider lProvider = (StatisticsProvider) getPersistenceManager();
  865         lStatistics.putAll( lProvider.retrieveStatistic() );
  866         lProvider = (StatisticsProvider) getInstancePool();
  867         lStatistics.putAll( lProvider.retrieveStatistic() );
  868         return lStatistics;
  869      }
  870   
  871      public void resetStatistic()
  872      {
  873      }
  874   
  875      // Private -------------------------------------------------------
  876   
  877      private void setupHomeMappingImpl(Method[] m,
  878                                        String finderName,
  879                                        String append)
  880         throws Exception
  881      {
  882         // Adrian Brock: This should go away when we don't support EJB1x
  883         boolean isEJB1x = metaData.getApplicationMetaData().isEJB1x();
  884   
  885         for (int i = 0; i < m.length; i++)
  886         {
  887            String methodName = m[i].getName();
  888            try
  889            {
  890               try // Try home method
  891               {
  892                  String ejbHomeMethodName = "ejbHome" + methodName.substring(0,1).toUpperCase() + methodName.substring(1);
  893                  homeMapping.put(m[i], beanClass.getMethod(ejbHomeMethodName, m[i].getParameterTypes()));
  894   
  895                  continue;
  896               }
  897               catch (NoSuchMethodException ignore) {} // just go on with other types of methods
  898   
  899   
  900               // Implemented by container (in both cases)
  901               if (methodName.startsWith("find"))
  902               {
  903                  homeMapping.put(m[i], this.getClass().getMethod(finderName, new Class[] { Invocation.class }));
  904               }
  905               else if (methodName.equals("create") ||
  906                     (isEJB1x == false && methodName.startsWith("create")))
  907               {
  908                  homeMapping.put(m[i], this.getClass().getMethod("create"+append, new Class[] { Invocation.class }));
  909                  beanMapping.put(m[i], this.getClass().getMethod("postCreate"+append, new Class[] { Invocation.class }));
  910               }
  911               else
  912               {
  913                  homeMapping.put(m[i], this.getClass().getMethod(methodName+append, new Class[] { Invocation.class }));
  914               }
  915            }
  916            catch (NoSuchMethodException e)
  917            {
  918               throw new NoSuchMethodException("Could not find matching method for "+m[i]);
  919            }
  920         }
  921      }
  922   
  923      protected void setupHomeMapping() throws Exception
  924      {
  925         try {
  926            if (homeInterface != null)
  927            {
  928               Method[] m = homeInterface.getMethods();
  929               setupHomeMappingImpl( m, "find", "Home" );
  930            }
  931            if (localHomeInterface != null)
  932            {
  933               Method[] m = localHomeInterface.getMethods();
  934               setupHomeMappingImpl( m, "findLocal", "LocalHome" );
  935            }
  936   
  937            // Special methods
  938   
  939            // Get the One on Handle (getEJBObject), get the class
  940            Class handleClass = Class.forName("javax.ejb.Handle");
  941   
  942            // Get the methods (there is only one)
  943            Method[] handleMethods = handleClass.getMethods();
  944   
  945            //Just to make sure let's iterate
  946            for (int j=0; j<handleMethods.length ;j++)
  947            {
  948               //Get only the one called handle.getEJBObject
  949               if (handleMethods[j].getName().equals("getEJBObject"))
  950               {
  951                  //Map it in the home stuff
  952                  homeMapping.put(handleMethods[j],
  953                                  this.getClass().getMethod("getEJBObject",
  954                                                            new Class[] {Invocation.class}));
  955               }
  956            }
  957         }
  958         catch (Exception e)
  959         {
  960            // ditch the half built mappings
  961            homeMapping.clear();
  962            beanMapping.clear();
  963   
  964            throw e;
  965         }
  966      }
  967   
  968      private void setupBeanMappingImpl( Method[] m, String intfName )
  969         throws Exception
  970      {
  971         for (int i = 0; i < m.length; i++)
  972         {
  973            if (!m[i].getDeclaringClass().getName().equals(intfName))
  974            {
  975               // Implemented by bean
  976               beanMapping.put(m[i], beanClass.getMethod(m[i].getName(), m[i].getParameterTypes()));
  977            }
  978            else
  979            {
  980               // Implemented by container
  981               beanMapping.put(m[i], getClass().getMethod(m[i].getName(),
  982                                                          new Class[] { Invocation.class }));
  983            }
  984         }
  985      }
  986   
  987      protected void setupBeanMapping() throws Exception
  988      {
  989         try {
  990            if (remoteInterface != null)
  991            {
  992               Method[] m = remoteInterface.getMethods();
  993               setupBeanMappingImpl( m, "javax.ejb.EJBObject" );
  994            }
  995            if (localInterface != null)
  996            {
  997               Method[] m = localInterface.getMethods();
  998               setupBeanMappingImpl( m, "javax.ejb.EJBLocalObject" );
  999            }
 1000            if( TimedObject.class.isAssignableFrom( beanClass ) ) {
 1001                // Map ejbTimeout
 1002                beanMapping.put(
 1003                   TimedObject.class.getMethod( "ejbTimeout", new Class[] { Timer.class } ),
 1004                   beanClass.getMethod( "ejbTimeout", new Class[] { Timer.class } )
 1005                );
 1006            }
 1007         }
 1008         catch (Exception e)
 1009         {
 1010            // ditch the half built mappings
 1011            homeMapping.clear();
 1012            beanMapping.clear();
 1013   
 1014            throw e;
 1015         }
 1016      }
 1017   
 1018      protected void setupMarshalledInvocationMapping() throws Exception
 1019      {
 1020         // Create method mappings for container invoker
 1021         if (homeInterface != null)
 1022         {
 1023            Method [] m = homeInterface.getMethods();
 1024            for (int i = 0 ; i<m.length ; i++)
 1025            {
 1026               marshalledInvocationMapping.put( new Long(MarshalledInvocation.calculateHash(m[i])), m[i]);
 1027            }
 1028         }
 1029   
 1030         if (remoteInterface != null)
 1031         {
 1032            Method [] m = remoteInterface.getMethods();
 1033            for (int j = 0 ; j<m.length ; j++)
 1034            {
 1035               marshalledInvocationMapping.put( new Long(MarshalledInvocation.calculateHash(m[j])), m[j]);
 1036            }
 1037         }
 1038   
 1039         // Get the getEJBObjectMethod
 1040         Method getEJBObjectMethod = Class.forName("javax.ejb.Handle").getMethod("getEJBObject", new Class[0]);
 1041   
 1042         // Hash it
 1043         marshalledInvocationMapping.put(new Long(MarshalledInvocation.calculateHash(getEJBObjectMethod)),getEJBObjectMethod);
 1044      }
 1045   
 1046      Interceptor createContainerInterceptor()
 1047      {
 1048         return new ContainerInterceptor();
 1049      }
 1050   
 1051      protected void checkCoherency () throws Exception
 1052      {
 1053         // Check clustering cohrency wrt metadata
 1054         //
 1055         if (metaData.isClustered())
 1056         {
 1057            boolean clusteredProxyFactoryFound = false;
 1058            for (Iterator it = proxyFactories.keySet().iterator(); it.hasNext(); )
 1059            {
 1060               String invokerBinding = (String)it.next();
 1061               EJBProxyFactory ci = (EJBProxyFactory)proxyFactories.get(invokerBinding);
 1062               if (ci instanceof org.jboss.proxy.ejb.ClusterProxyFactory)
 1063                  clusteredProxyFactoryFound = true;
 1064            }
 1065   
 1066            if (!clusteredProxyFactoryFound)
 1067            {
 1068               log.warn("*** EJB '" + this.metaData.getEjbName() + "' deployed as CLUSTERED but not a single clustered-invoker is bound to container ***");
 1069            }
 1070         }
 1071      }
 1072   
 1073      private Object findSingleObject(Transaction tx,
 1074                                      Method method,
 1075                                      Object[] args,
 1076                                      EntityEnterpriseContext instance,
 1077                                      GenericEntityObjectFactory factory)
 1078         throws Exception
 1079      {
 1080         if(method.getName().equals("findByPrimaryKey"))
 1081         {
 1082            if(args[0] == null)
 1083               throw new IllegalArgumentException("findByPrimaryKey called with null argument.");
 1084   
 1085            if(metaData.getContainerConfiguration().getCommitOption() != ConfigurationMetaData.B_COMMIT_OPTION)
 1086            {
 1087               Object key = instance.getCacheKey();
 1088               if(key == null)
 1089               {
 1090                  key = ((EntityCache)instanceCache).createCacheKey(args[0]);
 1091               }
 1092   
 1093               if(instanceCache.isActive(key))
 1094               {
 1095                  return factory.getEntityEJBObject(key);
 1096               }
 1097            }
 1098         }
 1099         else if(!metaData.getContainerConfiguration().getSyncOnCommitOnly())
 1100         {
 1101            EntityContainer.synchronizeEntitiesWithinTransaction(tx);
 1102         }
 1103   
 1104         return getPersistenceManager().findEntity(method, args, instance, factory);
 1105      }
 1106   
 1107      // Inner classes -------------------------------------------------
 1108   
 1109      /**
 1110       * This is the last step before invocation - all interceptors are done
 1111       */
 1112      class ContainerInterceptor
 1113         extends AbstractContainerInterceptor
 1114      {
 1115         public Object invokeHome(Invocation mi) throws Exception
 1116         {
 1117            // Invoke and handle exceptions
 1118            Method miMethod = mi.getMethod();
 1119            Method m = (Method) homeMapping.get(miMethod);
 1120            if( m == null )
 1121            {
 1122               String msg = "Invalid invocation, check your deployment packaging"
 1123                  +", method="+miMethod;
 1124               throw new EJBException(msg);
 1125            }
 1126   
 1127            if (m.getDeclaringClass().equals(EntityContainer.class))
 1128            {
 1129               try
 1130               {
 1131                  return mi.performCall(EntityContainer.this, m, new Object[] { mi });
 1132               }
 1133               catch (Exception e)
 1134               {
 1135                  rethrow(e);
 1136               }
 1137            }
 1138            else // Home method
 1139            {
 1140               EnterpriseContext ctx = (EnterpriseContext) mi.getEnterpriseContext();
 1141               try
 1142               {
 1143                  AllowedOperationsAssociation.pushInMethodFlag(AllowedOperationsAssociation.IN_EJB_HOME);
 1144                  return mi.performCall(ctx.getInstance(), m, mi.getArguments());
 1145               }
 1146               catch (Exception e)
 1147               {
 1148                  rethrow(e);
 1149               }
 1150               finally{
 1151                  AllowedOperationsAssociation.popInMethodFlag();
 1152               }
 1153            }
 1154   
 1155            // We will never get this far, but the compiler does not know that
 1156            throw new org.jboss.util.UnreachableStatementException();
 1157         }
 1158   
 1159         public Object invoke(Invocation mi) throws Exception
 1160         {
 1161            // Get method
 1162            Method miMethod = mi.getMethod();
 1163            Method m = (Method) beanMapping.get(miMethod);
 1164            if( m == null )
 1165            {
 1166               String msg = "Invalid invocation, check your deployment packaging"
 1167                  +", method="+miMethod;
 1168               throw new EJBException(msg);
 1169            }
 1170   
 1171            // Select instance to invoke (container or bean)
 1172            if (m.getDeclaringClass().equals(EntityContainer.class))
 1173            {
 1174               // Invoke container
 1175               try
 1176               {
 1177                  return mi.performCall(EntityContainer.this, m, new Object[]{ mi });
 1178               }
 1179               catch (Exception e)
 1180               {
 1181                  rethrow(e);
 1182               }
 1183            }
 1184            else
 1185            {
 1186               // Invoke bean instance
 1187               try
 1188               {
 1189                  EnterpriseContext ctx = (EnterpriseContext) mi.getEnterpriseContext();
 1190                  Object instance = ctx.getInstance();
 1191   
 1192                  return mi.performCall(instance, m, mi.getArguments());
 1193               }
 1194               catch (Exception e)
 1195               {
 1196                  rethrow(e);
 1197               }
 1198            }
 1199   
 1200            // We will never get this far, but the compiler does not know that
 1201            throw new org.jboss.util.UnreachableStatementException();
 1202         }
 1203      }
 1204   }

Save This Page
Home » jboss-5.0.0.CR1-src » org » jboss » ejb » [javadoc | source]