[jboss-cvs] JBossAS SVN: r108726 - projects/ejb3/branches/infinispan-int/core/src/main/java/org/jboss/ejb3/cache/simple.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Thu Oct 21 14:15:34 EDT 2010


Author: pferraro
Date: 2010-10-21 14:15:34 -0400 (Thu, 21 Oct 2010)
New Revision: 108726

Added:
   projects/ejb3/branches/infinispan-int/core/src/main/java/org/jboss/ejb3/cache/simple/SimpleStatefulCache.java
   projects/ejb3/branches/infinispan-int/core/src/main/java/org/jboss/ejb3/cache/simple/SimpleStatefulCacheFactory.java
Log:
Revert - ejb3-core is too monolithic to move the simple provider to a separate module

Added: projects/ejb3/branches/infinispan-int/core/src/main/java/org/jboss/ejb3/cache/simple/SimpleStatefulCache.java
===================================================================
--- projects/ejb3/branches/infinispan-int/core/src/main/java/org/jboss/ejb3/cache/simple/SimpleStatefulCache.java	                        (rev 0)
+++ projects/ejb3/branches/infinispan-int/core/src/main/java/org/jboss/ejb3/cache/simple/SimpleStatefulCache.java	2010-10-21 18:15:34 UTC (rev 108726)
@@ -0,0 +1,660 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.ejb3.cache.simple;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Queue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import javax.ejb.EJBException;
+import javax.ejb.NoSuchEJBException;
+
+import org.jboss.aop.Advisor;
+import org.jboss.ejb3.EJBContainer;
+import org.jboss.ejb3.annotation.CacheConfig;
+import org.jboss.ejb3.annotation.PersistenceManager;
+import org.jboss.ejb3.cache.StatefulCache;
+import org.jboss.ejb3.cache.persistence.PersistenceManagerFactory;
+import org.jboss.ejb3.cache.persistence.PersistenceManagerFactoryRegistry;
+import org.jboss.ejb3.stateful.StatefulBeanContext;
+import org.jboss.ejb3.stateful.StatefulContainer;
+import org.jboss.logging.Logger;
+
+/**
+ * Comment
+ *
+ * @author <a href="mailto:bill at jboss.org">Bill Burke</a>
+ * @version $Revision: 101649 $
+ */
+ at SuppressWarnings("deprecation")
+public class SimpleStatefulCache implements StatefulCache
+{
+   private Logger log = Logger.getLogger(SimpleStatefulCache.class);
+
+   private StatefulContainer container;
+   protected CacheMap cacheMap;
+   private int maxSize = 1000;
+   private StatefulSessionPersistenceManager pm;
+   private long sessionTimeout = 300; // 5 minutes
+   private long removalTimeout = 0; // 0 == Never
+   private Thread timeoutTask;
+   private RemovalTimeoutTask removalTask = null;
+   private boolean running = true;
+   private int createCount = 0;
+   private int passivatedCount = 0;
+   private int removeCount = 0;
+   
+   private Queue<StatefulBeanContext> passivationQueue = new LinkedBlockingQueue<StatefulBeanContext>();
+
+   protected class CacheMap extends LinkedHashMap<Object, StatefulBeanContext>
+   {
+      private static final long serialVersionUID = 4514182777643616159L;
+
+      public CacheMap()
+      {
+         super(maxSize, 0.75F, true);
+      }
+      
+      public CacheMap(Map<? extends Object, ? extends StatefulBeanContext> original)
+      {
+         super(original);
+      }
+
+      @Override
+      public boolean removeEldestEntry(Entry<Object, StatefulBeanContext> entry)
+      {
+         boolean removeIt = size() > maxSize;
+         if (removeIt)
+         {
+            StatefulBeanContext centry = entry.getValue();
+            synchronized (centry)
+            {
+               if (centry.getCanPassivate())
+               {
+                  passivate(centry);
+                  // its ok to evict because bean will be passivated.
+               }
+               else
+               {
+                  centry.markedForPassivation = true;
+                  
+                  if (!centry.isInUse())
+                  {
+                     // Can't passivate but not in use means a child bean is 
+                     // in use.
+                     // It's not ok to evict because bean will not be passivated
+                     removeIt = false;
+                  }
+               }               
+            }
+         }
+         return removeIt;
+      }
+   }
+   
+   protected class RemovalTimeoutTask extends Thread
+   {
+      public RemovalTimeoutTask(String name)
+      {
+         super(name);
+      }
+      
+      protected void block() throws InterruptedException
+      {
+         Thread.sleep(removalTimeout * 1000);
+      }
+      
+      protected void preRemoval()
+      {
+         
+      }
+      
+      protected void postRemoval()
+      {
+         
+      }
+
+      @Override
+      public void run()
+      {
+         while (running)
+         { 
+            try
+            {
+               this.block();
+            }
+            catch (InterruptedException e)
+            {
+               running = false;
+               return;
+            }
+            try
+            {
+               // Invoke pre-removal callback
+               this.preRemoval();
+               
+               long now = System.currentTimeMillis();
+               
+               synchronized (cacheMap)
+               {
+                  if (!running) return;
+                   
+                  Iterator<Entry<Object, StatefulBeanContext>> it = cacheMap.entrySet().iterator();
+                  while (it.hasNext())
+                  {
+                     Entry<Object, StatefulBeanContext> entry = it.next();
+                     StatefulBeanContext centry = entry.getValue();
+                     if (now - centry.lastUsed >= removalTimeout * 1000)
+                     {
+                        synchronized (centry)
+                        {                                                                    
+                           it.remove();
+                        }
+                     }
+                  }                  
+               }
+               
+               List<StatefulBeanContext> beans = pm.getPassivatedBeans();  
+               Iterator<StatefulBeanContext> it = beans.iterator();
+               while (it.hasNext())
+               {       
+                  StatefulBeanContext centry = it.next();
+                  if (now - centry.lastUsed >= removalTimeout * 1000)
+                  {
+                     get(centry.getId(), false);
+                     remove(centry.getId());
+                  }
+               }
+               
+               // Invoke post-removal callback
+               this.postRemoval();
+            }
+            catch (Exception ex)
+            {
+               log.error("problem removing SFSB thread", ex);
+            }
+         }
+      }
+   }
+
+   protected class SessionTimeoutTask extends Thread
+   {
+      public SessionTimeoutTask(String name)
+      {
+         super(name);
+      }
+
+      public void block() throws InterruptedException
+      {
+         Thread.sleep(sessionTimeout * 1000);
+      }
+      
+      /**
+       * I'm done passivating.
+       */
+      protected void passivationCompleted()
+      {
+         
+      }
+      
+      /**
+       * I'm done selecting candidates for passivation.
+       */
+      protected void prePassivationCompleted()
+      {
+         
+      }
+
+      @Override
+      public void run()
+      {
+         while (running)
+         {
+            try
+            {
+               block();
+            }
+            catch (InterruptedException e)
+            {
+               running = false;
+               return;
+            }
+            try
+            {
+               /*
+                * EJBTHREE-1549
+                * 
+                * Passivation is potentially a long-running
+                * operation, so copy the contents quickly and 
+                * perform passivation off a queue.
+                */
+               synchronized (cacheMap)
+               {
+                  if (!running) return;
+                  
+                  boolean trace = log.isTraceEnabled();
+                  Iterator<Entry<Object, StatefulBeanContext>> it = cacheMap.entrySet().iterator();
+                  long now = System.currentTimeMillis();
+                  while (it.hasNext())
+                  {
+                     Entry<Object, StatefulBeanContext> entry = it.next();
+                     StatefulBeanContext centry = entry.getValue();
+                     if (now - centry.lastUsed >= sessionTimeout * 1000)
+                     {
+                        synchronized (centry)
+                        {                     
+                           if (centry.getCanPassivate())
+                           {
+                              if (!centry.getCanRemoveFromCache())
+                              {
+                                 passivationQueue.add(centry);
+                              }
+                              else if (trace)
+                              {
+                                 log.trace("Removing " + entry.getKey() + " from cache");
+                              }
+                           }
+                           else
+                           {
+                              centry.markedForPassivation = true;                              
+                              assert centry.isInUse() : centry + " is not in use, and thus will never be passivated";
+                           }
+                           // its ok to evict because it will be passivated
+                           // or we determined above that we can remove it
+                           it.remove();
+                        }
+                     }
+                     else if (trace)
+                     {
+                        log.trace("Not passivating; id=" + centry.getId() +
+                              " only inactive " + Math.max(0, now - centry.lastUsed) + " ms");
+                     }
+                  }                  
+               }
+               
+               prePassivationCompleted();
+               
+               StatefulBeanContext ctx;
+               while ((ctx = passivationQueue.poll()) != null)
+               {  
+                  passivate(ctx);
+               }
+               
+               // Make internal callback that we're done
+               this.passivationCompleted();
+            }
+
+            catch (Exception ex)
+            {
+               log.error("problem passivation thread", ex);
+            }
+         }
+      }
+   }
+
+   @Override
+   public void initialize(EJBContainer container) throws Exception
+   {
+      this.container = (StatefulContainer) container;
+      Advisor advisor = container.getAdvisor();
+      cacheMap = new CacheMap();
+      PersistenceManager pmConfig = (PersistenceManager) advisor.resolveAnnotation(PersistenceManager.class);
+      String pmConfigValue = pmConfig.value();
+      PersistenceManagerFactoryRegistry pmFactoryRegistry = container.getDeployment()
+            .getPersistenceManagerFactoryRegistry();
+      PersistenceManagerFactory pmFactory = pmFactoryRegistry.getPersistenceManagerFactory(pmConfigValue);
+      this.pm = pmFactory.createPersistenceManager();
+      pm.initialize(container);
+      CacheConfig config = (CacheConfig) advisor.resolveAnnotation(CacheConfig.class);
+      maxSize = config.maxSize();
+      sessionTimeout = config.idleTimeoutSeconds();
+      removalTimeout = config.removalTimeoutSeconds();
+      log = Logger.getLogger(getClass().getName() + "." + container.getEjbName());
+      log.debug("Initializing SimpleStatefulCache with maxSize: " +maxSize + " timeout: " +sessionTimeout +
+              " for " +container.getObjectName().getCanonicalName() );
+      timeoutTask = new SessionTimeoutTask("SFSB Passivation Thread - " + container.getObjectName().getCanonicalName());
+   
+      if (removalTimeout > 0)
+         removalTask = new RemovalTimeoutTask("SFSB Removal Thread - " + container.getObjectName().getCanonicalName());
+   }
+
+   public SimpleStatefulCache()
+   {
+   }
+
+   @Override
+   public void start()
+   {
+      running = true;
+      timeoutTask.start();
+      
+      if (removalTask != null)
+         removalTask.start();
+   }
+
+   @Override
+   public void stop()
+   {
+      synchronized (cacheMap)
+      {
+         running = false;
+         timeoutTask.interrupt();
+         if (removalTask != null)
+            removalTask.interrupt();
+         cacheMap.clear();
+         try
+         {
+            pm.destroy();
+         }
+         catch (Exception e)
+         {
+            throw new RuntimeException(e);
+         }
+      }
+   }
+
+   protected void passivate(StatefulBeanContext ctx)
+   {
+      ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
+      try
+      {
+         Thread.currentThread().setContextClassLoader(((EJBContainer) ctx.getContainer()).getClassloader());
+         synchronized(pm)
+         {
+            pm.passivateSession(ctx);
+         }
+         ++passivatedCount;
+      }
+      finally
+      {
+         Thread.currentThread().setContextClassLoader(oldCl);
+      }
+   }
+
+   public StatefulBeanContext create()
+   {
+      return create(null, null);
+   }
+
+   @Override
+   public StatefulBeanContext create(Class<?>[] initTypes, Object[] initValues)
+   {
+      StatefulBeanContext ctx = null;
+      try
+      {
+         ctx = container.create(initTypes, initValues);
+         if (log.isTraceEnabled())
+         {
+            log.trace("Caching context " + ctx.getId() + " of type " + ctx.getClass());
+         }
+         synchronized (cacheMap)
+         {
+            cacheMap.put(ctx.getId(), ctx);
+            ctx.setInUse(true);
+            ctx.lastUsed = System.currentTimeMillis();
+         }
+         ++createCount;
+      }
+      catch (EJBException e)
+      {
+         e.printStackTrace();
+         throw e;
+      }
+      catch (Exception e)
+      {
+         e.printStackTrace();
+         throw new EJBException(e);
+      }
+      return ctx;
+   }
+   
+   @Override
+   public StatefulBeanContext get(Object key) throws EJBException
+   {
+      return get(key, true);
+   }
+   
+   @Override
+   public StatefulBeanContext get(Object key, boolean markInUse) throws EJBException
+   {
+      StatefulBeanContext entry = null;
+      synchronized (cacheMap)
+      {
+         entry = cacheMap.get(key);
+      }
+      if(entry == null)
+      {
+         // TODO: optimize
+         synchronized (cacheMap)
+         {
+            entry = cacheMap.get(key);
+            if(entry == null)
+            {
+               Iterator<StatefulBeanContext> i = passivationQueue.iterator();
+               while(i.hasNext())
+               {
+                  StatefulBeanContext ctx = i.next();
+                  if(ctx.getId().equals(key))
+                  {
+                     boolean passivationCanceled = passivationQueue.remove(ctx);
+                     if(passivationCanceled)
+                     {
+                        entry = ctx;
+                        cacheMap.put(key, entry);
+                     }
+                     break;
+                  }
+               }
+            }
+         }
+      }
+      if (entry == null)
+      {
+         synchronized(pm)
+         {
+            synchronized (cacheMap)
+            {
+               entry = cacheMap.get(key);
+            }
+            if(entry == null)
+            {
+               entry = pm.activateSession(key);
+               if (entry == null)
+               {
+                  throw new NoSuchEJBException("Could not find stateful bean: " + key);
+               }
+               --passivatedCount;
+               
+               // We cache the entry even if we will throw an exception below
+               // as we may still need it for its children and XPC references
+               if (log.isTraceEnabled())
+               {
+                  log.trace("Caching activated context " + entry.getId() + " of type " + entry.getClass());
+               }
+               
+               synchronized (cacheMap)
+               {
+                  cacheMap.put(key, entry);
+               }
+            }
+         }
+      }
+      
+      // Now we know entry isn't null
+      if (markInUse)
+      { 
+         if (entry.isRemoved())
+         {
+            throw new NoSuchEJBException("Could not find stateful bean: " + key +
+                                         " (bean was marked as removed");
+         }      
+      
+         entry.setInUse(true);
+         entry.lastUsed = System.currentTimeMillis();
+      }
+      
+      return entry;
+   }
+
+   @Override
+   public StatefulBeanContext peek(Object key) throws NoSuchEJBException
+   {
+      return get(key, false);
+   }
+   
+   @Override
+   public void release(StatefulBeanContext ctx)
+   {
+      synchronized (ctx)
+      {
+         ctx.setInUse(false);
+         ctx.lastUsed = System.currentTimeMillis();
+         if (ctx.markedForPassivation)
+         {
+            passivate(ctx);
+         }
+      }
+   }
+
+   @Override
+   public void remove(Object key)
+   {
+      if(log.isTraceEnabled())
+      {
+         log.trace("Removing context " + key);
+      }
+      // don't directly use the cacheMap to get the 
+      // object from the key. Instead, use the get() method
+      // which will even activate any sessions which have been
+      // passivated (see https://jira.jboss.org/jira/browse/EJBTHREE-2030)
+      StatefulBeanContext ctx = this.get(key);
+      if(ctx == null)
+         throw new NoSuchEJBException("Could not find Stateful bean: " + key);
+      if (!ctx.isRemoved())
+         container.destroy(ctx);
+      
+      ++removeCount;
+      
+      if (ctx.getCanRemoveFromCache())
+      {
+         synchronized (cacheMap)
+         {
+            cacheMap.remove(key);
+         }
+      }
+   }
+
+   @Override
+   public int getCacheSize()
+   {
+      return cacheMap.size();
+   }
+
+   @Override
+   public int getTotalSize()
+   {
+      return getCacheSize() + getPassivatedCount();
+   }
+   
+   @Override
+   public int getCreateCount()
+   {
+      return createCount;
+   }
+   
+   @Override
+   public int getPassivatedCount()
+   {
+      return passivatedCount;
+   }
+   
+   @Override
+   public int getRemoveCount()
+   {
+      return removeCount;
+   }
+   
+   @Override
+   public int getAvailableCount()
+   {
+      final int maxSize = this.getMaxSize();
+      if (maxSize < 0)
+      {
+         return maxSize;
+      }
+      final int currentSize = this.getCurrentSize();
+      final int available = maxSize - currentSize;
+      return available;
+   }
+   
+   @Override
+   public int getMaxSize()
+   {
+      return maxSize;
+   }
+   
+   @Override
+   public int getCurrentSize()
+   {
+      return cacheMap.size();
+   }
+   
+   @Override
+   public boolean isStarted()
+   {
+      return this.running;
+   }
+
+   protected Thread getTimeoutTask()
+   {
+      return timeoutTask;
+   }
+   
+   protected void setTimeoutTask(Thread timeoutTask)
+   {
+      this.timeoutTask = timeoutTask;
+   }
+
+   protected long getSessionTimeout()
+   {
+      return sessionTimeout;
+   }
+
+   protected long getRemovalTimeout()
+   {
+      return removalTimeout;
+   }
+
+   protected RemovalTimeoutTask getRemovalTask()
+   {
+      return removalTask;
+   }
+
+   protected void setRemovalTask(RemovalTimeoutTask removalTask)
+   {
+      this.removalTask = removalTask;
+   }
+}

Added: projects/ejb3/branches/infinispan-int/core/src/main/java/org/jboss/ejb3/cache/simple/SimpleStatefulCacheFactory.java
===================================================================
--- projects/ejb3/branches/infinispan-int/core/src/main/java/org/jboss/ejb3/cache/simple/SimpleStatefulCacheFactory.java	                        (rev 0)
+++ projects/ejb3/branches/infinispan-int/core/src/main/java/org/jboss/ejb3/cache/simple/SimpleStatefulCacheFactory.java	2010-10-21 18:15:34 UTC (rev 108726)
@@ -0,0 +1,41 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2007, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.ejb3.cache.simple;
+
+import org.jboss.ejb3.cache.Ejb3CacheFactory;
+import org.jboss.ejb3.cache.StatefulCache;
+
+/**
+ * Factory for obtaining SimpleStatefulCache instances
+ * 
+ * @author <a href="mailto:andrew.rubinger at redhat.com">ALR</a>
+ * @version $Revision: $
+ */
+ at SuppressWarnings("deprecation")
+public class SimpleStatefulCacheFactory implements Ejb3CacheFactory
+{
+   @Override
+   public StatefulCache createCache()
+   {
+      return new SimpleStatefulCache();
+   }
+}



More information about the jboss-cvs-commits mailing list