Package org.jboss.ha.cachemanager

Source Code of org.jboss.ha.cachemanager.CacheManager$StartStopListener

/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, 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.ha.cachemanager;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.management.JMException;
import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.StringRefAddr;

import org.jboss.cache.Cache;
import org.jboss.cache.CacheStatus;
import org.jboss.cache.config.Configuration;
import org.jboss.cache.config.ConfigurationRegistry;
import org.jboss.cache.jmx.CacheJmxWrapper;
import org.jboss.cache.notifications.annotation.CacheListener;
import org.jboss.cache.notifications.annotation.CacheStarted;
import org.jboss.cache.notifications.annotation.CacheStopped;
import org.jboss.cache.notifications.event.CacheStartedEvent;
import org.jboss.cache.notifications.event.CacheStoppedEvent;
import org.jboss.cache.pojo.PojoCache;
import org.jboss.cache.pojo.PojoCacheFactory;
import org.jboss.cache.pojo.jmx.PojoCacheJmxWrapper;
import org.jboss.ha.framework.server.CacheManagerLocator;
import org.jboss.ha.framework.server.PojoCacheManager;
import org.jboss.ha.framework.server.PojoCacheManagerLocator;
import org.jboss.logging.Logger;
import org.jboss.util.naming.NonSerializableFactory;
import org.jgroups.ChannelFactory;

/**
* JBoss AS specific {@link CacheManager}. Extends the core JBoss Cache
* cache manager by also handling, PojoCache, by registering created caches
* in JMX, and by registering itself in JNDI.
*
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
* @version $Revision: 1.1 $
*/
public class CacheManager
   extends org.jboss.cache.CacheManagerImpl
   implements org.jboss.cache.CacheManager, PojoCacheManager, MBeanRegistration, CacheManagerMBean
{
   private static final Logger log = Logger.getLogger(CacheManager.class);
  
   public static final String DEFAULT_CORE_CACHE_JMX_ATTRIBUTES = "service=Cache,config=";
   public static final String DEFAULT_POJO_CACHE_JMX_ATTRIBUTES = "service=Cache,cacheType=PojoCache,config=";
  
   private MBeanServer mbeanServer;
   private String jmxDomain;
   private String coreCacheJmxAttributes = DEFAULT_CORE_CACHE_JMX_ATTRIBUTES;
   private String pojoCacheJmxAttributes = DEFAULT_POJO_CACHE_JMX_ATTRIBUTES;

   private Map<String, PojoCache> pojoCaches = new HashMap<String, PojoCache>();

   private Map<String, Integer> pojoCacheCheckouts = new HashMap<String, Integer>();

   private Map<String, String> configAliases = new HashMap<String, String>();
  
   private boolean registerCachesInJmx = true;
  
   private Map<String, Boolean> startupCaches = new HashMap<String, Boolean>();
  
   private String jndiName;
   private boolean started;
  
   /**
    * Create a new CacheManagerImpl.
    *
    */
   public CacheManager()
   {
      super();
   }

   /**
    * Create a new CacheManagerImpl.
    *
    * @param configRegistry
    * @param factory
    */
   public CacheManager(ConfigurationRegistry configRegistry, ChannelFactory factory)
   {
      super(configRegistry, factory);
   }

   /**
    * Create a new CacheManagerImpl.
    *
    * @param configFileName
    * @param factory
    */
   public CacheManager(String configFileName, ChannelFactory factory)
   {
      super(configFileName, factory);
   }
  
   // -------------------------------------------------------- PojoCacheManager

   @SuppressWarnings("unchecked")
   public Set<String> getConfigurationNames()
   {
      synchronized (pojoCaches)
      {
         Set<String> configNames = super.getConfigurationNames();
         configNames.addAll(getPojoCacheNames());
         configNames.addAll(configAliases.keySet());
         return configNames;
      }
   }

   public Set<String> getPojoCacheNames()
   {
      synchronized (pojoCaches)
      {
         return new HashSet<String>(pojoCaches.keySet());
      }
   }

   public PojoCache getPojoCache(String configName, boolean create) throws Exception
   {
      // Check if there's an alias involved
      configName = resolveAlias(configName);
     
      PojoCache cache = null;
      synchronized (pojoCaches)
      {
         if (getCacheNames().contains(configName))
            throw new IllegalStateException("Cannot create PojoCache: plain cache already created for config " + configName);
        
         cache = pojoCaches.get(configName);
         if (cache == null && create)
         {
            Configuration config = getConfigurationRegistry().getConfiguration(configName);
            if (getChannelFactory() != null && config.getMultiplexerStack() != null)
            {
               config.getRuntimeConfig().setMuxChannelFactory(getChannelFactory());
            }
            cache = createPojoCache(config);
            registerPojoCache(cache, configName);
         }
         else if (cache != null)
         {
            incrementPojoCacheCheckout(configName);
         }
      }

      // Wrap the pojocache to control classloading and disable stop/destroy
      return cache == null ? null : new PojoCacheManagerManagedPojoCache(cache);
   }
  
   /**
    * Extension point for subclasses, where we actually use a
    * {@link PojoCacheFactory} to create a PojoCache.
    *
    * @param config the Configuration for the cache
    * @return the PojoCache
    */
   @SuppressWarnings("unchecked")
   protected PojoCache createPojoCache(Configuration config)
   {
       return PojoCacheFactory.createCache(config, false);
   }

   public void registerPojoCache(PojoCache cache, String configName)
   {
      synchronized (pojoCaches)
      {
         if (pojoCaches.containsKey(configName) || getCacheNames().contains(configName))
            throw new IllegalStateException(configName + " already registered");
        
         pojoCaches.put(configName, cache);
         incrementPojoCacheCheckout(configName);
        
         if (registerCachesInJmx && mbeanServer != null)
         {
            String oName = getObjectName(getPojoCacheJmxAttributes(), configName);
            PojoCacheJmxWrapper wrapper = new PojoCacheJmxWrapper(cache);
            try
            {
               mbeanServer.registerMBean(wrapper, new ObjectName(oName));
            }
            catch (JMException e)
            {
               throw new RuntimeException("Cannot register cache under name " + oName, e);
            }
           
            // Synchronize the start/stop of the plain and pojo cache
            cache.getCache().addCacheListener(new StartStopListener(wrapper));
         }
      }
   }
  
   // -------------------------------------------------------------  Overrides
  
   @Override
   public Cache<Object, Object> getCache(String configName, boolean create) throws Exception
   {
      // Check if there's an alias involved
      configName = resolveAlias(configName);
     
      synchronized (pojoCaches)
      {
         if (create && pojoCaches.containsKey(configName))
         {
            log.debug("Plain cache requested for config " + configName +
                      " but a PojoCache is already registered; returning " +
                      " the PojoCache's underlying plain cache");
            PojoCache pc = getPojoCache(configName, false);
            if (pc != null)
               return wrapCache(pc.getCache());
         }
        
         return wrapCache(super.getCache(configName, create));
      }
   }
   
   @Override
   public void registerCache(Cache<Object, Object> cache, String configName)
   {
      synchronized (pojoCaches)
      {
         if (pojoCaches.containsKey(configName))
            throw new IllegalStateException(configName + " already registered");
        
         super.registerCache(cache, configName);
        
         if (registerCachesInJmx && mbeanServer != null)
         {
            String oName = getObjectName(getCoreCacheJmxAttributes(), configName);
            CacheJmxWrapper wrapper = new CacheJmxWrapper(cache);
            try
            {
               mbeanServer.registerMBean(wrapper, new ObjectName(oName));
            }
            catch (JMException e)
            {
               throw new RuntimeException("Cannot register cache under name " + oName, e);
            }
           
            // Synchronize the start/stop of the plain and pojo cache
            cache.addCacheListener(new StartStopListener(wrapper));
         }
      }
   }
   @Override
   public void releaseCache(String configName)
   {
      // Check if there's an alias involved
      configName = resolveAlias(configName)
     
      synchronized (pojoCaches)
      {
         if (pojoCaches.containsKey(configName))
         {
            if (decrementPojoCacheCheckout(configName) == 0)
            {
               PojoCache cache = pojoCaches.remove(configName);
               destroyPojoCache(configName, cache);
            }           
         }
         else
         {
            super.releaseCache(configName);
           
            if (registerCachesInJmx && mbeanServer != null && !getCacheNames().contains(configName))
            {
               String oNameStr = getObjectName(getCoreCacheJmxAttributes(), configName);
               try
               {
                  ObjectName oName = new ObjectName(oNameStr);
                  if (mbeanServer.isRegistered(oName))
                  {
                     mbeanServer.unregisterMBean(oName);
                  }
               }
               catch (JMException e)
               {
                  log.error("Problem unregistering CacheJmxWrapper " + oNameStr, e);
               }
              
            }
         }
      }
   }

   @Override
   public void start() throws Exception
   {
      if (!started)
      {
         super.start();
        
         startEagerStartCaches();
        
         CacheManagerLocator locator = CacheManagerLocator.getCacheManagerLocator();
         if (locator.getDirectlyRegisteredManager() == null)
            locator.registerCacheManager(this);
        
         PojoCacheManagerLocator pclocator = PojoCacheManagerLocator.getCacheManagerLocator();
         if (pclocator.getDirectlyRegisteredManager() == null)
            pclocator.registerCacheManager(this);
        
         // Bind ourself in the public JNDI space if configured to do so
         if (jndiName != null)
         {
            Context ctx = new InitialContext();
            this.bind(jndiName, this, CacheManager.class, ctx);
            log.debug("Bound in JNDI under " + jndiName);
         }
        
         started = true;
      }
   }

   @Override
   public void stop()
   {
      if (started)
      {
         releaseEagerStartCaches();
        
         synchronized (pojoCaches)
         {
            for (Iterator<Map.Entry<String, PojoCache>> it = pojoCaches.entrySet().iterator(); it.hasNext();)
            {
               Map.Entry<String, PojoCache> entry = it.next();
               destroyPojoCache(entry.getKey(), entry.getValue());
               it.remove();
            }
            pojoCaches.clear();
            pojoCacheCheckouts.clear();
         }
        
         super.stop();
        
         if (jndiName != null)
         {
            InitialContext ctx = null;
            try
            {
               // the following statement fails when the server is being shut down (07/19/2007)
               ctx = new InitialContext();
               ctx.unbind(jndiName);
            }
            catch (Exception e) {
               log.error("partition unbind operation failed", e);
            }
            finally
            {
               if (ctx != null)
               {
                  try
                  {
                     ctx.close();
                  }
                  catch (NamingException e)
                  {
                     log.error("Caught exception closing naming context", e);
                  }
               }
            }
           
            try
            {
               NonSerializableFactory.unbind (jndiName);
            }
            catch (NameNotFoundException e)
            {
               log.error("Caught exception unbinding from NonSerializableFactory", e);
            }        
         }

         CacheManagerLocator locator = CacheManagerLocator.getCacheManagerLocator();
         if (locator.getDirectlyRegisteredManager() == this)
            locator.deregisterCacheManager();

         PojoCacheManagerLocator pclocator = PojoCacheManagerLocator.getCacheManagerLocator();
         if (pclocator.getDirectlyRegisteredManager() == this)
            pclocator.deregisterCacheManager();
        
         started = false;
      }
   }
  
  
  
   // -------------------------------------------------------------  Properties

   public String getJmxDomain()
   {
      return jmxDomain;
   }

   public void setJmxDomain(String jmxDomain)
   {
      this.jmxDomain = jmxDomain;
   }

   public String getCoreCacheJmxAttributes()
   {
      return coreCacheJmxAttributes;
   }

   public void setCoreCacheJmxAttributes(String coreCacheJmxAttributes)
   {
      this.coreCacheJmxAttributes = coreCacheJmxAttributes;
   }

   public String getPojoCacheJmxAttributes()
   {
      return pojoCacheJmxAttributes;
   }

   public void setPojoCacheJmxAttributes(String pojoCacheJmxAttributes)
   {
      this.pojoCacheJmxAttributes = pojoCacheJmxAttributes;
   }
  
   public boolean getRegisterCachesInJmx()
   {
      return registerCachesInJmx;
   }

   public void setRegisterCachesInJmx(boolean register)
   {
      this.registerCachesInJmx = register;
   }

   public String getJndiName()
   {
      return jndiName;
   }

   public void setJndiName(String jndiName)
   {
      this.jndiName = jndiName;
   }
  
  
   public Map<String, String> getConfigAliases()
   {
      synchronized (configAliases)
      {
         return new HashMap<String, String>(configAliases);
      }
   }
  
   public void setConfigAliases(Map<String, String> aliases)
   {
      synchronized (configAliases)
      {
         configAliases.clear();
         if (aliases != null)
            configAliases.putAll(aliases);
      }
   }
  
   public void setEagerStartCaches(Set<String> configNames)
   {
      if (configNames != null)
      {
         for (String name : configNames)
         {
            startupCaches.put(name, Boolean.FALSE);
         }
      }
   }
  
   public void setEagerStartPojoCaches(Set<String> configNames)
   {
      if (configNames != null)
      {
         for (String name : configNames)
         {
            startupCaches.put(name, Boolean.TRUE);
         }
      }
   }
  
  
  
   // ------------------------------------------------------  MBeanRegistration

   public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception
   {
      this.mbeanServer = server;
      if (jmxDomain == null)
      {
         jmxDomain = name.getDomain();
      }
      return name;
   }

   public void postDeregister()
   {
      // no-op     
   }

   public void preDeregister() throws Exception
   {
      // TODO Auto-generated method stub
     
   }

   public void postRegister(Boolean registrationDone)
   {
      // no-op
   }

   // ----------------------------------------------------------------  Private
  
   /**
    * Wrap the pojocache to control classloading and disable stop/destroy
    */
   private Cache wrapCache(Cache toWrap)
   {
      return toWrap == null ? null : new CacheManagerManagedCache(toWrap);
   }

   private int incrementPojoCacheCheckout(String configName)
   {
      synchronized (pojoCacheCheckouts)
      {
         Integer count = pojoCacheCheckouts.get(configName);
         if (count == null)
            count = new Integer(0);
         Integer newVal = new Integer(count.intValue() + 1);
         pojoCacheCheckouts.put(configName, newVal);
         return newVal.intValue();
      }
   }

   private int decrementPojoCacheCheckout(String configName)
   {
      synchronized (pojoCacheCheckouts)
      {
         Integer count = pojoCacheCheckouts.get(configName);
         if (count == null || count.intValue() < 1)
            throw new IllegalStateException("invalid count of " + count + " for " + configName);

         Integer newVal = new Integer(count.intValue() - 1);
         pojoCacheCheckouts.put(configName, newVal);
         return newVal.intValue();
      }
   }

   private void destroyPojoCache(String configName, PojoCache pojoCache)
   {
      Cache<Object, Object> cache = pojoCache.getCache();
      if (cache.getCacheStatus() == CacheStatus.STARTED)
      {
         pojoCache.stop();
      }
      if (cache.getCacheStatus() != CacheStatus.DESTROYED && cache.getCacheStatus() != CacheStatus.INSTANTIATED)
      {
         pojoCache.destroy();
      }
     
      if (registerCachesInJmx && mbeanServer != null)
      {
         String oNameStr = getObjectName(getPojoCacheJmxAttributes(), configName);
         try
         {
            ObjectName oName = new ObjectName(oNameStr);
            if (mbeanServer.isRegistered(oName))
            {
               mbeanServer.unregisterMBean(oName);
            }
         }
         catch (JMException e)
         {
            log.error("Problem unregistering PojoCacheJmxWrapper " + oNameStr, e);
         }
      }
   }
  
   private String getObjectName(String attributesBase, String configName)
   {
      String base = getJmxDomain() == null ? "" : getJmxDomain();
      return base + ":" + attributesBase + configName;
   }
  
   @CacheListener
   public static class StartStopListener
   {
      private final CacheJmxWrapper plainWrapper;
      private final PojoCacheJmxWrapper pojoWrapper;
     
      private StartStopListener(CacheJmxWrapper wrapper)
      {
         assert wrapper != null : "wrapper is null";
         this.plainWrapper = wrapper;
         this.pojoWrapper = null;
      }
     
      private StartStopListener(PojoCacheJmxWrapper wrapper)
      {
         assert wrapper != null : "wrapper is null";
         this.pojoWrapper = wrapper;
         this.plainWrapper = null;
      }
     
      @CacheStarted
      public void cacheStarted(CacheStartedEvent event)
      {
         if (plainWrapper != null)
            plainWrapper.start();
         else
            pojoWrapper.start();
      }
     
      @CacheStopped
      public void cacheStopped(CacheStoppedEvent event)
      {
         if (plainWrapper != null)
            plainWrapper.stop();
         else
            pojoWrapper.stop();
        
      }
   }

   /**
    * Helper method that binds the partition in the JNDI tree.
    * @param jndiName Name under which the object must be bound
    * @param who Object to bind in JNDI
    * @param classType Class type under which should appear the bound object
    * @param ctx Naming context under which we bind the object
    * @throws Exception Thrown if a naming exception occurs during binding
    */  
   private void bind(String jndiName, Object who, Class classType, Context ctx) throws Exception
   {
      // Ah ! This service isn't serializable, so we use a helper class
      //
      NonSerializableFactory.bind(jndiName, who);
      Name n = ctx.getNameParser("").parse(jndiName);
      while (n.size () > 1)
      {
         String ctxName = n.get (0);
         try
         {
            ctx = (Context)ctx.lookup (ctxName);
         }
         catch (NameNotFoundException e)
         {
            log.debug ("creating Subcontext " + ctxName);
            ctx = ctx.createSubcontext (ctxName);
         }
         n = n.getSuffix (1);
      }

      // The helper class NonSerializableFactory uses address type nns, we go on to
      // use the helper class to bind the service object in JNDI
      //
      StringRefAddr addr = new StringRefAddr("nns", jndiName);
      Reference ref = new Reference(classType.getName (), addr, NonSerializableFactory.class.getName (), null);
      ctx.rebind (n.get (0), ref);
   }
  
   private String resolveAlias(String configName)
   {
      String alias = configAliases.get(configName);
      return alias == null ? configName : alias;
   }
  
   private void startEagerStartCaches() throws Exception
   {
      for (Map.Entry<String, Boolean> entry : startupCaches.entrySet())
      {
         Cache cache = null;
         if (entry.getValue().booleanValue())
         {
            PojoCache pc = getPojoCache(entry.getKey(), true);
            cache = pc.getCache();
         }
         else
         {
            cache = getCache(entry.getKey(), true);
         }
        
         if (cache.getCacheStatus() != CacheStatus.STARTED)
         {
            if (cache.getCacheStatus() != CacheStatus.CREATED)
            {
               cache.create();
            }
            cache.start();
         }
      }
   }
  
   private void releaseEagerStartCaches()
   {
      for (String name : startupCaches.keySet())
      {
         releaseCache(name);
      }
   }

}
TOP

Related Classes of org.jboss.ha.cachemanager.CacheManager$StartStopListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.