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.util.HashMap;
   26   import java.util.Hashtable;
   27   import java.util.Iterator;
   28   import java.util.Map;
   29   
   30   import javax.ejb.CreateException;
   31   import javax.ejb.EJBMetaData;
   32   import javax.ejb.EJBObject;
   33   import javax.ejb.Handle;
   34   import javax.ejb.HomeHandle;
   35   import javax.ejb.RemoveException;
   36   import javax.ejb.TimedObject;
   37   import javax.ejb.Timer;
   38   import javax.ejb.EJBException;
   39   import javax.management.ObjectName;
   40   
   41   import org.jboss.invocation.Invocation;
   42   import org.jboss.metadata.MessageDrivenMetaData;
   43   import org.jboss.util.NullArgumentException;
   44   
   45   /**
   46    * The container for <em>MessageDriven</em> beans.
   47    *
   48    * @author <a href="mailto:peter.antman@tim.se">Peter Antman</a>.
   49    * @author <a href="mailto:rickard.oberg@telkel.com">Rickard Oberg</a>
   50    * @author <a href="mailto:marc.fleury@telkel.com">Marc Fleury</a>
   51    * @author <a href="mailto:docodan@mvcsoft.com">Daniel OConnor</a>
   52    * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
   53    * @author <a href="mailto:Scott.Stark@jboss.org">Scott Stark</a>
   54    * @version $Revision: 66439 $
   55    *
   56    * @jmx:mbean extends="org.jboss.ejb.ContainerMBean"
   57    */
   58   public class MessageDrivenContainer
   59         extends Container
   60         implements EJBProxyFactoryContainer, InstancePoolContainer, MessageDrivenContainerMBean
   61   {
   62      /**
   63       * These are the mappings between the remote interface methods
   64       * and the bean methods.
   65       */
   66      protected Map beanMapping;
   67   
   68      /** This is the instancepool that is to be used. */
   69      protected InstancePool instancePool;
   70   
   71      /**
   72       * This is the first interceptor in the chain.
   73       * The last interceptor must be provided by the container itself.
   74       */
   75      protected Interceptor interceptor;
   76   
   77      protected long messageCount;
   78   
   79      public LocalProxyFactory getLocalProxyFactory()
   80      {
   81         return localProxyFactory;
   82      }
   83   
   84      public void setInstancePool(final InstancePool instancePool)
   85      {
   86         if (instancePool == null)
   87            throw new NullArgumentException("instancePool");
   88   
   89         this.instancePool = instancePool;
   90         this.instancePool.setContainer(this);
   91      }
   92   
   93      public InstancePool getInstancePool()
   94      {
   95         return instancePool;
   96      }
   97   
   98      public void addInterceptor(Interceptor in)
   99      {
  100         if (interceptor == null)
  101         {
  102            interceptor = in;
  103         }
  104         else
  105         {
  106            Interceptor current = interceptor;
  107   
  108            while (current.getNext() != null)
  109            {
  110               current = current.getNext();
  111            }
  112   
  113            current.setNext(in);
  114         }
  115      }
  116   
  117      public Interceptor getInterceptor()
  118      {
  119         return interceptor;
  120      }
  121   
  122      /**
  123       * @jmx:managed-attribute
  124       * @return the number of messages delivered
  125       */
  126      public long getMessageCount()
  127      {
  128         return messageCount;
  129      }
  130   
  131      /**
  132       * EJBProxyFactoryContainer - not needed, should we skip inherit this
  133       * or just throw Error??
  134       */
  135      public Class getHomeClass()
  136      {
  137         //throw new Error("HomeClass not valid for MessageDriven beans");
  138         return null;
  139      }
  140   
  141      public Class getRemoteClass()
  142      {
  143         //throw new Error("RemoteClass not valid for MessageDriven beans");
  144         return null;
  145      }
  146   
  147      public Class getLocalClass()
  148      {
  149         return null;
  150      }
  151   
  152      public Class getLocalHomeClass()
  153      {
  154         //throw new Error("LocalHomeClass not valid for MessageDriven beans");
  155         return null;
  156      }
  157   
  158      // Container implementation - overridden here ----------------------
  159   
  160      protected void createService() throws Exception
  161      {
  162         // Associate thread with classloader
  163         ClassLoader oldCl = SecurityActions.getContextClassLoader();
  164         SecurityActions.setContextClassLoader(getClassLoader());
  165         pushENC();
  166         try
  167         {
  168            // Call default init
  169            super.createService();
  170   
  171            // Map the bean methods
  172            Map map = new HashMap();
  173            MessageDrivenMetaData mdMetaData = (MessageDrivenMetaData)metaData;
  174            String type = mdMetaData.getMessagingType();
  175            if(type == null || type.length() == 0)
  176               type = MessageDrivenMetaData.DEFAULT_MESSAGING_TYPE;
  177            Class clazz = getClassLoader().loadClass(type);
  178            Method[] methods = clazz.getDeclaredMethods();
  179            for (int i = 0; i < methods.length; i++)
  180            {
  181               Method m = methods[i];
  182               map.put(m, beanClass.getMethod(m.getName(), m.getParameterTypes()));
  183               log.debug("Mapped " + m.getName() + " " + m.hashCode() + " to " + map.get(m));
  184            }
  185            if( TimedObject.class.isAssignableFrom( beanClass ) ) {
  186                // Map ejbTimeout
  187                map.put(
  188                   TimedObject.class.getMethod( "ejbTimeout", new Class[] { Timer.class } ),
  189                   beanClass.getMethod( "ejbTimeout", new Class[] { Timer.class } )
  190                );
  191            }
  192            beanMapping = map;
  193   
  194            // Try to register the instance pool as an MBean
  195            try
  196            {
  197               ObjectName containerName = super.getJmxName();
  198               Hashtable props = containerName.getKeyPropertyList();
  199               props.put("plugin", "pool");
  200               ObjectName poolName = new ObjectName(containerName.getDomain(), props);
  201               server.registerMBean(instancePool, poolName);
  202            }
  203            catch(Throwable t)
  204            {
  205               log.debug("Failed to register pool as mbean", t);
  206            }
  207            // Initialize pool
  208            instancePool.create();
  209   
  210            for (Iterator it = proxyFactories.keySet().iterator(); it.hasNext();)
  211            {
  212               String invokerBinding = (String) it.next();
  213               EJBProxyFactory ci = (EJBProxyFactory) proxyFactories.get(invokerBinding);
  214               // Try to register the container invoker as an MBean
  215               try
  216               {
  217                  ObjectName containerName = super.getJmxName();
  218                  Hashtable props = containerName.getKeyPropertyList();
  219                  props.put("plugin", "invoker");
  220                  props.put("binding", invokerBinding);
  221                  ObjectName invokerName = new ObjectName(containerName.getDomain(), props);
  222                  server.registerMBean(ci, invokerName);
  223               }
  224               catch(Throwable t)
  225               {
  226                  log.debug("Failed to register invoker binding as mbean", t);
  227               }
  228               ci.create();
  229            }
  230   
  231            // Initialize the interceptor by calling the chain
  232            Interceptor in = interceptor;
  233            while (in != null)
  234            {
  235               in.setContainer(this);
  236               in.create();
  237               in = in.getNext();
  238            }
  239   
  240         }
  241         finally
  242         {
  243            popENC();
  244            // Reset classloader
  245            SecurityActions.setContextClassLoader(oldCl);
  246         }
  247      }
  248   
  249      protected void startService() throws Exception
  250      {
  251         // Associate thread with classloader
  252         ClassLoader oldCl = SecurityActions.getContextClassLoader();
  253         SecurityActions.setContextClassLoader(getClassLoader());
  254         pushENC();
  255         try
  256         {
  257            // Call default start
  258            super.startService();
  259   
  260            // Start the instance pool
  261            instancePool.start();
  262   
  263            // Start all interceptors in the chain
  264            Interceptor in = interceptor;
  265            while (in != null)
  266            {
  267               in.start();
  268               in = in.getNext();
  269            }
  270   
  271            // Start container invoker
  272            for (Iterator it = proxyFactories.keySet().iterator(); it.hasNext();)
  273            {
  274               String invokerBinding = (String) it.next();
  275               EJBProxyFactory ci = (EJBProxyFactory) proxyFactories.get(invokerBinding);
  276               ci.start();
  277            }
  278            
  279            // Restore persisted ejb timers
  280            restoreTimers();         
  281         }
  282         finally
  283         {
  284            popENC();
  285            // Reset classloader
  286            SecurityActions.setContextClassLoader(oldCl);
  287         }
  288      }
  289   
  290      protected void stopService() throws Exception
  291      {
  292         // Associate thread with classloader
  293         ClassLoader oldCl = SecurityActions.getContextClassLoader();
  294         SecurityActions.setContextClassLoader(getClassLoader());
  295         pushENC();
  296         try
  297         {
  298            // Call default stop
  299            super.stopService();
  300   
  301            // Stop container invoker
  302            for (Iterator it = proxyFactories.keySet().iterator(); it.hasNext();)
  303            {
  304               String invokerBinding = (String) it.next();
  305               EJBProxyFactory ci = (EJBProxyFactory) proxyFactories.get(invokerBinding);
  306               ci.stop();
  307            }
  308   
  309            // Stop the instance pool
  310            instancePool.stop();
  311   
  312            // Stop all interceptors in the chain
  313            Interceptor in = interceptor;
  314            while (in != null)
  315            {
  316               in.stop();
  317               in = in.getNext();
  318            }
  319         }
  320         finally
  321         {
  322            popENC();
  323            // Reset classloader
  324            SecurityActions.setContextClassLoader(oldCl);
  325         }
  326      }
  327   
  328      protected void destroyService() throws Exception
  329      {
  330         // Associate thread with classloader
  331         ClassLoader oldCl = SecurityActions.getContextClassLoader();
  332         SecurityActions.setContextClassLoader(getClassLoader());
  333         pushENC();
  334         try
  335         {
  336            // Destroy container invoker
  337            for (Iterator it = proxyFactories.keySet().iterator(); it.hasNext();)
  338            {
  339               String invokerBinding = (String) it.next();
  340               EJBProxyFactory ci = (EJBProxyFactory) proxyFactories.get(invokerBinding);
  341               ci.destroy();
  342               ci.setContainer(null);
  343               try
  344               {
  345                  ObjectName containerName = super.getJmxName();
  346                  Hashtable props = containerName.getKeyPropertyList();
  347                  props.put("plugin", "invoker");
  348                  props.put("binding", invokerBinding);
  349                  ObjectName invokerName = new ObjectName(containerName.getDomain(), props);
  350                  server.unregisterMBean(invokerName);
  351               }
  352               catch(Throwable ignore)
  353               {
  354               }
  355            }
  356   
  357            // Destroy the pool
  358            instancePool.destroy();
  359            instancePool.setContainer(null);
  360            try
  361            {
  362               ObjectName containerName = super.getJmxName();
  363               Hashtable props = containerName.getKeyPropertyList();
  364               props.put("plugin", "pool");
  365               ObjectName poolName = new ObjectName(containerName.getDomain(), props);
  366               server.unregisterMBean(poolName);
  367            }
  368            catch(Throwable ignore)
  369            {
  370            }
  371   
  372            // Destroy all the interceptors in the chain
  373            Interceptor in = interceptor;
  374            while (in != null)
  375            {
  376               in.destroy();
  377               in.setContainer(null);
  378               in = in.getNext();
  379            }
  380   
  381            // Call default destroy
  382            super.destroyService();
  383         }
  384         finally
  385         {
  386            popENC();
  387            // Reset classloader
  388            SecurityActions.setContextClassLoader(oldCl);
  389         }
  390      }
  391   
  392      /**
  393       * @throws Error   Not valid for MDB
  394       */
  395      public Object internalInvokeHome(Invocation mi)
  396            throws Exception
  397      {
  398         throw new Error("invokeHome not valid for MessageDriven beans");
  399      }
  400   
  401      /**
  402       * This method does invocation interpositioning of tx and security,
  403       * retrieves the instance from an object table, and invokes the method
  404       * on the particular instance
  405       */
  406      public Object internalInvoke(Invocation mi) throws Exception
  407      {
  408         // Invoke through interceptors
  409         return getInterceptor().invoke(mi); 
  410      }
  411   
  412   
  413      // EJBHome implementation ----------------------------------------
  414   
  415      public EJBObject createHome()
  416            throws java.rmi.RemoteException, CreateException
  417      {
  418         throw new Error("createHome not valid for MessageDriven beans");
  419      }
  420   
  421   
  422      public void removeHome(Handle handle)
  423            throws java.rmi.RemoteException, RemoveException
  424      {
  425         throw new Error("removeHome not valid for MessageDriven beans");
  426         // TODO
  427      }
  428   
  429      public void removeHome(Object primaryKey)
  430            throws java.rmi.RemoteException, RemoveException
  431      {
  432         throw new Error("removeHome not valid for MessageDriven beans");
  433         // TODO
  434      }
  435   
  436      public EJBMetaData getEJBMetaDataHome()
  437            throws java.rmi.RemoteException
  438      {
  439         // TODO
  440         //return null;
  441         throw new Error("getEJBMetaDataHome not valid for MessageDriven beans");
  442      }
  443   
  444      public HomeHandle getHomeHandleHome()
  445            throws java.rmi.RemoteException
  446      {
  447         // TODO
  448         //return null;
  449         throw new Error("getHomeHandleHome not valid for MessageDriven beans");
  450      }
  451   
  452      Interceptor createContainerInterceptor()
  453      {
  454         return new ContainerInterceptor();
  455      }
  456   
  457      /**
  458       * This is the last step before invocation - all interceptors are done
  459       */
  460      class ContainerInterceptor
  461            extends AbstractContainerInterceptor
  462      {
  463         /**
  464          * @throws Error   Not valid for MDB
  465          */
  466         public Object invokeHome(Invocation mi) throws Exception
  467         {
  468            throw new Error("invokeHome not valid for MessageDriven beans");
  469         }
  470   
  471         /**
  472          * FIXME Design problem, who will do the acknowledging for
  473          * beans with bean managed transaction?? Probably best done in the
  474          * listener "proxys"
  475          */
  476         public Object invoke(Invocation mi)
  477               throws Exception
  478         {
  479            EnterpriseContext ctx = (EnterpriseContext) mi.getEnterpriseContext();
  480   
  481            // wire the transaction on the context,
  482            // this is how the instance remember the tx
  483            if (ctx.getTransaction() == null)
  484            {
  485               ctx.setTransaction(mi.getTransaction());
  486            }
  487   
  488            // Get method and instance to invoke upon
  489            Method m = (Method) beanMapping.get(mi.getMethod());
  490            if( m == null )
  491            {
  492               // This is a configuration error that should have been caught earlier
  493               String msg = MessageDrivenContainer.this.getBeanMetaData().getEjbName()
  494                  + " Invalid invocation, check your deployment packaging, interfaces, method=" + mi.getMethod();
  495               throw new EJBException(msg);
  496            }
  497   
  498            // we have a method that needs to be done by a bean instance
  499            try
  500            {
  501               messageCount++;
  502               return mi.performCall(ctx.getInstance(), m, mi.getArguments());
  503            }
  504            catch (Exception e)
  505            {
  506               rethrow(e);
  507            }
  508   
  509            // We will never get this far, but the compiler does not know that
  510            throw new org.jboss.util.UnreachableStatementException();
  511         }
  512      }
  513   }

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