[jbosscache-commits] JBoss Cache SVN: r4684 - in core/trunk/src/main/java/org/jboss/cache: registry and 1 other directory.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Thu Oct 25 01:59:01 EDT 2007


Author: bstansberry at jboss.com
Date: 2007-10-25 01:59:01 -0400 (Thu, 25 Oct 2007)
New Revision: 4684

Added:
   core/trunk/src/main/java/org/jboss/cache/registry/
   core/trunk/src/main/java/org/jboss/cache/registry/CacheConfigsXmlParser.java
   core/trunk/src/main/java/org/jboss/cache/registry/CacheRegistry.java
   core/trunk/src/main/java/org/jboss/cache/registry/CacheRegistryImpl.java
   core/trunk/src/main/java/org/jboss/cache/registry/ConfigurationRegistry.java
   core/trunk/src/main/java/org/jboss/cache/registry/XmlParsingConfigurationRegistry.java
Log:
[JBCACHE-1156] Registry for caches and configurations

Added: core/trunk/src/main/java/org/jboss/cache/registry/CacheConfigsXmlParser.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/registry/CacheConfigsXmlParser.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/registry/CacheConfigsXmlParser.java	2007-10-25 05:59:01 UTC (rev 4684)
@@ -0,0 +1,122 @@
+/*
+ * 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.cache.registry;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.ConfigurationException;
+import org.jboss.cache.factories.XmlConfigurationParser;
+import org.jboss.cache.xml.XmlHelper;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class CacheConfigsXmlParser 
+ {
+    /** Name of the root element in a cache configs XML document*/
+    public static final String DOCUMENT_ROOT = "cache-configs";
+    /** 
+     * Name of the element that represents an individual cache configuration 
+     * in a cache configs XML document.
+     */
+    public static final String CONFIG_ROOT = "cache-config";
+    /** 
+     * Name of the attribute in a {@link #CONFIG_ROOT cache-config} element that specifies
+     * the name of the configuration.
+     */
+    public static final String CONFIG_NAME = "name";
+    
+    private static final Log log = LogFactory.getLog(CacheConfigsXmlParser.class);
+    
+    private final XmlConfigurationParser parser = new XmlConfigurationParser();
+
+    public Map<String, Configuration> parseConfigs(String fileName) throws CloneNotSupportedException 
+    {
+       InputStream is = getAsInputStreamFromClassLoader(fileName);
+       if (is == null)
+       {
+          if (log.isDebugEnabled())
+             log.debug("Unable to find configuration file " + fileName + " in classpath; searching for this file on the filesystem instead.");
+          try
+          {
+             is = new FileInputStream(fileName);
+          }
+          catch (FileNotFoundException e)
+          {
+             throw new ConfigurationException("Unable to find config file " + fileName + " either in classpath or on the filesystem!", e);
+          }
+       }
+
+       return parseConfigs(is);
+    }
+     
+    public Map<String, Configuration> parseConfigs(InputStream stream) throws CloneNotSupportedException 
+    {            
+       // loop through all elements in XML.
+       Element root = XmlHelper.getDocumentRoot(stream);
+       NodeList list = root.getElementsByTagName(CONFIG_ROOT);
+       if (list == null || list.getLength() == 0) 
+          throw new ConfigurationException("Can't find " + CONFIG_ROOT + " tag");
+         
+       Map<String, Configuration> result = new HashMap<String, Configuration>();
+         
+       for (int i = 0; i < list.getLength(); i++)
+       {
+          Node node = list.item(i);
+          if (node.getNodeType() != Node.ELEMENT_NODE)
+          {
+             continue;
+          }
+            
+          Element element = (Element) node;
+          String name = element.getAttribute(CONFIG_NAME);
+          if (name == null || name.trim().length() == 0)
+              throw new ConfigurationException("Element " + element + " has no name attribute");
+            
+          Configuration c = parser.parseConfiguration(element);
+          // Prove that we can successfully clone it
+          c = c.clone();
+          result.put(name.trim(), c);
+       }
+         
+       return result;
+    }
+
+    protected InputStream getAsInputStreamFromClassLoader(String filename)
+    {
+       InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(filename);
+       if (is == null)
+       {
+          // check system class loader
+          is = getClass().getClassLoader().getResourceAsStream(filename);
+       }
+       return is;
+    }
+ }
\ No newline at end of file


Property changes on: core/trunk/src/main/java/org/jboss/cache/registry/CacheConfigsXmlParser.java
___________________________________________________________________
Name: svn:executable
   + *

Added: core/trunk/src/main/java/org/jboss/cache/registry/CacheRegistry.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/registry/CacheRegistry.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/registry/CacheRegistry.java	2007-10-25 05:59:01 UTC (rev 4684)
@@ -0,0 +1,95 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package org.jboss.cache.registry;
+
+import java.util.Set;
+
+import org.jboss.cache.Cache;
+import org.jboss.cache.config.Configuration;
+import org.jgroups.ChannelFactory;
+import org.jgroups.JChannelFactory;
+
+/**
+ * Factory and registry for JBoss Cache instances configured using
+ * named configurations.
+ * 
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 1 $
+ */
+public interface CacheRegistry {
+
+    /**
+     * Gets the names of all the configurations of which this object
+     * is aware.
+     * 
+     * @return a set of names. Will not be <code>null</code>.
+     */
+    Set<String> getConfigurationNames();
+    
+    /**
+     * Gets the name of all caches that are registered, i.e. that can be
+     * by a call to {@link #getCache(String, boolean) getCache(name, false)}.
+     * 
+     * @return a set of names. Will not be <code>null</code>.
+     */
+    Set<String> getCacheNames();
+    
+    /**
+     * Gets the JGroups <code>ChannelFactory</code> that will be injected
+     * into any {@link Configuration} that has a 
+     * {@link Configuration#getMultiplexerStack() multiplexer stack}
+     * configured.
+     * 
+     * @return
+     */
+    ChannelFactory getChannelFactory();
+    
+    /**
+     * Get a cache configured according to the given configuration name, 
+     * optionally instantiating the cache if it hasn't already been 
+     * instantiated.
+     * <p>
+     * The caller is free to invoke the {@link Cache#create()} and
+     * {@link Cache#start()} lifecycle methods on the returned cache, but
+     * the @link Cache#stop()} and {@link Cache#destroy()} methods should not
+     * be invoked, since it is quite possible other users are still using the 
+     * cache. Use {@link #releaseCache(String)} to notify this 
+     * registry that the caller is no longer using a cache; let the registry 
+     * control stopping and destroying the cache.
+     * </p>
+     * <p>
+     * If invoking this method leads to the instantiation of the cache,
+     * <code>create()</code> and <code>start()</code> will not be invoked
+     * on the cache before it is returned.
+     * </p>
+     * 
+     * @param configName    the name of the configuration
+     * @param create        should the cache be instantiated if it
+     *                      hasn't already been?
+     * @return              the cache, or <code>null</code> if 
+     *                      <code>create</code> is false and the cache hasn't
+     *                      been created previously.
+     *                      
+     * @throws IllegalArgumentException if this object is unaware of 
+     *                                  <code>configName</code>; i.e. the set
+     *                                  returned from {@link #getConfigurationNames()}
+     *                                  does not include <code>configName</code>
+     * @throws Exception if there is a problem instantiating the cache
+     */
+    Cache<Object, Object> getCache(String configName, boolean create) throws Exception;
+    
+    /**
+     * Notifies the registry that the caller is no longer using the given
+     * cache.  The registry may perform cleanup operations, such as 
+     * stopping and destroying the cache.
+     * 
+     * @param configName
+     */
+    void releaseCache(String configName);
+
+}
\ No newline at end of file


Property changes on: core/trunk/src/main/java/org/jboss/cache/registry/CacheRegistry.java
___________________________________________________________________
Name: svn:executable
   + *

Added: core/trunk/src/main/java/org/jboss/cache/registry/CacheRegistryImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/registry/CacheRegistryImpl.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/registry/CacheRegistryImpl.java	2007-10-25 05:59:01 UTC (rev 4684)
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, v. 2.1. This program is distributed in the
+ * hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
+ * distribution; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Red Hat Author(s): Brian Stansberry
+ */
+
+package org.jboss.cache.registry;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.jboss.cache.Cache;
+import org.jboss.cache.CacheStatus;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.config.Configuration;
+import org.jgroups.ChannelFactory;
+
+/**
+ * Basic implementation of {@link CacheRegistry}.
+ * 
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 1 $
+ */
+public class CacheRegistryImpl implements CacheRegistry
+{
+   private ConfigurationRegistry configRegistry;
+
+   private boolean configRegistryInjected;
+
+   private Map<String, Cache<Object, Object>> caches = new HashMap<String, Cache<Object, Object>>();
+
+   private Map<String, Integer> checkouts = new HashMap<String, Integer>();
+
+   private ChannelFactory channelFactory;
+
+   private boolean started;
+
+   /**
+    * Create a new CacheRegistryImpl.
+    */
+   public CacheRegistryImpl()
+   {
+   }
+
+   /**
+    * Create a new CacheRegistryImpl using the provided ConfigurationRegistry
+    * and ChannelFactory.
+    */
+   public CacheRegistryImpl(ConfigurationRegistry configRegistry, ChannelFactory factory)
+   {
+      this.configRegistry = configRegistry;
+      this.configRegistryInjected = true;
+      this.channelFactory = factory;
+   }
+
+   /**
+    * Create a new CacheRegistryImpl using the provided ChannelFactory and 
+    * using the provided file name to create an 
+    * {@link XmlParsingConfigurationRegistry}.
+    */
+   public CacheRegistryImpl(String configFileName, ChannelFactory factory)
+   {
+      configRegistry = new XmlParsingConfigurationRegistry(configFileName);
+      this.channelFactory = factory;
+   }
+
+   // ----------------------------------------------------------  CacheRegistry
+   
+   public ChannelFactory getChannelFactory()
+   {
+      return channelFactory;
+   }
+
+   @SuppressWarnings("unchecked")
+   public Set<String> getConfigurationNames()
+   {
+      synchronized (caches)
+      {
+         Set<String> configNames = configRegistry == null ? new HashSet<String>() 
+                                                          : configRegistry.getConfigurationNames();
+         configNames.addAll(getCacheNames());
+         return configNames;
+      }
+   }
+
+   public Set<String> getCacheNames()
+   {
+      synchronized (caches)
+      {
+         return new HashSet<String>(caches.keySet());
+      }
+   }
+
+   public Cache<Object, Object> getCache(String configName, boolean create) throws Exception
+   {
+      Cache<Object, Object> cache = null;
+      synchronized (caches)
+      {
+         cache = (Cache<Object, Object>) caches.get(configName);
+         if (cache == null && create)
+         {
+            Configuration config = configRegistry.getConfiguration(configName);
+            if (channelFactory != null && config.getMultiplexerStack() != null) {
+               config.getRuntimeConfig().setMuxChannelFactory(channelFactory);
+            }
+            cache = DefaultCacheFactory.getInstance().createCache(config, false);
+            registerCache(cache, configName);
+         }
+         else if (cache != null)
+         {
+            incrementCheckout(configName);
+         }
+      }
+
+      return cache;
+   }
+
+   public void releaseCache(String configName)
+   {
+      synchronized (caches)
+      {
+         if (!caches.containsKey(configName))
+            throw new IllegalStateException(configName + " not registered");
+         if (decrementCheckout(configName) == 0)
+         {
+            Cache<Object, Object> cache = caches.remove(configName);
+            destroyCache(cache);
+         }
+      }
+   }
+
+   // -----------------------------------------------------------------  Public
+   
+   public ConfigurationRegistry getConfigurationRegistry()
+   {
+      return configRegistry;
+   }
+
+   public void setConfigurationRegistry(ConfigurationRegistry configRegistry)
+   {
+      this.configRegistry = configRegistry;
+      this.configRegistryInjected = true;
+   }
+
+   public void setChannelFactory(ChannelFactory channelFactory)
+   {
+      this.channelFactory = channelFactory;
+   }
+
+   public void registerCache(Cache<Object, Object> cache, String configName)
+   {
+      synchronized (caches)
+      {
+         if (caches.containsKey(configName))
+            throw new IllegalStateException(configName + " already registered");
+         caches.put(configName, cache);
+         incrementCheckout(configName);
+      }
+   }
+
+   public void start() throws Exception
+   {
+      if (!started)
+      {
+         if (configRegistry == null)
+            throw new IllegalStateException("Must configure a ConfigurationRegistry before calling start()");
+         if (channelFactory == null)
+            throw new IllegalStateException("Must provide a ChannelFactory before calling start()");
+         
+         if (!configRegistryInjected)
+         {
+            ((XmlParsingConfigurationRegistry) configRegistry).start();
+         }
+         
+         started = true;
+      }
+   }
+
+   public void stop()
+   {
+      if (started)
+      {
+         synchronized (caches)
+         {
+            for (Iterator<Map.Entry<String, Cache<Object, Object>>> it = caches.entrySet().iterator(); it.hasNext();)
+            {
+               Map.Entry<String, Cache<Object, Object>> entry = it.next();
+               destroyCache(entry.getValue());
+               it.remove();
+            }
+            caches.clear();
+            checkouts.clear();
+         }
+         
+         if (!configRegistryInjected)
+         {
+            ((XmlParsingConfigurationRegistry) configRegistry).stop();
+         }
+         
+         started = false;
+      }
+   }
+
+   // ----------------------------------------------------------------  Private
+   
+   private int incrementCheckout(String configName)
+   {
+      synchronized (checkouts)
+      {
+         Integer count = (Integer) checkouts.get(configName);
+         if (count == null)
+            count = new Integer(0);
+         Integer newVal = new Integer(count.intValue() + 1);
+         checkouts.put(configName, newVal);
+         return newVal.intValue();
+      }
+   }
+
+   private int decrementCheckout(String configName)
+   {
+      synchronized (checkouts)
+      {
+         Integer count = (Integer) checkouts.get(configName);
+         if (count == null || count.intValue() < 1)
+            throw new IllegalStateException("invalid count of " + count + " for " + configName);
+
+         Integer newVal = new Integer(count.intValue() - 1);
+         checkouts.put(configName, newVal);
+         return newVal.intValue();
+      }
+   }
+
+   private void destroyCache(Cache<Object, Object> cache)
+   {
+      if (cache.getCacheStatus() == CacheStatus.STARTED)
+      {
+         cache.stop();
+      }
+      if (cache.getCacheStatus() != CacheStatus.DESTROYED && cache.getCacheStatus() != CacheStatus.INSTANTIATED)
+      {
+         cache.destroy();
+      }
+   }
+}


Property changes on: core/trunk/src/main/java/org/jboss/cache/registry/CacheRegistryImpl.java
___________________________________________________________________
Name: svn:executable
   + *

Added: core/trunk/src/main/java/org/jboss/cache/registry/ConfigurationRegistry.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/registry/ConfigurationRegistry.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/registry/ConfigurationRegistry.java	2007-10-25 05:59:01 UTC (rev 4684)
@@ -0,0 +1,67 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache.registry;
+
+import java.util.Set;
+
+import org.jboss.cache.config.Configuration;
+
+/**
+ * A registry for {@link Configuration}s.
+ * 
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+public interface ConfigurationRegistry
+{
+   /**
+    * Gets a {@link Configuration#clone() clone} of the {@link Configuration} 
+    * registered under the given name.
+    * <p>
+    * The returned object is a clone of the internally held configuration,
+    * so any changes made to it by the caller will not affect the internal
+    * state of this registry. 
+    * 
+    * @param configName the name of the configuration
+    * @return a <code>Configuration</code>. Will not be <code>null</code>.
+    * @throws IllegalArgumentException if no configuration is registered
+    *                                  under <code>configName</code>
+    */
+   Configuration getConfiguration(String configName) throws Exception;
+
+   /**
+    * Register the given configuration under the given name.
+    * <p>
+    * The configuration will be cloned before being stored internally,
+    * so the copy under the control of the registry will not be affected
+    * by any external changes.
+    * 
+    * @param configName the name of the configuration
+    * @param config     the configuration
+    * 
+    * @throws CloneNotSupportedException
+    * @throws IllegalStateException if a configuration is already registered
+    *                               under <code>configName</code>
+    */
+   void registerConfiguration(String configName, Configuration config) throws CloneNotSupportedException;
+   
+   /**
+    * Unregisters the named configuration.
+    * 
+    * @param configName the name of the configuration
+    * @throws IllegalStateException if no configuration is registered
+    *                                  under <code>configName</code>
+    */
+   void unregisterConfiguration(String configName);
+
+   /**
+    * Gets the names of all registered configurations.
+    * 
+    * @return
+    */
+   Set<String> getConfigurationNames();
+}
\ No newline at end of file


Property changes on: core/trunk/src/main/java/org/jboss/cache/registry/ConfigurationRegistry.java
___________________________________________________________________
Name: svn:executable
   + *

Added: core/trunk/src/main/java/org/jboss/cache/registry/XmlParsingConfigurationRegistry.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/registry/XmlParsingConfigurationRegistry.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/registry/XmlParsingConfigurationRegistry.java	2007-10-25 05:59:01 UTC (rev 4684)
@@ -0,0 +1,108 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package org.jboss.cache.registry;
+
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+import org.jboss.cache.config.Configuration;
+
+/**
+ * {@link ConfigurationRegistry} that obtains its initial set of configurations
+ * by parsing an XML document.
+ * 
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 1 $
+ */
+public class XmlParsingConfigurationRegistry implements ConfigurationRegistry 
+{    
+    private CacheConfigsXmlParser parser;
+    private String configResource;
+    private Map<String, Configuration> configs = new Hashtable<String, Configuration>();
+    private boolean started;
+    
+    public XmlParsingConfigurationRegistry(String configResource) 
+    {        
+        parser = new CacheConfigsXmlParser();
+        this.configResource = configResource;
+    }
+    
+    public void start() throws Exception
+    {
+        if (!started) 
+        {
+            configs.putAll(parser.parseConfigs(configResource));
+            started = true;
+        }
+    }
+    
+    public void stop() 
+    {
+        if (started) 
+        {
+            synchronized (configs) 
+            {
+                configs.clear();
+            }
+            started = false;
+        }
+    }
+    
+    public String getConfigResource() 
+    {
+        return configResource;
+    }
+
+    public Set<String> getConfigurationNames()
+    {
+        return new HashSet<String>(configs.keySet());
+    }
+    
+    public void registerConfiguration(String configName, Configuration config) 
+       throws CloneNotSupportedException
+    {
+        synchronized (configs) {
+            if (configs.containsKey(configName))
+                throw new IllegalStateException(configName + " already registered");
+            configs.put(configName, config.clone());
+        }
+    }
+    
+    public void unregisterConfiguration(String configName) 
+    {
+        synchronized (configs) {
+            if (configs.remove(configName) == null)
+                throw new IllegalStateException(configName + " not registered");            
+        }
+    }
+    
+    public Configuration getConfiguration(String configName) 
+    {
+       Configuration config = null;
+       synchronized (configs)
+       {
+          config = configs.get(configName);
+       }
+       
+       if (config == null)
+          throw new IllegalArgumentException("unknown config " + configName);
+        
+       // Don't hand out a ref to our master copy 
+       try
+       {
+          return config.clone();
+       }
+       catch (CloneNotSupportedException e)
+       {
+          // This should not happen, as we already cloned the config
+          throw new RuntimeException("Could not clone configuration " + configName, e);
+       }
+    }
+}


Property changes on: core/trunk/src/main/java/org/jboss/cache/registry/XmlParsingConfigurationRegistry.java
___________________________________________________________________
Name: svn:executable
   + *




More information about the jbosscache-commits mailing list