Convert from JBossCacheFactory prototype to the real JBC CacheManager

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@14262 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Brian Stansberry 2007-12-23 14:55:36 +00:00
parent 772b12b454
commit 8277156f00
4 changed files with 14 additions and 463 deletions

View File

@ -1,81 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2007, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.  All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* 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, as published by the Free Software Foundation.
*
* This program 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 distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cache.jbc2.builder;
import java.util.Set;
import org.jboss.cache.Cache;
/**
* Factory and registry for JBoss Cache instances configured using
* named configurations.
*
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
* @version $Revision: 1 $
*/
public interface JBossCacheFactory {
/**
* Gets all the names of all the configurations of which this object
* is aware.
*
* @return
*/
Set getConfigurationNames();
/**
* Get a cache configured according to the given configuration name.
* <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 session factories are
* still using the cache. Use {@link #releaseCache(String)} to notify this
* factory that the caller is no longer using a cache; let the factory
* control stopping and destroying the underlying cache.
* </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>
* @throws Exception if there is a problem instantiating the cache
*/
Cache getCache(String configName, boolean create) throws Exception;
/**
* Notifies the factory that the caller is no longer using the given
* cache. The factory may perform cleanup operations, such as
* stopping and destroying the cache.
*
* @param configName
*/
void releaseCache(String configName);
}

View File

@ -1,368 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2007, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.  All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* 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, as published by the Free Software Foundation.
*
* This program 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 distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cache.jbc2.builder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.hibernate.cache.CacheException;
import org.jboss.cache.Cache;
import org.jboss.cache.CacheStatus;
import org.jboss.cache.DefaultCacheFactory;
import org.jboss.cache.config.Configuration;
import org.jboss.cache.config.ConfigurationException;
import org.jboss.cache.xml.XmlHelper;
import org.jgroups.ChannelFactory;
import org.jgroups.JChannelFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;
/**
* A JBossCacheConfigurationFactory. This is a basic prototype of a
* JBCACHE-1156 solution; only in Hibernate code base for a very short
* period.
*
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
* @version $Revision: 1 $
*/
public class JBossCacheFactoryImpl implements JBossCacheFactory {
private static final Logger log = LoggerFactory.getLogger(JBossCacheFactoryImpl.class);
private static final String DOCUMENT_ROOT = "cache-configs";
private static final String CONFIG_ROOT = "cache-config";
private static final String CONFIG_NAME = "name";
private static JBossCacheFactoryImpl sharedFactory;
private static String sharedChannelFactoryCfg;
private XmlConfigurationParser parser;
private String configResource;
private Map configs = new HashMap();
private Map caches = new HashMap();
private Map checkouts = new HashMap();
private ChannelFactory channelFactory;
private boolean started;
public JBossCacheFactoryImpl(String configResource, ChannelFactory factory) {
parser = new XmlConfigurationParser();
this.configResource = configResource;
this.channelFactory = factory;
}
public static synchronized JBossCacheFactory getSharedInstance(String cacheConfigResource, String channelFactoryConfigResource) {
if (sharedFactory == null) {
ChannelFactory cf = new JChannelFactory();
try {
cf.setMultiplexerConfig(channelFactoryConfigResource);
}
catch (Exception e) {
throw new CacheException("Problem setting ChannelFactory config", e);
}
sharedFactory = new JBossCacheFactoryImpl(cacheConfigResource, cf);
sharedChannelFactoryCfg = channelFactoryConfigResource;
}
else {
// Validate that the provided resources match the existing singleton
if (!sharedFactory.getConfigResource().equals(cacheConfigResource)) {
throw new CacheException("Provided cacheConfigResource does " +
"not match the existing shared factory: provided = " +
cacheConfigResource + "; existing = " + sharedFactory.getConfigResource());
}
else if (!sharedChannelFactoryCfg.equals(channelFactoryConfigResource)) {
throw new IllegalStateException("Provided channelFactoryConfigResource does " +
"not match the existing shared factory: provided = " +
channelFactoryConfigResource + "; existing = " + sharedChannelFactoryCfg);
}
}
return sharedFactory;
}
public void start() {
if (!started) {
this.configs = parser.parseConfigs(configResource);
started = true;
}
}
public void stop() {
if (started) {
synchronized (caches) {
for (Iterator it = caches.entrySet().iterator(); it.hasNext(); ) {
Map.Entry entry = (Entry) it.next();
destroyCache((Cache) entry.getValue());
it.remove();
}
caches.clear();
checkouts.clear();
configs.clear();
}
started = false;
}
}
public String getConfigResource() {
return configResource;
}
public ChannelFactory getChannelFactory() {
return channelFactory;
}
public Set getConfigurationNames()
{
return new HashSet(configs.keySet());
}
public Cache getCache(String configName, boolean create) throws Exception
{
Cache cache = null;
synchronized (caches) {
cache = (Cache) caches.get(configName);
if (cache == null && create) {
Configuration config = getConfiguration(configName);
cache = DefaultCacheFactory.getInstance().createCache(config, false);
registerCache(cache, configName);
}
else if (cache != null) {
incrementCheckout(configName);
}
}
return cache;
}
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();
}
}
public void registerCache(Cache cache, String configName) {
synchronized (caches) {
if (caches.containsKey(configName))
throw new IllegalStateException(configName + " already registered");
caches.put(configName, cache);
incrementCheckout(configName);
}
}
public void releaseCache(String configName) {
synchronized (caches) {
if (!caches.containsKey(configName))
throw new IllegalStateException(configName + " not registered");
if (decrementCheckout(configName) == 0) {
Cache cache = (Cache) caches.remove(configName);
destroyCache(cache);
}
}
}
private void destroyCache(Cache cache) {
if (cache.getCacheStatus() == CacheStatus.STARTED) {
cache.stop();
}
if (cache.getCacheStatus() != CacheStatus.DESTROYED
&& cache.getCacheStatus() != CacheStatus.INSTANTIATED) {
cache.destroy();
}
}
public Configuration getConfiguration(String configName) throws Exception {
Element element = (Element) configs.get(configName);
if (element == null)
throw new IllegalArgumentException("unknown config " + configName);
Configuration config = parser.parseConfig(element);
if (channelFactory != null && config.getMultiplexerStack() != null) {
config.getRuntimeConfig().setMuxChannelFactory(channelFactory);
}
return config;
}
class XmlConfigurationParser extends org.jboss.cache.factories.XmlConfigurationParser {
public Map parseConfigs(String configs) {
InputStream is = getAsInputStreamFromClassLoader(configs);
if (is == null)
{
if (log.isDebugEnabled())
log.debug("Unable to find configuration file " + configs + " in classpath; searching for this file on the filesystem instead.");
try
{
is = new FileInputStream(configs);
}
catch (FileNotFoundException e)
{
throw new ConfigurationException("Unable to find config file " + configs + " either in classpath or on the filesystem!", e);
}
}
return parseConfigs(is);
}
public Map parseConfigs(InputStream stream) {
// 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 result = new HashMap();
for (int i = 0; i < list.getLength(); i++)
{
org.w3c.dom.Node node = list.item(i);
if (node.getNodeType() != org.w3c.dom.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");
result.put(name.trim(), element);
}
return result;
}
public Configuration parseConfig(Element config) throws Exception {
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = docBuilderFactory.newDocumentBuilder();
Document doc = builder.newDocument();
Element root = doc.createElement(DOCUMENT_ROOT);
doc.appendChild(root);
Node imported = doc.importNode(config, true);
root.appendChild(imported);
DOMImplementation domImpl = doc.getImplementation();
DOMImplementationLS impl =
(DOMImplementationLS)domImpl.getFeature("LS", "3.0");
LSSerializer writer = impl.createLSSerializer();
LSOutput output = impl.createLSOutput();
output.setEncoding("UTF-8");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
output.setByteStream(baos);
writer.write(doc, output);
ByteArrayInputStream is = new ByteArrayInputStream(baos.toByteArray());
return parseStream(is);
}
@Override
protected Element getMBeanElement(Element root)
{
// This is following JBoss convention.
NodeList list = root.getElementsByTagName(CONFIG_ROOT);
if (list == null) throw new ConfigurationException("Can't find " + CONFIG_ROOT + " tag");
if (list.getLength() > 1) throw new ConfigurationException("Has multiple " + CONFIG_ROOT + " tag");
Node node = list.item(0);
Element element = null;
if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE)
{
element = (Element) node;
}
else
{
throw new ConfigurationException("Can't find " + CONFIG_ROOT + " element");
}
return element;
}
}
public static void main(String[] args)
{
try
{
JChannelFactory cf = new JChannelFactory();
cf.setMultiplexerConfig("stacks.xml");
JBossCacheFactoryImpl factory = new JBossCacheFactoryImpl("jbc2-configs.xml", cf);
for (Iterator iter = factory.getConfigurationNames().iterator(); iter.hasNext(); )
{
String name = (String) iter.next();
Cache c = factory.getCache(name, true);
c.start();
System.out.println(name + " == " + c);
factory.releaseCache(name);
System.out.println(name + " == " + c.getCacheStatus());
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace(System.out);
}
}
}

View File

@ -33,6 +33,7 @@ import org.hibernate.cache.CacheException;
import org.hibernate.cfg.Settings; import org.hibernate.cfg.Settings;
import org.hibernate.util.NamingHelper; import org.hibernate.util.NamingHelper;
import org.hibernate.util.PropertiesHelper; import org.hibernate.util.PropertiesHelper;
import org.jboss.cache.CacheManager;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -49,7 +50,7 @@ public class JndiMultiplexingCacheInstanceManager extends MultiplexingCacheInsta
private static final Logger log = LoggerFactory.getLogger(JndiMultiplexingCacheInstanceManager.class); private static final Logger log = LoggerFactory.getLogger(JndiMultiplexingCacheInstanceManager.class);
/** /**
* Specifies the JNDI name under which the {@link JBossCacheFactory} to use is bound. * Specifies the JNDI name under which the {@link CacheManager} to use is bound.
* There is no default value -- the user must specify the property. * There is no default value -- the user must specify the property.
*/ */
public static final String CACHE_FACTORY_RESOURCE_PROP = "hibernate.cache.region.jbc2.cachefactory"; public static final String CACHE_FACTORY_RESOURCE_PROP = "hibernate.cache.region.jbc2.cachefactory";
@ -68,18 +69,18 @@ public class JndiMultiplexingCacheInstanceManager extends MultiplexingCacheInsta
if (name == null) if (name == null)
throw new CacheException("Configuration property " + CACHE_FACTORY_RESOURCE_PROP + " not set"); throw new CacheException("Configuration property " + CACHE_FACTORY_RESOURCE_PROP + " not set");
JBossCacheFactory cf = locateCacheFactory( name, NamingHelper.getJndiProperties( properties ) ); CacheManager cf = locateCacheFactory( name, NamingHelper.getJndiProperties( properties ) );
setCacheFactory( cf ); setCacheFactory( cf );
super.start(settings, properties); super.start(settings, properties);
} }
private JBossCacheFactory locateCacheFactory(String jndiNamespace, Properties jndiProperties) { private CacheManager locateCacheFactory(String jndiNamespace, Properties jndiProperties) {
Context ctx = null; Context ctx = null;
try { try {
ctx = new InitialContext( jndiProperties ); ctx = new InitialContext( jndiProperties );
return (JBossCacheFactory) ctx.lookup( jndiNamespace ); return (CacheManager) ctx.lookup( jndiNamespace );
} }
catch (NamingException ne) { catch (NamingException ne) {
String msg = "Unable to retreive Cache from JNDI [" + jndiNamespace + "]"; String msg = "Unable to retreive Cache from JNDI [" + jndiNamespace + "]";

View File

@ -27,6 +27,8 @@ import java.util.Properties;
import javax.transaction.TransactionManager; import javax.transaction.TransactionManager;
import org.jboss.cache.Cache; import org.jboss.cache.Cache;
import org.jboss.cache.CacheManager;
import org.jboss.cache.CacheManagerImpl;
import org.jboss.cache.CacheStatus; import org.jboss.cache.CacheStatus;
import org.jboss.cache.config.Configuration; import org.jboss.cache.config.Configuration;
import org.jgroups.ChannelFactory; import org.jgroups.ChannelFactory;
@ -106,9 +108,7 @@ public class MultiplexingCacheInstanceManager implements CacheInstanceManager {
public static final String DEF_CACHE_FACTORY_RESOURCE = "org/hibernate/cache/jbc2/builder/jbc2-configs.xml"; public static final String DEF_CACHE_FACTORY_RESOURCE = "org/hibernate/cache/jbc2/builder/jbc2-configs.xml";
/** /**
* Default value for {@link #CHANNEL_FACTORY_RESOURCE_PROP}. Specifies * Default value for {@link #CHANNEL_FACTORY_RESOURCE_PROP}. Specifies
* "stacks.xml", which can be found in the root of the JGroups jar file. * the "jgroups-stacks.xml" file in this package.
* Thus, leaving this value at default means using the default protocol
* stack configs provided by JGroups.
*/ */
public static final String DEF_MULTIPLEXER_RESOURCE = "org/hibernate/cache/jbc2/builder/jgroups-stacks.xml"; public static final String DEF_MULTIPLEXER_RESOURCE = "org/hibernate/cache/jbc2/builder/jgroups-stacks.xml";
/** /**
@ -142,7 +142,7 @@ public class MultiplexingCacheInstanceManager implements CacheInstanceManager {
private String tsConfig = null; private String tsConfig = null;
/** Our cache factory */ /** Our cache factory */
private JBossCacheFactory jbcFactory; private CacheManager jbcFactory;
/** Our channel factory */ /** Our channel factory */
private ChannelFactory channelFactory; private ChannelFactory channelFactory;
/** /**
@ -187,7 +187,7 @@ public class MultiplexingCacheInstanceManager implements CacheInstanceManager {
* *
* @return Value for property 'cacheFactory'. * @return Value for property 'cacheFactory'.
*/ */
public JBossCacheFactory getCacheFactory() { public CacheManager getCacheFactory() {
return jbcFactory; return jbcFactory;
} }
@ -197,7 +197,7 @@ public class MultiplexingCacheInstanceManager implements CacheInstanceManager {
* *
* @param factory Value to set for property 'cacheFactory'. * @param factory Value to set for property 'cacheFactory'.
*/ */
public void setCacheFactory(JBossCacheFactory factory) { public void setCacheFactory(CacheManager factory) {
this.jbcFactory = factory; this.jbcFactory = factory;
} }
@ -288,9 +288,8 @@ public class MultiplexingCacheInstanceManager implements CacheInstanceManager {
} }
String factoryRes = PropertiesHelper.getString(CACHE_FACTORY_RESOURCE_PROP, properties, DEF_CACHE_FACTORY_RESOURCE); String factoryRes = PropertiesHelper.getString(CACHE_FACTORY_RESOURCE_PROP, properties, DEF_CACHE_FACTORY_RESOURCE);
// FIXME use an impl from JBossCache jbcFactory = new CacheManagerImpl(factoryRes, channelFactory);
jbcFactory = new JBossCacheFactoryImpl(factoryRes, channelFactory); ((CacheManagerImpl) jbcFactory).start();
((JBossCacheFactoryImpl) jbcFactory).start();
selfCreatedFactory = true; selfCreatedFactory = true;
} }
@ -390,7 +389,7 @@ public class MultiplexingCacheInstanceManager implements CacheInstanceManager {
public void stop() { public void stop() {
releaseCaches(); releaseCaches();
if (selfCreatedFactory) { if (selfCreatedFactory) {
((JBossCacheFactoryImpl) jbcFactory).stop(); ((CacheManagerImpl) jbcFactory).stop();
} }
} }