View Javadoc

1   /**
2    *  Copyright 2003-2007 Greg Luck
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package net.sf.ehcache.hibernate;
17  
18  import net.sf.ehcache.CacheManager;
19  import net.sf.ehcache.util.ClassLoaderUtil;
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  import org.hibernate.cache.Cache;
23  import org.hibernate.cache.CacheException;
24  import org.hibernate.cache.CacheProvider;
25  import org.hibernate.cache.Timestamper;
26  
27  import java.net.URL;
28  import java.util.Properties;
29  
30  /**
31   * Singleton cache Provider plugin for Hibernate 3.2 and ehcache-1.2. New in this provider is support for
32   * non Serializable keys and values. This provider works as a Singleton. No matter how many Hibernate Configurations
33   * you have, only one ehcache CacheManager is used. See EhCacheProvider for a non-singleton implementation.
34   * <p/>
35   * Ehcache-1.2 also has many other features such as cluster support and listeners, which can be used seamlessly simply
36   * by configurion in ehcache.xml.
37   * <p/>
38   * Use <code>hibernate.cache.provider_class=net.sf.ehcache.hibernate.SingletonEhCacheProvider</code> in the Hibernate configuration
39   * to enable this provider for Hibernate's second level cache.
40   * <p/>
41   * Updated for ehcache-1.2. Note this provider requires ehcache-1.2.jar. Make sure ehcache-1.1.jar or earlier
42   * is not in the classpath or it will not work.
43   * <p/>
44   * See http://ehcache.sf.net for documentation on ehcache
45   * <p/>
46   *
47   * @author Greg Luck
48   * @author Emmanuel Bernard
49   * @version $Id: SingletonEhCacheProvider.java 512 2007-07-10 09:18:45Z gregluck $
50   */
51  public final class SingletonEhCacheProvider implements CacheProvider {
52  
53      /**
54       * The Hibernate system property specifying the location of the ehcache configuration file name.
55       * <p/
56       * If not set, ehcache.xml will be looked for in the root of the classpath.
57       * <p/>
58       * If set to say ehcache-1.xml, ehcache-1.xml will be looked for in the root of the classpath.
59       */
60      public static final String NET_SF_EHCACHE_CONFIGURATION_RESOURCE_NAME = "net.sf.ehcache.configurationResourceName";
61  
62      private static final Log LOG = LogFactory.getLog(SingletonEhCacheProvider.class);
63  
64      /**
65       * To be backwardly compatible with a lot of Hibernate code out there, allow multiple starts and stops on the
66       * one singleton CacheManager. Keep a count of references to only stop on when only one reference is held.
67       */
68      private static int referenceCount;
69  
70      private CacheManager manager;
71  
72  
73      /**
74       * Builds a Cache.
75       * <p/>
76       * Even though this method provides properties, they are not used.
77       * Properties for EHCache are specified in the ehcache.xml file.
78       * Configuration will be read from ehcache.xml for a cache declaration
79       * where the name attribute matches the name parameter in this builder.
80       *
81       * @param name       the name of the cache. Must match a cache configured in ehcache.xml
82       * @param properties not used
83       * @return a newly built cache will be built and initialised
84       * @throws org.hibernate.cache.CacheException
85       *          inter alia, if a cache of the same name already exists
86       */
87      public final Cache buildCache(String name, Properties properties) throws CacheException {
88          try {
89              net.sf.ehcache.Ehcache cache = manager.getEhcache(name);
90              if (cache == null) {
91                  SingletonEhCacheProvider.LOG.warn("Could not find a specific ehcache configuration for cache named ["
92                          + name + "]; using defaults.");
93                  manager.addCache(name);
94                  cache = manager.getEhcache(name);
95                  SingletonEhCacheProvider.LOG.debug("started EHCache region: " + name);
96              }
97              return new EhCache(cache);
98          } catch (net.sf.ehcache.CacheException e) {
99              throw new CacheException(e);
100         }
101     }
102 
103     /**
104      * Returns the next timestamp.
105      */
106     public final long nextTimestamp() {
107         return Timestamper.next();
108     }
109 
110     /**
111      * Callback to perform any necessary initialization of the underlying cache implementation
112      * during SessionFactory construction.
113      * <p/>
114      *
115      * @param properties current configuration settings.
116      */
117     public final void start(Properties properties) throws CacheException {
118         String configurationResourceName = null;
119         if (properties != null) {
120             configurationResourceName = (String) properties.get(NET_SF_EHCACHE_CONFIGURATION_RESOURCE_NAME);
121         }
122         if (configurationResourceName == null || configurationResourceName.length() == 0) {
123             manager = CacheManager.create();
124             referenceCount++;
125         } else {
126             if (!configurationResourceName.startsWith("/")) {
127                 configurationResourceName = "/" + configurationResourceName;
128                 if (LOG.isDebugEnabled()) {
129                     LOG.debug("prepending / to " + configurationResourceName + ". It should be placed in the root"
130                             + "of the classpath rather than in a package.");
131                 }
132             }
133             URL url = loadResource(configurationResourceName);
134             manager = CacheManager.create(url);
135             referenceCount++;
136         }
137     }
138 
139     private URL loadResource(String configurationResourceName) {
140         ClassLoader standardClassloader = ClassLoaderUtil.getStandardClassLoader();
141         URL url = null;
142         if (standardClassloader != null) {
143             url = standardClassloader.getResource(configurationResourceName);
144         }
145         if (url == null) {
146             url = this.getClass().getResource(configurationResourceName);
147         }
148         if (LOG.isDebugEnabled()) {
149             LOG.debug("Creating EhCacheProvider from a specified resource: "
150                     + configurationResourceName + " Resolved to URL: " + url);
151         }
152         if (url == null) {
153             if (LOG.isWarnEnabled()) {
154                 LOG.warn("A configurationResourceName was set to " + configurationResourceName +
155                         " but the resource could not be loaded from the classpath." +
156                         "Ehcache will configure itself using defaults.");
157             }
158         }
159         return url;
160     }
161 
162     /**
163      * Callback to perform any necessary cleanup of the underlying cache implementation
164      * during SessionFactory.close().
165      */
166     public void stop() {
167         if (manager != null) {
168             if (--referenceCount == 0) {
169                 manager.shutdown();
170             }
171             manager = null;
172         }
173     }
174 
175     /**
176      * Not sure what this is supposed to do.
177      *
178      * @return false to be safe
179      */
180     public final boolean isMinimalPutsEnabledByDefault() {
181         return false;
182     }
183 
184 }