Save This Page
Home » jboss-5.0.0.CR1-src » org » jboss » ejb » plugins » [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.plugins;
   23   
   24   import java.rmi.RemoteException;
   25   import java.util.LinkedList;
   26   import java.lang.reflect.UndeclaredThrowableException;
   27   import javax.ejb.EJBException;
   28   import javax.ejb.CreateException;
   29   
   30   import org.jboss.ejb.Container;
   31   import org.jboss.ejb.InstancePool;
   32   import org.jboss.ejb.EnterpriseContext;
   33   
   34   import org.jboss.deployment.DeploymentException;
   35   import org.jboss.metadata.MetaData;
   36   import org.jboss.metadata.XmlLoadable;
   37   import org.jboss.system.ServiceMBeanSupport;
   38   
   39   import org.w3c.dom.Element;
   40   import EDU.oswego.cs.dl.util.concurrent.FIFOSemaphore;
   41   
   42   /**
   43    *  Abstract Instance Pool class containing the basic logic to create
   44    *  an EJB Instance Pool.
   45    *
   46    *  @author <a href="mailto:rickard.oberg@telkel.com">Rickard Oberg</a>
   47    *  @author <a href="mailto:marc.fleury@jboss.org">Marc Fleury</a>
   48    *  @author <a href="mailto:andreas.schaefer@madplanet.com">Andreas Schaefer</a>
   49    *  @author <a href="mailto:sacha.labourey@cogito-info.ch">Sacha Labourey</a>
   50    *  @author <a href="mailto:scott.stark@jboss.org">Scott Stark/a>
   51    *  @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
   52    *  @version $Revision: 38303 $
   53    *
   54    * @jmx:mbean extends="org.jboss.system.ServiceMBean"
   55    */
   56   public abstract class AbstractInstancePool
   57      extends ServiceMBeanSupport
   58      implements AbstractInstancePoolMBean, InstancePool, XmlLoadable
   59   {
   60      // Constants -----------------------------------------------------
   61   
   62      // Attributes ----------------------------------------------------
   63      /** A FIFO semaphore that is set when the strict max size behavior is in effect.
   64       When set, only maxSize instances may be active and any attempt to get an
   65       instance will block until an instance is freed.
   66       */
   67      private FIFOSemaphore strictMaxSize;
   68      /** The time in milliseconds to wait for the strictMaxSize semaphore.
   69       */
   70      private long strictTimeout = Long.MAX_VALUE;
   71      /** The Container the instance pool is associated with */
   72      protected Container container;
   73      /** The pool data structure */
   74      protected LinkedList pool = new LinkedList();
   75      /** The maximum number of instances allowed in the pool */
   76      protected int maxSize = 30;
   77      /** determine if we reuse EnterpriseContext objects i.e. if we actually do pooling */
   78      protected boolean reclaim = false;
   79   
   80   
   81      // Static --------------------------------------------------------
   82   
   83      // Constructors --------------------------------------------------
   84   
   85      // Public --------------------------------------------------------
   86   
   87      /**
   88       *   Set the callback to the container. This is for initialization.
   89       *   The IM may extract the configuration from the container.
   90       *
   91       * @param   c
   92       */
   93      public void setContainer(Container c)
   94      {
   95         this.container = c;
   96      }
   97   
   98      /**
   99       * @return Callback to the container which can be null if not set proviously
  100       */
  101      public Container getContainer()
  102      {
  103         return container;
  104      }
  105   
  106      /**
  107       * @jmx:managed-attribute
  108       * @return the current pool size
  109       */
  110      public int getCurrentSize()
  111      {
  112         synchronized (pool)
  113         {
  114            return this.pool.size();
  115         }
  116      }
  117   
  118      /**
  119       * @jmx:managed-attribute
  120       * @return the current pool size
  121       */
  122      public int getMaxSize()
  123      {
  124         return this.maxSize;
  125      }
  126   
  127      /** Get the current avaiable count from the strict max view. If there is
  128       * no strict max then this will be Long.MAX_VALUE to indicate there is no
  129       * restriction.
  130       * @jmx:managed-attribute
  131       * @return the current avaiable count from the strict max view
  132       */
  133      public long getAvailableCount()
  134      {
  135         long size = Long.MAX_VALUE;
  136         if( strictMaxSize != null )
  137            size = strictMaxSize.permits();
  138         return size;
  139      }
  140   
  141      /**
  142       *   Get an instance without identity.
  143       *   Can be used by finders,create-methods, and activation
  144       *
  145       * @return     Context /w instance
  146       * @exception   RemoteException
  147       */
  148      public EnterpriseContext get()
  149         throws Exception
  150      {
  151         boolean trace = log.isTraceEnabled();
  152         if( trace )
  153            log.trace("Get instance "+this+"#"+pool.size()+"#"+getContainer().getBeanClass());
  154   
  155         if( strictMaxSize != null )
  156         {
  157            // Block until an instance is available
  158            boolean acquired = strictMaxSize.attempt(strictTimeout);
  159            if( trace )
  160               log.trace("Acquired("+acquired+") strictMaxSize semaphore, remaining="+strictMaxSize.permits());
  161            if( acquired == false )
  162               throw new EJBException("Failed to acquire the pool semaphore, strictTimeout="+strictTimeout);
  163         }
  164   
  165         synchronized (pool)
  166         {
  167            if ( pool.isEmpty() == false )
  168            {
  169               return (EnterpriseContext) pool.removeFirst();
  170            }
  171         }
  172   
  173         // Pool is empty, create an instance
  174         try
  175         {
  176            Object instance = container.createBeanClassInstance();
  177            return create(instance);
  178         }
  179         catch (Throwable e)
  180         {
  181            // Release the strict max size mutex if it exists
  182            if( strictMaxSize != null )
  183            {
  184               strictMaxSize.release();
  185            }
  186            // Don't wrap CreateExceptions
  187            if( e instanceof CreateException )
  188               throw (CreateException) e;
  189   
  190            // Wrap e in an Exception if needed
  191            Exception ex = null;
  192            if(e instanceof Exception)
  193            {
  194               ex = (Exception)e;
  195            } else
  196            {
  197               ex = new UndeclaredThrowableException(e);
  198            }
  199            throw new EJBException("Could not instantiate bean", ex);
  200         }
  201      }
  202   
  203      /**
  204       *   Return an instance after invocation.
  205       *
  206       *   Called in 2 cases:
  207       *   a) Done with finder method
  208       *   b) Just removed
  209       *
  210       * @param   ctx
  211       */
  212      public void free(EnterpriseContext ctx)
  213      {
  214         if( log.isTraceEnabled() )
  215         {
  216            String msg = pool.size() + "/" + maxSize+" Free instance:"+this
  217               +"#"+ctx.getId()
  218               +"#"+ctx.getTransaction()
  219               +"#"+reclaim
  220               +"#"+getContainer().getBeanClass();
  221            log.trace(msg);
  222         }
  223   
  224         ctx.clear();
  225   
  226         try
  227         {
  228            // If the pool is not full, add the unused context back into the pool,
  229            // otherwise, just discard the extraneous context and leave it for GC
  230            boolean addedToPool = false;
  231            
  232            synchronized (pool)
  233            {
  234               if (pool.size() < maxSize)
  235               {
  236                  pool.addFirst(ctx);
  237                  addedToPool = true;
  238               }
  239            }
  240            
  241            if (addedToPool)
  242            {
  243               // If we block when maxSize instances are in use, invoke release on strictMaxSize
  244               if(strictMaxSize != null)
  245               {
  246                  strictMaxSize.release();
  247               }
  248            }
  249            else
  250            {
  251               // Get rid of the extraneous instance; strictMaxSize should be null
  252               // (otherwise we wouldn't have gotten the extra instance)
  253               discard(ctx);
  254            }
  255         }
  256         catch (Exception ignored)
  257         {
  258         }
  259      }
  260   
  261      public void discard(EnterpriseContext ctx)
  262      {
  263         if( log.isTraceEnabled() )
  264         {
  265            String msg = "Discard instance:"+this+"#"+ctx
  266               +"#"+ctx.getTransaction()
  267               +"#"+reclaim
  268               +"#"+getContainer().getBeanClass();
  269            log.trace(msg);
  270         }
  271   
  272         // If we block when maxSize instances are in use, invoke release on strictMaxSize
  273         if( strictMaxSize != null )
  274            strictMaxSize.release();
  275   
  276         // Throw away, unsetContext()
  277         try
  278         {
  279            ctx.discard();
  280         }
  281         catch (RemoteException e)
  282         {
  283            if( log.isTraceEnabled() )
  284               log.trace("Ctx.discard error", e);
  285         }
  286      }
  287   
  288      public void clear()
  289      {
  290         synchronized (pool)
  291         {
  292            freeAll();
  293         }
  294      }
  295   
  296      /**
  297       * XmlLoadable implementation
  298       */
  299      public void importXml(Element element) throws DeploymentException
  300      {
  301         String maximumSize = MetaData.getElementContent(MetaData.getUniqueChild(element, "MaximumSize"));
  302         try
  303         {
  304            this.maxSize = Integer.parseInt(maximumSize);
  305         }
  306         catch (NumberFormatException e)
  307         {
  308            throw new DeploymentException("Invalid MaximumSize value for instance pool configuration");
  309         }
  310   
  311         // Get whether the pool will block when MaximumSize instances are active
  312         String strictValue = MetaData.getElementContent(MetaData.getOptionalChild(element, "strictMaximumSize"));
  313         Boolean strictFlag = Boolean.valueOf(strictValue);
  314         if( strictFlag == Boolean.TRUE )
  315            this.strictMaxSize = new FIFOSemaphore(this.maxSize);
  316         String delay = MetaData.getElementContent(MetaData.getOptionalChild(element, "strictTimeout"));
  317         try
  318         {
  319            if( delay != null )
  320               this.strictTimeout = Long.parseLong(delay);
  321         }
  322         catch (NumberFormatException e)
  323         {
  324            throw new DeploymentException("Invalid strictTimeout value for instance pool configuration");
  325         }
  326      }
  327   
  328      // Package protected ---------------------------------------------
  329   
  330      // Protected -----------------------------------------------------
  331      protected abstract EnterpriseContext create(Object instance)
  332      throws Exception;
  333   
  334      protected void destroyService() throws Exception
  335      {
  336        freeAll();
  337        this.container = null;
  338      }
  339   
  340      // Private -------------------------------------------------------
  341   
  342      /**
  343       * At undeployment we want to free completely the pool.
  344       */
  345      private void freeAll()
  346      {
  347         LinkedList clone = (LinkedList)pool.clone();
  348         for (int i = 0; i < clone.size(); i++)
  349         {
  350            EnterpriseContext ec = (EnterpriseContext)clone.get(i);
  351            // Clear TX so that still TX entity pools get killed as well
  352            ec.clear();
  353            discard(ec);
  354         }
  355         pool.clear();
  356      }
  357   
  358      // Inner classes -------------------------------------------------
  359   
  360   }

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