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.lang.reflect.Constructor;
   25   import java.rmi.NoSuchObjectException;
   26   import java.rmi.RemoteException;
   27   import java.util.Map;
   28   
   29   import org.jboss.deployment.DeploymentException;
   30   import org.jboss.ejb.BeanLock;
   31   import org.jboss.ejb.BeanLockExt;
   32   import org.jboss.ejb.Container;
   33   import org.jboss.ejb.EnterpriseContext;
   34   import org.jboss.ejb.InstanceCache;
   35   import org.jboss.logging.Logger;
   36   import org.jboss.metadata.MetaData;
   37   import org.jboss.metadata.XmlLoadable;
   38   import org.jboss.monitor.MetricsConstants;
   39   import org.jboss.monitor.Monitorable;
   40   import org.jboss.monitor.client.BeanCacheSnapshot;
   41   import org.jboss.util.CachePolicy;
   42   import org.w3c.dom.Element;
   43   
   44   /**
   45    * Base class for caches of entity and stateful beans. <p>
   46    * It manages the cache entries through a {@link CachePolicy} object;
   47    * the implementation of the cache policy object must respect the following
   48    * requirements:
   49    * <ul>
   50    * <li> Have a public constructor that takes a single argument of type
   51    * AbstractInstanceCache.class or a subclass
   52    * </ul>
   53    *
   54    * @author <a href="mailto:simone.bordet@compaq.com">Simone Bordet</a>
   55    * @author <a href="bill@burkecentral.com">Bill Burke</a>
   56    * @author <a href="marc.fleury@jboss.org">Marc Fleury</a>
   57    * @author Scott.Stark@jboss.org
   58    * @version $Revision: 43998 $
   59    * @jmx:mbean
   60    */
   61   public abstract class AbstractInstanceCache
   62      implements InstanceCache, XmlLoadable, Monitorable, MetricsConstants,
   63         AbstractInstanceCacheMBean
   64   {
   65      // Constants -----------------------------------------------------
   66   
   67      // Attributes ----------------------------------------------------
   68      protected static Logger log = Logger.getLogger(AbstractInstanceCache.class);
   69   
   70      /* The object that is delegated to implement the desired caching policy */
   71      private CachePolicy m_cache;
   72      /* The mutex object for the cache */
   73      private final Object m_cacheLock = new Object();
   74   
   75      // Static --------------------------------------------------------
   76   
   77      // Constructors --------------------------------------------------
   78   
   79      // Monitorable implementation ------------------------------------
   80      public void sample(Object s)
   81      {
   82         if( m_cache == null )
   83            return;
   84   
   85         synchronized (getCacheLock())
   86         {
   87            BeanCacheSnapshot snapshot = (BeanCacheSnapshot)s;
   88            snapshot.m_passivatingBeans = 0;
   89            CachePolicy policy = getCache();
   90            if (policy instanceof Monitorable)
   91            {
   92               ((Monitorable)policy).sample(s);
   93            }
   94         }
   95      }
   96      public Map retrieveStatistic()
   97      {
   98         return null;
   99      }
  100      public void resetStatistic()
  101      {
  102      }
  103   
  104      // Public --------------------------------------------------------
  105      /* From InstanceCache interface */
  106      public EnterpriseContext get(Object id)
  107         throws RemoteException, NoSuchObjectException
  108      {
  109         if (id == null) throw new IllegalArgumentException("Can't get an object with a null key");
  110   
  111         EnterpriseContext ctx;
  112   
  113         synchronized (getCacheLock())
  114         {
  115            CachePolicy cache = getCache();
  116            ctx = (EnterpriseContext)cache.get(id);
  117            if (ctx == null)
  118            {
  119               try
  120               {
  121                  ctx = acquireContext();
  122                  setKey(id, ctx);
  123                  if (doActivate(ctx) == false)
  124                     // This is a recursive activation
  125                     return ctx;
  126                  logActivation(id);
  127                  // the cache will throw an IllegalStateException if we try to insert
  128                  // something that is in the cache already, so we don't check here
  129                  cache.insert(id, ctx);
  130               }
  131               catch (Throwable x)
  132               {
  133                  log.debug("Activation failure", x);
  134                  throw new NoSuchObjectException(x.getMessage());
  135               }
  136            }
  137         }
  138   
  139         return ctx;
  140      }
  141   
  142      /* From InstanceCache interface */
  143      public void insert(EnterpriseContext ctx)
  144      {
  145         if (ctx == null) throw new IllegalArgumentException("Can't insert a null object in the cache");
  146   
  147         Object key = getKey(ctx);
  148         synchronized (getCacheLock())
  149         {
  150            // the cache will throw an IllegalStateException if we try to insert
  151   	 // something that is in the cache already, so we don't check here
  152            getCache().insert(key, ctx);
  153         }
  154      }
  155   
  156      /**
  157       * Tries to passivate the instance. If the instance is in use then the instance
  158       * will be passivated later according to the container's commit option and max age.
  159       */
  160      protected void tryToPassivate(EnterpriseContext ctx)
  161      {
  162         tryToPassivate(ctx, false);
  163      }
  164   
  165      /**
  166       * Tries to passivate the instance. If the instance is in use and passivateAfterCommit
  167       * parameter is true then the instance will passivated after the transaction commits.
  168       * Otherwise, the instance will be passivated later according to the container's
  169       * commit option and max age.
  170       */
  171      protected void tryToPassivate(EnterpriseContext ctx, boolean passivateAfterCommit)
  172      {
  173         Object id = ctx.getId();
  174         if (id == null) return;
  175         BeanLock lock = getContainer().getLockManager().getLock(id);
  176         boolean lockedBean = false;
  177         try
  178         {
  179            /* If this is a BeanLockExt only attempt the lock as the call to
  180            remove is going to have to acquire the cache lock, but this may already
  181            be held since this method is called by passivation policies without
  182            the cache lock. This can lead to a deadlock as in the case of a size based
  183            eviction during a cache get attempts to lock the bean that has been
  184            locked by an age based background thread as seen in bug 987389 on
  185            sourceforge.
  186            */
  187            if( lock instanceof BeanLockExt )
  188            {
  189               BeanLockExt lock2 = (BeanLockExt) lock;
  190               lockedBean = lock2.attemptSync();
  191               if( lockedBean == false )
  192               {
  193                  unableToPassivateDueToCtxLock(ctx, passivateAfterCommit);
  194                  return;
  195               }
  196            }
  197            else
  198            {
  199               // Use the blocking sync
  200               lock.sync();
  201               lockedBean = true;
  202            }
  203   
  204            if (canPassivate(ctx))
  205            {
  206               try
  207               {
  208                  remove(id);
  209                  passivate(ctx);
  210                  freeContext(ctx);
  211               }
  212               catch (Exception ignored)
  213               {
  214                  log.warn("failed to passivate, id="+id, ignored);
  215               }
  216            }
  217            else
  218            {
  219               // Touch the entry to make it MRU
  220               synchronized (getCacheLock())
  221               {
  222                  getCache().get(id);
  223               }
  224   
  225               unableToPassivateDueToCtxLock(ctx, passivateAfterCommit);
  226            }
  227         }
  228         finally
  229         {
  230            if( lockedBean )
  231               lock.releaseSync();
  232            getContainer().getLockManager().removeLockRef(id);
  233         }
  234      }
  235   
  236      /**
  237       * Passivates and removes the instance from the cache.
  238       * If the instance is in use then removal and passivation will be scheduled until
  239       * after transaction ends
  240       */
  241      public void release(EnterpriseContext ctx)
  242      {
  243         if (ctx == null) throw new IllegalArgumentException("Can't release a null object");
  244   
  245         // Here I remove the bean; call to remove(id) is wrong
  246         // cause will remove also the cache lock that is needed
  247         // by the passivation, that eventually will remove it.
  248         /* the removal should only be done if the instance is not in use.
  249            this is taken care of in tryToPassivate
  250         Object id = getKey(ctx);
  251         synchronized (getCacheLock())
  252         {
  253            if (getCache().peek(id) != null)
  254               getCache().remove(id);
  255         }
  256         */
  257         tryToPassivate(ctx, true);
  258      }
  259   
  260      /**
  261       * From InstanceCache interface
  262       * @jmx:managed-operation
  263       */
  264      public void remove(Object id)
  265      {
  266         if (id == null) throw new IllegalArgumentException("Can't remove an object using a null key");
  267   
  268         synchronized (getCacheLock())
  269         {
  270            if (getCache().peek(id) != null)
  271            {
  272               getCache().remove(id);
  273            }
  274         }
  275      }
  276   
  277      public boolean isActive(Object id)
  278      {
  279         // Check whether an object with the given id is available in the cache
  280         synchronized (getCacheLock())
  281         {
  282            return getCache().peek(id) != null;
  283         }
  284      }
  285   
  286      /** Get the current cache size
  287       * @jmx:managed-attribute
  288       * @return the size of the cache
  289       */
  290      public long getCacheSize()
  291      {
  292         int cacheSize = m_cache != null ? m_cache.size() : 0;
  293         return cacheSize;
  294      }
  295      /** Flush the cache.
  296       * @jmx:managed-operation
  297       */
  298      public void flush()
  299      {
  300         if( m_cache != null )
  301            m_cache.flush();
  302      }
  303      /** Get the passivated count.
  304       * @jmx:managed-attribute
  305       * @return the number of passivated instances.
  306       */
  307      public long getPassivatedCount()
  308      {
  309         return 0;
  310      }
  311   
  312      /**
  313       * Display the cache policy.
  314       * 
  315       * @jmx:managed-attribute
  316       * @return the cache policy as a string.
  317       */
  318      public String getCachePolicyString()
  319      {
  320         return m_cache.toString();
  321      }
  322      
  323      // XmlLoadable implementation ----------------------------------------------
  324      public void importXml(Element element) throws DeploymentException
  325      {
  326         // This one is mandatory
  327         String p = MetaData.getElementContent(MetaData.getUniqueChild(element, "cache-policy"));
  328         try
  329         {
  330            Class cls = SecurityActions.getContextClassLoader().loadClass(p);
  331            Constructor ctor = cls.getConstructor(new Class[] {AbstractInstanceCache.class});
  332            m_cache = (CachePolicy)ctor.newInstance(new Object[] {this});
  333         }
  334         catch (Exception x)
  335         {
  336            throw new DeploymentException("Can't create cache policy", x);
  337         }
  338   
  339         Element policyConf = MetaData.getOptionalChild(element, "cache-policy-conf");
  340         if (policyConf != null)
  341         {
  342            if (m_cache instanceof XmlLoadable)
  343            {
  344               try
  345               {
  346                  ((XmlLoadable)m_cache).importXml(policyConf);
  347               }
  348               catch (Exception x)
  349               {
  350                  throw new DeploymentException("Can't import policy configuration", x);
  351               }
  352            }
  353         }
  354      }
  355   
  356      /* From Service interface*/
  357      public void create() throws Exception
  358      {
  359         getCache().create();
  360      }
  361      /* From Service interface*/
  362      public void start() throws Exception
  363      {
  364         getCache().start();
  365      }
  366      /* From Service interface*/
  367      public void stop()
  368      {
  369         // Empty the cache
  370         synchronized (getCacheLock())
  371         {
  372            getCache().stop();
  373         }
  374      }
  375      /* From Service interface*/
  376      public void destroy()
  377      {
  378         synchronized (getCacheLock())
  379         {
  380            getCache().destroy();
  381         }
  382         this.m_cache = null;
  383      }
  384   
  385      // Y overrides ---------------------------------------------------
  386   
  387      // Package protected ---------------------------------------------
  388   
  389      // Protected -----------------------------------------------------
  390      protected void logActivation(Object id)
  391      {
  392         if( log.isTraceEnabled() )
  393         {
  394            StringBuffer m_buffer=new StringBuffer(100);
  395            m_buffer.append("Activated bean ");
  396            m_buffer.append(getContainer().getBeanMetaData().getEjbName());
  397            m_buffer.append(" with id = ");
  398            m_buffer.append(id);
  399            log.trace(m_buffer.toString());
  400         }
  401      }
  402   
  403      protected void logPassivation(Object id)
  404      {
  405         if( log.isTraceEnabled() )
  406         {
  407            StringBuffer m_buffer=new StringBuffer(100);
  408            m_buffer.append("Passivated bean ");
  409            m_buffer.append(getContainer().getBeanMetaData().getEjbName());
  410            m_buffer.append(" with id = ");
  411            m_buffer.append(id);
  412            log.trace(m_buffer.toString());
  413         }
  414      }
  415   
  416      protected void unableToPassivateDueToCtxLock(EnterpriseContext ctx, boolean passivateAfterCommit)
  417      {
  418         log.warn("Unable to passivate due to ctx lock, id="+ctx.getId());
  419      }
  420   
  421      /**
  422       * Returns the container for this cache.
  423       */
  424      protected abstract Container getContainer();
  425      /**
  426       * Returns the cache policy used for this cache.
  427       */
  428      protected CachePolicy getCache() {return m_cache;}
  429      /**
  430       * Returns the mutex used to sync access to the cache policy object
  431       */
  432      public Object getCacheLock()
  433      {
  434         return m_cacheLock;
  435      }
  436      /**
  437       * Passivates the given EnterpriseContext
  438       */
  439      protected abstract void passivate(EnterpriseContext ctx) throws RemoteException;
  440      /**
  441       * Activates the given EnterpriseContext
  442       */
  443      protected abstract void activate(EnterpriseContext ctx) throws RemoteException;
  444      /**
  445       * Activate the given EnterpriseContext
  446       * 
  447       * @param ctx the context
  448       * @return false if we recursively activating
  449       * @throws RemoteException for any error
  450       */
  451      protected boolean doActivate(EnterpriseContext ctx) throws RemoteException
  452      {
  453         activate(ctx);
  454         return true;
  455      }
  456      /**
  457       * Acquires an EnterpriseContext from the pool
  458       */
  459      protected abstract EnterpriseContext acquireContext() throws Exception;
  460      /**
  461       * Frees the given EnterpriseContext to the pool
  462       */
  463      protected abstract void freeContext(EnterpriseContext ctx);
  464      /**
  465       * Returns the key used by the cache to map the given context
  466       */
  467      protected abstract Object getKey(EnterpriseContext ctx);
  468      /**
  469       * Sets the given id as key for the given context
  470       */
  471      protected abstract void setKey(Object id, EnterpriseContext ctx);
  472      /**
  473       * Returns whether the given context can be passivated or not
  474       *
  475       */
  476      protected abstract boolean canPassivate(EnterpriseContext ctx);
  477   
  478      // Private -------------------------------------------------------
  479   
  480      // Inner classes -------------------------------------------------
  481   }

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