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.util.HashMap;
   25   
   26   import org.jboss.monitor.EntityLockMonitor;
   27   import org.jboss.monitor.LockMonitor;
   28   import org.jboss.logging.Logger;
   29   import javax.naming.InitialContext;
   30   
   31   /**
   32    * Manages BeanLocks.  All BeanLocks have a reference count.
   33    * When the reference count goes to 0, the lock is released from the
   34    * id -> lock mapping.
   35    *
   36    * @author <a href="bill@burkecentral.com">Bill Burke</a>
   37    * @author <a href="marc.fleury@jboss.org">Marc Fleury</a>
   38    * @author Scott.Stark@jboss.org
   39    */
   40   public class BeanLockManager
   41   {
   42      private static final int NUMBER_OF_INSTANCES=40;
   43      private static Logger log = Logger.getLogger(BeanLockManager.class);
   44   
   45      /** Multiple instances of hashMap to diminish locking contentions.
   46       *  Rules for accessing this are determined by {@link getHashMap(Object)}*/
   47      private HashMap map[] = new HashMap[NUMBER_OF_INSTANCES];
   48   
   49   
   50      /** The container this manager reports to */
   51      private Container container;
   52   
   53      /** Reentrancy of calls */
   54      private boolean reentrant = false;
   55      private int txTimeout = 5000;
   56      /** The logging trace flag, only set in ctor */
   57      private boolean trace;
   58      public Class lockClass;
   59      protected LockMonitor monitor = null;
   60   
   61      private BeanLockManager()
   62      {
   63          for (int i=0;i<map.length;i++)
   64          {
   65              map[i] = new HashMap();
   66          }
   67      }
   68      public BeanLockManager(Container container)
   69      {
   70         this();
   71         this.container = container;
   72         trace = log.isTraceEnabled();
   73         try
   74         {
   75            InitialContext ctx = new InitialContext();
   76            EntityLockMonitor elm = (EntityLockMonitor) ctx.lookup(EntityLockMonitor.JNDI_NAME);
   77            String jndiName = container.getBeanMetaData().getContainerObjectNameJndiName();
   78            monitor = elm.getEntityLockMonitor(jndiName);
   79         }
   80         catch (Exception ignored)
   81         {
   82            // Ignore the lack of an EntityLockMonitor
   83         }
   84      }
   85   
   86      public LockMonitor getLockMonitor()
   87      {
   88         return monitor;
   89      }
   90   
   91      private HashMap getHashMap(Object id)
   92      {
   93          final int mapInUse = id.hashCode()%NUMBER_OF_INSTANCES;
   94          if (mapInUse>0)
   95          {
   96              return map[mapInUse];
   97          }
   98          else
   99          {
  100              return map[mapInUse*-1];
  101          }
  102      }
  103   
  104      /**
  105       * returns the lock associated with the key passed.  If there is
  106       * no lock one is created this call also increments the number of
  107       * references interested in Lock.
  108       *
  109       * WARNING: All access to this method MUST have an equivalent
  110       * removeLockRef cleanup call, or this will create a leak in the map,
  111       */
  112      public BeanLock getLock(Object id)
  113      {
  114         if (id == null)
  115            throw new IllegalArgumentException("Attempt to get lock ref with a null object");
  116   
  117         HashMap mapInUse = getHashMap(id);
  118   
  119         synchronized (mapInUse)
  120         {
  121           BeanLock lock = (BeanLock) mapInUse.get(id);
  122           if (lock!=null)
  123           {
  124               lock.addRef();
  125               return lock;
  126           }
  127         }
  128   
  129         try
  130         {
  131             BeanLock lock2 = (BeanLock)createLock(id);
  132             synchronized(mapInUse)
  133             {
  134                 BeanLock lock = (BeanLock) mapInUse.get(id);
  135                 // in case of bad luck, this might happen
  136                 if (lock != null)
  137                 {
  138                     lock.addRef();
  139                     return lock;
  140                 }
  141                 mapInUse.put(id, lock2);
  142                 lock2.addRef();
  143                 return lock2;
  144             }
  145         }
  146         catch (Exception e)
  147         {
  148             // schrouf: should we really proceed with lock object
  149             // in case of exception ??
  150             log.warn("Failed to initialize lock:"+id, e);
  151             throw new RuntimeException (e);
  152         }
  153      }
  154   
  155      private BeanLock createLock(Object id) throws Exception
  156      {
  157          BeanLock lock = (BeanLock) lockClass.newInstance();
  158          lock.setId(id);
  159          lock.setTimeout(txTimeout);
  160          lock.setContainer(container);
  161   
  162          return lock;
  163      }
  164   
  165      public void removeLockRef(Object id)
  166      {
  167         if (id == null)
  168            throw new IllegalArgumentException("Attempt to remove lock ref with a null object");
  169   
  170         HashMap mapInUse = getHashMap(id);
  171   
  172         synchronized(mapInUse)
  173         {
  174             BeanLock lock = (BeanLock) mapInUse.get(id);
  175   
  176             if (lock != null)
  177             {
  178                try
  179                {
  180                   lock.removeRef();
  181                   if( trace )
  182                      log.trace("Remove ref lock:"+lock);
  183                }
  184                finally
  185                {
  186                   // schrouf: ALLWAYS ensure proper map lock removal even in case
  187                   // of exception within lock.removeRef ! There seems to be a bug
  188                   // in the ref counting of QueuedPessimisticEJBLock under certain
  189                   // conditions ( lock.ref < 0 should never happen !!! )
  190                   if (lock.getRefs() <= 0)
  191                   {
  192                      Object mapLock = mapInUse.remove(lock.getId());
  193                      if( trace )
  194                         log.trace("Lock no longer referenced, lock: "+lock);
  195                   }
  196                }
  197             }
  198         }
  199      }
  200   
  201      public boolean canPassivate(Object id)
  202      {
  203         if (id == null)
  204            throw new IllegalArgumentException("Attempt to passivate with a null object");
  205   
  206         HashMap mapInUse = getHashMap(id);
  207         synchronized (mapInUse)
  208         {
  209             BeanLock lock = (BeanLock) mapInUse.get(id);
  210             if (lock == null)
  211                throw new IllegalStateException("Attempt to passivate without a lock");
  212   
  213             return (lock.getRefs() <= 1);
  214         }
  215      }
  216   
  217      public void setLockCLass(Class lockClass)
  218      {
  219         this.lockClass = lockClass;
  220      }
  221   
  222      public void setReentrant(boolean reentrant)
  223      {
  224         this.reentrant = reentrant;
  225      }
  226   
  227      public void setContainer(Container container)
  228      {
  229         this.container = container;
  230      }
  231   }

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