replaced EhCache classes
git-svn-id: https://svn.apache.org/repos/asf/incubator/jsecurity/trunk@731329 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/support/ehcache/src/org/jsecurity/cache/ehcache/EhCache.java b/support/ehcache/src/org/jsecurity/cache/ehcache/EhCache.java
new file mode 100644
index 0000000..19649ba
--- /dev/null
+++ b/support/ehcache/src/org/jsecurity/cache/ehcache/EhCache.java
@@ -0,0 +1,236 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jsecurity.cache.ehcache;
+
+import net.sf.ehcache.Element;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jsecurity.cache.Cache;
+import org.jsecurity.cache.CacheException;
+
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * JSecurity {@link org.jsecurity.cache.Cache} implementation that wraps an {@link net.sf.ehcache.Ehcache} instance.
+ *
+ * @author Jeremy Haile
+ * @author Les Hazlewood
+ * @since 0.2
+ */
+@SuppressWarnings("unchecked")
+public class EhCache implements Cache {
+
+ /** Private internal log instance. */
+ private static final Log log = LogFactory.getLog(EhCache.class);
+
+ /**
+ * The wrapped Ehcache instance.
+ */
+ private net.sf.ehcache.Ehcache cache;
+
+ /**
+ * Constructs a new EhCache instance with the given cache.
+ *
+ * @param cache - delegate EhCache instance this JSecurity cache instance will wrap.
+ */
+ public EhCache(net.sf.ehcache.Cache cache) {
+ if (cache == null) {
+ throw new IllegalArgumentException("Cache argument cannot be null.");
+ }
+ this.cache = cache;
+ }
+
+ /**
+ * Gets a value of an element which matches the given key.
+ *
+ * @param key the key of the element to return.
+ * @return The value placed into the cache with an earlier put, or null if not found or expired
+ */
+ public Object get(Object key) throws CacheException {
+ try {
+ if (log.isTraceEnabled()) {
+ log.trace("Getting object from cache [" + cache.getName() + "] for key [" + key + "]");
+ }
+ if (key == null) {
+ return null;
+ } else {
+ Element element = cache.get(key);
+ if (element == null) {
+ if (log.isTraceEnabled()) {
+ log.trace("Element for [" + key + "] is null.");
+ }
+ return null;
+ } else {
+ return element.getObjectValue();
+ }
+ }
+ }
+ catch (Throwable t) {
+ throw new CacheException(t);
+ }
+ }
+
+ /**
+ * Puts an object into the cache.
+ *
+ * @param key the key.
+ * @param value the value.
+ */
+ public void put(Object key, Object value) throws CacheException {
+ if (log.isTraceEnabled()) {
+ log.trace("Putting object in cache [" + cache.getName() + "] for key [" + key + "]");
+ }
+ try {
+ Element element = new Element(key, value);
+ cache.put(element);
+ }
+ catch (Throwable t) {
+ throw new CacheException(t);
+ }
+ }
+
+ /**
+ * Removes the element which matches the key.
+ *
+ * <p>If no element matches, nothing is removed and no Exception is thrown.</p>
+ *
+ * @param key the key of the element to remove
+ */
+ public void remove(Object key) throws CacheException {
+ if (log.isTraceEnabled()) {
+ log.trace("Removing object from cache [" + cache.getName() + "] for key [" + key + "]");
+ }
+ try {
+ cache.remove(key);
+ } catch (Throwable t) {
+ throw new CacheException(t);
+ }
+ }
+
+ /**
+ * Removes all elements in the cache, but leaves the cache in a useable state.
+ */
+ public void clear() throws CacheException {
+ if (log.isTraceEnabled()) {
+ log.trace("Clearing all objects from cache [" + cache.getName() + "]");
+ }
+ try {
+ cache.removeAll();
+ } catch (Throwable t) {
+ throw new CacheException(t);
+ }
+ }
+
+ public int size() {
+ try {
+ return cache.getSize();
+ } catch (Throwable t) {
+ throw new CacheException(t);
+ }
+ }
+
+ public Set keys() {
+ try {
+ List keys = cache.getKeys();
+ if (keys != null && !keys.isEmpty()) {
+ return Collections.unmodifiableSet(new LinkedHashSet(keys));
+ } else {
+ return Collections.EMPTY_SET;
+ }
+ } catch (Throwable t) {
+ throw new CacheException(t);
+ }
+ }
+
+ public Set values() {
+ try {
+ List keys = cache.getKeys();
+ if (keys != null && !keys.isEmpty()) {
+ Set values = new LinkedHashSet(keys.size());
+ for (Object key : keys) {
+ values.add(cache.get(key));
+ }
+ return Collections.unmodifiableSet(values);
+ } else {
+ return Collections.EMPTY_SET;
+ }
+ } catch (Throwable t) {
+ throw new CacheException(t);
+ }
+ }
+
+ /**
+ * Returns the size (in bytes) that this EhCache is using in memory (RAM), or <code>-1</code> if that
+ * number is unknown or cannot be calculated.
+ *
+ * @return the size (in bytes) that this EhCache is using in memory (RAM), or <code>-1</code> if that
+ * number is unknown or cannot be calculated.
+ */
+ public long getMemoryUsage() {
+ try {
+ return cache.calculateInMemorySize();
+ }
+ catch (Throwable t) {
+ return -1;
+ }
+ }
+
+ /**
+ * Returns the size (in bytes) that this EhCache's memory store is using (RAM), or <code>-1</code> if
+ * that number is unknown or cannot be calculated.
+ *
+ * @return the size (in bytes) that this EhCache's memory store is using (RAM), or <code>-1</code> if
+ * that number is unknown or cannot be calculated.
+ */
+ public long getMemoryStoreSize() {
+ try {
+ return cache.getMemoryStoreSize();
+ }
+ catch (Throwable t) {
+ throw new CacheException(t);
+ }
+ }
+
+ /**
+ * Returns the size (in bytes) that this EhCache's disk store is consuming or <code>-1</code> if
+ * that number is unknown or cannot be calculated.
+ *
+ * @return the size (in bytes) that this EhCache's disk store is consuming or <code>-1</code> if
+ * that number is unknown or cannot be calculated.
+ */
+ public long getDiskStoreSize() {
+ try {
+ return cache.getDiskStoreSize();
+ } catch (Throwable t) {
+ throw new CacheException(t);
+ }
+ }
+
+ /**
+ * Returns "EhCache [" + cache.getName() + "]"
+ *
+ * @return "EhCache [" + cache.getName() + "]"
+ */
+ public String toString() {
+ return "EhCache [" + cache.getName() + "]";
+ }
+}
diff --git a/support/ehcache/src/org/jsecurity/cache/ehcache/EhCacheManager.java b/support/ehcache/src/org/jsecurity/cache/ehcache/EhCacheManager.java
new file mode 100644
index 0000000..67b4ee0
--- /dev/null
+++ b/support/ehcache/src/org/jsecurity/cache/ehcache/EhCacheManager.java
@@ -0,0 +1,291 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jsecurity.cache.ehcache;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jsecurity.cache.Cache;
+import org.jsecurity.cache.CacheException;
+import org.jsecurity.cache.CacheManager;
+import org.jsecurity.io.ResourceUtils;
+import org.jsecurity.session.mgt.eis.CachingSessionDAO;
+import org.jsecurity.util.Destroyable;
+import org.jsecurity.util.Initializable;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * JSecurity <code>CacheManager</code> implementation utilizing the Ehcache framework for all cache functionality.
+ * <p/>
+ * This class can {@link #setCacheManager(net.sf.ehcache.CacheManager) accept} a manually configured
+ * {@link net.sf.ehcache.CacheManager net.sf.ehcache.CacheManager} instance,
+ * or an <code>ehcache.xml</code> path location can be specified instead and one will be constructed. If neither are
+ * specified, JSecurity's failsafe <code><a href="./ehcache.xml">ehcache.xml</a></code> file will be used by default.
+ *
+ * <p>This implementation requires EhCache 1.2 and above. Make sure EhCache 1.1 or earlier
+ * is not in the classpath or it will not work.</p>
+ *
+ * <p>Please see the <a href="http://ehcache.sf.net" target="_top">Ehcache website</a> for their documentation.</p>
+ *
+ * @author Jeremy Haile
+ * @author Les Hazlewood
+ * @see <a href="http://ehcache.sf.net" target="_top">The Ehcache website</a>
+ * @since 0.2
+ */
+public class EhCacheManager implements CacheManager, Initializable, Destroyable {
+
+ /**
+ * The default name for the active sessions cache, equal to
+ * {@link CachingSessionDAO#ACTIVE_SESSION_CACHE_NAME CachingSessionDAO.ACTIVE_SESSION_CACHE_NAME}.
+ */
+ public static final String DEFAULT_ACTIVE_SESSIONS_CACHE_NAME = CachingSessionDAO.ACTIVE_SESSION_CACHE_NAME;
+
+ /**
+ * The default maximum number of active sessions in cache <em>memory</em>, equal to <code>20,000</code>.
+ */
+ public static final int DEFAULT_ACTIVE_SESSIONS_CACHE_MAX_ELEM_IN_MEM = 20000;
+
+ /**
+ * The default time the active sessions disk expiration thread will run, equal to <code>600</code> (10 minutes).
+ */
+ public static final int DEFAULT_ACTIVE_SESSIONS_DISK_EXPIRY_THREAD_INTERVAL_SECONDS = 600;
+
+ /**
+ * This class's private log instance.
+ */
+ private static final Log log = LogFactory.getLog(EhCacheManager.class);
+
+ /**
+ * The EhCache cache manager used by this implementation to create caches.
+ */
+ protected net.sf.ehcache.CacheManager manager;
+
+ /**
+ * Indicates if the CacheManager instance was implicitly/automatically created by this instance, indicating that
+ * it should be automatically cleaned up as well on shutdown.
+ */
+ private boolean cacheManagerImplicitlyCreated = false;
+
+ /**
+ * Classpath file location of the ehcache CacheManager config file.
+ */
+ private String cacheManagerConfigFile = "classpath:org/jsecurity/cache/ehcache/ehcache.xml";
+
+ /**
+ * Default no argument constructor
+ */
+ public EhCacheManager() {
+ }
+
+ /**
+ * Returns the wrapped Ehcache {@link net.sf.ehcache.CacheManager CacheManager} instance.
+ *
+ * @return the wrapped Ehcache {@link net.sf.ehcache.CacheManager CacheManager} instance.
+ */
+ public net.sf.ehcache.CacheManager getCacheManager() {
+ return manager;
+ }
+
+ /**
+ * Sets the wrapped Ehcache {@link net.sf.ehcache.CacheManager CacheManager} instance.
+ *
+ * @param manager the wrapped Ehcache {@link net.sf.ehcache.CacheManager CacheManager} instance.
+ */
+ public void setCacheManager(net.sf.ehcache.CacheManager manager) {
+ this.manager = manager;
+ }
+
+ /**
+ * Returns the resource location of the config file used to initialize a new
+ * EhCache CacheManager instance. The string can be any resource path supported by the
+ * {@link ResourceUtils#getInputStreamForPath(String)} call.
+ *
+ * <p>This property is ignored if the CacheManager instance is injected directly - that is, it is only used to
+ * lazily create a CacheManager if one is not already provided.</p>
+ *
+ * @return the resource location of the config file used to initialize the wrapped
+ * EhCache CacheManager instance.
+ */
+ public String getCacheManagerConfigFile() {
+ return this.cacheManagerConfigFile;
+ }
+
+ /**
+ * Sets the resource location of the config file used to initialize the wrapped
+ * EhCache CacheManager instance. The string can be any resource path supported by the
+ * {@link org.jsecurity.io.ResourceUtils#getInputStreamForPath(String)} call.
+ *
+ * <p>This property is ignored if the CacheManager instance is injected directly - that is, it is only used to
+ * lazily create a CacheManager if one is not already provided.</p>
+ *
+ * @param classpathLocation resource location of the config file used to create the wrapped
+ * EhCache CacheManager instance.
+ */
+ public void setCacheManagerConfigFile(String classpathLocation) {
+ this.cacheManagerConfigFile = classpathLocation;
+ }
+
+ /**
+ * Acquires the InputStream for the ehcache configuration file using
+ * {@link ResourceUtils#getInputStreamForPath(String) ResourceUtils.getInputStreamForPath} with the
+ * path returned from {@link #getCacheManagerConfigFile() getCacheManagerConfigFile()}.
+ *
+ * @return the InputStream for the ehcache configuration file.
+ */
+ protected InputStream getCacheManagerConfigFileInputStream() {
+ String configFile = getCacheManagerConfigFile();
+ try {
+ return ResourceUtils.getInputStreamForPath(configFile);
+ } catch (IOException e) {
+ throw new IllegalStateException("Unable to obtain input stream for cacheManagerConfigFile.", e);
+ }
+ }
+
+ /**
+ * Loads an existing EhCache from the cache manager, or starts a new cache if one is not found.
+ *
+ * @param name the name of the cache to load/create.
+ */
+ public final Cache getCache(String name) throws CacheException {
+
+ if (log.isTraceEnabled()) {
+ log.trace("Loading a new EhCache cache named [" + name + "]");
+ }
+
+ try {
+ net.sf.ehcache.Cache cache = getCacheManager().getCache(name);
+ if (cache == null) {
+ if (log.isInfoEnabled()) {
+ log.info("Could not find a specific ehcache configuration for cache named [" + name + "]; using defaults.");
+ }
+ if (name.equals(DEFAULT_ACTIVE_SESSIONS_CACHE_NAME)) {
+ if (log.isInfoEnabled()) {
+ log.info("Creating " + DEFAULT_ACTIVE_SESSIONS_CACHE_NAME + " cache with default JSecurity " +
+ "session cache settings.");
+ }
+ cache = buildDefaultActiveSessionsCache();
+ manager.addCache(cache);
+ } else {
+ manager.addCache(name);
+ }
+
+ cache = manager.getCache(name);
+
+ if (log.isInfoEnabled()) {
+ log.info("Started EHCache named [" + name + "]");
+ }
+ } else {
+ if (log.isInfoEnabled()) {
+ log.info("Using preconfigured EHCache named [" + cache.getName() + "]");
+ }
+ }
+ return new EhCache(cache);
+ } catch (net.sf.ehcache.CacheException e) {
+ throw new CacheException(e);
+ }
+ }
+
+ /**
+ * Builds the default cache instance to use for JSecurity's Session Cache when enterprise Sessions are
+ * enabled.
+ *
+ * @return the default cache instance to use for JSecurity's Session Cache when enterprise Sessions are
+ * enabled.
+ * @throws CacheException if there is a problem constructing the Cache instance.
+ */
+ private net.sf.ehcache.Cache buildDefaultActiveSessionsCache() throws CacheException {
+ return new net.sf.ehcache.Cache(DEFAULT_ACTIVE_SESSIONS_CACHE_NAME,
+ DEFAULT_ACTIVE_SESSIONS_CACHE_MAX_ELEM_IN_MEM,
+ true,
+ true,
+ 0,
+ 0,
+ true,
+ DEFAULT_ACTIVE_SESSIONS_DISK_EXPIRY_THREAD_INTERVAL_SECONDS);
+ }
+
+ /**
+ * Initializes this instance.
+ *
+ * <p>If a {@link #setCacheManager CacheManager} has been
+ * explicitly set (e.g. via Dependency Injection or programatically) prior to calling this
+ * method, this method does nothing.</p>
+ *
+ * <p>However, if no <tt>CacheManager</tt> has been set, the default Ehcache singleton will be initialized, where
+ * Ehcache will look for an <tt>ehcache.xml</tt> file at the root of the classpath. If one is not found,
+ * Ehcache will use its own failsafe configuration file.</p>
+ *
+ * <p>Because JSecurity cannot use the failsafe defaults (failsafe expunges cached objects after 2 minutes,
+ * something not desireable for JSecurity sessions), this class manages an internal default configuration for
+ * this case.</p>
+ *
+ * @throws org.jsecurity.cache.CacheException
+ * if there are any CacheExceptions thrown by EhCache.
+ * @see net.sf.ehcache.CacheManager#create
+ */
+ public final void init() throws CacheException {
+ try {
+ net.sf.ehcache.CacheManager cacheMgr = getCacheManager();
+ if (cacheMgr == null) {
+ if (log.isDebugEnabled()) {
+ log.debug("cacheManager property not set. Constructing CacheManager instance... ");
+ }
+ //using the CacheManager constructor, the resulting instance is _not_ a VM singleton
+ //(as would be the case by calling CacheManager.getInstance(). We do not use the getInstance here
+ //because we need to know if we need to destroy the CacheManager instance - using the static call,
+ //we don't know which component is responsible for shutting it down. By using a single EhCacheManager,
+ //it will always know to shut down the instance if it was responsible for creating it.
+ cacheMgr = new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream());
+ if (log.isTraceEnabled()) {
+ log.trace("instantiated Ehcache CacheManager instance.");
+ }
+ cacheManagerImplicitlyCreated = true;
+ setCacheManager(cacheMgr);
+ if (log.isDebugEnabled()) {
+ log.debug("implicit cacheManager created successfully.");
+ }
+ }
+ } catch (Exception e) {
+ throw new CacheException(e);
+ }
+ }
+
+ /**
+ * Shuts-down the wrapped Ehcache CacheManager <b>only if implicitly created</b>.
+ *
+ * <p>If another component injected
+ * a non-null CacheManager into this instace before calling {@link #init() init}, this instance expects that same
+ * component to also destroy the CacheManager instance, and it will not attempt to do so.
+ */
+ public void destroy() {
+ if (cacheManagerImplicitlyCreated) {
+ try {
+ net.sf.ehcache.CacheManager cacheMgr = getCacheManager();
+ cacheMgr.shutdown();
+ } catch (Exception e) {
+ if (log.isWarnEnabled()) {
+ log.warn("Unable to cleanly shutdown implicitly created CacheManager instance. " +
+ "Ignoring (shutting down)...");
+ }
+ }
+ cacheManagerImplicitlyCreated = false;
+ }
+ }
+}
diff --git a/support/ehcache/src/org/jsecurity/cache/ehcache/ehcache.xml b/support/ehcache/src/org/jsecurity/cache/ehcache/ehcache.xml
new file mode 100644
index 0000000..d55b492
--- /dev/null
+++ b/support/ehcache/src/org/jsecurity/cache/ehcache/ehcache.xml
@@ -0,0 +1,97 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+<ehcache>
+
+ <!-- Sets the path to the directory where cache .data files are created.
+
+If the path is a Java System Property it is replaced by
+its value in the running VM.
+
+The following properties are translated:
+user.home - User's home directory
+user.dir - User's current working directory
+java.io.tmpdir - Default temp file path -->
+ <diskStore path="java.io.tmpdir/jsecurity-ehcache"/>
+
+
+ <!--Default Cache configuration. These will applied to caches programmatically created through
+ the CacheManager.
+
+ The following attributes are required:
+
+ maxElementsInMemory - Sets the maximum number of objects that will be created in memory
+ eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the
+ element is never expired.
+ overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache
+ has reached the maxInMemory limit.
+
+ The following attributes are optional:
+ timeToIdleSeconds - Sets the time to idle for an element before it expires.
+ i.e. The maximum amount of time between accesses before an element expires
+ Is only used if the element is not eternal.
+ Optional attribute. A value of 0 means that an Element can idle for infinity.
+ The default value is 0.
+ timeToLiveSeconds - Sets the time to live for an element before it expires.
+ i.e. The maximum time between creation time and when an element expires.
+ Is only used if the element is not eternal.
+ Optional attribute. A value of 0 means that and Element can live for infinity.
+ The default value is 0.
+ diskPersistent - Whether the disk store persists between restarts of the Virtual Machine.
+ The default value is false.
+ diskExpiryThreadIntervalSeconds- The number of seconds between runs of the disk expiry thread. The default value
+ is 120 seconds.
+ memoryStoreEvictionPolicy - Policy would be enforced upon reaching the maxElementsInMemory limit. Default
+ policy is Least Recently Used (specified as LRU). Other policies available -
+ First In First Out (specified as FIFO) and Less Frequently Used
+ (specified as LFU)
+ -->
+
+ <defaultCache
+ maxElementsInMemory="10000"
+ eternal="false"
+ timeToIdleSeconds="120"
+ timeToLiveSeconds="120"
+ overflowToDisk="false"
+ diskPersistent="false"
+ diskExpiryThreadIntervalSeconds="120"
+ />
+
+ <!-- We want eternal="true" (with no timeToIdle or timeToLive settings) because JSecurity manages session
+expirations explicitly. If we set it to false and then set corresponding timeToIdle and timeToLive properties,
+ehcache would evict sessions without JSecurity's knowledge, which would cause many problems
+(e.g. "My JSecurity session timeout is 30 minutes - why isn't a session available after 2 minutes?"
+Answer - ehcache expired it due to the timeToIdle property set to 120 seconds.)
+
+diskPersistent=true since we want an enterprise session management feature - ability to use sessions after
+even after a JVM restart. -->
+ <!-- <cache name="jsecurity-activeSessionCache"
+ maxElementsInMemory="20000"
+ eternal="true"
+ overflowToDisk="true"
+ diskPersistent="true"
+ diskExpiryThreadIntervalSeconds="600"/> -->
+
+ <cache name="org.jsecurity.realm.text.PropertiesRealm-0-accounts"
+ maxElementsInMemory="1000"
+ eternal="true"
+ overflowToDisk="true"/>
+
+</ehcache>
+
+
diff --git a/support/ehcache/src/org/jsecurity/cache/ehcache/package-info.java b/support/ehcache/src/org/jsecurity/cache/ehcache/package-info.java
new file mode 100644
index 0000000..8724f40
--- /dev/null
+++ b/support/ehcache/src/org/jsecurity/cache/ehcache/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/**
+ * <a href="http://ehcache.sourceforge.net" target="_top">Ehcache</a>-based implementations of JSecurity's
+ * cache interfaces.
+ */
+package org.jsecurity.cache.ehcache;
\ No newline at end of file