Package org.jboss.ha.framework.server

Source Code of org.jboss.ha.framework.server.DistributedStateImpl

/*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, JBoss Inc., and individual contributors as indicated
  * by the @authors tag. See the copyright.txt 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.framework.server;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jboss.cache.Cache;
import org.jboss.cache.CacheException;
import org.jboss.cache.Fqn;
import org.jboss.cache.Node;
import org.jboss.cache.config.Configuration.CacheMode;
import org.jboss.cache.notifications.annotation.CacheListener;
import org.jboss.cache.notifications.annotation.NodeModified;
import org.jboss.cache.notifications.event.NodeModifiedEvent;
import org.jboss.cache.notifications.event.NodeModifiedEvent.ModificationType;
import org.jboss.ha.core.framework.server.ChannelSource;
import org.jboss.ha.framework.server.spi.ManagedDistributedState;
import org.jboss.logging.Logger;
import org.jgroups.Channel;

/**
*   This class manages distributed state across the cluster.
*
* @author  <a href="mailto:sacha.labourey@cogito-info.ch">Sacha Labourey</a>.
* @author  <a href="mailto:bill@burkecentral.com">Bill Burke</a>.
* @author  Scott.Stark@jboss.org
* @version $Revision:77673 $
*/
@CacheListener
public class DistributedStateImpl
   implements ManagedDistributedState, DistributedStateImplMBean, ChannelSource
{
   // Constants -----------------------------------------------------

   public static final Serializable ROOT = "__DISTRIBUTED_STATE__";
   public static final Fqn<Serializable>  ROOTFQN = Fqn.fromElements(ROOT);
   public static final int ROOTFQNSIZE = ROOTFQN.size();
  
   protected static final String SERVICE_NAME = "DistributedState";

   // Attributes ----------------------------------------------------

   protected Map<String, List<Object>> keyListeners = new HashMap<String, List<Object>>();
   protected Logger log = Logger.getLogger(this.getClass());
   protected String name = null;
   protected Cache<Serializable, Serializable> cache;
   protected boolean replAsync;
   protected HAPartitionCacheHandlerImpl cacheHandler;
   protected boolean acquiredCache = false;

   // Public --------------------------------------------------------

   public void createService() throws Exception
   {
   }

   public void startService() throws Exception
   {
      if (this.cache == null)
      {
         if (cacheHandler == null)
         {
            throw new IllegalStateException("No clustered cache available");
         }
        
         @SuppressWarnings("unchecked")
         Cache c = null;
         synchronized (cacheHandler)
         {
            c = cacheHandler.getCache();
            if (c == null)
            {
               cacheHandler.acquireCache();
               c = cacheHandler.getCache();
               acquiredCache = true;
            }
         }
         cacheHandler.startCache();
         @SuppressWarnings("unchecked")
         Cache<Serializable, Serializable> unchecked = c;
         internalSetClusteredCache(unchecked);
      }

      this.cache.addCacheListener(this);
   }

   public void stopService() throws Exception
   {     
      this.cache.removeCacheListener(this);
     
      if (acquiredCache)
      {
         cacheHandler.releaseCache();
         cache = null;
         acquiredCache = false;
      }
   }

   public void destroyService() throws Exception
   {
   }

   public String listContent() throws Exception
   {
      StringBuilder result = new StringBuilder();
      Collection<String> cats = this.getAllCategories();
      if (cats == null) return result.toString();

      Iterator<String> catsIter = cats.iterator();
      while (catsIter.hasNext())
      {
         String category = (String) catsIter.next();
         Iterator<Serializable> keysIter = this.getAllKeys(category).iterator();

         result.append("-----------------------------------------------\n");
         result.append("Logger : ").append(category).append("\n\n");
         result.append("KEY\t:\tVALUE\n");

         while (keysIter.hasNext())
         {
            Serializable key = (Serializable) keysIter.next();
            String value = this.get(category, key).toString();
            result.append("'").append(key);
            result.append("'\t:\t'");
            result.append(value);
            result.append("'\n");
         }
         result.append("\n");
      }
      return result.toString();
   }

   public String listXmlContent() throws Exception
   {
      StringBuilder result = new StringBuilder();
      result.append("<DistributedState>\n");
      Collection<String> cats = this.getAllCategories();
      if (cats != null)
      {
         Iterator<String> catsIter = cats.iterator();
         while (catsIter.hasNext())
         {
            String category = (String) catsIter.next();
            Iterator<Serializable> keysIter = this.getAllKeys(category).iterator();

            result.append("\t<Logger>\n");
            result.append("\t\t<LoggerName>").append(category).append("</LoggerName>\n");

            while (keysIter.hasNext())
            {
               Serializable key = (Serializable) keysIter.next();
               String value = this.get(category, key).toString();
               result.append("\t\t<Entry>\n");
               result.append("\t\t\t<Key>").append(key).append("</Key>\n");
               result.append("\t\t\t<Value>").append(value).append("</Value>\n");
               result.append("\t\t</Entry>\n");
            }
            result.append("\t</Logger>\n");
         }
      }

      result.append("</DistributedState>\n");

      return result.toString();
   }

   public Cache<Serializable, Serializable> getClusteredCache()
   {
      return this.cache;
   }

   /**
    * Sets the cache to use.
    *
    * @param cache the cache
    *
    * @throws IllegalStateException if the cache isn't configured for replication
    */
   public void setClusteredCache(Cache<Serializable, Serializable> cache)
   {
      internalSetClusteredCache(cache);
      acquiredCache = false;
   }

   public HAPartitionCacheHandlerImpl getCacheHandler()
   {
      return cacheHandler;
   }

   public void setCacheHandler(HAPartitionCacheHandlerImpl cacheHandler)
   {
      this.cacheHandler = cacheHandler;
   }

  
  

   // DistributedState implementation ----------------------------------------------
   /*
   * (non-Javadoc)
   *
   * @see org.jboss.ha.framework.interfaces.DistributedState#set(java.lang.String,
   *      java.io.Serializable, java.io.Serializable)
   */
   public void set(String category, Serializable key, Serializable value) throws Exception
   {
      this.set(category, key, value, true);
   }

   /*
    * (non-Javadoc)
    *
    * @see org.jboss.ha.framework.interfaces.DistributedState#set(java.lang.String,
    *      java.io.Serializable, java.io.Serializable, boolean) @param
    *      asynchronousCall is not supported yet. TreeCache cannot switch this
    *      on the fly. Will take value from TreeCache-config instead.
    */
   public void set(String category, Serializable key, Serializable value, boolean asynchronousCall) throws Exception
   {
      if (this.replAsync != asynchronousCall)
      {
         if (asynchronousCall)
         {
            this.cache.getInvocationContext().getOptionOverrides().setForceAsynchronous(true);
         }
         else
         {
            this.cache.getInvocationContext().getOptionOverrides().setForceSynchronous(true);
         }
      }
      this.cache.put(this.buildFqn(category), key, value);
   }

   /*
     * (non-Javadoc)
     *
     * @see org.jboss.ha.framework.interfaces.DistributedState#remove(java.lang.String,
     *      java.io.Serializable) @return - returns null in case of
     *      CacheException
     */
   public Serializable remove(String category, Serializable key) throws Exception
   {
      return this.remove(category, key, true);
   }

   /*
    * (non-Javadoc)
    *
    * @see org.jboss.ha.framework.interfaces.DistributedState#remove(java.lang.String,
    *      java.io.Serializable, boolean)
    */
   public Serializable remove(String category, Serializable key, boolean asynchronousCall) throws Exception
   {
      Serializable retVal = this.get(category, key);
      if (retVal != null)
      {
         if (this.replAsync != asynchronousCall)
         {
            if (asynchronousCall)
            {
               this.cache.getInvocationContext().getOptionOverrides().setForceAsynchronous(true);
            }
            else
            {
               this.cache.getInvocationContext().getOptionOverrides().setForceSynchronous(true);
            }
         }
         this.cache.remove(this.buildFqn(category), key);
      }
      return retVal;
   }

   /*
     * (non-Javadoc)
     *
     * @see org.jboss.ha.framework.interfaces.DistributedState#get(java.lang.String,
     *      java.io.Serializable)
     */
   public Serializable get(String category, Serializable key)
   {
      try
      {
         return (Serializable) this.cache.get(this.buildFqn(category), key);
      }
      catch (CacheException ce)
      {
         return null;
      }
   }

   public Collection<String> getAllCategories()
   {
      try
      {
         @SuppressWarnings("unchecked")
         Node base = this.cache.getRoot().getChild(ROOTFQN);
         @SuppressWarnings("unchecked")
         Collection<String> keys = (base == null ? null : base.getChildrenNames());
         if (keys != null && keys.size() > 0)
         {
            keys = Collections.unmodifiableCollection(keys);
         }
         return keys;
      }
      catch (CacheException ce)
      {
         return null;
      }
   }

   /*
     * (non-Javadoc)
     *
     * @see org.jboss.ha.framework.interfaces.DistributedState#getAllKeys(java.lang.String)
     *      @return - returns null in case of CacheException
     */
   public Collection<Serializable> getAllKeys(String category)
   {
      try
      {
         Node<Serializable, Serializable> node = this.getNode(category);
         if (node == null) return null;
         return node.getKeys();
      }
      catch (CacheException ce)
      {
         return null;
      }
   }

   /*
     * (non-Javadoc)
     *
     * @see org.jboss.ha.framework.interfaces.DistributedState#getAllValues(java.lang.String)
     *      @return - returns null in case of CacheException
     */
   public Collection<Serializable> getAllValues(String category)
   {
      try
      {
         Node<Serializable, Serializable> categoryNode = this.getNode(category);
         if (categoryNode == null) return null;
         Set<Serializable> childNodes = categoryNode.getKeys();
         if (childNodes == null) return null;
         Map<Serializable, Serializable> entries = categoryNode.getData();
         if (entries == null) return null;
         Collection<Serializable> retVal = new HashSet<Serializable>(entries.values());
         return Collections.unmodifiableCollection(retVal);
      }
      catch (CacheException ce)
      {
         return null;
      }
   }

   @SuppressWarnings("deprecation")
   public void registerDSListenerEx(String category, DSListenerEx subscriber)
   {
      this.registerListener(category, subscriber);
   }

   @SuppressWarnings("deprecation")
   public void unregisterDSListenerEx(String category, DSListenerEx subscriber)
   {
      this.unregisterListener(category, subscriber);
   }

   @SuppressWarnings("deprecation")
   public void registerDSListener(String category, DSListener subscriber)
   {
      this.registerListener(category, subscriber);
   }

   @SuppressWarnings("deprecation")
   public void unregisterDSListener(String category, DSListener subscriber)
   {
      this.unregisterListener(category, subscriber);
   }

   // ChannelSource -------------------------------------------------

   public Channel getChannel()
   {
      Channel result = null;
      if (cache != null)
      {
         result = cache.getConfiguration().getRuntimeConfig().getChannel();
      }
      return result;
   }
  
   // Package protected ---------------------------------------------

   // Protected -----------------------------------------------------

   protected void registerListener(String category, Object subscriber)
   {
      synchronized (this.keyListeners)
      {
         List<Object> listeners = this.keyListeners.get(category);
         if (listeners == null)
         {
            listeners = new ArrayList<Object>();
            this.keyListeners.put(category, listeners);
         }
         listeners.add(subscriber);
      }
   }

   protected void unregisterListener(String category, Object subscriber)
   {
      synchronized (this.keyListeners)
      {
         List<Object> listeners = this.keyListeners.get(category);
         if (listeners == null) return;

         listeners.remove(subscriber);
         if (listeners.size() == 0)
         {
            this.keyListeners.remove(category);
         }
      }
   }

   @SuppressWarnings("deprecation")
   protected void notifyKeyListeners(String category, Serializable key, Serializable value, boolean locallyModified)
   {
      synchronized (this.keyListeners)
      {
         List<Object> listeners = this.keyListeners.get(category);
         if (listeners == null) return;
         String strKey = key.toString();

         for (Object listener: listeners)
         {
            if (listener instanceof DSListener)
            {
               DSListener dslistener = (DSListener) listener;
               dslistener.valueHasChanged(category, strKey, value, locallyModified);
            }
            else
            {
               DSListenerEx dslistener = (DSListenerEx) listener;
               dslistener.valueHasChanged(category, key, value, locallyModified);
            }
         }
      }
   }

   @SuppressWarnings("deprecation")
   protected void notifyKeyListenersOfRemove(String category, Serializable key, Serializable oldContent,
         boolean locallyModified)
   {
      synchronized (this.keyListeners)
      {
         List<Object> listeners = this.keyListeners.get(category);
         if (listeners == null) return;
         String strKey = key.toString();

         for (Object listener: listeners)
         {
            if (listener instanceof DSListener)
            {
               DSListener dslistener = (DSListener) listener;
               dslistener.keyHasBeenRemoved(category, strKey, oldContent, locallyModified);
            }
            else
            {
               DSListenerEx dslistener = (DSListenerEx) listener;
               dslistener.keyHasBeenRemoved(category, key, oldContent, locallyModified);
            }
         }
      }
   }

   protected void cleanupKeyListeners()
   {
      // NOT IMPLEMENTED YET
   }

   /** ExtendedTreeCacheListener methods */

   // Private -------------------------------------------------------
   protected Fqn<Serializable> buildFqn(String category)
   {
      return Fqn.fromRelativeElements(ROOTFQN, category);
   }

   protected Fqn<Serializable>  buildFqn(String category, Serializable key)
   {
      return Fqn.fromElements(ROOT, category, key);
   }

   protected Fqn<Serializable> buildFqn(String category, Serializable key, Serializable value)
   {
      return Fqn.fromElements(ROOT, category, key, value);
   }

   protected Node<Serializable, Serializable> getNode(String category) throws CacheException
   {
      return this.cache.getRoot().getChild(this.buildFqn(category));
   }

   // @CacheListener  -------------------------------------------------

   @NodeModified
   public void nodeModified(NodeModifiedEvent event)
   {
      if (event.isPre()) return;

      // we're only interested in put and remove data operations
      ModificationType modType = event.getModificationType();
      if (!modType.equals(ModificationType.PUT_DATA) && !modType.equals(ModificationType.REMOVE_DATA)) return;

      // ignore changes for other roots in a shared cache
      @SuppressWarnings("unchecked")
      Fqn<Serializable>  fqn = event.getFqn();
      if (!fqn.isChildOf(ROOTFQN)) return;

      Serializable key = null;
      Serializable value = null;

      // there should be exactly one key/value pair in the map
      @SuppressWarnings("unchecked")
      Map<Serializable, Serializable> data = event.getData();
      if (data != null && !data.isEmpty())
      {
         key = (Serializable) data.keySet().iterator().next();
         value = (Serializable) data.get(key);
      }

      if (modType.equals(ModificationType.PUT_DATA))
      {
         DistributedStateImpl.this.notifyKeyListeners((String) fqn.get(ROOTFQNSIZE), key, value, event.isOriginLocal());
      }
      else
      {
         DistributedStateImpl.this.notifyKeyListenersOfRemove((String) fqn.get(ROOTFQNSIZE), key, value, event.isOriginLocal());
      }
   }
  
   // Private ------------------------------------------------------------
  
   private void internalSetClusteredCache(Cache<Serializable, Serializable> cache)
   {
      this.cache = cache;
      if (this.cache != null)
      {       
        CacheMode cm = cache.getConfiguration().getCacheMode();
        if (CacheMode.REPL_ASYNC == cm)
        {
           this.replAsync = true;
        }
        else if (CacheMode.REPL_SYNC == cm)
        {
           this.replAsync = false;
        }
        else
        {
           throw new IllegalStateException("Cache must be configured for replication, not " + cm);
        }
      }
   }

}
TOP

Related Classes of org.jboss.ha.framework.server.DistributedStateImpl

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.