Rename package and maven coordinates for major release
diff --git a/NOTICE.txt b/NOTICE.txt
index fe4cbd7..ed776f5 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -1,5 +1,5 @@
Apache Commons JCS
-Copyright 2001-2017 The Apache Software Foundation.
+Copyright 2001-2020 The Apache Software Foundation.
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
diff --git a/README.md b/README.md
index ba2a3cb..ddafd09 100644
--- a/README.md
+++ b/README.md
@@ -61,8 +61,8 @@
```xml
<dependency>
<groupId>org.apache.commons</groupId>
- <artifactId>commons-jcs</artifactId>
- <version>2.0</version>
+ <artifactId>commons-jcs3</artifactId>
+ <version>3.0</version>
</dependency>
```
diff --git a/commons-jcs-core/pom.xml b/commons-jcs-core/pom.xml
index 66fc82d..62ef52a 100644
--- a/commons-jcs-core/pom.xml
+++ b/commons-jcs-core/pom.xml
@@ -21,12 +21,12 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.commons</groupId>
- <artifactId>commons-jcs</artifactId>
+ <artifactId>commons-jcs3</artifactId>
<version>3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
- <artifactId>commons-jcs-core</artifactId>
+ <artifactId>commons-jcs3-core</artifactId>
<version>3.0-SNAPSHOT</version>
<packaging>jar</packaging>
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/JCS.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/JCS.java
deleted file mode 100644
index 8a006a2..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/JCS.java
+++ /dev/null
@@ -1,210 +0,0 @@
-package org.apache.commons.jcs;
-
-import java.util.Properties;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.access.GroupCacheAccess;
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-import org.apache.commons.jcs.engine.control.group.GroupAttrName;
-
-/**
- * Simple class for using JCS. To use JCS in your application, you can use the static methods of
- * this class to get access objects (instances of this class) for your cache regions. One CacheAccess
- * object should be created for each region you want to access. If you have several regions, then
- * get instances for each. For best performance the getInstance call should be made in an
- * initialization method.
- */
-public abstract class JCS
-{
- /** cache.ccf alternative. */
- private static String configFilename = null;
-
- /** alternative configuration properties */
- private static Properties configProps = null;
-
- /** Cache manager use by the various forms of defineRegion and getAccess */
- private static CompositeCacheManager cacheMgr;
-
- /**
- * Set the filename that the cache manager will be initialized with. Only matters before the
- * instance is initialized.
- * <p>
- * @param configFilename
- */
- public static void setConfigFilename( String configFilename )
- {
- JCS.configFilename = configFilename;
- }
-
- /**
- * Set the properties that the cache manager will be initialized with. Only
- * matters before the instance is initialized.
- *
- * @param configProps
- */
- public static void setConfigProperties( Properties configProps )
- {
- JCS.configProps = configProps;
- }
-
- /**
- * Shut down the cache manager and set the instance to null
- */
- public static void shutdown()
- {
- synchronized ( JCS.class )
- {
- if ( cacheMgr != null && cacheMgr.isInitialized())
- {
- cacheMgr.shutDown();
- }
-
- cacheMgr = null;
- }
- }
-
- /**
- * Helper method which checks to make sure the cacheMgr class field is set, and if not requests
- * an instance from CacheManagerFactory.
- *
- * @throws CacheException if the configuration cannot be loaded
- */
- private static CompositeCacheManager getCacheManager() throws CacheException
- {
- synchronized ( JCS.class )
- {
- if ( cacheMgr == null || !cacheMgr.isInitialized())
- {
- if ( configProps != null )
- {
- cacheMgr = CompositeCacheManager.getUnconfiguredInstance();
- cacheMgr.configure( configProps );
- }
- else if ( configFilename != null )
- {
- cacheMgr = CompositeCacheManager.getUnconfiguredInstance();
- cacheMgr.configure( configFilename );
- }
- else
- {
- cacheMgr = CompositeCacheManager.getInstance();
- }
- }
-
- return cacheMgr;
- }
- }
-
- /**
- * Get a CacheAccess which accesses the provided region.
- * <p>
- * @param region Region that return CacheAccess will provide access to
- * @return A CacheAccess which provides access to a given region.
- * @throws CacheException
- */
- public static <K, V> CacheAccess<K, V> getInstance( String region )
- throws CacheException
- {
- CompositeCache<K, V> cache = getCacheManager().getCache( region );
- return new CacheAccess<>( cache );
- }
-
- /**
- * Get a CacheAccess which accesses the provided region.
- * <p>
- * @param region Region that return CacheAccess will provide access to
- * @param icca CacheAttributes for region
- * @return A CacheAccess which provides access to a given region.
- * @throws CacheException
- */
- public static <K, V> CacheAccess<K, V> getInstance( String region, ICompositeCacheAttributes icca )
- throws CacheException
- {
- CompositeCache<K, V> cache = getCacheManager().getCache( region, icca );
- return new CacheAccess<>( cache );
- }
-
- /**
- * Get a CacheAccess which accesses the provided region.
- * <p>
- * @param region Region that return CacheAccess will provide access to
- * @param icca CacheAttributes for region
- * @param eattr ElementAttributes for the region
- * @return A CacheAccess which provides access to a given region.
- * @throws CacheException
- */
- public static <K, V> CacheAccess<K, V> getInstance( String region, ICompositeCacheAttributes icca, IElementAttributes eattr )
- throws CacheException
- {
- CompositeCache<K, V> cache = getCacheManager().getCache( region, icca, eattr );
- return new CacheAccess<>( cache );
- }
-
- /**
- * Get a GroupCacheAccess which accesses the provided region.
- * <p>
- * @param region Region that return GroupCacheAccess will provide access to
- * @return A GroupCacheAccess which provides access to a given region.
- * @throws CacheException
- */
- public static <K, V> GroupCacheAccess<K, V> getGroupCacheInstance( String region )
- throws CacheException
- {
- CompositeCache<GroupAttrName<K>, V> cache = getCacheManager().getCache( region );
- return new GroupCacheAccess<>( cache );
- }
-
- /**
- * Get a GroupCacheAccess which accesses the provided region.
- * <p>
- * @param region Region that return GroupCacheAccess will provide access to
- * @param icca CacheAttributes for region
- * @return A GroupCacheAccess which provides access to a given region.
- * @throws CacheException
- */
- public static <K, V> GroupCacheAccess<K, V> getGroupCacheInstance( String region, ICompositeCacheAttributes icca )
- throws CacheException
- {
- CompositeCache<GroupAttrName<K>, V> cache = getCacheManager().getCache( region, icca );
- return new GroupCacheAccess<>( cache );
- }
-
- /**
- * Get a GroupCacheAccess which accesses the provided region.
- * <p>
- * @param region Region that return CacheAccess will provide access to
- * @param icca CacheAttributes for region
- * @param eattr ElementAttributes for the region
- * @return A GroupCacheAccess which provides access to a given region.
- * @throws CacheException
- */
- public static <K, V> GroupCacheAccess<K, V> getGroupCacheInstance( String region, ICompositeCacheAttributes icca, IElementAttributes eattr )
- throws CacheException
- {
- CompositeCache<GroupAttrName<K>, V> cache = getCacheManager().getCache( region, icca, eattr );
- return new GroupCacheAccess<>( cache );
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/AbstractCacheAccess.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/AbstractCacheAccess.java
deleted file mode 100644
index c727c7c..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/AbstractCacheAccess.java
+++ /dev/null
@@ -1,203 +0,0 @@
-package org.apache.commons.jcs.access;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-
-import org.apache.commons.jcs.access.behavior.ICacheAccessManagement;
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.stats.behavior.ICacheStats;
-
-/**
- * This class provides the common methods for all types of access to the cache.
- * <p>
- * An instance of this class is tied to a specific cache region. Static methods are provided to get
- * such instances.
- * <p>
- * Using this class you can retrieve an item, the item's wrapper, and the element's configuration. You can also put an
- * item in the cache, remove an item, and clear a region.
- * <p>
- * The JCS class is the preferred way to access these methods.
- */
-public abstract class AbstractCacheAccess<K, V>
- implements ICacheAccessManagement
-{
- /**
- * The cache that a given instance of this class provides access to.
- * <p>
- * TODO Should this be the interface?
- */
- private final CompositeCache<K, V> cacheControl;
-
- /**
- * Constructor for the CacheAccess object.
- * <p>
- * @param cacheControl The cache which the created instance accesses
- */
- protected AbstractCacheAccess( CompositeCache<K, V> cacheControl )
- {
- this.cacheControl = cacheControl;
- }
-
- /**
- * Removes all of the elements from a region.
- * <p>
- * @throws CacheException
- */
- @Override
- public void clear()
- throws CacheException
- {
- try
- {
- this.getCacheControl().removeAll();
- }
- catch ( IOException e )
- {
- throw new CacheException( e );
- }
- }
-
- /**
- * This method is does not reset the attributes for items already in the cache. It could
- * potentially do this for items in memory, and maybe on disk (which would be slow) but not
- * remote items. Rather than have unpredictable behavior, this method just sets the default
- * attributes. Items subsequently put into the cache will use these defaults if they do not
- * specify specific attributes.
- * <p>
- * @param attr the default attributes.
- * @throws CacheException if something goes wrong.
- */
- @Override
- public void setDefaultElementAttributes( IElementAttributes attr )
- throws CacheException
- {
- this.getCacheControl().setElementAttributes( attr );
- }
-
- /**
- * Retrieves A COPY OF the default element attributes used by this region. This does not provide
- * a reference to the element attributes.
- * <p>
- * Each time an element is added to the cache without element attributes, the default element
- * attributes are cloned.
- * <p>
- * @return the default element attributes used by this region.
- * @throws CacheException
- */
- @Override
- public IElementAttributes getDefaultElementAttributes()
- throws CacheException
- {
- return this.getCacheControl().getElementAttributes();
- }
-
- /**
- * This returns the ICacheStats object with information on this region and its auxiliaries.
- * <p>
- * This data can be formatted as needed.
- * <p>
- * @return ICacheStats
- */
- @Override
- public ICacheStats getStatistics()
- {
- return this.getCacheControl().getStatistics();
- }
-
- /**
- * @return A String version of the stats.
- */
- @Override
- public String getStats()
- {
- return this.getCacheControl().getStats();
- }
-
- /**
- * Dispose this region. Flushes objects to and closes auxiliary caches. This is a shutdown
- * command!
- * <p>
- * To simply remove all elements from the region use clear().
- */
- @Override
- public void dispose()
- {
- this.getCacheControl().dispose();
- }
-
- /**
- * Gets the ICompositeCacheAttributes of the cache region.
- * <p>
- * @return ICompositeCacheAttributes, the controllers config info, defined in the top section of
- * a region definition.
- */
- @Override
- public ICompositeCacheAttributes getCacheAttributes()
- {
- return this.getCacheControl().getCacheAttributes();
- }
-
- /**
- * Sets the ICompositeCacheAttributes of the cache region.
- * <p>
- * @param cattr The new ICompositeCacheAttribute value
- */
- @Override
- public void setCacheAttributes( ICompositeCacheAttributes cattr )
- {
- this.getCacheControl().setCacheAttributes( cattr );
- }
-
- /**
- * This instructs the memory cache to remove the <i>numberToFree</i> according to its eviction
- * policy. For example, the LRUMemoryCache will remove the <i>numberToFree</i> least recently
- * used items. These will be spooled to disk if a disk auxiliary is available.
- * <p>
- * @param numberToFree
- * @return the number that were removed. if you ask to free 5, but there are only 3, you will
- * get 3.
- * @throws CacheException
- */
- @Override
- public int freeMemoryElements( int numberToFree )
- throws CacheException
- {
- int numFreed = -1;
- try
- {
- numFreed = this.getCacheControl().getMemoryCache().freeElements( numberToFree );
- }
- catch ( IOException ioe )
- {
- String message = "Failure freeing memory elements.";
- throw new CacheException( message, ioe );
- }
- return numFreed;
- }
-
- public CompositeCache<K, V> getCacheControl() {
- return cacheControl;
- }
-
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/CacheAccess.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/CacheAccess.java
deleted file mode 100644
index 90b42c0..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/CacheAccess.java
+++ /dev/null
@@ -1,332 +0,0 @@
-package org.apache.commons.jcs.access;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-
-import org.apache.commons.jcs.access.behavior.ICacheAccess;
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.access.exception.InvalidArgumentException;
-import org.apache.commons.jcs.access.exception.InvalidHandleException;
-import org.apache.commons.jcs.access.exception.ObjectExistsException;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-
-/**
- * This class provides an interface for all types of access to the cache.
- * <p>
- * An instance of this class is tied to a specific cache region. Static methods are provided to get
- * such instances.
- * <p>
- * Using this class you can retrieve an item, the item's wrapper, and the element's configuration. You can also put an
- * item in the cache, remove an item, and clear a region.
- * <p>
- * The JCS class is the preferred way to access these methods.
- */
-public class CacheAccess<K, V>
- extends AbstractCacheAccess<K, V>
- implements ICacheAccess<K, V>
-{
- /**
- * Constructor for the CacheAccess object.
- * <p>
- * @param cacheControl The cache which the created instance accesses
- */
- public CacheAccess( CompositeCache<K, V> cacheControl )
- {
- super(cacheControl);
- }
-
- /**
- * Retrieve an object from the cache region this instance provides access to.
- * <p>
- * @param name Key the object is stored as
- * @return The object if found or null
- */
- @Override
- public V get( K name )
- {
- ICacheElement<K, V> element = this.getCacheControl().get( name );
-
- return ( element != null ) ? element.getVal() : null;
- }
-
- /**
- * Retrieve an object from the cache region this instance provides access to.
- * If the object cannot be found in the cache, it will be retrieved by
- * calling the supplier and subsequently storing it in the cache.
- * <p>
- * @param name
- * @param supplier supplier to be called if the value is not found
- * @return Object.
- */
- @Override
- public V get(K name, Supplier<V> supplier)
- {
- V value = get(name);
-
- if (value == null)
- {
- value = supplier.get();
- put(name, value);
- }
-
- return value;
- }
-
- /**
- * Retrieve matching objects from the cache region this instance provides access to.
- * <p>
- * @param pattern - a key pattern for the objects stored
- * @return A map of key to values. These are stripped from the wrapper.
- */
- @Override
- public Map<K, V> getMatching( String pattern )
- {
- Map<K, V> unwrappedResults;
-
- Map<K, ICacheElement<K, V>> wrappedResults = this.getCacheControl().getMatching( pattern );
-
- if ( wrappedResults == null )
- {
- unwrappedResults = new HashMap<>();
- }
- else
- {
- unwrappedResults = wrappedResults.entrySet()
- .stream()
- .filter(entry -> entry.getValue() != null)
- .collect(Collectors.toMap(
- entry -> entry.getKey(),
- entry -> entry.getValue().getVal()));
- }
-
- return unwrappedResults;
- }
-
- /**
- * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other
- * attributes.
- * <p>
- * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
- * defensive copy is made.
- * <p>
- * This method is most useful if you want to determine things such as the how long the element
- * has been in the cache.
- * <p>
- * The last access time in the ElementAttributes should be current.
- * <p>
- * @param name Key the Serializable is stored as
- * @return The ICacheElement<K, V> if the object is found or null
- */
- @Override
- public ICacheElement<K, V> getCacheElement( K name )
- {
- return this.getCacheControl().get( name );
- }
-
- /**
- * Get multiple elements from the cache based on a set of cache keys.
- * <p>
- * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other
- * attributes.
- * <p>
- * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
- * defensive copy is made.
- * <p>
- * This method is most useful if you want to determine things such as the how long the element
- * has been in the cache.
- * <p>
- * The last access time in the ElementAttributes should be current.
- * <p>
- * @param names set of Serializable cache keys
- * @return a map of K key to ICacheElement<K, V> element, or empty map if none of the keys are present
- */
- @Override
- public Map<K, ICacheElement<K, V>> getCacheElements( Set<K> names )
- {
- return this.getCacheControl().getMultiple( names );
- }
-
- /**
- * Get multiple elements from the cache based on a set of cache keys.
- * <p>
- * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other
- * attributes.
- * <p>
- * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
- * defensive copy is made.
- * <p>
- * This method is most useful if you want to determine things such as the how long the element
- * has been in the cache.
- * <p>
- * The last access time in the ElementAttributes should be current.
- * <p>
- * @param pattern key search pattern
- * @return a map of K key to ICacheElement<K, V> element, or empty map if no keys match the pattern
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatchingCacheElements( String pattern )
- {
- return this.getCacheControl().getMatching( pattern );
- }
-
- /**
- * Place a new object in the cache, associated with key name. If there is currently an object
- * associated with name in the region an ObjectExistsException is thrown. Names are scoped to a
- * region so they must be unique within the region they are placed.
- * <p>
- * @param key Key object will be stored with
- * @param value Object to store
- * @throws CacheException and ObjectExistsException is thrown if the item is already in the
- * cache.
- */
- @Override
- public void putSafe( K key, V value )
- {
- if ( this.getCacheControl().get( key ) != null )
- {
- throw new ObjectExistsException( "putSafe failed. Object exists in the cache for key [" + key
- + "]. Remove first or use a non-safe put to override the value." );
- }
- put( key, value );
- }
-
- /**
- * Place a new object in the cache, associated with key name. If there is currently an object
- * associated with name in the region it is replaced. Names are scoped to a region so they must
- * be unique within the region they are placed.
- * @param name Key object will be stored with
- * @param obj Object to store
- */
- @Override
- public void put( K name, V obj )
- {
- // Call put with a copy of the contained caches default attributes.
- // the attributes are copied by the cacheControl
- put( name, obj, this.getCacheControl().getElementAttributes() );
- }
-
- /**
- * Constructs a cache element with these attributes, and puts it into the cache.
- * <p>
- * If the key or the value is null, and InvalidArgumentException is thrown.
- * <p>
- * @see org.apache.commons.jcs.access.behavior.ICacheAccess#put(Object, Object, IElementAttributes)
- */
- @Override
- public void put( K key, V val, IElementAttributes attr )
- {
- if ( key == null )
- {
- throw new InvalidArgumentException( "Key must not be null" );
- }
-
- if ( val == null )
- {
- throw new InvalidArgumentException( "Value must not be null" );
- }
-
- // Create the element and update. This may throw an IOException which
- // should be wrapped by cache access.
- try
- {
- CacheElement<K, V> ce = new CacheElement<>( this.getCacheControl().getCacheName(), key,
- val );
-
- ce.setElementAttributes( attr );
-
- this.getCacheControl().update( ce );
- }
- catch ( IOException e )
- {
- throw new CacheException( e );
- }
- }
-
- /**
- * Removes a single item by name.
- * <p>
- * @param name the name of the item to remove.
- */
- @Override
- public void remove( K name )
- {
- this.getCacheControl().remove( name );
- }
-
- /**
- * Reset attributes for a particular element in the cache. NOTE: this method is currently not
- * implemented.
- * <p>
- * @param name Key of object to reset attributes for
- * @param attr New attributes for the object
- * @throws InvalidHandleException if the item does not exist.
- */
- @Override
- public void resetElementAttributes( K name, IElementAttributes attr )
- {
- ICacheElement<K, V> element = this.getCacheControl().get( name );
-
- if ( element == null )
- {
- throw new InvalidHandleException( "Object for name [" + name + "] is not in the cache" );
- }
-
- // Although it will work currently, don't assume pass by reference here,
- // i.e. don't do this:
- // element.setElementAttributes( attr );
- // Another reason to call put is to force the changes to be distributed.
-
- put( element.getKey(), element.getVal(), attr );
- }
-
- /**
- * GetElementAttributes will return an attribute object describing the current attributes
- * associated with the object name. The name object must override the Object.equals and
- * Object.hashCode methods.
- * <p>
- * @param name Key of object to get attributes for
- * @return Attributes for the object, null if object not in cache
- */
- @Override
- public IElementAttributes getElementAttributes( K name ) throws CacheException
- {
- IElementAttributes attr = null;
-
- try
- {
- attr = this.getCacheControl().getElementAttributes( name );
- }
- catch ( IOException ioe )
- {
- throw new CacheException("Failure getting element attributes", ioe);
- }
-
- return attr;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/GroupCacheAccess.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/GroupCacheAccess.java
deleted file mode 100644
index d98fe1a..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/GroupCacheAccess.java
+++ /dev/null
@@ -1,206 +0,0 @@
-package org.apache.commons.jcs.access;
-
-import java.io.IOException;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.access.behavior.IGroupCacheAccess;
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.access.exception.InvalidArgumentException;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.control.group.GroupAttrName;
-import org.apache.commons.jcs.engine.control.group.GroupId;
-
-/**
- * Access for groups.
- */
-public class GroupCacheAccess<K, V>
- extends AbstractCacheAccess<GroupAttrName<K>, V>
- implements IGroupCacheAccess<K, V>
-{
- /**
- * Constructor for the GroupCacheAccess object
- * <p>
- * @param cacheControl
- */
- public GroupCacheAccess( CompositeCache<GroupAttrName<K>, V> cacheControl )
- {
- super(cacheControl);
- }
-
- /**
- * Gets an item out of the cache that is in a specified group.
- * <p>
- * @param name
- * The key name.
- * @param group
- * The group name.
- * @return The cached value, null if not found.
- */
- @Override
- public V getFromGroup( K name, String group )
- {
- ICacheElement<GroupAttrName<K>, V> element = this.getCacheControl().get( getGroupAttrName( group, name ) );
- return ( element != null ) ? element.getVal() : null;
- }
-
- /**
- * Internal method used for group functionality.
- * <p>
- * @param group
- * @param name
- * @return GroupAttrName
- */
- private GroupAttrName<K> getGroupAttrName( String group, K name )
- {
- GroupId gid = new GroupId( this.getCacheControl().getCacheName(), group );
- return new GroupAttrName<>( gid, name );
- }
-
- /**
- * Allows the user to put an object into a group within a particular cache
- * region. This method sets the object's attributes to the default for the
- * region.
- * <p>
- * @param name
- * The key name.
- * @param groupName
- * The group name.
- * @param value
- * The object to cache
- * @throws CacheException
- */
- @Override
- public void putInGroup( K name, String groupName, V value )
- throws CacheException
- {
- putInGroup( name, groupName, value, null );
- }
-
- /**
- * Allows the user to put an object into a group within a particular cache
- * region. This method allows the object's attributes to be individually
- * specified.
- * <p>
- * @param name
- * The key name.
- * @param groupName
- * The group name.
- * @param value
- * The object to cache
- * @param attr
- * The objects attributes.
- * @throws CacheException
- */
- @Override
- public void putInGroup( K name, String groupName, V value, IElementAttributes attr )
- throws CacheException
- {
- if ( name == null )
- {
- throw new InvalidArgumentException( "Key must not be null" );
- }
-
- if ( value == null )
- {
- throw new InvalidArgumentException( "Value must not be null" );
- }
-
- // Create the element and update. This may throw an IOException which
- // should be wrapped by cache access.
- try
- {
- GroupAttrName<K> key = getGroupAttrName( groupName, name );
- CacheElement<GroupAttrName<K>, V> ce =
- new CacheElement<>( this.getCacheControl().getCacheName(), key, value );
-
- IElementAttributes attributes = (attr == null) ? this.getCacheControl().getElementAttributes() : attr;
- ce.setElementAttributes( attributes );
-
- this.getCacheControl().update( ce );
- }
- catch ( IOException e )
- {
- throw new CacheException( e );
- }
-
- }
-
- /**
- * Removes a single item by name from a group.
- *
- * @param name
- * @param group
- */
- @Override
- public void removeFromGroup( K name, String group )
- {
- GroupAttrName<K> key = getGroupAttrName( group, name );
- this.getCacheControl().remove( key );
- }
-
- /**
- * Gets the set of keys of objects currently in the group.
- * <p>
- * @param group
- * @return A Set of keys.
- */
- @Override
- public Set<K> getGroupKeys( String group )
- {
- GroupId groupId = new GroupId( this.getCacheControl().getCacheName(), group );
-
- return this.getCacheControl().getKeySet()
- .stream()
- .filter(gan -> gan.groupId.equals(groupId))
- .map(gan -> gan.attrName)
- .collect(Collectors.toSet());
- }
-
- /**
- * Gets the set of group names in the cache
- * <p>
- * @return A Set of group names.
- */
- public Set<String> getGroupNames()
- {
- return this.getCacheControl().getKeySet()
- .stream()
- .map(gan -> gan.groupId.groupName)
- .collect(Collectors.toSet());
- }
-
- /**
- * Invalidates a group: remove all the group members
- * <p>
- * @param group
- * The name of the group to invalidate
- */
- @Override
- public void invalidateGroup( String group )
- {
- this.getCacheControl().remove(getGroupAttrName(group, null));
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/behavior/ICacheAccess.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/behavior/ICacheAccess.java
deleted file mode 100644
index f48abdd..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/behavior/ICacheAccess.java
+++ /dev/null
@@ -1,178 +0,0 @@
-package org.apache.commons.jcs.access.behavior;
-
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Supplier;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-
-/**
- * ICacheAccess defines the behavior for client access.
- */
-public interface ICacheAccess<K, V>
- extends ICacheAccessManagement
-{
- /**
- * Basic get method.
- * <p>
- * @param name
- * @return Object or null if not found.
- */
- V get(K name);
-
- /**
- * Basic get method. If the object cannot be found in the cache, it will be
- * retrieved by calling the supplier and subsequently storing it in the cache.
- * <p>
- * @param name
- * @param supplier supplier to be called if the value is not found
- * @return Object.
- */
- V get(K name, Supplier<V> supplier);
-
- /**
- * Retrieve matching objects from the cache region this instance provides access to.
- * <p>
- * @param pattern - a key pattern for the objects stored
- * @return A map of key to values. These are stripped from the wrapper.
- */
- Map<K, V> getMatching(String pattern);
-
- /**
- * Puts in cache if an item does not exist with the name in that region.
- * <p>
- * @param name
- * @param obj
- * @throws CacheException
- */
- void putSafe(K name, V obj)
- throws CacheException;
-
- /**
- * Puts and/or overrides an element with the name in that region.
- * <p>
- * @param name
- * @param obj
- * @throws CacheException
- */
- void put(K name, V obj)
- throws CacheException;
-
- /**
- * Description of the Method
- * <p>
- * @param name
- * @param obj
- * @param attr
- * @throws CacheException
- */
- void put(K name, V obj, IElementAttributes attr)
- throws CacheException;
-
- /**
- * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other
- * attributes.
- * <p>
- * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
- * defensive copy is made.
- * <p>
- * This method is most useful if you want to determine things such as the how long the element
- * has been in the cache.
- * <p>
- * The last access time in the ElementAttributes should be current.
- * <p>
- * @param name Key the object is stored as
- * @return The ICacheElement<K, V> if the object is found or null
- */
- ICacheElement<K, V> getCacheElement(K name);
-
- /**
- * Get multiple elements from the cache based on a set of cache keys.
- * <p>
- * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other
- * attributes.
- * <p>
- * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
- * defensive copy is made.
- * <p>
- * This method is most useful if you want to determine things such as the how long the element
- * has been in the cache.
- * <p>
- * The last access time in the ElementAttributes should be current.
- * <p>
- * @param names set of Object cache keys
- * @return a map of Object key to ICacheElement<K, V> element, or empty map if none of the keys are
- * present
- */
- Map<K, ICacheElement<K, V>> getCacheElements(Set<K> names);
-
- /**
- * Get multiple elements from the cache based on a set of cache keys.
- * <p>
- * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other
- * attributes.
- * <p>
- * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
- * defensive copy is made.
- * <p>
- * This method is most useful if you want to determine things such as the how long the element
- * has been in the cache.
- * <p>
- * The last access time in the ElementAttributes should be current.
- * <p>
- * @param pattern key search pattern
- * @return a map of Object key to ICacheElement<K, V> element, or empty map if no keys match the
- * pattern
- */
- Map<K, ICacheElement<K, V>> getMatchingCacheElements(String pattern);
-
- /**
- * Remove an object for this key if one exists, else do nothing.
- * <p>
- * @param name
- * @throws CacheException
- */
- void remove(K name)
- throws CacheException;
-
- /**
- * Reset the attributes on the object matching this key name.
- * <p>
- * @param name
- * @param attributes
- * @throws CacheException
- */
- void resetElementAttributes(K name, IElementAttributes attributes)
- throws CacheException;
-
- /**
- * Gets the elementAttributes attribute of the ICacheAccess object
- * <p>
- * @param name
- * @return The elementAttributes value
- * @throws CacheException
- */
- IElementAttributes getElementAttributes(K name)
- throws CacheException;
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/behavior/ICacheAccessManagement.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/behavior/ICacheAccessManagement.java
deleted file mode 100644
index 21c01f4..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/behavior/ICacheAccessManagement.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package org.apache.commons.jcs.access.behavior;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.stats.behavior.ICacheStats;
-
-/**
- * ICacheAccessManagement defines the methods for cache management, cleanup and shutdown.
- */
-public interface ICacheAccessManagement
-{
- /**
- * Dispose this region. Flushes objects to and closes auxiliary caches. This is a shutdown
- * command!
- * <p>
- * To simply remove all elements from the region use clear().
- */
- void dispose();
-
- /**
- * Removes all of the elements from a region.
- * <p>
- * @throws CacheException
- */
- void clear() throws CacheException;
-
- /**
- * GetElementAttributes will return an attribute object describing the current attributes
- * associated with the object name. If no name parameter is available, the attributes for the
- * region will be returned. The name object must override the Object.equals and Object.hashCode
- * methods.
- * <p>
- * @return The elementAttributes value
- * @throws CacheException
- */
- IElementAttributes getDefaultElementAttributes()
- throws CacheException;
-
- /**
- * This method is does not reset the attributes for items already in the cache. It could
- * potentially do this for items in memory, and maybe on disk (which would be slow) but not
- * remote items. Rather than have unpredictable behavior, this method just sets the default
- * attributes. Items subsequently put into the cache will use these defaults if they do not
- * specify specific attributes.
- * <p>
- * @param attr the default attributes.
- * @throws CacheException if something goes wrong.
- */
- void setDefaultElementAttributes( IElementAttributes attr ) throws CacheException;
-
- /**
- * Gets the ICompositeCacheAttributes of the cache region
- * <p>
- * @return ICompositeCacheAttributes
- */
- ICompositeCacheAttributes getCacheAttributes();
-
- /**
- * Sets the ICompositeCacheAttributes of the cache region
- * <p>
- * @param cattr The new ICompositeCacheAttribute value
- */
- void setCacheAttributes( ICompositeCacheAttributes cattr );
-
- /**
- * This instructs the memory cache to remove the <i>numberToFree</i> according to its eviction
- * policy. For example, the LRUMemoryCache will remove the <i>numberToFree</i> least recently
- * used items. These will be spooled to disk if a disk auxiliary is available.
- * <p>
- * @param numberToFree
- * @return the number that were removed. if you ask to free 5, but there are only 3, you will
- * get 3.
- * @throws CacheException
- */
- int freeMemoryElements( int numberToFree )
- throws CacheException;
-
- /**
- * This returns the ICacheStats object with information on this region and its auxiliaries.
- * <p>
- * This data can be formatted as needed.
- * <p>
- * @return ICacheStats
- */
- ICacheStats getStatistics();
-
- /**
- * @return A String version of the stats.
- */
- String getStats();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/behavior/IGroupCacheAccess.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/behavior/IGroupCacheAccess.java
deleted file mode 100644
index 4527d24..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/behavior/IGroupCacheAccess.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package org.apache.commons.jcs.access.behavior;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-
-import java.util.Set;
-
-/**
- * IGroupCacheAccess defines group specific behavior for the client access
- * classes.
- */
-public interface IGroupCacheAccess<K, V>
- extends ICacheAccessManagement
-{
- /**
- * Gets the g attribute of the IGroupCacheAccess object
- * <p>
- * @param name
- * @param group
- * the name of the group to associate this with.
- * @return The object that is keyed by the name in the group
- */
- V getFromGroup( K name, String group );
-
- /**
- * Puts an item in the cache associated with this group.
- * <p>
- * @param key
- * @param group
- * @param obj
- * @throws CacheException
- */
- void putInGroup( K key, String group, V obj )
- throws CacheException;
-
- /**
- * Put in the cache associated with this group using these attributes.
- * <p>
- * @param key
- * @param group
- * @param obj
- * @param attr
- * @throws CacheException
- */
- void putInGroup( K key, String group, V obj, IElementAttributes attr )
- throws CacheException;
-
- /**
- * Remove the item from this group in this region by this name.
- * <p>
- * @param name
- * @param group
- */
- void removeFromGroup( K name, String group );
-
- /**
- * Gets the set of keys of objects currently in the group
- * <p>
- * @param group
- * @return the set of group keys.
- */
- Set<K> getGroupKeys( String group );
-
- /**
- * Invalidates a group
- * <p>
- * @param group
- */
- void invalidateGroup( String group );
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/CacheException.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/CacheException.java
deleted file mode 100644
index 78479b1..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/CacheException.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.apache.commons.jcs.access.exception;
-
-/*
- * 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.
- */
-
-/**
- * This is the most general exception the cache throws.
- */
-public class CacheException
- extends RuntimeException
-{
- /** Don't change. */
- private static final long serialVersionUID = 8725795372935590265L;
-
- /**
- * Default
- */
- public CacheException()
- {
- super();
- }
-
- /**
- * Constructor for the CacheException object
- * @param nested a nested exception
- */
- public CacheException( Throwable nested )
- {
- super(nested);
- }
-
- /**
- * Constructor for the CacheException object
- * @param message the exception message
- */
- public CacheException( String message )
- {
- super(message);
- }
-
- /**
- * Constructor for the CacheException object
- * @param message the exception message
- * @param nested a nested exception
- */
- public CacheException(String message, Throwable nested)
- {
- super(message, nested);
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/ConfigurationException.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/ConfigurationException.java
deleted file mode 100644
index 03f4890..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/ConfigurationException.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.apache.commons.jcs.access.exception;
-
-/*
- * 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.
- */
-
-/** Thrown if there is some severe configuration problem that makes the cache nonfunctional. */
-public class ConfigurationException
- extends CacheException
-{
- /** Don't change. */
- private static final long serialVersionUID = 6881044536186097055L;
-
- /** Constructor for the ConfigurationException object */
- public ConfigurationException()
- {
- super();
- }
-
- /**
- * Constructor for the ConfigurationException object.
- * <p>
- * @param message
- */
- public ConfigurationException( String message )
- {
- super( message );
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/InvalidArgumentException.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/InvalidArgumentException.java
deleted file mode 100644
index cfb4435..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/InvalidArgumentException.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.apache.commons.jcs.access.exception;
-
-/*
- * 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.
- */
-
-/**
- * InvalidArgumentException is thrown if an argument is passed to the cache that is invalid. For
- * instance, null values passed to put result in this exception.
- */
-public class InvalidArgumentException
- extends CacheException
-{
- /** Don't change. */
- private static final long serialVersionUID = -6058373692208755562L;
-
- /** Constructor for the InvalidArgumentException object */
- public InvalidArgumentException()
- {
- super();
- }
-
- /**
- * Constructor for the InvalidArgumentException object.
- * <p>
- * @param message
- */
- public InvalidArgumentException( String message )
- {
- super( message );
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/InvalidGroupException.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/InvalidGroupException.java
deleted file mode 100644
index 870a402..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/InvalidGroupException.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.apache.commons.jcs.access.exception;
-
-/*
- * 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.
- */
-
-/**
- * InvalidGroupException
- */
-public class InvalidGroupException
- extends CacheException
-{
- /** Don't change. */
- private static final long serialVersionUID = -5219807114008843480L;
-
- /** Constructor for the InvalidGroupException object */
- public InvalidGroupException()
- {
- super();
- }
-
- /**
- * Constructor for the InvalidGroupException object
- * <p>
- * @param message
- */
- public InvalidGroupException( String message )
- {
- super( message );
- }
-
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/InvalidHandleException.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/InvalidHandleException.java
deleted file mode 100644
index 6b0e6d3..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/InvalidHandleException.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package org.apache.commons.jcs.access.exception;
-
-/*
- * 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.
- */
-
-/**
- * InvalidHandleException is not used.
- */
-public class InvalidHandleException
- extends CacheException
-{
- /** Don't change. */
- private static final long serialVersionUID = -5947822454839845924L;
-
- /** Constructor for the InvalidHandleException object */
- public InvalidHandleException()
- {
- // nothing
- super();
- }
-
- /**
- * Constructor for the InvalidHandleException object.
- * <p>
- * @param message
- */
- public InvalidHandleException( String message )
- {
- super( message );
- }
-
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/ObjectExistsException.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/ObjectExistsException.java
deleted file mode 100644
index edef1a4..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/ObjectExistsException.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.apache.commons.jcs.access.exception;
-
-/*
- * 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.
- */
-
-/**
- * The putSafe method on the JCS convenience class throws this exception if the object is already
- * present in the cache.
- * <p>
- * I'm removing this exception from normal use.
- * <p>
- * The overhead of throwing exceptions and the cumbersomeness of coding around exceptions warrants
- * removal. Exceptions like this don't make sense to throw in the course of normal operations to
- * signify a normal and expected condition. Returning null if an object isn't found is sufficient.
- */
-public class ObjectExistsException
- extends CacheException
-{
- /** Don't change. */
- private static final long serialVersionUID = -3779745827993383872L;
-
- /** Constructor for the ObjectExistsException object */
- public ObjectExistsException()
- {
- super();
- }
-
- /**
- * Constructor for the ObjectExistsException object
- * @param message
- */
- public ObjectExistsException( String message )
- {
- super( message );
- }
-
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/ObjectNotFoundException.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/ObjectNotFoundException.java
deleted file mode 100644
index 8dca2de..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/exception/ObjectNotFoundException.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.apache.commons.jcs.access.exception;
-
-/*
- * 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.
- */
-
-/**
- * ObjectNotFoundException
- * <p>
- * TODO see if we can remove this.
- * <p>
- * This is thrown from the composite cache if you as for the element attributes and the element does
- * not exist.
- */
-public class ObjectNotFoundException
- extends CacheException
-{
- /** Don't change. */
- private static final long serialVersionUID = 5684353421076546842L;
-
- /** Constructor for the ObjectNotFoundException object */
- public ObjectNotFoundException()
- {
- super();
- }
-
- /**
- * Constructor for the ObjectNotFoundException object
- * @param message
- */
- public ObjectNotFoundException( String message )
- {
- super( message );
- }
-
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/admin/CacheElementInfo.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/admin/CacheElementInfo.java
deleted file mode 100644
index 1c09423..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/admin/CacheElementInfo.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package org.apache.commons.jcs.admin;
-
-/*
- * 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.
- */
-
-import java.beans.ConstructorProperties;
-
-
-/**
- * Stores info on a cache element for the template
- */
-public class CacheElementInfo
-{
- /** element key */
- private final String key;
-
- /** is it eternal */
- private final boolean eternal;
-
- /** when it was created */
- private final String createTime;
-
- /** max life */
- private final long maxLifeSeconds;
-
- /** when it will expire */
- private final long expiresInSeconds;
-
- /**
- * Parameterized constructor
- *
- * @param key element key
- * @param eternal is it eternal
- * @param createTime when it was created
- * @param maxLifeSeconds max life
- * @param expiresInSeconds when it will expire
- */
- @ConstructorProperties({"key", "eternal", "createTime", "maxLifeSeconds", "expiresInSeconds"})
- public CacheElementInfo(String key, boolean eternal, String createTime,
- long maxLifeSeconds, long expiresInSeconds)
- {
- super();
- this.key = key;
- this.eternal = eternal;
- this.createTime = createTime;
- this.maxLifeSeconds = maxLifeSeconds;
- this.expiresInSeconds = expiresInSeconds;
- }
-
- /**
- * @return a string representation of the key
- */
- public String getKey()
- {
- return this.key;
- }
-
- /**
- * @return true if the item does not expire
- */
- public boolean isEternal()
- {
- return this.eternal;
- }
-
- /**
- * @return the time the object was created
- */
- public String getCreateTime()
- {
- return this.createTime;
- }
-
- /**
- * Ignored if isEternal
- * @return the longest this object can live.
- */
- public long getMaxLifeSeconds()
- {
- return this.maxLifeSeconds;
- }
-
- /**
- * Ignored if isEternal
- * @return how many seconds until this object expires.
- */
- public long getExpiresInSeconds()
- {
- return this.expiresInSeconds;
- }
-
- /**
- * @return string info on the item
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\nCacheElementInfo " );
- buf.append( "\n Key [" ).append( getKey() ).append( "]" );
- buf.append( "\n Eternal [" ).append( isEternal() ).append( "]" );
- buf.append( "\n CreateTime [" ).append( getCreateTime() ).append( "]" );
- buf.append( "\n MaxLifeSeconds [" ).append( getMaxLifeSeconds() ).append( "]" );
- buf.append( "\n ExpiresInSeconds [" ).append( getExpiresInSeconds() ).append( "]" );
-
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/admin/CacheRegionInfo.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/admin/CacheRegionInfo.java
deleted file mode 100644
index 520d38e..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/admin/CacheRegionInfo.java
+++ /dev/null
@@ -1,180 +0,0 @@
-package org.apache.commons.jcs.admin;
-
-/*
- * 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.
- */
-
-import java.beans.ConstructorProperties;
-
-
-
-/**
- * Stores info on a cache region for the template
- */
-public class CacheRegionInfo
-{
- /** The name of the cache region */
- private final String cacheName;
-
- /** The size of the cache region */
- private final int cacheSize;
-
- /** The status of the cache region */
- private final String cacheStatus;
-
- /** The statistics of the cache region */
- private final String cacheStatistics;
-
- /** The number of memory hits in the cache region */
- private final long hitCountRam;
-
- /** The number of auxiliary hits in the cache region */
- private final long hitCountAux;
-
- /** The number of misses in the cache region because the items were not found */
- private final long missCountNotFound;
-
- /** The number of misses in the cache region because the items were expired */
- private final long missCountExpired;
-
- /** The number of bytes counted so far, will be a total of all items */
- private final long byteCount;
-
- /**
- * Parameterized constructor
- *
- * @param cacheName The name of the cache region
- * @param cacheSize The size of the cache region
- * @param cacheStatus The status of the cache region
- * @param cacheStatistics The statistics of the cache region
- * @param hitCountRam The number of memory hits in the cache region
- * @param hitCountAux The number of auxiliary hits in the cache region
- * @param missCountNotFound The number of misses in the cache region because the items were not found
- * @param missCountExpired The number of misses in the cache region because the items were expired
- * @param byteCount The number of bytes counted so far, will be a total of all items
- */
- @ConstructorProperties({"cacheName", "cacheSize", "cacheStatus", "cacheStatistics",
- "hitCountRam", "hitCountAux", "missCountNotFound", "missCountExpired", "byteCount"})
- public CacheRegionInfo(String cacheName, int cacheSize, String cacheStatus,
- String cacheStatistics, long hitCountRam, long hitCountAux,
- long missCountNotFound, long missCountExpired, long byteCount)
- {
- super();
- this.cacheName = cacheName;
- this.cacheSize = cacheSize;
- this.cacheStatus = cacheStatus;
- this.cacheStatistics = cacheStatistics;
- this.hitCountRam = hitCountRam;
- this.hitCountAux = hitCountAux;
- this.missCountNotFound = missCountNotFound;
- this.missCountExpired = missCountExpired;
- this.byteCount = byteCount;
- }
-
- /**
- * @return the cacheName
- */
- public String getCacheName()
- {
- return this.cacheName;
- }
-
- /**
- * @return the cacheSize
- */
- public int getCacheSize()
- {
- return this.cacheSize;
- }
-
- /**
- * @return a status string
- */
- public String getCacheStatus()
- {
- return this.cacheStatus;
- }
-
- /**
- * Return the statistics for the region.
- * <p>
- * @return String
- */
- public String getCacheStatistics()
- {
- return this.cacheStatistics;
- }
-
- /**
- * @return the hitCountRam
- */
- public long getHitCountRam()
- {
- return hitCountRam;
- }
-
- /**
- * @return the hitCountAux
- */
- public long getHitCountAux()
- {
- return hitCountAux;
- }
-
- /**
- * @return the missCountNotFound
- */
- public long getMissCountNotFound()
- {
- return missCountNotFound;
- }
-
- /**
- * @return the missCountExpired
- */
- public long getMissCountExpired()
- {
- return missCountExpired;
- }
-
- /**
- * @return total byte count
- */
- public long getByteCount()
- {
- return this.byteCount;
- }
-
- /**
- * @return string info on the region
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\nCacheRegionInfo " );
- if ( cacheName != null )
- {
- buf.append( "\n CacheName [" + cacheName + "]" );
- buf.append( "\n Status [" + cacheStatus + "]" );
- }
- buf.append( "\n ByteCount [" + getByteCount() + "]" );
-
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/admin/CountingOnlyOutputStream.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/admin/CountingOnlyOutputStream.java
deleted file mode 100644
index ea0baf8..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/admin/CountingOnlyOutputStream.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package org.apache.commons.jcs.admin;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * Keeps track of the number of bytes written to it, but doesn't write them anywhere.
- */
-public class CountingOnlyOutputStream
- extends OutputStream
-{
- /** number of bytes passed through */
- private int count; // TODO should this be long?
-
- /**
- * count as we write.
- * <p>
- * @param b
- * @throws IOException
- */
- @Override
- public void write( byte[] b )
- throws IOException
- {
- this.count += b.length;
- }
-
- /**
- * count as we write.
- * <p>
- * @param b
- * @param off
- * @param len
- * @throws IOException
- */
- @Override
- public void write( byte[] b, int off, int len )
- throws IOException
- {
- this.count += len;
- }
-
- /**
- * count as we write.
- * <p>
- * @param b
- * @throws IOException
- */
- @Override
- public void write( int b )
- throws IOException
- {
- this.count++;
- }
-
- /**
- * The number of bytes that have passed through this stream.
- * <p>
- * @return int
- */
- public int getCount()
- {
- return this.count;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/admin/JCSAdmin.jsp b/commons-jcs-core/src/main/java/org/apache/commons/jcs/admin/JCSAdmin.jsp
deleted file mode 100644
index d92b0af..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/admin/JCSAdmin.jsp
+++ /dev/null
@@ -1,310 +0,0 @@
-<%--
- 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.
---%>
-<%@page import="org.apache.commons.jcs.JCS"%>
-<%@page import="org.apache.commons.jcs.access.CacheAccess" %>
-<%@page import="org.apache.commons.jcs.admin.CacheElementInfo" %>
-<%@page import="org.apache.commons.jcs.admin.CacheRegionInfo" %>
-<%@page import="java.io.Serializable" %>
-<%@page import="java.util.HashMap" %>
-
-<jsp:useBean id="jcsBean" scope="request" class="org.apache.commons.jcs.admin.JCSAdminBean" />
-
-<html>
-<head>
-
-<SCRIPT LANGUAGE="Javascript">
- function decision( message, url )
- {
- if( confirm(message) )
- {
- location.href = url;
- }
- }
-</SCRIPT>
-
-<title> JCS Admin Servlet </title>
-
-</head>
-
-<body>
-
-<%
- String CACHE_NAME_PARAM = "cacheName";
- String ACTION_PARAM = "action";
- String CLEAR_ALL_REGIONS_ACTION = "clearAllRegions";
- String CLEAR_REGION_ACTION = "clearRegion";
- String REMOVE_ACTION = "remove";
- String DETAIL_ACTION = "detail";
- String REGION_SUMMARY_ACTION = "regionSummary";
- String ITEM_ACTION = "item";
- String KEY_PARAM = "key";
- String SILENT_PARAM = "silent";
-
- String DEFAULT_TEMPLATE_NAME = "DEFAULT";
- String REGION_DETAIL_TEMPLATE_NAME = "DETAIL";
- String ITEM_TEMPLATE_NAME = "ITEM";
- String REGION_SUMMARY_TEMPLATE_NAME = "SUMMARY";
-
- String templateName = DEFAULT_TEMPLATE_NAME;
-
- HashMap<String, Object> context = new HashMap<String, Object>();
-
- // Get cacheName for actions from request (might be null)
- String cacheName = request.getParameter( CACHE_NAME_PARAM );
-
- if ( cacheName != null )
- {
- cacheName = cacheName.trim();
- }
-
- // If an action was provided, handle it
- String action = request.getParameter( ACTION_PARAM );
-
- if ( action != null )
- {
- if ( action.equals( CLEAR_ALL_REGIONS_ACTION ) )
- {
- jcsBean.clearAllRegions();
- }
- else if ( action.equals( CLEAR_REGION_ACTION ) )
- {
- if ( cacheName == null )
- {
- // Not Allowed
- }
- else
- {
- jcsBean.clearRegion( cacheName );
- }
- }
- else if ( action.equals( REMOVE_ACTION ) )
- {
- String[] keys = request.getParameterValues( KEY_PARAM );
-
- for ( int i = 0; i < keys.length; i++ )
- {
- jcsBean.removeItem( cacheName, keys[ i ] );
- }
-
- templateName = REGION_DETAIL_TEMPLATE_NAME;
- }
- else if ( action.equals( DETAIL_ACTION ) )
- {
- templateName = REGION_DETAIL_TEMPLATE_NAME;
- }
- else if ( action.equals( ITEM_ACTION ) )
- {
- templateName = ITEM_TEMPLATE_NAME;
- }
- else if ( action.equals( REGION_SUMMARY_ACTION ) )
- {
- templateName = REGION_SUMMARY_TEMPLATE_NAME;
- }
- }
-
- if ( request.getParameter( SILENT_PARAM ) != null )
- {
- // If silent parameter was passed, no output should be produced.
- //return null;
- }
- else
- {
- // Populate the context based on the template
- if ( templateName == REGION_DETAIL_TEMPLATE_NAME )
- {
- //context.put( "cacheName", cacheName );
- context.put( "elementInfoRecords", jcsBean.buildElementInfo( cacheName ) );
- }
- else if ( templateName == DEFAULT_TEMPLATE_NAME )
- {
- context.put( "cacheInfoRecords", jcsBean.buildCacheInfo() );
- }
- }
-
-///////////////////////////////////////////////////////////////////////////////////
- //handle display
-
- if ( templateName == ITEM_TEMPLATE_NAME )
- {
- String key = request.getParameter( KEY_PARAM );
-
- if ( key != null )
- {
- key = key.trim();
- }
-
- CacheAccess<Serializable, Serializable> cache = JCS.getInstance( cacheName );
- org.apache.commons.jcs.engine.behavior.ICacheElement<?, ?> element = cache.getCacheElement( key );
-%>
-<h1> Item for key [<%=key%>] in region [<%=cacheName%>] </h1>
-
-<a href="JCSAdmin.jsp?action=detail&cacheName=<%=cacheName%>">Region Detail</a>
-| <a href="JCSAdmin.jsp">All Regions</a>
-
- <pre>
- <%=element%>
- </pre>
-<%
- }
- else if ( templateName == REGION_SUMMARY_TEMPLATE_NAME )
- {
-%>
-
-<h1> Summary for region [<%=cacheName%>] </h1>
-
-<a href="JCSAdmin.jsp">All Regions</a>
-
-<%
- CacheAccess<?, ?> cache = JCS.getInstance( cacheName );
- String stats = cache.getStats();
-%>
-
- <br>
-<b> Stats for region [<%=cacheName%>] </b>
-
- <pre>
- <%=stats%>
- </pre>
-
-<%
- }
- else if ( templateName == REGION_DETAIL_TEMPLATE_NAME )
- {
-%>
-
-<h1> Detail for region [<%=cacheName%>] </h1>
-
-<a href="JCSAdmin.jsp">All Regions</a>
-
-<table border="1" cellpadding="5" >
- <tr>
- <th> Key </th>
- <th> Eternal? </th>
- <th> Create time </th>
- <th> Max Life (s) </th>
- <th> Till Expiration (s) </th>
- </tr>
-<%
- CacheElementInfo[] list = (CacheElementInfo[]) context.get( "elementInfoRecords" );
- for (CacheElementInfo element : list)
- {
-%>
- <tr>
- <td> <%=element.getKey()%> </td>
- <td> <%=element.isEternal()%> </td>
- <td> <%=element.getCreateTime()%> </td>
- <td> <%=element.getMaxLifeSeconds()%> </td>
- <td> <%=element.getExpiresInSeconds()%> </td>
- <td>
- <a href="JCSAdmin.jsp?action=item&cacheName=<%=cacheName%>&key=<%=element.getKey()%>"> View </a>
- | <a href="JCSAdmin.jsp?action=remove&cacheName=<%=cacheName%>&key=<%=element.getKey()%>"> Remove </a>
- </td>
- </tr>
-<%
- }
-
- CacheAccess<?, ?> cache = JCS.getInstance( cacheName );
- String stats = cache.getStats();
-%>
- </table>
-
- <br>
-<b> Stats for region [<%=cacheName%>] </b>
-
- <pre>
- <%=stats%>
- </pre>
-<%
- }
- else
- {
-%>
-
-<h1> Cache Regions </h1>
-
-<p>
-These are the regions which are currently defined in the cache. 'Items' and
-'Bytes' refer to the elements currently in memory (not spooled). You can clear
-all items for a region by selecting 'Remove all' next to the desired region
-below. You can also <a href="javascript:decision('Clicking OK will clear all the data from all regions!','JCSAdmin.jsp?action=clearAllRegions')">Clear all regions</a>
-which empties the entire cache.
-</p>
-<p>
- <form action="JCSAdmin.jsp">
- <input type="hidden" name="action" value="item">
- Retrieve (key) <input type="text" name="key">
- (region) <select name="cacheName">
-<%
- CacheRegionInfo[] listSelect = (CacheRegionInfo[]) context.get( "cacheInfoRecords" );
- for (CacheRegionInfo record : listSelect)
- {
- %>
- <option value="<%=record.getCacheName()%>"><%=record.getCacheName()%></option>
- <%
- }
-%>
- </select>
- <input type="submit">
- </form>
-</p>
-
-<table border="1" cellpadding="5" >
- <tr>
- <th> Cache Name </th>
- <th> Items </th>
- <th> Bytes </th>
- <th> Status </th>
- <th> Memory Hits </th>
- <th> Aux Hits </th>
- <th> Not Found Misses </th>
- <th> Expired Misses </th>
- </tr>
-
-<%
- CacheRegionInfo[] list = (CacheRegionInfo[]) context.get( "cacheInfoRecords" );
- for (CacheRegionInfo record : listSelect)
- {
-%>
- <tr>
- <td> <%=record.getCacheName()%> </td>
- <td> <%=record.getCacheSize()%> </td>
- <td> <%=record.getByteCount()%> </td>
- <td> <%=record.getCacheStatus()%> </td>
- <td> <%=record.getHitCountRam()%> </td>
- <td> <%=record.getHitCountAux()%> </td>
- <td> <%=record.getMissCountNotFound()%> </td>
- <td> <%=record.getMissCountExpired()%> </td>
- <td>
- <a href="JCSAdmin.jsp?action=regionSummary&cacheName=<%=record.getCacheName()%>"> Summary </a>
- | <a href="JCSAdmin.jsp?action=detail&cacheName=<%=record.getCacheName()%>"> Detail </a>
- | <a href="javascript:decision('Clicking OK will remove all the data from the region [<%=record.getCacheName()%>]!','JCSAdmin.jsp?action=clearRegion&cacheName=<%=record.getCacheName()%>')"> Clear </a>
- </td>
- </tr>
-<%
- }
-%>
- </table>
-<%
- }
-%>
-
-
-</body>
-
-</html>
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/admin/JCSAdminBean.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/admin/JCSAdminBean.java
deleted file mode 100644
index 42fa3b7..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/admin/JCSAdminBean.java
+++ /dev/null
@@ -1,391 +0,0 @@
-package org.apache.commons.jcs.admin;
-
-import java.io.IOException;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.text.DateFormat;
-import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.stream.Collectors;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.auxiliary.remote.server.RemoteCacheServer;
-import org.apache.commons.jcs.auxiliary.remote.server.RemoteCacheServerFactory;
-import org.apache.commons.jcs.engine.CacheElementSerialized;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-import org.apache.commons.jcs.engine.memory.behavior.IMemoryCache;
-
-/**
- * A servlet which provides HTTP access to JCS. Allows a summary of regions to be viewed, and
- * removeAll to be run on individual regions or all regions. Also provides the ability to remove
- * items (any number of key arguments can be provided with action 'remove'). Should be initialized
- * with a properties file that provides at least a classpath resource loader.
- */
-public class JCSAdminBean implements JCSJMXBean
-{
- /** The cache manager. */
- private final CompositeCacheManager cacheHub;
-
- /**
- * Default constructor
- */
- public JCSAdminBean()
- {
- super();
- try
- {
- this.cacheHub = CompositeCacheManager.getInstance();
- }
- catch (CacheException e)
- {
- throw new RuntimeException("Could not retrieve cache manager instance", e);
- }
- }
-
- /**
- * Parameterized constructor
- *
- * @param cacheHub the cache manager instance
- */
- public JCSAdminBean(CompositeCacheManager cacheHub)
- {
- super();
- this.cacheHub = cacheHub;
- }
-
- /**
- * Builds up info about each element in a region.
- * <p>
- * @param cacheName
- * @return List of CacheElementInfo objects
- * @throws IOException
- */
- @Override
- public List<CacheElementInfo> buildElementInfo( String cacheName )
- throws IOException
- {
- CompositeCache<Object, Object> cache = cacheHub.getCache( cacheName );
-
- // Convert all keys to string, store in a sorted map
- TreeMap<String, ?> keys = new TreeMap<>(cache.getMemoryCache().getKeySet()
- .stream()
- .collect(Collectors.toMap(k -> k.toString(), k -> k)));
-
- LinkedList<CacheElementInfo> records = new LinkedList<>();
-
- DateFormat format = DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT );
-
- long now = System.currentTimeMillis();
-
- for (Map.Entry<String, ?> key : keys.entrySet())
- {
- ICacheElement<?, ?> element = cache.getMemoryCache().getQuiet( key.getValue() );
-
- IElementAttributes attributes = element.getElementAttributes();
-
- CacheElementInfo elementInfo = new CacheElementInfo(
- key.getKey(),
- attributes.getIsEternal(),
- format.format(new Date(attributes.getCreateTime())),
- attributes.getMaxLife(),
- (now - attributes.getCreateTime() - attributes.getMaxLife() * 1000 ) / -1000);
-
- records.add( elementInfo );
- }
-
- return records;
- }
-
- /**
- * Builds up data on every region.
- * <p>
- * TODO we need a most light weight method that does not count bytes. The byte counting can
- * really swamp a server.
- * @return List of CacheRegionInfo objects
- */
- @Override
- public List<CacheRegionInfo> buildCacheInfo()
- {
- TreeSet<String> cacheNames = new TreeSet<>(cacheHub.getCacheNames());
-
- LinkedList<CacheRegionInfo> cacheInfo = new LinkedList<>();
-
- for (String cacheName : cacheNames)
- {
- CompositeCache<?, ?> cache = cacheHub.getCache( cacheName );
-
- CacheRegionInfo regionInfo = new CacheRegionInfo(
- cache.getCacheName(),
- cache.getSize(),
- cache.getStatus().toString(),
- cache.getStats(),
- cache.getHitCountRam(),
- cache.getHitCountAux(),
- cache.getMissCountNotFound(),
- cache.getMissCountExpired(),
- getByteCount( cache ));
-
- cacheInfo.add( regionInfo );
- }
-
- return cacheInfo;
- }
-
-
- /**
- * Tries to estimate how much data is in a region. This is expensive. If there are any non serializable objects in
- * the region or an error occurs, suppresses exceptions and returns 0.
- * <p>
- *
- * @return int The size of the region in bytes.
- */
- @Override
- public long getByteCount(String cacheName)
- {
- return getByteCount(cacheHub.getCache(cacheName));
- }
-
- /**
- * Tries to estimate how much data is in a region. This is expensive. If there are any non serializable objects in
- * the region or an error occurs, suppresses exceptions and returns 0.
- * <p>
- *
- * @return int The size of the region in bytes.
- */
- public <K, V> long getByteCount(CompositeCache<K, V> cache)
- {
- if (cache == null)
- {
- throw new IllegalArgumentException("The cache object specified was null.");
- }
-
- long size = 0;
- IMemoryCache<K, V> memCache = cache.getMemoryCache();
-
- for (K key : memCache.getKeySet())
- {
- ICacheElement<K, V> ice = null;
- try
- {
- ice = memCache.get(key);
- }
- catch (IOException e)
- {
- throw new RuntimeException("IOException while trying to get a cached element", e);
- }
-
- if (ice == null)
- {
- continue;
- }
-
- if (ice instanceof CacheElementSerialized)
- {
- size += ((CacheElementSerialized<K, V>) ice).getSerializedValue().length;
- }
- else
- {
- Object element = ice.getVal();
-
- //CountingOnlyOutputStream: Keeps track of the number of bytes written to it, but doesn't write them anywhere.
- CountingOnlyOutputStream counter = new CountingOnlyOutputStream();
- try (ObjectOutputStream out = new ObjectOutputStream(counter);)
- {
- out.writeObject(element);
- }
- catch (IOException e)
- {
- throw new RuntimeException("IOException while trying to measure the size of the cached element", e);
- }
- finally
- {
- try
- {
- counter.close();
- }
- catch (IOException e)
- {
- // ignore
- }
- }
-
- // 4 bytes lost for the serialization header
- size += counter.getCount() - 4;
- }
- }
-
- return size;
- }
-
- /**
- * Clears all regions in the cache.
- * <p>
- * If this class is running within a remote cache server, clears all regions via the <code>RemoteCacheServer</code>
- * API, so that removes will be broadcast to client machines. Otherwise clears all regions in the cache directly via
- * the usual cache API.
- */
- @Override
- public void clearAllRegions() throws IOException
- {
- RemoteCacheServer<?, ?> remoteCacheServer = RemoteCacheServerFactory.getRemoteCacheServer();
-
- if (remoteCacheServer == null)
- {
- // Not running in a remote cache server.
- // Remove objects from the cache directly, as no need to broadcast removes to client machines...
- for (String name : cacheHub.getCacheNames())
- {
- cacheHub.getCache(name).removeAll();
- }
- }
- else
- {
- // Running in a remote cache server.
- // Remove objects via the RemoteCacheServer API, so that removes will be broadcast to client machines...
- // Call remoteCacheServer.removeAll(String) for each cacheName...
- for (String name : cacheHub.getCacheNames())
- {
- remoteCacheServer.removeAll(name);
- }
- }
- }
-
- /**
- * Clears a particular cache region.
- * <p>
- * If this class is running within a remote cache server, clears the region via the <code>RemoteCacheServer</code>
- * API, so that removes will be broadcast to client machines. Otherwise clears the region directly via the usual
- * cache API.
- */
- @Override
- public void clearRegion(String cacheName) throws IOException
- {
- if (cacheName == null)
- {
- throw new IllegalArgumentException("The cache name specified was null.");
- }
- if (RemoteCacheServerFactory.getRemoteCacheServer() == null)
- {
- // Not running in a remote cache server.
- // Remove objects from the cache directly, as no need to broadcast removes to client machines...
- cacheHub.getCache(cacheName).removeAll();
- }
- else
- {
- // Running in a remote cache server.
- // Remove objects via the RemoteCacheServer API, so that removes will be broadcast to client machines...
- try
- {
- // Call remoteCacheServer.removeAll(String)...
- RemoteCacheServer<?, ?> remoteCacheServer = RemoteCacheServerFactory.getRemoteCacheServer();
- remoteCacheServer.removeAll(cacheName);
- }
- catch (IOException e)
- {
- throw new IllegalStateException("Failed to remove all elements from cache region [" + cacheName + "]: " + e, e);
- }
- }
- }
-
- /**
- * Removes a particular item from a particular region.
- * <p>
- * If this class is running within a remote cache server, removes the item via the <code>RemoteCacheServer</code>
- * API, so that removes will be broadcast to client machines. Otherwise clears the region directly via the usual
- * cache API.
- *
- * @param cacheName
- * @param key
- *
- * @throws IOException
- */
- @Override
- public void removeItem(String cacheName, String key) throws IOException
- {
- if (cacheName == null)
- {
- throw new IllegalArgumentException("The cache name specified was null.");
- }
- if (key == null)
- {
- throw new IllegalArgumentException("The key specified was null.");
- }
- if (RemoteCacheServerFactory.getRemoteCacheServer() == null)
- {
- // Not running in a remote cache server.
- // Remove objects from the cache directly, as no need to broadcast removes to client machines...
- cacheHub.getCache(cacheName).remove(key);
- }
- else
- {
- // Running in a remote cache server.
- // Remove objects via the RemoteCacheServer API, so that removes will be broadcast to client machines...
- try
- {
- Object keyToRemove = null;
- CompositeCache<?, ?> cache = CompositeCacheManager.getInstance().getCache(cacheName);
-
- // A String key was supplied, but to remove elements via the RemoteCacheServer API, we need the
- // actual key object as stored in the cache (i.e. a Serializable object). To find the key in this form,
- // we iterate through all keys stored in the memory cache until we find one whose toString matches
- // the string supplied...
- Set<?> allKeysInCache = cache.getMemoryCache().getKeySet();
- for (Object keyInCache : allKeysInCache)
- {
- if (keyInCache.toString().equals(key))
- {
- if (keyToRemove == null)
- {
- keyToRemove = keyInCache;
- }
- else
- {
- // A key matching the one specified was already found...
- throw new IllegalStateException("Unexpectedly found duplicate keys in the cache region matching the key specified.");
- }
- }
- }
- if (keyToRemove == null)
- {
- throw new IllegalStateException("No match for this key could be found in the set of keys retrieved from the memory cache.");
- }
- // At this point, we have retrieved the matching K key.
-
- // Call remoteCacheServer.remove(String, Serializable)...
- RemoteCacheServer<Serializable, Serializable> remoteCacheServer = RemoteCacheServerFactory.getRemoteCacheServer();
- remoteCacheServer.remove(cacheName, key);
- }
- catch (Exception e)
- {
- throw new IllegalStateException("Failed to remove element with key [" + key + ", " + key.getClass() + "] from cache region [" + cacheName + "]: " + e, e);
- }
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/admin/JCSJMXBean.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/admin/JCSJMXBean.java
deleted file mode 100644
index 41b756a..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/admin/JCSJMXBean.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package org.apache.commons.jcs.admin;
-
-import java.io.IOException;
-import java.util.List;
-
-/*
- * 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.
- */
-
-import javax.management.MXBean;
-
-/**
- * A MXBean to expose the JCS statistics to JMX
- */
-@MXBean
-public interface JCSJMXBean
-{
- /**
- * Builds up info about each element in a region.
- * <p>
- * @param cacheName
- * @return List of CacheElementInfo objects
- * @throws IOException
- */
- List<CacheElementInfo> buildElementInfo( String cacheName ) throws IOException;
-
- /**
- * Builds up data on every region.
- * <p>
- * TODO we need a most light weight method that does not count bytes. The byte counting can
- * really swamp a server.
- * @return List of CacheRegionInfo objects
- */
- List<CacheRegionInfo> buildCacheInfo();
-
- /**
- * Tries to estimate how much data is in a region. This is expensive. If there are any non serializable objects in
- * the region or an error occurs, suppresses exceptions and returns 0.
- * <p>
- *
- * @return long The size of the region in bytes.
- */
- long getByteCount(String cacheName);
-
- /**
- * Clears all regions in the cache.
- * <p>
- * If this class is running within a remote cache server, clears all regions via the <code>RemoteCacheServer</code>
- * API, so that removes will be broadcast to client machines. Otherwise clears all regions in the cache directly via
- * the usual cache API.
- */
- void clearAllRegions() throws IOException;
-
- /**
- * Clears a particular cache region.
- * <p>
- * If this class is running within a remote cache server, clears the region via the <code>RemoteCacheServer</code>
- * API, so that removes will be broadcast to client machines. Otherwise clears the region directly via the usual
- * cache API.
- */
- void clearRegion(String cacheName) throws IOException;
-
- /**
- * Removes a particular item from a particular region.
- * <p>
- * If this class is running within a remote cache server, removes the item via the <code>RemoteCacheServer</code>
- * API, so that removes will be broadcast to client machines. Otherwise clears the region directly via the usual
- * cache API.
- *
- * @param cacheName
- * @param key
- *
- * @throws IOException
- */
- void removeItem(String cacheName, String key) throws IOException;
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCache.java
deleted file mode 100644
index b0ee573..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCache.java
+++ /dev/null
@@ -1,257 +0,0 @@
-package org.apache.commons.jcs.auxiliary;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.logging.CacheEvent;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.engine.match.KeyMatcherPatternImpl;
-import org.apache.commons.jcs.engine.match.behavior.IKeyMatcher;
-import org.apache.commons.jcs.utils.serialization.StandardSerializer;
-
-/** This holds convenience methods used by most auxiliary caches. */
-public abstract class AbstractAuxiliaryCache<K, V>
- implements AuxiliaryCache<K, V>
-{
- /** An optional event logger */
- private ICacheEventLogger cacheEventLogger;
-
- /** The serializer. Uses a standard serializer by default. */
- private IElementSerializer elementSerializer = new StandardSerializer();
-
- /** Key matcher used by the getMatching API */
- private IKeyMatcher<K> keyMatcher = new KeyMatcherPatternImpl<>();
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- *
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- */
- protected Map<K, ICacheElement<K, V>> processGetMultiple(Set<K> keys) throws IOException
- {
- if (keys != null)
- {
- return keys.stream()
- .map(key -> {
- try
- {
- return get(key);
- }
- catch (IOException e)
- {
- return null;
- }
- })
- .filter(element -> element != null)
- .collect(Collectors.toMap(
- element -> element.getKey(),
- element -> element));
- }
-
- return new HashMap<>();
- }
-
- /**
- * Gets the item from the cache.
- *
- * @param key
- * @return ICacheElement, a wrapper around the key, value, and attributes
- * @throws IOException
- */
- @Override
- public abstract ICacheElement<K, V> get( K key ) throws IOException;
-
- /**
- * Logs an event if an event logger is configured.
- * <p>
- * @param item
- * @param eventName
- * @return ICacheEvent
- */
- protected ICacheEvent<K> createICacheEvent( ICacheElement<K, V> item, String eventName )
- {
- if ( cacheEventLogger == null )
- {
- return new CacheEvent<>();
- }
- String diskLocation = getEventLoggingExtraInfo();
- String regionName = null;
- K key = null;
- if ( item != null )
- {
- regionName = item.getCacheName();
- key = item.getKey();
- }
- return cacheEventLogger.createICacheEvent( getAuxiliaryCacheAttributes().getName(), regionName, eventName,
- diskLocation, key );
- }
-
- /**
- * Logs an event if an event logger is configured.
- * <p>
- * @param regionName
- * @param key
- * @param eventName
- * @return ICacheEvent
- */
- protected <T> ICacheEvent<T> createICacheEvent( String regionName, T key, String eventName )
- {
- if ( cacheEventLogger == null )
- {
- return new CacheEvent<>();
- }
- String diskLocation = getEventLoggingExtraInfo();
- return cacheEventLogger.createICacheEvent( getAuxiliaryCacheAttributes().getName(), regionName, eventName,
- diskLocation, key );
-
- }
-
- /**
- * Logs an event if an event logger is configured.
- * <p>
- * @param cacheEvent
- */
- protected <T> void logICacheEvent( ICacheEvent<T> cacheEvent )
- {
- if ( cacheEventLogger != null )
- {
- cacheEventLogger.logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Logs an event if an event logger is configured.
- * <p>
- * @param source
- * @param eventName
- * @param optionalDetails
- */
- protected void logApplicationEvent( String source, String eventName, String optionalDetails )
- {
- if ( cacheEventLogger != null )
- {
- cacheEventLogger.logApplicationEvent( source, eventName, optionalDetails );
- }
- }
-
- /**
- * Logs an event if an event logger is configured.
- * <p>
- * @param source
- * @param eventName
- * @param errorMessage
- */
- protected void logError( String source, String eventName, String errorMessage )
- {
- if ( cacheEventLogger != null )
- {
- cacheEventLogger.logError( source, eventName, errorMessage );
- }
- }
-
- /**
- * Gets the extra info for the event log.
- * <p>
- * @return IP, or disk location, etc.
- */
- public abstract String getEventLoggingExtraInfo();
-
- /**
- * Allows it to be injected.
- * <p>
- * @param cacheEventLogger
- */
- @Override
- public void setCacheEventLogger( ICacheEventLogger cacheEventLogger )
- {
- this.cacheEventLogger = cacheEventLogger;
- }
-
- /**
- * Allows it to be injected.
- * <p>
- * @return cacheEventLogger
- */
- public ICacheEventLogger getCacheEventLogger()
- {
- return this.cacheEventLogger;
- }
-
- /**
- * Allows you to inject a custom serializer. A good example would be a compressing standard
- * serializer.
- * <p>
- * Does not allow you to set it to null.
- * <p>
- * @param elementSerializer
- */
- @Override
- public void setElementSerializer( IElementSerializer elementSerializer )
- {
- if ( elementSerializer != null )
- {
- this.elementSerializer = elementSerializer;
- }
- }
-
- /**
- * Allows it to be injected.
- * <p>
- * @return elementSerializer
- */
- public IElementSerializer getElementSerializer()
- {
- return this.elementSerializer;
- }
-
- /**
- * Sets the key matcher used by get matching.
- * <p>
- * @param keyMatcher
- */
- @Override
- public void setKeyMatcher( IKeyMatcher<K> keyMatcher )
- {
- if ( keyMatcher != null )
- {
- this.keyMatcher = keyMatcher;
- }
- }
-
- /**
- * Returns the key matcher used by get matching.
- * <p>
- * @return keyMatcher
- */
- public IKeyMatcher<K> getKeyMatcher()
- {
- return this.keyMatcher;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheAttributes.java
deleted file mode 100644
index e268c60..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheAttributes.java
+++ /dev/null
@@ -1,146 +0,0 @@
-package org.apache.commons.jcs.auxiliary;
-
-import org.apache.commons.jcs.engine.behavior.ICacheEventQueue;
-
-/*
- * 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.
- */
-
-/**
- * This has common attributes used by all auxiliaries.
- */
-public abstract class AbstractAuxiliaryCacheAttributes
- implements AuxiliaryCacheAttributes
-{
- /** Don't change */
- private static final long serialVersionUID = -6594609334959187673L;
-
- /** cacheName */
- private String cacheName;
-
- /** name */
- private String name;
-
- /** eventQueueType -- pooled, or single threaded */
- private ICacheEventQueue.QueueType eventQueueType;
-
- /** Named when pooled */
- private String eventQueuePoolName;
-
- /**
- * @param name
- */
- @Override
- public void setCacheName( String name )
- {
- this.cacheName = name;
- }
-
- /**
- * Gets the cacheName attribute of the AuxiliaryCacheAttributes object
- * <p>
- * @return The cacheName value
- */
- @Override
- public String getCacheName()
- {
- return this.cacheName;
- }
-
- /**
- * This is the name of the auxiliary in configuration file.
- * <p>
- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes#setName(java.lang.String)
- */
- @Override
- public void setName( String s )
- {
- this.name = s;
- }
-
- /**
- * Gets the name attribute of the AuxiliaryCacheAttributes object
- * <p>
- * @return The name value
- */
- @Override
- public String getName()
- {
- return this.name;
- }
-
- /**
- * SINGLE is the default. If you choose POOLED, the value of EventQueuePoolName will be used
- * <p>
- * @param queueType SINGLE or POOLED
- */
- @Override
- public void setEventQueueType( ICacheEventQueue.QueueType queueType )
- {
- this.eventQueueType = queueType;
- }
-
- /**
- * @return SINGLE or POOLED
- */
- @Override
- public ICacheEventQueue.QueueType getEventQueueType()
- {
- return eventQueueType;
- }
-
- /**
- * If you choose a POOLED event queue type, the value of EventQueuePoolName will be used. This
- * is ignored if the pool type is SINGLE
- * <p>
- * @param s SINGLE or POOLED
- */
- @Override
- public void setEventQueuePoolName( String s )
- {
- eventQueuePoolName = s;
- }
-
- /**
- * Sets the pool name to use. If a pool is not found by this name, the thread pool manager will
- * return a default configuration.
- * <p>
- * @return name of thread pool to use for this auxiliary
- */
- @Override
- public String getEventQueuePoolName()
- {
- return eventQueuePoolName;
- }
-
- /**
- * @see java.lang.Object#clone()
- */
- @Override
- public AbstractAuxiliaryCacheAttributes clone()
- {
- try
- {
- return (AbstractAuxiliaryCacheAttributes)super.clone();
- }
- catch (CloneNotSupportedException e)
- {
- throw new RuntimeException("Clone not supported. This should never happen.", e);
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheEventLogging.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheEventLogging.java
deleted file mode 100644
index 9b74c60..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheEventLogging.java
+++ /dev/null
@@ -1,342 +0,0 @@
-package org.apache.commons.jcs.auxiliary;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.Map;
-import java.util.Set;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-
-/**
- * All ICacheEvents are defined as final. Children must implement process events. These are wrapped
- * in event log parent calls.
- *
- * You can override the public method, but if you don't, the default will call getWithTiming.
- */
-public abstract class AbstractAuxiliaryCacheEventLogging<K, V>
- extends AbstractAuxiliaryCache<K, V>
-{
- /**
- * Puts an item into the cache.
- *
- * @param cacheElement
- * @throws IOException
- */
- @Override
- public void update( ICacheElement<K, V> cacheElement )
- throws IOException
- {
- updateWithEventLogging( cacheElement );
- }
-
- /**
- * Puts an item into the cache. Wrapped in logging.
- *
- * @param cacheElement
- * @throws IOException
- */
- protected final void updateWithEventLogging( ICacheElement<K, V> cacheElement )
- throws IOException
- {
- ICacheEvent<K> cacheEvent = createICacheEvent( cacheElement, ICacheEventLogger.UPDATE_EVENT );
- try
- {
- processUpdate( cacheElement );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Implementation of put.
- *
- * @param cacheElement
- * @throws IOException
- */
- protected abstract void processUpdate( ICacheElement<K, V> cacheElement )
- throws IOException;
-
- /**
- * Gets the item from the cache.
- *
- * @param key
- * @return ICacheElement, a wrapper around the key, value, and attributes
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> get( K key )
- throws IOException
- {
- return getWithEventLogging( key );
- }
-
- /**
- * Gets the item from the cache. Wrapped in logging.
- *
- * @param key
- * @return ICacheElement, a wrapper around the key, value, and attributes
- * @throws IOException
- */
- protected final ICacheElement<K, V> getWithEventLogging( K key )
- throws IOException
- {
- ICacheEvent<K> cacheEvent = createICacheEvent( getCacheName(), key, ICacheEventLogger.GET_EVENT );
- try
- {
- return processGet( key );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Implementation of get.
- *
- * @param key
- * @return ICacheElement, a wrapper around the key, value, and attributes
- * @throws IOException
- */
- protected abstract ICacheElement<K, V> processGet( K key )
- throws IOException;
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- *
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
- throws IOException
- {
- return getMultipleWithEventLogging( keys );
- }
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- *
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- * @throws IOException
- */
- protected final Map<K, ICacheElement<K, V>> getMultipleWithEventLogging(Set<K> keys )
- throws IOException
- {
- ICacheEvent<Serializable> cacheEvent = createICacheEvent( getCacheName(), (Serializable) keys,
- ICacheEventLogger.GETMULTIPLE_EVENT );
- try
- {
- return processGetMultiple( keys );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Gets items from the cache matching the given pattern. Items from memory will replace those
- * from remote sources.
- *
- * This only works with string keys. It's too expensive to do a toString on every key.
- *
- * Auxiliaries will do their best to handle simple expressions. For instance, the JDBC disk
- * cache will convert * to % and . to _
- *
- * @param pattern
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data matching the pattern.
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching( String pattern )
- throws IOException
- {
- return getMatchingWithEventLogging( pattern );
- }
-
- /**
- * Gets matching items from the cache based on the given pattern.
- *
- * @param pattern
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data matching the pattern.
- * @throws IOException
- */
- protected final Map<K, ICacheElement<K, V>> getMatchingWithEventLogging( String pattern )
- throws IOException
- {
- ICacheEvent<String> cacheEvent = createICacheEvent( getCacheName(), pattern, ICacheEventLogger.GETMATCHING_EVENT );
- try
- {
- return processGetMatching( pattern );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Implementation of getMatching.
- *
- * @param pattern
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data matching the pattern.
- * @throws IOException
- */
- protected abstract Map<K, ICacheElement<K, V>> processGetMatching( String pattern )
- throws IOException;
-
- /**
- * Removes the item from the cache. Wraps the remove in event logs.
- *
- * @param key
- * @return boolean, whether or not the item was removed
- * @throws IOException
- */
- @Override
- public boolean remove( K key )
- throws IOException
- {
- return removeWithEventLogging( key );
- }
-
- /**
- * Removes the item from the cache. Wraps the remove in event logs.
- *
- * @param key
- * @return boolean, whether or not the item was removed
- * @throws IOException
- */
- protected final boolean removeWithEventLogging( K key )
- throws IOException
- {
- ICacheEvent<K> cacheEvent = createICacheEvent( getCacheName(), key, ICacheEventLogger.REMOVE_EVENT );
- try
- {
- return processRemove( key );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Specific implementation of remove.
- *
- * @param key
- * @return boolean, whether or not the item was removed
- * @throws IOException
- */
- protected abstract boolean processRemove( K key )
- throws IOException;
-
- /**
- * Removes all from the region. Wraps the removeAll in event logs.
- *
- * @throws IOException
- */
- @Override
- public void removeAll()
- throws IOException
- {
- removeAllWithEventLogging();
- }
-
- /**
- * Removes all from the region. Wraps the removeAll in event logs.
- *
- * @throws IOException
- */
- protected final void removeAllWithEventLogging()
- throws IOException
- {
- ICacheEvent<String> cacheEvent = createICacheEvent( getCacheName(), "all", ICacheEventLogger.REMOVEALL_EVENT );
- try
- {
- processRemoveAll();
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Specific implementation of removeAll.
- *
- * @throws IOException
- */
- protected abstract void processRemoveAll()
- throws IOException;
-
- /**
- * Synchronously dispose the remote cache; if failed, replace the remote handle with a zombie.
- *
- * @throws IOException
- */
- @Override
- public void dispose()
- throws IOException
- {
- disposeWithEventLogging();
- }
-
- /**
- * Synchronously dispose the remote cache; if failed, replace the remote handle with a zombie.
- * Wraps the removeAll in event logs.
- *
- * @throws IOException
- */
- protected final void disposeWithEventLogging()
- throws IOException
- {
- ICacheEvent<String> cacheEvent = createICacheEvent( getCacheName(), "none", ICacheEventLogger.DISPOSE_EVENT );
- try
- {
- processDispose();
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Specific implementation of dispose.
- *
- * @throws IOException
- */
- protected abstract void processDispose()
- throws IOException;
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheFactory.java
deleted file mode 100644
index 657015e..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheFactory.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.apache.commons.jcs.auxiliary;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheFactory;
-
-/**
- * Base class for auxiliary cache factories.
- */
-public abstract class AbstractAuxiliaryCacheFactory
- implements AuxiliaryCacheFactory
-{
- /** The auxiliary name. The composite cache manager keeps this in a map, keyed by name. */
- private String name = this.getClass().getSimpleName();
-
- /**
- * Initialize this factory
- */
- @Override
- public void initialize()
- {
- // empty
- }
-
- /**
- * Dispose of this factory, clean up shared resources
- */
- @Override
- public void dispose()
- {
- // empty
- }
-
- /**
- * Gets the name attribute of the DiskCacheFactory object
- * <p>
- * @return The name value
- */
- @Override
- public String getName()
- {
- return this.name;
- }
-
- /**
- * Sets the name attribute of the DiskCacheFactory object
- * <p>
- * @param name The new name value
- */
- @Override
- public void setName( String name )
- {
- this.name = name;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheMonitor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheMonitor.java
deleted file mode 100644
index 25aa937..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AbstractAuxiliaryCacheMonitor.java
+++ /dev/null
@@ -1,197 +0,0 @@
-package org.apache.commons.jcs.auxiliary;
-
-/*
- * 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.
- */
-
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * Used to monitor and repair any failed connection for the lateral cache service. By default the
- * monitor operates in a failure driven mode. That is, it goes into a wait state until there is an
- * error. Upon the notification of a connection error, the monitor changes to operate in a time
- * driven mode. That is, it attempts to recover the connections on a periodic basis. When all failed
- * connections are restored, it changes back to the failure driven mode.
- */
-public abstract class AbstractAuxiliaryCacheMonitor extends Thread
-{
- /** The logger */
- protected final Log log = LogManager.getLog( this.getClass() );
-
- /** How long to wait between runs */
- protected static long idlePeriod = 20 * 1000;
-
- /**
- * Must make sure AbstractAuxiliaryCacheMonitor is started before any error can be detected!
- */
- protected AtomicBoolean allright = new AtomicBoolean(true);
-
- /**
- * shutdown flag
- */
- private AtomicBoolean shutdown = new AtomicBoolean(false);
-
- /** Synchronization helper lock */
- private Lock lock = new ReentrantLock();
-
- /** Synchronization helper condition */
- private Condition trigger = lock.newCondition();
-
- /**
- * Constructor
- *
- * @param name the thread name
- */
- public AbstractAuxiliaryCacheMonitor(String name)
- {
- super(name);
- }
-
- /**
- * Configures the idle period between repairs.
- * <p>
- * @param idlePeriod The new idlePeriod value
- */
- public static void setIdlePeriod( long idlePeriod )
- {
- if ( idlePeriod > AbstractAuxiliaryCacheMonitor.idlePeriod )
- {
- AbstractAuxiliaryCacheMonitor.idlePeriod = idlePeriod;
- }
- }
-
- /**
- * Notifies the cache monitor that an error occurred, and kicks off the error recovery process.
- */
- public void notifyError()
- {
- if (allright.compareAndSet(true, false))
- {
- signalTrigger();
- }
- }
-
- /**
- * Notifies the cache monitor that the service shall shut down
- */
- public void notifyShutdown()
- {
- if (shutdown.compareAndSet(false, true))
- {
- signalTrigger();
- }
- }
-
- // Trigger continuation of loop
- private void signalTrigger()
- {
- try
- {
- lock.lock();
- trigger.signal();
- }
- finally
- {
- lock.unlock();
- }
- }
-
- /**
- * Clean up all resources before shutdown
- */
- protected abstract void dispose();
-
- /**
- * do actual work
- */
- protected abstract void doWork();
-
- /**
- * Main processing method for the AbstractAuxiliaryCacheMonitor object
- */
- @Override
- public void run()
- {
- do
- {
- if ( allright.get() )
- {
- log.debug( "ERROR DRIVEN MODE: allright = true, cache monitor will wait for an error." );
- }
- else
- {
- log.debug( "ERROR DRIVEN MODE: allright = false cache monitor running." );
- }
-
- if ( allright.get() )
- {
- // Failure driven mode.
- try
- {
- lock.lock();
- trigger.await();
- // wake up only if there is an error.
- }
- catch ( InterruptedException ignore )
- {
- //no op, this is expected
- }
- finally
- {
- lock.unlock();
- }
- }
-
- // check for requested shutdown
- if ( shutdown.get() )
- {
- log.info( "Shutting down cache monitor" );
- dispose();
- return;
- }
-
- // The "allright" flag must be false here.
- // Simply presume we can fix all the errors until proven otherwise.
- allright.set(true);
-
- log.debug( "Cache monitor running." );
-
- doWork();
-
- try
- {
- // don't want to sleep after waking from an error
- // run immediately and sleep here.
- log.debug( "Cache monitor sleeping for {0} between runs.", idlePeriod );
-
- Thread.sleep( idlePeriod );
- }
- catch ( InterruptedException ex )
- {
- // ignore;
- }
- }
- while ( true );
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AuxiliaryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AuxiliaryCache.java
deleted file mode 100644
index 3bc3a52..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AuxiliaryCache.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package org.apache.commons.jcs.auxiliary;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICache;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-
-import java.io.IOException;
-import java.util.Set;
-
-/**
- * Tag interface for auxiliary caches. Currently this provides no additional methods over what is in
- * ICache, but I anticipate that will change. For example, there will be a mechanism for determining
- * the type (disk/lateral/remote) of the auxiliary here -- and the existing getCacheType will be
- * removed from ICache.
- */
-public interface AuxiliaryCache<K, V>
- extends ICache<K, V>
-{
- /**
- * Get a set of the keys for all elements in the auxiliary cache.
- * <p>
- * @return a set of the key type
- * TODO This should probably be done in chunks with a range passed in. This
- * will be a problem if someone puts a 1,000,000 or so items in a
- * region.
- * @throws IOException if access to the auxiliary cache fails
- */
- Set<K> getKeySet() throws IOException;
-
- /**
- * @return the historical and statistical data for a region's auxiliary cache.
- */
- IStats getStatistics();
-
- /**
- * This returns the generic attributes for an auxiliary cache. Most implementations will cast
- * this to a more specific type.
- * <p>
- * @return the attributes for the auxiliary cache
- */
- AuxiliaryCacheAttributes getAuxiliaryCacheAttributes();
-
- /**
- * Allows you to inject a custom serializer. A good example would be a compressing standard
- * serializer.
- * <p>
- * @param elementSerializer
- */
- void setElementSerializer( IElementSerializer elementSerializer );
-
- /**
- * Every Auxiliary must allow for the use of an event logger.
- * <p>
- * @param cacheEventLogger
- */
- void setCacheEventLogger( ICacheEventLogger cacheEventLogger );
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AuxiliaryCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AuxiliaryCacheAttributes.java
deleted file mode 100644
index f962cd2..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AuxiliaryCacheAttributes.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package org.apache.commons.jcs.auxiliary;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-
-import org.apache.commons.jcs.engine.behavior.ICacheEventQueue;
-
-/**
- * This is a nominal interface that auxiliary cache attributes should implement. This allows the
- * auxiliary mangers to share a common interface.
- */
-public interface AuxiliaryCacheAttributes
- extends Serializable, Cloneable
-{
- /**
- * Sets the name of the cache, referenced by the appropriate manager.
- * <p>
- * @param s The new cacheName value
- */
- void setCacheName( String s );
-
- /**
- * Gets the cacheName attribute of the AuxiliaryCacheAttributes object
- * <p>
- * @return The cacheName value
- */
- String getCacheName();
-
- /**
- * Name known by by configurator
- * <p>
- * @param s The new name value
- */
- void setName( String s );
-
- /**
- * Gets the name attribute of the AuxiliaryCacheAttributes object
- * <p>
- * @return The name value
- */
- String getName();
-
- /**
- * SINGLE is the default. If you choose POOLED, the value of EventQueuePoolName will be used
- * <p>
- * @param s SINGLE or POOLED
- */
- void setEventQueueType( ICacheEventQueue.QueueType s );
-
- /**
- * @return SINGLE or POOLED
- */
- ICacheEventQueue.QueueType getEventQueueType();
-
- /**
- * If you choose a POOLED event queue type, the value of EventQueuePoolName will be used. This
- * is ignored if the pool type is SINGLE
- * <p>
- * @param s SINGLE or POOLED
- */
- void setEventQueuePoolName( String s );
-
- /**
- * Sets the pool name to use. If a pool is not found by this name, the thread pool manager will
- * return a default configuration.
- * <p>
- * @return name of thread pool to use for this auxiliary
- */
- String getEventQueuePoolName();
-
- /**
- * Clone object
- */
- AuxiliaryCacheAttributes clone();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AuxiliaryCacheConfigurator.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AuxiliaryCacheConfigurator.java
deleted file mode 100644
index 02aea4e..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AuxiliaryCacheConfigurator.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package org.apache.commons.jcs.auxiliary;
-
-import java.util.Properties;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.config.OptionConverter;
-import org.apache.commons.jcs.utils.config.PropertySetter;
-import org.apache.commons.jcs.utils.serialization.StandardSerializer;
-
-/**
- * Configuration util for auxiliary caches. I plan to move the auxiliary configuration from the
- * composite cache configurator here.
- */
-public class AuxiliaryCacheConfigurator
-{
- /** The logger. */
- private static final Log log = LogManager.getLog( AuxiliaryCacheConfigurator.class );
-
- /** .attributes */
- public static final String ATTRIBUTE_PREFIX = ".attributes";
-
- /**
- * jcs.auxiliary.NAME.cacheeventlogger=CLASSNAME
- * <p>
- * jcs.auxiliary.NAME.cacheeventlogger.attributes.CUSTOMPROPERTY=VALUE
- */
- public static final String CACHE_EVENT_LOGGER_PREFIX = ".cacheeventlogger";
-
- /**
- * jcs.auxiliary.NAME.serializer=CLASSNAME
- * <p>
- * jcs.auxiliary.NAME.serializer.attributes.CUSTOMPROPERTY=VALUE
- */
- public static final String SERIALIZER_PREFIX = ".serializer";
-
- /**
- * Parses the event logger config, if there is any for the auxiliary.
- * <p>
- * @param props
- * @param auxPrefix - ex. AUXILIARY_PREFIX + auxName
- * @return cacheEventLogger
- */
- public static ICacheEventLogger parseCacheEventLogger( Properties props, String auxPrefix )
- {
- ICacheEventLogger cacheEventLogger = null;
-
- // auxFactory was not previously initialized.
- String eventLoggerClassName = auxPrefix + CACHE_EVENT_LOGGER_PREFIX;
- cacheEventLogger = OptionConverter.instantiateByKey( props, eventLoggerClassName, null );
- if ( cacheEventLogger != null )
- {
- String cacheEventLoggerAttributePrefix = auxPrefix + CACHE_EVENT_LOGGER_PREFIX + ATTRIBUTE_PREFIX;
- PropertySetter.setProperties( cacheEventLogger, props, cacheEventLoggerAttributePrefix + "." );
- log.info( "Using custom cache event logger [{0}] for auxiliary [{1}]",
- cacheEventLogger, auxPrefix );
- }
- else
- {
- log.info( "No cache event logger defined for auxiliary [{0}]", auxPrefix );
- }
- return cacheEventLogger;
- }
-
- /**
- * Parses the element config, if there is any for the auxiliary.
- * <p>
- * @param props
- * @param auxPrefix - ex. AUXILIARY_PREFIX + auxName
- * @return cacheEventLogger
- */
- public static IElementSerializer parseElementSerializer( Properties props, String auxPrefix )
- {
- // TODO take in the entire prop key
- IElementSerializer elementSerializer = null;
-
- // auxFactory was not previously initialized.
- String elementSerializerClassName = auxPrefix + SERIALIZER_PREFIX;
- elementSerializer = OptionConverter.instantiateByKey( props, elementSerializerClassName, null );
- if ( elementSerializer != null )
- {
- String attributePrefix = auxPrefix + SERIALIZER_PREFIX + ATTRIBUTE_PREFIX;
- PropertySetter.setProperties( elementSerializer, props, attributePrefix + "." );
- log.info( "Using custom element serializer [{0}] for auxiliary [{1}]",
- elementSerializer, auxPrefix );
- }
- else
- {
- // use the default standard serializer
- elementSerializer = new StandardSerializer();
- log.info( "Using standard serializer [{0}] for auxiliary [{1}]",
- elementSerializer, auxPrefix );
- }
- return elementSerializer;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AuxiliaryCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AuxiliaryCacheFactory.java
deleted file mode 100644
index 8175c4a..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/AuxiliaryCacheFactory.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package org.apache.commons.jcs.auxiliary;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-
-/**
- * All auxiliary caches must have a factory that the cache configurator can use to create instances.
- */
-public interface AuxiliaryCacheFactory
-{
- /**
- * Creates an auxiliary using the supplied attributes. Adds it to the composite cache manager.
- *
- * @param attr
- * @param cacheMgr This allows auxiliaries to reference the manager without assuming that it is
- * a singleton. This will allow JCS to be a non-singleton. Also, it makes it easier to
- * test.
- * @param cacheEventLogger
- * @param elementSerializer
- * @return AuxiliaryCache
- * @throws Exception if cache instance could not be created
- */
- <K, V> AuxiliaryCache<K, V> createCache(
- AuxiliaryCacheAttributes attr, ICompositeCacheManager cacheMgr,
- ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
- throws Exception;
-
- /**
- * Initialize this factory
- */
- void initialize();
-
- /**
- * Dispose of this factory, clean up shared resources
- */
- void dispose();
-
- /**
- * Sets the name attribute of the AuxiliaryCacheFactory object
- *
- * @param s The new name value
- */
- void setName( String s );
-
- /**
- * Gets the name attribute of the AuxiliaryCacheFactory object
- *
- * @return The name value
- */
- String getName();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCache.java
deleted file mode 100644
index e82712f..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCache.java
+++ /dev/null
@@ -1,840 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheEventLogging;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes;
-import org.apache.commons.jcs.engine.CacheEventQueueFactory;
-import org.apache.commons.jcs.engine.CacheInfo;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.behavior.ICache;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheEventQueue;
-import org.apache.commons.jcs.engine.behavior.ICacheListener;
-import org.apache.commons.jcs.engine.stats.StatElement;
-import org.apache.commons.jcs.engine.stats.Stats;
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.struct.LRUMap;
-
-/**
- * Abstract class providing a base implementation of a disk cache, which can be easily extended to
- * implement a disk cache for a specific persistence mechanism.
- *
- * When implementing the abstract methods note that while this base class handles most things, it
- * does not acquire or release any locks. Implementations should do so as necessary. This is mainly
- * done to minimize the time spent in critical sections.
- *
- * Error handling in this class needs to be addressed. Currently if an exception is thrown by the
- * persistence mechanism, this class destroys the event queue. Should it also destroy purgatory?
- * Should it dispose itself?
- */
-public abstract class AbstractDiskCache<K, V>
- extends AbstractAuxiliaryCacheEventLogging<K, V>
-{
- /** The logger */
- private static final Log log = LogManager.getLog( AbstractDiskCache.class );
-
- /** Generic disk cache attributes */
- private IDiskCacheAttributes diskCacheAttributes = null;
-
- /**
- * Map where elements are stored between being added to this cache and actually spooled to disk.
- * This allows puts to the disk cache to return quickly, and the more expensive operation of
- * serializing the elements to persistent storage queued for later.
- *
- * If the elements are pulled into the memory cache while the are still in purgatory, writing to
- * disk can be canceled.
- */
- private Map<K, PurgatoryElement<K, V>> purgatory;
-
- /**
- * The CacheEventQueue where changes will be queued for asynchronous updating of the persistent
- * storage.
- */
- private ICacheEventQueue<K, V> cacheEventQueue;
-
- /**
- * Indicates whether the cache is 'alive': initialized, but not yet disposed. Child classes must
- * set this to true.
- */
- private boolean alive = false;
-
- /** Every cache will have a name, subclasses must set this when they are initialized. */
- private String cacheName;
-
- /** DEBUG: Keeps a count of the number of purgatory hits for debug messages */
- private int purgHits = 0;
-
- /**
- * We lock here, so that we cannot get an update after a remove all. an individual removal locks
- * the item.
- */
- private final ReentrantReadWriteLock removeAllLock = new ReentrantReadWriteLock();
-
- // ----------------------------------------------------------- constructors
-
- /**
- * Construct the abstract disk cache, create event queues and purgatory. Child classes should
- * set the alive flag to true after they are initialized.
- *
- * @param attr
- */
- protected AbstractDiskCache( IDiskCacheAttributes attr )
- {
- this.diskCacheAttributes = attr;
- this.cacheName = attr.getCacheName();
-
- // create queue
- CacheEventQueueFactory<K, V> fact = new CacheEventQueueFactory<>();
- this.cacheEventQueue = fact.createCacheEventQueue( new MyCacheListener(), CacheInfo.listenerId, cacheName,
- diskCacheAttributes.getEventQueuePoolName(),
- diskCacheAttributes.getEventQueueType() );
-
- // create purgatory
- initPurgatory();
- }
-
- /**
- * @return true if the cache is alive
- */
- public boolean isAlive()
- {
- return alive;
- }
-
- /**
- * @param alive set the alive status
- */
- public void setAlive(boolean alive)
- {
- this.alive = alive;
- }
-
- /**
- * Purgatory size of -1 means to use a HashMap with no size limit. Anything greater will use an
- * LRU map of some sort.
- *
- * TODO Currently setting this to 0 will cause nothing to be put to disk, since it will assume
- * that if an item is not in purgatory, then it must have been plucked. We should make 0
- * work, a way to not use purgatory.
- */
- private void initPurgatory()
- {
- // we need this so we can stop the updates from happening after a
- // removeall
- removeAllLock.writeLock().lock();
-
- try
- {
- synchronized (this)
- {
- if ( diskCacheAttributes.getMaxPurgatorySize() >= 0 )
- {
- purgatory = new LRUMap<>( diskCacheAttributes.getMaxPurgatorySize() );
- }
- else
- {
- purgatory = new HashMap<>();
- }
- }
- }
- finally
- {
- removeAllLock.writeLock().unlock();
- }
- }
-
- // ------------------------------------------------------- interface ICache
-
- /**
- * Adds the provided element to the cache. Element will be added to purgatory, and then queued
- * for later writing to the serialized storage mechanism.
- *
- * An update results in a put event being created. The put event will call the handlePut method
- * defined here. The handlePut method calls the implemented doPut on the child.
- *
- * @param cacheElement
- * @throws IOException
- * @see org.apache.commons.jcs.engine.behavior.ICache#update
- */
- @Override
- public final void update( ICacheElement<K, V> cacheElement )
- throws IOException
- {
- log.debug( "Putting element in purgatory, cacheName: {0}, key: {1}",
- () -> cacheName, () -> cacheElement.getKey() );
-
- try
- {
- // Wrap the CacheElement in a PurgatoryElement
- PurgatoryElement<K, V> pe = new PurgatoryElement<>( cacheElement );
-
- // Indicates the the element is eligible to be spooled to disk,
- // this will remain true unless the item is pulled back into
- // memory.
- pe.setSpoolable( true );
-
- // Add the element to purgatory
- synchronized ( purgatory )
- {
- purgatory.put( pe.getKey(), pe );
- }
-
- // Queue element for serialization
- cacheEventQueue.addPutEvent( pe );
- }
- catch ( IOException ex )
- {
- log.error( "Problem adding put event to queue.", ex );
-
- cacheEventQueue.destroy();
- }
- }
-
- /**
- * Check to see if the item is in purgatory. If so, return it. If not, check to see if we have
- * it on disk.
- *
- * @param key
- * @return ICacheElement<K, V> or null
- * @see AuxiliaryCache#get
- */
- @Override
- public final ICacheElement<K, V> get( K key )
- {
- // If not alive, always return null.
-
- if ( !alive )
- {
- log.debug( "get was called, but the disk cache is not alive." );
- return null;
- }
-
- PurgatoryElement<K, V> pe = null;
- synchronized ( purgatory )
- {
- pe = purgatory.get( key );
- }
-
- // If the element was found in purgatory
- if ( pe != null )
- {
- purgHits++;
-
- if ( purgHits % 100 == 0 )
- {
- log.debug( "Purgatory hits = {0}", purgHits );
- }
-
- // Since the element will go back to the memory cache, we could set
- // spoolable to false, which will prevent the queue listener from
- // serializing the element. This would not match the disk cache
- // behavior and the behavior of other auxiliaries. Gets never remove
- // items from auxiliaries.
- // Beyond consistency, the items should stay in purgatory and get
- // spooled since the mem cache may be set to 0. If an item is
- // active, it will keep getting put into purgatory and removed. The
- // CompositeCache now does not put an item to memory from disk if
- // the size is 0.
- // Do not set spoolable to false. Just let it go to disk. This
- // will allow the memory size = 0 setting to work well.
-
- log.debug( "Found element in purgatory, cacheName: {0}, key: {1}",
- cacheName, key );
-
- return pe.getCacheElement();
- }
-
- // If we reach this point, element was not found in purgatory, so get
- // it from the cache.
- try
- {
- return doGet( key );
- }
- catch ( Exception e )
- {
- log.error( e );
-
- cacheEventQueue.destroy();
- }
-
- return null;
- }
-
- /**
- * Gets items from the cache matching the given pattern. Items from memory will replace those
- * from remote sources.
- *
- * This only works with string keys. It's too expensive to do a toString on every key.
- *
- * Auxiliaries will do their best to handle simple expressions. For instance, the JDBC disk
- * cache will convert * to % and . to _
- *
- * @param pattern
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data matching the pattern.
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching( String pattern )
- throws IOException
- {
- // Get the keys from purgatory
- Set<K> keyArray = null;
-
- // this avoids locking purgatory, but it uses more memory
- synchronized ( purgatory )
- {
- keyArray = new HashSet<>(purgatory.keySet());
- }
-
- Set<K> matchingKeys = getKeyMatcher().getMatchingKeysFromArray( pattern, keyArray );
-
- // call getMultiple with the set
- Map<K, ICacheElement<K, V>> result = processGetMultiple( matchingKeys );
-
- // Get the keys from disk
- Map<K, ICacheElement<K, V>> diskMatches = doGetMatching( pattern );
-
- result.putAll( diskMatches );
-
- return result;
- }
-
- /**
- * The keys in the cache.
- *
- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet()
- */
- @Override
- public abstract Set<K> getKeySet() throws IOException;
-
- /**
- * Removes are not queued. A call to remove is immediate.
- *
- * @param key
- * @return whether the item was present to be removed.
- * @throws IOException
- * @see org.apache.commons.jcs.engine.behavior.ICache#remove
- */
- @Override
- public final boolean remove( K key )
- throws IOException
- {
- PurgatoryElement<K, V> pe = null;
-
- synchronized ( purgatory )
- {
- // I'm getting the object, so I can lock on the element
- // Remove element from purgatory if it is there
- pe = purgatory.get( key );
- }
-
- if ( pe != null )
- {
- synchronized ( pe.getCacheElement() )
- {
- synchronized ( purgatory )
- {
- purgatory.remove( key );
- }
-
- // no way to remove from queue, just make sure it doesn't get on
- // disk and then removed right afterwards
- pe.setSpoolable( false );
-
- // Remove from persistent store immediately
- doRemove( key );
- }
- }
- else
- {
- // Remove from persistent store immediately
- doRemove( key );
- }
-
- return false;
- }
-
- /**
- * @throws IOException
- * @see org.apache.commons.jcs.engine.behavior.ICache#removeAll
- */
- @Override
- public final void removeAll()
- throws IOException
- {
- if ( this.diskCacheAttributes.isAllowRemoveAll() )
- {
- // Replace purgatory with a new empty hashtable
- initPurgatory();
-
- // Remove all from persistent store immediately
- doRemoveAll();
- }
- else
- {
- log.info( "RemoveAll was requested but the request was not "
- + "fulfilled: allowRemoveAll is set to false." );
- }
- }
-
- /**
- * Adds a dispose request to the disk cache.
- *
- * Disposal proceeds in several steps.
- * <ol>
- * <li>Prior to this call the Composite cache dumped the memory into the disk cache. If it is
- * large then we need to wait for the event queue to finish.</li>
- * <li>Wait until the event queue is empty of until the configured ShutdownSpoolTimeLimit is
- * reached.</li>
- * <li>Call doDispose on the concrete impl.</li>
- * </ol>
- * @throws IOException
- */
- @Override
- public final void dispose()
- throws IOException
- {
- Thread t = new Thread(() ->
- {
- boolean keepGoing = true;
- // long total = 0;
- long interval = 100;
- while ( keepGoing )
- {
- keepGoing = !cacheEventQueue.isEmpty();
- try
- {
- Thread.sleep( interval );
- // total += interval;
- // log.info( "total = " + total );
- }
- catch ( InterruptedException e )
- {
- break;
- }
- }
- log.info( "No longer waiting for event queue to finish: {0}",
- () -> cacheEventQueue.getStatistics() );
- });
- t.start();
- // wait up to 60 seconds for dispose and then quit if not done.
- try
- {
- t.join( this.diskCacheAttributes.getShutdownSpoolTimeLimit() * 1000L );
- }
- catch ( InterruptedException ex )
- {
- log.error( "The Shutdown Spool Process was interrupted.", ex );
- }
-
- log.info( "In dispose, destroying event queue." );
- // This stops the processor thread.
- cacheEventQueue.destroy();
-
- // Invoke any implementation specific disposal code
- // need to handle the disposal first.
- doDispose();
-
- alive = false;
- }
-
- /**
- * @return the region name.
- * @see ICache#getCacheName
- */
- @Override
- public String getCacheName()
- {
- return cacheName;
- }
-
- /**
- * Gets basic stats for the abstract disk cache.
- *
- * @return String
- */
- @Override
- public String getStats()
- {
- return getStatistics().toString();
- }
-
- /**
- * Returns semi-structured data.
- *
- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getStatistics()
- */
- @Override
- public IStats getStatistics()
- {
- IStats stats = new Stats();
- stats.setTypeName( "Abstract Disk Cache" );
-
- ArrayList<IStatElement<?>> elems = new ArrayList<>();
-
- elems.add(new StatElement<>( "Purgatory Hits", Integer.valueOf(purgHits) ) );
- elems.add(new StatElement<>( "Purgatory Size", Integer.valueOf(purgatory.size()) ) );
-
- // get the stats from the event queue too
- IStats eqStats = this.cacheEventQueue.getStatistics();
- elems.addAll(eqStats.getStatElements());
-
- stats.setStatElements( elems );
-
- return stats;
- }
-
- /**
- * @return the status -- alive or disposed from CacheConstants
- * @see ICache#getStatus
- */
- @Override
- public CacheStatus getStatus()
- {
- return ( alive ? CacheStatus.ALIVE : CacheStatus.DISPOSED );
- }
-
- /**
- * Size cannot be determined without knowledge of the cache implementation, so subclasses will
- * need to implement this method.
- *
- * @return the number of items.
- * @see ICache#getSize
- */
- @Override
- public abstract int getSize();
-
- /**
- * @see org.apache.commons.jcs.engine.behavior.ICacheType#getCacheType
- * @return Always returns DISK_CACHE since subclasses should all be of that type.
- */
- @Override
- public CacheType getCacheType()
- {
- return CacheType.DISK_CACHE;
- }
-
- /**
- * Cache that implements the CacheListener interface, and calls appropriate methods in its
- * parent class.
- */
- protected class MyCacheListener
- implements ICacheListener<K, V>
- {
- /** Id of the listener */
- private long listenerId = 0;
-
- /**
- * @return cacheElement.getElementAttributes();
- * @throws IOException
- * @see ICacheListener#getListenerId
- */
- @Override
- public long getListenerId()
- throws IOException
- {
- return this.listenerId;
- }
-
- /**
- * @param id
- * @throws IOException
- * @see ICacheListener#setListenerId
- */
- @Override
- public void setListenerId( long id )
- throws IOException
- {
- this.listenerId = id;
- }
-
- /**
- * @param element
- * @throws IOException
- * @see ICacheListener#handlePut NOTE: This checks if the element is a puratory element and
- * behaves differently depending. However since we have control over how elements are
- * added to the cache event queue, that may not be needed ( they are always
- * PurgatoryElements ).
- */
- @Override
- public void handlePut( ICacheElement<K, V> element )
- throws IOException
- {
- if ( alive )
- {
- // If the element is a PurgatoryElement<K, V> we must check to see
- // if it is still spoolable, and remove it from purgatory.
- if ( element instanceof PurgatoryElement )
- {
- PurgatoryElement<K, V> pe = (PurgatoryElement<K, V>) element;
-
- synchronized ( pe.getCacheElement() )
- {
- // TODO consider a timeout.
- // we need this so that we can have multiple update
- // threads and still have removeAll requests come in that
- // always win
- removeAllLock.readLock().lock();
-
- try
- {
- // TODO consider changing purgatory sync
- // String keyAsString = element.getKey().toString();
- synchronized ( purgatory )
- {
- // If the element has already been removed from
- // purgatory do nothing
- if ( !purgatory.containsKey( pe.getKey() ) )
- {
- return;
- }
-
- element = pe.getCacheElement();
- }
-
- // I took this out of the purgatory sync block.
- // If the element is still eligible, spool it.
- if ( pe.isSpoolable() )
- {
- doUpdate( element );
- }
- }
- finally
- {
- removeAllLock.readLock().unlock();
- }
-
- synchronized ( purgatory )
- {
- // After the update has completed, it is safe to
- // remove the element from purgatory.
- purgatory.remove( element.getKey() );
- }
- }
- }
- else
- {
- // call the child's implementation
- doUpdate( element );
- }
- }
- else
- {
- /*
- * The cache is not alive, hence the element should be removed from purgatory. All
- * elements should be removed eventually. Perhaps, the alive check should have been
- * done before it went in the queue. This block handles the case where the disk
- * cache fails during normal operations.
- */
- synchronized ( purgatory )
- {
- purgatory.remove( element.getKey() );
- }
- }
- }
-
- /**
- * @param cacheName
- * @param key
- * @throws IOException
- * @see ICacheListener#handleRemove
- */
- @Override
- public void handleRemove( String cacheName, K key )
- throws IOException
- {
- if ( alive )
- {
- if ( doRemove( key ) )
- {
- log.debug( "Element removed, key: " + key );
- }
- }
- }
-
- /**
- * @param cacheName
- * @throws IOException
- * @see ICacheListener#handleRemoveAll
- */
- @Override
- public void handleRemoveAll( String cacheName )
- throws IOException
- {
- if ( alive )
- {
- doRemoveAll();
- }
- }
-
- /**
- * @param cacheName
- * @throws IOException
- * @see ICacheListener#handleDispose
- */
- @Override
- public void handleDispose( String cacheName )
- throws IOException
- {
- if ( alive )
- {
- doDispose();
- }
- }
- }
-
- /**
- * Before the event logging layer, the subclasses implemented the do* methods. Now the do*
- * methods call the *WithEventLogging method on the super. The *WithEventLogging methods call
- * the abstract process* methods. The children implement the process methods.
- *
- * ex. doGet calls getWithEventLogging, which calls processGet
- */
-
- /**
- * Get a value from the persistent store.
- *
- * Before the event logging layer, the subclasses implemented the do* methods. Now the do*
- * methods call the *EventLogging method on the super. The *WithEventLogging methods call the
- * abstract process* methods. The children implement the process methods.
- *
- * @param key Key to locate value for.
- * @return An object matching key, or null.
- * @throws IOException
- */
- protected final ICacheElement<K, V> doGet( K key )
- throws IOException
- {
- return super.getWithEventLogging( key );
- }
-
- /**
- * Get a value from the persistent store.
- *
- * Before the event logging layer, the subclasses implemented the do* methods. Now the do*
- * methods call the *EventLogging method on the super. The *WithEventLogging methods call the
- * abstract process* methods. The children implement the process methods.
- *
- * @param pattern Used to match keys.
- * @return A map of matches..
- * @throws IOException
- */
- protected final Map<K, ICacheElement<K, V>> doGetMatching( String pattern )
- throws IOException
- {
- return super.getMatchingWithEventLogging( pattern );
- }
-
- /**
- * Add a cache element to the persistent store.
- *
- * Before the event logging layer, the subclasses implemented the do* methods. Now the do*
- * methods call the *EventLogging method on the super. The *WithEventLogging methods call the
- * abstract process* methods. The children implement the process methods.
- *
- * @param cacheElement
- * @throws IOException
- */
- protected final void doUpdate( ICacheElement<K, V> cacheElement )
- throws IOException
- {
- super.updateWithEventLogging( cacheElement );
- }
-
- /**
- * Remove an object from the persistent store if found.
- *
- * Before the event logging layer, the subclasses implemented the do* methods. Now the do*
- * methods call the *EventLogging method on the super. The *WithEventLogging methods call the
- * abstract process* methods. The children implement the process methods.
- *
- * @param key Key of object to remove.
- * @return whether or no the item was present when removed
- * @throws IOException
- */
- protected final boolean doRemove( K key )
- throws IOException
- {
- return super.removeWithEventLogging( key );
- }
-
- /**
- * Remove all objects from the persistent store.
- *
- * Before the event logging layer, the subclasses implemented the do* methods. Now the do*
- * methods call the *EventLogging method on the super. The *WithEventLogging methods call the
- * abstract process* methods. The children implement the process methods.
- *
- * @throws IOException
- */
- protected final void doRemoveAll()
- throws IOException
- {
- super.removeAllWithEventLogging();
- }
-
- /**
- * Dispose of the persistent store. Note that disposal of purgatory and setting alive to false
- * does NOT need to be done by this method.
- *
- * Before the event logging layer, the subclasses implemented the do* methods. Now the do*
- * methods call the *EventLogging method on the super. The *WithEventLogging methods call the
- * abstract process* methods. The children implement the process methods.
- *
- * @throws IOException
- */
- protected final void doDispose()
- throws IOException
- {
- super.disposeWithEventLogging();
- }
-
- /**
- * Gets the extra info for the event log.
- *
- * @return disk location
- */
- @Override
- public String getEventLoggingExtraInfo()
- {
- return getDiskLocation();
- }
-
- /**
- * This is used by the event logging.
- *
- * @return the location of the disk, either path or ip.
- */
- protected abstract String getDiskLocation();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCacheAttributes.java
deleted file mode 100644
index da5213b..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCacheAttributes.java
+++ /dev/null
@@ -1,221 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk;
-
-/*
- * 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.
- */
-
-import java.io.File;
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This has common attributes that any conceivable disk cache would need.
- */
-public abstract class AbstractDiskCacheAttributes extends AbstractAuxiliaryCacheAttributes implements IDiskCacheAttributes
-{
- /** Don't change. */
- private static final long serialVersionUID = 8306631920391711229L;
-
- /** The logger */
- private static final Log log = LogManager.getLog(AbstractDiskCacheAttributes.class);
-
- /** path to disk */
- private File diskPath;
-
- /** if this is false, we will not execute remove all */
- private boolean allowRemoveAll = true;
-
- /** default to 5000 */
- private int maxPurgatorySize = MAX_PURGATORY_SIZE_DEFAULT;
-
- /** Default amount of time to allow for key persistence on shutdown */
- private static final int DEFAULT_shutdownSpoolTimeLimit = 60;
-
- /**
- * This default determines how long the shutdown will wait for the key spool and data defrag to
- * finish.
- */
- private int shutdownSpoolTimeLimit = DEFAULT_shutdownSpoolTimeLimit;
-
- /** Type of disk limit: SIZE or COUNT */
- private DiskLimitType diskLimitType = DiskLimitType.COUNT;
-
- /**
- * Sets the diskPath attribute of the DiskCacheAttributes object
- * <p>
- *
- * @param path
- * The new diskPath value
- */
- @Override
- public void setDiskPath(String path)
- {
- setDiskPath(new File(path));
- }
-
- /**
- * Sets the diskPath attribute of the DiskCacheAttributes object
- * <p>
- *
- * @param diskPath
- * The new diskPath value
- */
- public void setDiskPath(File diskPath)
- {
- this.diskPath = diskPath;
- boolean result = this.diskPath.isDirectory();
-
- if (!result)
- {
- result = this.diskPath.mkdirs();
- }
- if (!result)
- {
- log.error("Failed to create directory {0}", diskPath);
- }
- }
-
- /**
- * Gets the diskPath attribute of the attributes object
- * <p>
- *
- * @return The diskPath value
- */
- @Override
- public File getDiskPath()
- {
- return this.diskPath;
- }
-
- /**
- * Gets the maxKeySize attribute of the DiskCacheAttributes object
- * <p>
- *
- * @return The maxPurgatorySize value
- */
- @Override
- public int getMaxPurgatorySize()
- {
- return maxPurgatorySize;
- }
-
- /**
- * Sets the maxPurgatorySize attribute of the DiskCacheAttributes object
- * <p>
- *
- * @param maxPurgatorySize
- * The new maxPurgatorySize value
- */
- @Override
- public void setMaxPurgatorySize(int maxPurgatorySize)
- {
- this.maxPurgatorySize = maxPurgatorySize;
- }
-
- /**
- * Get the amount of time in seconds we will wait for elements to move to disk during shutdown
- * for a particular region.
- * <p>
- *
- * @return the time in seconds.
- */
- @Override
- public int getShutdownSpoolTimeLimit()
- {
- return this.shutdownSpoolTimeLimit;
- }
-
- /**
- * Sets the amount of time in seconds we will wait for elements to move to disk during shutdown
- * for a particular region.
- * <p>
- * This is how long we give the event queue to empty.
- * <p>
- * The default is 60 seconds.
- * <p>
- *
- * @param shutdownSpoolTimeLimit
- * the time in seconds
- */
- @Override
- public void setShutdownSpoolTimeLimit(int shutdownSpoolTimeLimit)
- {
- this.shutdownSpoolTimeLimit = shutdownSpoolTimeLimit;
- }
-
- /**
- * @param allowRemoveAll
- * The allowRemoveAll to set.
- */
- @Override
- public void setAllowRemoveAll(boolean allowRemoveAll)
- {
- this.allowRemoveAll = allowRemoveAll;
- }
-
- /**
- * @return Returns the allowRemoveAll.
- */
- @Override
- public boolean isAllowRemoveAll()
- {
- return allowRemoveAll;
- }
-
- /**
- * Includes the common attributes for a debug message.
- * <p>
- *
- * @return String
- */
- @Override
- public String toString()
- {
- StringBuilder str = new StringBuilder();
- str.append("AbstractDiskCacheAttributes ");
- str.append("\n diskPath = " + getDiskPath());
- str.append("\n maxPurgatorySize = " + getMaxPurgatorySize());
- str.append("\n allowRemoveAll = " + isAllowRemoveAll());
- str.append("\n ShutdownSpoolTimeLimit = " + getShutdownSpoolTimeLimit());
- return str.toString();
- }
-
- @Override
- public void setDiskLimitType(DiskLimitType diskLimitType)
- {
- this.diskLimitType = diskLimitType;
- }
-
- @Override
- public void setDiskLimitTypeName(String diskLimitTypeName)
- {
- if (diskLimitTypeName != null)
- {
- diskLimitType = DiskLimitType.valueOf(diskLimitTypeName.trim());
- }
- }
-
- @Override
- public DiskLimitType getDiskLimitType()
- {
- return diskLimitType;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/PurgatoryElement.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/PurgatoryElement.java
deleted file mode 100644
index db257bd..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/PurgatoryElement.java
+++ /dev/null
@@ -1,156 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-
-/**
- * Implementation of cache elements in purgatory.
- *
- * Elements are stored in purgatory when they are spooled to the auxiliary cache, but have not yet
- * been written to disk.
- */
-public class PurgatoryElement<K, V>
- extends CacheElement<K, V>
-{
- /** Don't change */
- private static final long serialVersionUID = -8152034342684135628L;
-
- /** Is the element ready to be spooled? */
- private boolean spoolable = false;
-
- /** Wrapped cache Element */
- private ICacheElement<K, V> cacheElement;
-
- /**
- * Constructor for the PurgatoryElement<K, V> object
- *
- * @param cacheElement CacheElement
- */
- public PurgatoryElement( ICacheElement<K, V> cacheElement )
- {
- super(cacheElement.getCacheName(),
- cacheElement.getKey(), cacheElement.getVal(),
- cacheElement.getElementAttributes());
- this.cacheElement = cacheElement;
- }
-
- /**
- * Gets the spoolable property.
- *
- * @return The spoolable value
- */
- public boolean isSpoolable()
- {
- return spoolable;
- }
-
- /**
- * Sets the spoolable property.
- *
- * @param spoolable The new spoolable value
- */
- public void setSpoolable( boolean spoolable )
- {
- this.spoolable = spoolable;
- }
-
- /**
- * Get the wrapped cache element.
- *
- * @return ICacheElement
- */
- public ICacheElement<K, V> getCacheElement()
- {
- return cacheElement;
- }
-
- // ------------------------------------------------ interface ICacheElement
-
- /**
- * @return cacheElement.getCacheName();
- * @see ICacheElement#getCacheName
- */
- @Override
- public String getCacheName()
- {
- return cacheElement.getCacheName();
- }
-
- /**
- * @return cacheElement.getKey();
- * @see ICacheElement#getKey
- */
- @Override
- public K getKey()
- {
- return cacheElement.getKey();
- }
-
- /**
- * @return cacheElement.getVal();
- * @see ICacheElement#getVal
- */
- @Override
- public V getVal()
- {
- return cacheElement.getVal();
- }
-
- /**
- * @return cacheElement.getElementAttributes();
- * @see ICacheElement#getElementAttributes
- */
- @Override
- public IElementAttributes getElementAttributes()
- {
- return cacheElement.getElementAttributes();
- }
-
- /**
- * @param attr
- * @see ICacheElement#setElementAttributes
- */
- @Override
- public void setElementAttributes( IElementAttributes attr )
- {
- cacheElement.setElementAttributes( attr );
- }
-
- /**
- * @return debug string
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "[PurgatoryElement: " );
- buf.append( " isSpoolable = " + isSpoolable() );
- buf.append( " CacheElement = " + getCacheElement() );
- buf.append( " CacheName = " + getCacheName() );
- buf.append( " Key = " + getKey() );
- buf.append( " Value = " + getVal() );
- buf.append( " ElementAttributes = " + getElementAttributes() );
- buf.append( "]" );
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/behavior/IDiskCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/behavior/IDiskCacheAttributes.java
deleted file mode 100644
index f7d32fd..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/behavior/IDiskCacheAttributes.java
+++ /dev/null
@@ -1,131 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.behavior;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-
-import java.io.File;
-
-/**
- * Common disk cache attributes.
- */
-public interface IDiskCacheAttributes
- extends AuxiliaryCacheAttributes
-{
- enum DiskLimitType {
- /** limit elements by count (default) */
- COUNT,
- /** limit elements by their size */
- SIZE
- }
- /**
- * This is the default purgatory size limit. Purgatory is the area where
- * items to be spooled are temporarily stored. It basically provides access
- * to items on the to-be-spooled queue.
- */
- int MAX_PURGATORY_SIZE_DEFAULT = 5000;
-
- /**
- * Sets the diskPath attribute of the IJISPCacheAttributes object
- * <p>
- * @param path
- * The new diskPath value
- */
- void setDiskPath( String path );
-
- /**
- * Gets the diskPath attribute of the attributes object
- * <p>
- * @return The diskPath value
- */
- File getDiskPath();
-
- /**
- * Gets the maxKeySize attribute of the DiskCacheAttributes object
- * <p>
- * @return The maxPurgatorySize value
- */
- int getMaxPurgatorySize();
-
- /**
- * Sets the maxPurgatorySize attribute of the DiskCacheAttributes object
- * <p>
- * @param maxPurgatorySize
- * The new maxPurgatorySize value
- */
- void setMaxPurgatorySize( int maxPurgatorySize );
-
- /**
- * Get the amount of time in seconds we will wait for elements to move to
- * disk during shutdown for a particular region.
- * <p>
- * @return the time in seconds.
- */
- int getShutdownSpoolTimeLimit();
-
- /**
- * Sets the amount of time in seconds we will wait for elements to move to
- * disk during shutdown for a particular region.
- * <p>
- * This is how long we give the event queue to empty.
- * <p>
- * The default is 60 seconds.
- * <p>
- * @param shutdownSpoolTimeLimit
- * the time in seconds
- */
- void setShutdownSpoolTimeLimit( int shutdownSpoolTimeLimit );
-
- /**
- * If this is true then remove all is not prohibited.
- * <p>
- * @return boolean
- */
- boolean isAllowRemoveAll();
-
- /**
- * If this is false, then remove all requests will not be honored.
- * <p>
- * This provides a safety mechanism for the persistent store.
- * <p>
- * @param allowRemoveAll
- */
- void setAllowRemoveAll( boolean allowRemoveAll );
-
- /**
- * set the type of the limit of the cache size
- * @param diskLimitType COUNT - limit by count of the elements, SIZE, limit by sum of element's size
- */
- void setDiskLimitType(DiskLimitType diskLimitType);
-
- /**
- * Translates and stores String values of DiskLimitType
- *
- * Allowed values: "COUNT" and "SIZE"
- * @param diskLimitTypeName
- */
- void setDiskLimitTypeName(String diskLimitTypeName);
-
- /**
- *
- * @return active DiskLimitType
- */
- DiskLimitType getDiskLimitType();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDisk.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDisk.java
deleted file mode 100644
index e246770..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDisk.java
+++ /dev/null
@@ -1,517 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.block;
-
-/*
- * 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.
- */
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.nio.file.StandardOpenOption;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.serialization.StandardSerializer;
-
-/**
- * This class manages reading an writing data to disk. When asked to write a value, it returns a
- * block array. It can read an object from the block numbers in a byte array.
- * <p>
- * @author Aaron Smuts
- */
-public class BlockDisk implements AutoCloseable
-{
- /** The logger */
- private static final Log log = LogManager.getLog(BlockDisk.class);
-
- /** The size of the header that indicates the amount of data stored in an occupied block. */
- public static final byte HEADER_SIZE_BYTES = 4;
- // N.B. 4 bytes is the size used for ByteBuffer.putInt(int value) and ByteBuffer.getInt()
-
- /** defaults to 4kb */
- private static final int DEFAULT_BLOCK_SIZE_BYTES = 4 * 1024;
-
- /** Size of the blocks */
- private final int blockSizeBytes;
-
- /**
- * the total number of blocks that have been used. If there are no free, we will use this to
- * calculate the position of the next block.
- */
- private final AtomicInteger numberOfBlocks = new AtomicInteger(0);
-
- /** Empty blocks that can be reused. */
- private final ConcurrentLinkedQueue<Integer> emptyBlocks = new ConcurrentLinkedQueue<>();
-
- /** The serializer. */
- private final IElementSerializer elementSerializer;
-
- /** Location of the spot on disk */
- private final String filepath;
-
- /** File channel for multiple concurrent reads and writes */
- private final FileChannel fc;
-
- /** How many bytes have we put to disk */
- private final AtomicLong putBytes = new AtomicLong(0);
-
- /** How many items have we put to disk */
- private final AtomicLong putCount = new AtomicLong(0);
-
- /**
- * Constructor for the Disk object
- * <p>
- * @param file
- * @param elementSerializer
- * @throws IOException
- */
- public BlockDisk(File file, IElementSerializer elementSerializer)
- throws IOException
- {
- this(file, DEFAULT_BLOCK_SIZE_BYTES, elementSerializer);
- }
-
- /**
- * Creates the file and set the block size in bytes.
- * <p>
- * @param file
- * @param blockSizeBytes
- * @throws IOException
- */
- public BlockDisk(File file, int blockSizeBytes)
- throws IOException
- {
- this(file, blockSizeBytes, new StandardSerializer());
- }
-
- /**
- * Creates the file and set the block size in bytes.
- * <p>
- * @param file
- * @param blockSizeBytes
- * @param elementSerializer
- * @throws IOException
- */
- public BlockDisk(File file, int blockSizeBytes, IElementSerializer elementSerializer)
- throws IOException
- {
- this.filepath = file.getAbsolutePath();
- this.fc = FileChannel.open(file.toPath(),
- StandardOpenOption.CREATE,
- StandardOpenOption.READ,
- StandardOpenOption.WRITE);
- this.numberOfBlocks.set((int) Math.ceil(1f * this.fc.size() / blockSizeBytes));
-
- log.info("Constructing BlockDisk, blockSizeBytes [{0}]", blockSizeBytes);
-
- this.blockSizeBytes = blockSizeBytes;
- this.elementSerializer = elementSerializer;
- }
-
- /**
- * Allocate a given number of blocks from the available set
- *
- * @param numBlocksNeeded
- * @return an array of allocated blocks
- */
- private int[] allocateBlocks(int numBlocksNeeded)
- {
- assert numBlocksNeeded >= 1;
-
- int[] blocks = new int[numBlocksNeeded];
- // get them from the empty list or take the next one
- for (int i = 0; i < numBlocksNeeded; i++)
- {
- Integer emptyBlock = emptyBlocks.poll();
- if (emptyBlock == null)
- {
- emptyBlock = Integer.valueOf(numberOfBlocks.getAndIncrement());
- }
- blocks[i] = emptyBlock.intValue();
- }
-
- return blocks;
- }
-
- /**
- * This writes an object to disk and returns the blocks it was stored in.
- * <p>
- * The program flow is as follows:
- * <ol>
- * <li>Serialize the object.</li>
- * <li>Determine the number of blocks needed.</li>
- * <li>Look for free blocks in the emptyBlock list.</li>
- * <li>If there were not enough in the empty list. Take the nextBlock and increment it.</li>
- * <li>If the data will not fit in one block, create sub arrays.</li>
- * <li>Write the subarrays to disk.</li>
- * <li>If the process fails we should decrement the block count if we took from it.</li>
- * </ol>
- * @param object
- * @return the blocks we used.
- * @throws IOException
- */
- protected <T> int[] write(T object)
- throws IOException
- {
- // serialize the object
- byte[] data = elementSerializer.serialize(object);
-
- log.debug("write, total pre-chunking data.length = {0}", data.length);
-
- this.putBytes.addAndGet(data.length);
- this.putCount.incrementAndGet();
-
- // figure out how many blocks we need.
- int numBlocksNeeded = calculateTheNumberOfBlocksNeeded(data);
-
- log.debug("numBlocksNeeded = {0}", numBlocksNeeded);
-
- // allocate blocks
- int[] blocks = allocateBlocks(numBlocksNeeded);
-
- int offset = 0;
- final int maxChunkSize = blockSizeBytes - HEADER_SIZE_BYTES;
- ByteBuffer headerBuffer = ByteBuffer.allocate(HEADER_SIZE_BYTES);
- ByteBuffer dataBuffer = ByteBuffer.wrap(data);
-
- for (int i = 0; i < numBlocksNeeded; i++)
- {
- headerBuffer.clear();
- int length = Math.min(maxChunkSize, data.length - offset);
- headerBuffer.putInt(length);
- headerBuffer.flip();
-
- dataBuffer.position(offset).limit(offset + length);
- ByteBuffer slice = dataBuffer.slice();
-
- long position = calculateByteOffsetForBlockAsLong(blocks[i]);
- // write the header
- int written = fc.write(headerBuffer, position);
- assert written == HEADER_SIZE_BYTES;
-
- //write the data
- written = fc.write(slice, position + HEADER_SIZE_BYTES);
- assert written == length;
-
- offset += length;
- }
-
- //fc.force(false);
-
- return blocks;
- }
-
- /**
- * Return the amount to put in each block. Fill them all the way, minus the header.
- * <p>
- * @param complete
- * @param numBlocksNeeded
- * @return byte[][]
- */
- protected byte[][] getBlockChunks(byte[] complete, int numBlocksNeeded)
- {
- byte[][] chunks = new byte[numBlocksNeeded][];
-
- if (numBlocksNeeded == 1)
- {
- chunks[0] = complete;
- }
- else
- {
- int maxChunkSize = this.blockSizeBytes - HEADER_SIZE_BYTES;
- int totalBytes = complete.length;
- int totalUsed = 0;
- for (short i = 0; i < numBlocksNeeded; i++)
- {
- // use the max that can be written to a block or whatever is left in the original
- // array
- int chunkSize = Math.min(maxChunkSize, totalBytes - totalUsed);
- byte[] chunk = new byte[chunkSize];
- // copy from the used position to the chunk size on the complete array to the chunk
- // array.
- System.arraycopy(complete, totalUsed, chunk, 0, chunkSize);
- chunks[i] = chunk;
- totalUsed += chunkSize;
- }
- }
-
- return chunks;
- }
-
- /**
- * Reads an object that is located in the specified blocks.
- * <p>
- * @param blockNumbers
- * @return the object instance
- * @throws IOException
- * @throws ClassNotFoundException
- */
- protected <T> T read(int[] blockNumbers)
- throws IOException, ClassNotFoundException
- {
- final ByteBuffer data;
-
- if (blockNumbers.length == 1)
- {
- data = readBlock(blockNumbers[0]);
- }
- else
- {
- data = ByteBuffer.allocate(blockNumbers.length * getBlockSizeBytes());
- // get all the blocks into data
- for (short i = 0; i < blockNumbers.length; i++)
- {
- ByteBuffer chunk = readBlock(blockNumbers[i]);
- data.put(chunk);
- }
-
- data.flip();
- }
-
- log.debug("read, total post combination data.length = {0}", () -> data.limit());
-
- return elementSerializer.deSerialize(data.array(), null);
- }
-
- /**
- * This reads the occupied data in a block.
- * <p>
- * The first four bytes of the record should tell us how long it is. The data is read into a
- * byte array and then an object is constructed from the byte array.
- * <p>
- * @return byte[]
- * @param block
- * @throws IOException
- */
- private ByteBuffer readBlock(int block)
- throws IOException
- {
- int datalen = 0;
-
- String message = null;
- boolean corrupted = false;
- long fileLength = fc.size();
-
- long position = calculateByteOffsetForBlockAsLong(block);
-// if (position > fileLength)
-// {
-// corrupted = true;
-// message = "Record " + position + " starts past EOF.";
-// }
-// else
- {
- ByteBuffer datalength = ByteBuffer.allocate(HEADER_SIZE_BYTES);
- fc.read(datalength, position);
- datalength.flip();
- datalen = datalength.getInt();
- if (position + datalen > fileLength)
- {
- corrupted = true;
- message = "Record " + position + " exceeds file length.";
- }
- }
-
- if (corrupted)
- {
- log.warn("\n The file is corrupt: \n {0}", message);
- throw new IOException("The File Is Corrupt, need to reset");
- }
-
- ByteBuffer data = ByteBuffer.allocate(datalen);
- fc.read(data, position + HEADER_SIZE_BYTES);
- data.flip();
-
- return data;
- }
-
- /**
- * Add these blocks to the emptyBlock list.
- * <p>
- * @param blocksToFree
- */
- protected void freeBlocks(int[] blocksToFree)
- {
- if (blocksToFree != null)
- {
- for (short i = 0; i < blocksToFree.length; i++)
- {
- emptyBlocks.offer(Integer.valueOf(blocksToFree[i]));
- }
- }
- }
-
- /**
- * Calculates the file offset for a particular block.
- * <p>
- * @param block number
- * @return the byte offset for this block in the file as a long
- * @since 2.0
- */
- protected long calculateByteOffsetForBlockAsLong(int block)
- {
- return (long) block * blockSizeBytes;
- }
-
- /**
- * The number of blocks needed.
- * <p>
- * @param data
- * @return the number of blocks needed to store the byte array
- */
- protected int calculateTheNumberOfBlocksNeeded(byte[] data)
- {
- int dataLength = data.length;
-
- int oneBlock = blockSizeBytes - HEADER_SIZE_BYTES;
-
- // takes care of 0 = HEADER_SIZE_BYTES + blockSizeBytes
- if (dataLength <= oneBlock)
- {
- return 1;
- }
-
- int dividend = dataLength / oneBlock;
-
- if (dataLength % oneBlock != 0)
- {
- dividend++;
- }
- return dividend;
- }
-
- /**
- * Returns the file length.
- * <p>
- * @return the size of the file.
- * @throws IOException
- */
- protected long length()
- throws IOException
- {
- return fc.size();
- }
-
- /**
- * Closes the file.
- * <p>
- * @throws IOException
- */
- @Override
- public void close()
- throws IOException
- {
- this.numberOfBlocks.set(0);
- this.emptyBlocks.clear();
- fc.close();
- }
-
- /**
- * Resets the file.
- * <p>
- * @throws IOException
- */
- protected synchronized void reset()
- throws IOException
- {
- this.numberOfBlocks.set(0);
- this.emptyBlocks.clear();
- fc.truncate(0);
- fc.force(true);
- }
-
- /**
- * @return Returns the numberOfBlocks.
- */
- protected int getNumberOfBlocks()
- {
- return numberOfBlocks.get();
- }
-
- /**
- * @return Returns the blockSizeBytes.
- */
- protected int getBlockSizeBytes()
- {
- return blockSizeBytes;
- }
-
- /**
- * @return Returns the average size of the an element inserted.
- */
- protected long getAveragePutSizeBytes()
- {
- long count = this.putCount.get();
-
- if (count == 0)
- {
- return 0;
- }
- return this.putBytes.get() / count;
- }
-
- /**
- * @return Returns the number of empty blocks.
- */
- protected int getEmptyBlocks()
- {
- return this.emptyBlocks.size();
- }
-
- /**
- * For debugging only.
- * <p>
- * @return String with details.
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append("\nBlock Disk ");
- buf.append("\n Filepath [" + filepath + "]");
- buf.append("\n NumberOfBlocks [" + this.numberOfBlocks.get() + "]");
- buf.append("\n BlockSizeBytes [" + this.blockSizeBytes + "]");
- buf.append("\n Put Bytes [" + this.putBytes + "]");
- buf.append("\n Put Count [" + this.putCount + "]");
- buf.append("\n Average Size [" + getAveragePutSizeBytes() + "]");
- buf.append("\n Empty Blocks [" + this.getEmptyBlocks() + "]");
- try
- {
- buf.append("\n Length [" + length() + "]");
- }
- catch (IOException e)
- {
- // swallow
- }
- return buf.toString();
- }
-
- /**
- * This is used for debugging.
- * <p>
- * @return the file path.
- */
- protected String getFilePath()
- {
- return filepath;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCache.java
deleted file mode 100644
index 1fd383c..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCache.java
+++ /dev/null
@@ -1,709 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.block;
-
-/*
- * 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.
- */
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.stream.Collectors;
-
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.behavior.IRequireScheduler;
-import org.apache.commons.jcs.engine.control.group.GroupAttrName;
-import org.apache.commons.jcs.engine.control.group.GroupId;
-import org.apache.commons.jcs.engine.stats.StatElement;
-import org.apache.commons.jcs.engine.stats.Stats;
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * There is one BlockDiskCache per region. It manages the key and data store.
- * <p>
- * @author Aaron Smuts
- */
-public class BlockDiskCache<K, V>
- extends AbstractDiskCache<K, V>
- implements IRequireScheduler
-{
- /** The logger. */
- private static final Log log = LogManager.getLog( BlockDiskCache.class );
-
- /** The name to prefix all log messages with. */
- private final String logCacheName;
-
- /** The name of the file to store data. */
- private final String fileName;
-
- /** The data access object */
- private BlockDisk dataFile;
-
- /** Attributes governing the behavior of the block disk cache. */
- private final BlockDiskCacheAttributes blockDiskCacheAttributes;
-
- /** The root directory for keys and data. */
- private final File rootDirectory;
-
- /** Store, loads, and persists the keys */
- private BlockDiskKeyStore<K> keyStore;
-
- /**
- * Use this lock to synchronize reads and writes to the underlying storage mechanism. We don't
- * need a reentrant lock, since we only lock one level.
- */
- private final ReentrantReadWriteLock storageLock = new ReentrantReadWriteLock();
-
- private ScheduledFuture<?> future;
-
- /**
- * Constructs the BlockDisk after setting up the root directory.
- * <p>
- * @param cacheAttributes
- */
- public BlockDiskCache( BlockDiskCacheAttributes cacheAttributes )
- {
- this( cacheAttributes, null );
- }
-
- /**
- * Constructs the BlockDisk after setting up the root directory.
- * <p>
- * @param cacheAttributes
- * @param elementSerializer used if supplied, the super's super will not set a null
- */
- public BlockDiskCache( BlockDiskCacheAttributes cacheAttributes, IElementSerializer elementSerializer )
- {
- super( cacheAttributes );
- setElementSerializer( elementSerializer );
-
- this.blockDiskCacheAttributes = cacheAttributes;
- this.logCacheName = "Region [" + getCacheName() + "] ";
-
- log.info("{0}: Constructing BlockDiskCache with attributes {1}", logCacheName, cacheAttributes );
-
- // Make a clean file name
- this.fileName = getCacheName().replaceAll("[^a-zA-Z0-9-_\\.]", "_");
- this.rootDirectory = cacheAttributes.getDiskPath();
-
- log.info("{0}: Cache file root directory: [{1}]", logCacheName, rootDirectory);
-
- try
- {
- if ( this.blockDiskCacheAttributes.getBlockSizeBytes() > 0 )
- {
- this.dataFile = new BlockDisk( new File( rootDirectory, fileName + ".data" ),
- this.blockDiskCacheAttributes.getBlockSizeBytes(),
- getElementSerializer() );
- }
- else
- {
- this.dataFile = new BlockDisk( new File( rootDirectory, fileName + ".data" ),
- getElementSerializer() );
- }
-
- keyStore = new BlockDiskKeyStore<>( this.blockDiskCacheAttributes, this );
-
- boolean alright = verifyDisk();
-
- if ( keyStore.size() == 0 || !alright )
- {
- this.reset();
- }
-
- // Initialization finished successfully, so set alive to true.
- setAlive(true);
- log.info("{0}: Block Disk Cache is alive.", logCacheName);
- }
- catch ( IOException e )
- {
- log.error("{0}: Failure initializing for fileName: {1} and root directory: {2}",
- logCacheName, fileName, rootDirectory, e);
- }
- }
-
- /**
- * @see org.apache.commons.jcs.engine.behavior.IRequireScheduler#setScheduledExecutorService(java.util.concurrent.ScheduledExecutorService)
- */
- @Override
- public void setScheduledExecutorService(ScheduledExecutorService scheduledExecutor)
- {
- // add this region to the persistence thread.
- // TODO we might need to stagger this a bit.
- if ( this.blockDiskCacheAttributes.getKeyPersistenceIntervalSeconds() > 0 )
- {
- future = scheduledExecutor.scheduleAtFixedRate(keyStore::saveKeys,
- this.blockDiskCacheAttributes.getKeyPersistenceIntervalSeconds(),
- this.blockDiskCacheAttributes.getKeyPersistenceIntervalSeconds(),
- TimeUnit.SECONDS);
- }
- }
-
- /**
- * We need to verify that the file on disk uses the same block size and that the file is the
- * proper size.
- * <p>
- * @return true if it looks ok
- */
- protected boolean verifyDisk()
- {
- boolean alright = false;
- // simply try to read a few. If it works, then the file is probably ok.
- // TODO add more.
-
- storageLock.readLock().lock();
-
- try
- {
- this.keyStore.entrySet().stream()
- .limit(100)
- .forEach(entry -> {
- try
- {
- Object data = this.dataFile.read(entry.getValue());
- if ( data == null )
- {
- throw new IOException("Data is null");
- }
- }
- catch (IOException | ClassNotFoundException e)
- {
- throw new RuntimeException(logCacheName
- + " Couldn't find data for key [" + entry.getKey() + "]", e);
- }
- });
- alright = true;
- }
- catch ( Exception e )
- {
- log.warn("{0}: Problem verifying disk.", logCacheName, e);
- alright = false;
- }
- finally
- {
- storageLock.readLock().unlock();
- }
-
- return alright;
- }
-
- /**
- * Return the keys in this cache.
- * <p>
- * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#getKeySet()
- */
- @Override
- public Set<K> getKeySet() throws IOException
- {
- HashSet<K> keys = new HashSet<>();
-
- storageLock.readLock().lock();
-
- try
- {
- keys.addAll(this.keyStore.keySet());
- }
- finally
- {
- storageLock.readLock().unlock();
- }
-
- return keys;
- }
-
- /**
- * Gets matching items from the cache.
- * <p>
- * @param pattern
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache matching keys
- */
- @Override
- public Map<K, ICacheElement<K, V>> processGetMatching( String pattern )
- {
- Set<K> keyArray = null;
- storageLock.readLock().lock();
- try
- {
- keyArray = new HashSet<>(keyStore.keySet());
- }
- finally
- {
- storageLock.readLock().unlock();
- }
-
- Set<K> matchingKeys = getKeyMatcher().getMatchingKeysFromArray( pattern, keyArray );
-
- Map<K, ICacheElement<K, V>> elements = matchingKeys.stream()
- .collect(Collectors.toMap(
- key -> key,
- key -> processGet( key ))).entrySet().stream()
- .filter(entry -> entry.getValue() != null)
- .collect(Collectors.toMap(
- entry -> entry.getKey(),
- entry -> entry.getValue()));
-
- return elements;
- }
-
- /**
- * Returns the number of keys.
- * <p>
- * (non-Javadoc)
- * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#getSize()
- */
- @Override
- public int getSize()
- {
- return this.keyStore.size();
- }
-
- /**
- * Gets the ICacheElement<K, V> for the key if it is in the cache. The program flow is as follows:
- * <ol>
- * <li>Make sure the disk cache is alive.</li> <li>Get a read lock.</li> <li>See if the key is
- * in the key store.</li> <li>If we found a key, ask the BlockDisk for the object at the
- * blocks..</li> <li>Release the lock.</li>
- * </ol>
- * @param key
- * @return ICacheElement
- * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#get(Object)
- */
- @Override
- protected ICacheElement<K, V> processGet( K key )
- {
- if ( !isAlive() )
- {
- log.debug("{0}: No longer alive so returning null for key = {1}", logCacheName, key );
- return null;
- }
-
- log.debug("{0}: Trying to get from disk: {1}", logCacheName, key );
-
- ICacheElement<K, V> object = null;
-
-
- try
- {
- storageLock.readLock().lock();
- try {
- int[] ded = this.keyStore.get( key );
- if ( ded != null )
- {
- object = this.dataFile.read( ded );
- }
- } finally {
- storageLock.readLock().unlock();
- }
-
- }
- catch ( IOException ioe )
- {
- log.error("{0}: Failure getting from disk--IOException, key = {1}", logCacheName, key, ioe );
- reset();
- }
- catch ( Exception e )
- {
- log.error("{0}: Failure getting from disk, key = {1}", logCacheName, key, e );
- }
- return object;
- }
-
- /**
- * Writes an element to disk. The program flow is as follows:
- * <ol>
- * <li>Acquire write lock.</li> <li>See id an item exists for this key.</li> <li>If an item
- * already exists, add its blocks to the remove list.</li> <li>Have the Block disk write the
- * item.</li> <li>Create a descriptor and add it to the key map.</li> <li>Release the write
- * lock.</li>
- * </ol>
- * @param element
- * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#update(ICacheElement)
- */
- @Override
- protected void processUpdate( ICacheElement<K, V> element )
- {
- if ( !isAlive() )
- {
- log.debug("{0}: No longer alive; aborting put of key = {1}",
- () -> logCacheName, () -> element.getKey());
- return;
- }
-
- int[] old = null;
-
- // make sure this only locks for one particular cache region
- storageLock.writeLock().lock();
-
- try
- {
- old = this.keyStore.get( element.getKey() );
-
- if ( old != null )
- {
- this.dataFile.freeBlocks( old );
- }
-
- int[] blocks = this.dataFile.write( element );
-
- this.keyStore.put( element.getKey(), blocks );
-
- log.debug("{0}: Put to file [{1}] key [{2}]", () -> logCacheName,
- () -> fileName, () -> element.getKey());
- }
- catch ( IOException e )
- {
- log.error("{0}: Failure updating element, key: {1} old: {2}",
- logCacheName, element.getKey(), Arrays.toString(old), e);
- }
- finally
- {
- storageLock.writeLock().unlock();
- }
-
- log.debug("{0}: Storing element on disk, key: {1}", () -> logCacheName,
- () -> element.getKey() );
- }
-
- /**
- * Returns true if the removal was successful; or false if there is nothing to remove. Current
- * implementation always result in a disk orphan.
- * <p>
- * @param key
- * @return true if removed anything
- * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#remove(Object)
- */
- @Override
- protected boolean processRemove( K key )
- {
- if ( !isAlive() )
- {
- log.debug("{0}: No longer alive so returning false for key = {1}", logCacheName, key );
- return false;
- }
-
- boolean reset = false;
- boolean removed = false;
-
- storageLock.writeLock().lock();
-
- try
- {
- if (key instanceof String && key.toString().endsWith(NAME_COMPONENT_DELIMITER))
- {
- removed = performPartialKeyRemoval((String) key);
- }
- else if (key instanceof GroupAttrName && ((GroupAttrName<?>) key).attrName == null)
- {
- removed = performGroupRemoval(((GroupAttrName<?>) key).groupId);
- }
- else
- {
- removed = performSingleKeyRemoval(key);
- }
- }
- catch ( Exception e )
- {
- log.error("{0}: Problem removing element.", logCacheName, e );
- reset = true;
- }
- finally
- {
- storageLock.writeLock().unlock();
- }
-
- if ( reset )
- {
- reset();
- }
-
- return removed;
- }
-
- /**
- * Remove all elements from the group. This does not use the iterator to remove. It builds a
- * list of group elements and then removes them one by one.
- * <p>
- * This operates under a lock obtained in doRemove().
- * <p>
- *
- * @param key
- * @return true if an element was removed
- */
- private boolean performGroupRemoval(GroupId key)
- {
- // remove all keys of the same name group.
- List<K> itemsToRemove = keyStore.keySet()
- .stream()
- .filter(k -> k instanceof GroupAttrName && ((GroupAttrName<?>) k).groupId.equals(key))
- .collect(Collectors.toList());
-
- // remove matches.
- // Don't add to recycle bin here
- // https://issues.apache.org/jira/browse/JCS-67
- itemsToRemove.forEach(fullKey -> performSingleKeyRemoval(fullKey));
- // TODO this needs to update the remove count separately
-
- return !itemsToRemove.isEmpty();
- }
-
- /**
- * Iterates over the keyset. Builds a list of matches. Removes all the keys in the list. Does
- * not remove via the iterator, since the map impl may not support it.
- * <p>
- * This operates under a lock obtained in doRemove().
- * <p>
- *
- * @param key
- * @return true if there was a match
- */
- private boolean performPartialKeyRemoval(String key)
- {
- // remove all keys of the same name hierarchy.
- List<K> itemsToRemove = keyStore.keySet()
- .stream()
- .filter(k -> k instanceof String && k.toString().startsWith(key))
- .collect(Collectors.toList());
-
- // remove matches.
- // Don't add to recycle bin here
- // https://issues.apache.org/jira/browse/JCS-67
- itemsToRemove.forEach(fullKey -> performSingleKeyRemoval(fullKey));
- // TODO this needs to update the remove count separately
-
- return !itemsToRemove.isEmpty();
- }
-
-
- private boolean performSingleKeyRemoval(K key) {
- boolean removed;
- // remove single item.
- int[] ded = this.keyStore.remove( key );
- removed = ded != null;
- if ( removed )
- {
- this.dataFile.freeBlocks( ded );
- }
-
- log.debug("{0}: Disk removal: Removed from key hash, key [{1}] removed = {2}",
- logCacheName, key, removed);
- return removed;
- }
-
- /**
- * Resets the keyfile, the disk file, and the memory key map.
- * <p>
- * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#removeAll()
- */
- @Override
- protected void processRemoveAll()
- {
- reset();
- }
-
- /**
- * Dispose of the disk cache in a background thread. Joins against this thread to put a cap on
- * the disposal time.
- * <p>
- * TODO make dispose window configurable.
- */
- @Override
- public void processDispose()
- {
- Thread t = new Thread(this::disposeInternal, "BlockDiskCache-DisposalThread" );
- t.start();
- // wait up to 60 seconds for dispose and then quit if not done.
- try
- {
- t.join( 60 * 1000 );
- }
- catch ( InterruptedException ex )
- {
- log.error("{0}: Interrupted while waiting for disposal thread to finish.",
- logCacheName, ex );
- }
- }
-
- /**
- * Internal method that handles the disposal.
- */
- protected void disposeInternal()
- {
- if ( !isAlive() )
- {
- log.error("{0}: Not alive and dispose was called, filename: {1}", logCacheName, fileName);
- return;
- }
- storageLock.writeLock().lock();
- try
- {
- // Prevents any interaction with the cache while we're shutting down.
- setAlive(false);
- this.keyStore.saveKeys();
-
- if (future != null)
- {
- future.cancel(true);
- }
-
- try
- {
- log.debug("{0}: Closing files, base filename: {1}", logCacheName, fileName );
- dataFile.close();
- // dataFile = null;
-
- // TOD make a close
- // keyFile.close();
- // keyFile = null;
- }
- catch ( IOException e )
- {
- log.error("{0}: Failure closing files in dispose, filename: {1}",
- logCacheName, fileName, e );
- }
- }
- finally
- {
- storageLock.writeLock().unlock();
- }
-
- log.info("{0}: Shutdown complete.", logCacheName);
- }
-
- /**
- * Returns the attributes.
- * <p>
- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getAuxiliaryCacheAttributes()
- */
- @Override
- public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
- {
- return this.blockDiskCacheAttributes;
- }
-
- /**
- * Reset effectively clears the disk cache, creating new files, recyclebins, and keymaps.
- * <p>
- * It can be used to handle errors by last resort, force content update, or removeall.
- */
- private void reset()
- {
- log.info("{0}: Resetting cache", logCacheName);
-
- try
- {
- storageLock.writeLock().lock();
-
- this.keyStore.reset();
-
- if ( dataFile != null )
- {
- dataFile.reset();
- }
- }
- catch ( IOException e )
- {
- log.error("{0}: Failure resetting state", logCacheName, e );
- }
- finally
- {
- storageLock.writeLock().unlock();
- }
- }
-
- /**
- * Add these blocks to the emptyBlock list.
- * <p>
- * @param blocksToFree
- */
- protected void freeBlocks( int[] blocksToFree )
- {
- this.dataFile.freeBlocks( blocksToFree );
- }
-
- /**
- * Returns info about the disk cache.
- * <p>
- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getStatistics()
- */
- @Override
- public IStats getStatistics()
- {
- IStats stats = new Stats();
- stats.setTypeName( "Block Disk Cache" );
-
- ArrayList<IStatElement<?>> elems = new ArrayList<>();
-
- elems.add(new StatElement<>( "Is Alive", Boolean.valueOf(isAlive()) ) );
- elems.add(new StatElement<>( "Key Map Size", Integer.valueOf(this.keyStore.size()) ) );
-
- if (this.dataFile != null)
- {
- try
- {
- elems.add(new StatElement<>( "Data File Length", Long.valueOf(this.dataFile.length()) ) );
- }
- catch ( IOException e )
- {
- log.error( e );
- }
-
- elems.add(new StatElement<>( "Block Size Bytes",
- Integer.valueOf(this.dataFile.getBlockSizeBytes()) ) );
- elems.add(new StatElement<>( "Number Of Blocks",
- Integer.valueOf(this.dataFile.getNumberOfBlocks()) ) );
- elems.add(new StatElement<>( "Average Put Size Bytes",
- Long.valueOf(this.dataFile.getAveragePutSizeBytes()) ) );
- elems.add(new StatElement<>( "Empty Blocks",
- Integer.valueOf(this.dataFile.getEmptyBlocks()) ) );
- }
-
- // get the stats from the super too
- IStats sStats = super.getStatistics();
- elems.addAll(sStats.getStatElements());
-
- stats.setStatElements( elems );
-
- return stats;
- }
-
- /**
- * This is used by the event logging.
- * <p>
- * @return the location of the disk, either path or ip.
- */
- @Override
- protected String getDiskLocation()
- {
- return dataFile.getFilePath();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheAttributes.java
deleted file mode 100644
index e520dda..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheAttributes.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.block;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.disk.AbstractDiskCacheAttributes;
-
-/**
- * This holds attributes for Block Disk Cache configuration.
- * <p>
- * @author Aaron Smuts
- */
-public class BlockDiskCacheAttributes
- extends AbstractDiskCacheAttributes
-{
- /** Don't change */
- private static final long serialVersionUID = 6568840097657265989L;
-
- /** The size per block in bytes. */
- private int blockSizeBytes;
-
- /** Maximum number of keys to be kept in memory */
- private static final int DEFAULT_MAX_KEY_SIZE = 5000;
-
- /** -1 means no limit. */
- private int maxKeySize = DEFAULT_MAX_KEY_SIZE;
-
- /** How often should we persist the keys. */
- private static final long DEFAULT_KEY_PERSISTENCE_INTERVAL_SECONDS = 5 * 60;
-
- /** The keys will be persisted at this interval. -1 mean never. */
- private long keyPersistenceIntervalSeconds = DEFAULT_KEY_PERSISTENCE_INTERVAL_SECONDS;
-
- /**
- * The size of the blocks. All blocks are the same size.
- * <p>
- * @param blockSizeBytes The blockSizeBytes to set.
- */
- public void setBlockSizeBytes( int blockSizeBytes )
- {
- this.blockSizeBytes = blockSizeBytes;
- }
-
- /**
- * @return Returns the blockSizeBytes.
- */
- public int getBlockSizeBytes()
- {
- return blockSizeBytes;
- }
-
- /**
- * @param maxKeySize The maxKeySize to set.
- */
- public void setMaxKeySize( int maxKeySize )
- {
- this.maxKeySize = maxKeySize;
- }
-
- /**
- * @return Returns the maxKeySize.
- */
- public int getMaxKeySize()
- {
- return maxKeySize;
- }
-
- /**
- * @param keyPersistenceIntervalSeconds The keyPersistenceIntervalSeconds to set.
- */
- public void setKeyPersistenceIntervalSeconds( long keyPersistenceIntervalSeconds )
- {
- this.keyPersistenceIntervalSeconds = keyPersistenceIntervalSeconds;
- }
-
- /**
- * @return Returns the keyPersistenceIntervalSeconds.
- */
- public long getKeyPersistenceIntervalSeconds()
- {
- return keyPersistenceIntervalSeconds;
- }
-
- /**
- * Write out the values for debugging purposes.
- * <p>
- * @return String
- */
- @Override
- public String toString()
- {
- StringBuilder str = new StringBuilder();
- str.append( "\nBlockDiskAttributes " );
- str.append( "\n DiskPath [" + this.getDiskPath() + "]" );
- str.append( "\n MaxKeySize [" + this.getMaxKeySize() + "]" );
- str.append( "\n MaxPurgatorySize [" + this.getMaxPurgatorySize() + "]" );
- str.append( "\n BlockSizeBytes [" + this.getBlockSizeBytes() + "]" );
- str.append( "\n KeyPersistenceIntervalSeconds [" + this.getKeyPersistenceIntervalSeconds() + "]" );
- str.append( "\n DiskLimitType [" + this.getDiskLimitType() + "]" );
- return str.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheFactory.java
deleted file mode 100644
index 7a88db4..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheFactory.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.block;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * Creates disk cache instances.
- */
-public class BlockDiskCacheFactory
- extends AbstractAuxiliaryCacheFactory
-{
- /** The logger */
- private static final Log log = LogManager.getLog( BlockDiskCacheFactory.class );
-
- /**
- * Create an instance of the BlockDiskCache.
- * <p>
- * @param iaca the cache attributes for this cache
- * @param cacheMgr This allows auxiliaries to reference the manager without assuming that it is
- * a singleton. This will allow JCS to be a non-singleton. Also, it makes it easier
- * to test.
- * @param cacheEventLogger
- * @param elementSerializer
- * @return BlockDiskCache
- */
- @Override
- public <K, V> BlockDiskCache<K, V> createCache( AuxiliaryCacheAttributes iaca, ICompositeCacheManager cacheMgr,
- ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
- {
- BlockDiskCacheAttributes idca = (BlockDiskCacheAttributes) iaca;
- log.debug("Creating DiskCache for attributes = {0}", idca);
-
- BlockDiskCache<K, V> cache = new BlockDiskCache<>( idca, elementSerializer );
- cache.setCacheEventLogger( cacheEventLogger );
-
- return cache;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskElementDescriptor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskElementDescriptor.java
deleted file mode 100644
index 73fd657..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskElementDescriptor.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.block;
-
-/*
- * 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.
- */
-
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.io.Serializable;
-
-/**
- * This represents an element on disk. This is used when we persist the keys. We only store the
- * block addresses in memory. We don't need the length here, since all the blocks are the same size
- * receyle bin.
- * <p>
- * @author Aaron Smuts
- */
-public class BlockDiskElementDescriptor<K>
- implements Serializable, Externalizable
-{
- /** Don't change */
- private static final long serialVersionUID = -1400659301208101411L;
-
- /** The key */
- private K key;
-
- /** The array of block numbers */
- private int[] blocks;
-
- /**
- * @param key The key to set.
- */
- public void setKey( K key )
- {
- this.key = key;
- }
-
- /**
- * @return Returns the key.
- */
- public K getKey()
- {
- return key;
- }
-
- /**
- * @param blocks The blocks to set.
- */
- public void setBlocks( int[] blocks )
- {
- this.blocks = blocks;
- }
-
- /**
- * This holds the block numbers. An item my be dispersed between multiple blocks.
- * <p>
- * @return Returns the blocks.
- */
- public int[] getBlocks()
- {
- return blocks;
- }
-
- /**
- * For debugging.
- * <p>
- * @return Info on the descriptor.
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\nBlockDiskElementDescriptor" );
- buf.append( "\n key [" + this.getKey() + "]" );
- buf.append( "\n blocks [" );
- if ( this.getBlocks() != null )
- {
- for ( int i = 0; i < blocks.length; i++ )
- {
- buf.append( this.getBlocks()[i] );
- }
- }
- buf.append( "]" );
- return buf.toString();
- }
-
- /**
- * Saves on reflection.
- * <p>
- * (non-Javadoc)
- * @see java.io.Externalizable#readExternal(java.io.ObjectInput)
- */
- @Override
- @SuppressWarnings("unchecked") // Need cast to K
- public void readExternal( ObjectInput input )
- throws IOException, ClassNotFoundException
- {
- this.key = (K) input.readObject();
- this.blocks = (int[]) input.readObject();
- }
-
- /**
- * Saves on reflection.
- * <p>
- * (non-Javadoc)
- * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
- */
- @Override
- public void writeExternal( ObjectOutput output )
- throws IOException
- {
- output.writeObject( this.key );
- output.writeObject( this.blocks );
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskKeyStore.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskKeyStore.java
deleted file mode 100644
index 94118c4..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskKeyStore.java
+++ /dev/null
@@ -1,550 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.block;
-
-/*
- * 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.
- */
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.EOFException;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
-import org.apache.commons.jcs.io.ObjectInputStreamClassLoaderAware;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.struct.AbstractLRUMap;
-import org.apache.commons.jcs.utils.struct.LRUMap;
-import org.apache.commons.jcs.utils.timing.ElapsedTimer;
-
-/**
- * This is responsible for storing the keys.
- * <p>
- *
- * @author Aaron Smuts
- */
-public class BlockDiskKeyStore<K>
-{
- /** The logger */
- private static final Log log = LogManager.getLog(BlockDiskKeyStore.class);
-
- /** Attributes governing the behavior of the block disk cache. */
- private final BlockDiskCacheAttributes blockDiskCacheAttributes;
-
- /** The key to block map */
- private Map<K, int[]> keyHash;
-
- /** The file where we persist the keys */
- private final File keyFile;
-
- /** The name to prefix log messages with. */
- protected final String logCacheName;
-
- /** Name of the file where we persist the keys */
- private final String fileName;
-
- /** The maximum number of keys to store in memory */
- private final int maxKeySize;
-
- /**
- * we need this so we can communicate free blocks to the data store when
- * keys fall off the LRU
- */
- protected final BlockDiskCache<K, ?> blockDiskCache;
-
- private DiskLimitType diskLimitType = DiskLimitType.COUNT;
-
- private int blockSize;
-
- /**
- * Set the configuration options.
- * <p>
- *
- * @param cacheAttributes
- * @param blockDiskCache
- * used for freeing
- */
- public BlockDiskKeyStore(BlockDiskCacheAttributes cacheAttributes, BlockDiskCache<K, ?> blockDiskCache)
- {
- this.blockDiskCacheAttributes = cacheAttributes;
- this.logCacheName = "Region [" + this.blockDiskCacheAttributes.getCacheName() + "] ";
- this.fileName = this.blockDiskCacheAttributes.getCacheName();
- this.maxKeySize = cacheAttributes.getMaxKeySize();
- this.blockDiskCache = blockDiskCache;
- this.diskLimitType = cacheAttributes.getDiskLimitType();
- this.blockSize = cacheAttributes.getBlockSizeBytes();
-
- File rootDirectory = cacheAttributes.getDiskPath();
-
- log.info("{0}: Cache file root directory [{1}]", logCacheName, rootDirectory);
-
- this.keyFile = new File(rootDirectory, fileName + ".key");
-
- log.info("{0}: Key File [{1}]", logCacheName, this.keyFile.getAbsolutePath());
-
- if (keyFile.length() > 0)
- {
- loadKeys();
- if (!verify())
- {
- log.warn("{0}: Key File is invalid. Resetting file.", logCacheName);
- initKeyMap();
- reset();
- }
- }
- else
- {
- initKeyMap();
- }
- }
-
- /**
- * Saves key file to disk. This gets the LRUMap entry set and write the
- * entries out one by one after putting them in a wrapper.
- */
- protected void saveKeys()
- {
- try
- {
- ElapsedTimer timer = new ElapsedTimer();
- int numKeys = keyHash.size();
- log.info("{0}: Saving keys to [{1}], key count [{2}]", () -> logCacheName,
- () -> this.keyFile.getAbsolutePath(), () -> numKeys);
-
- synchronized (keyFile)
- {
- FileOutputStream fos = new FileOutputStream(keyFile);
- BufferedOutputStream bos = new BufferedOutputStream(fos, 65536);
-
- try (ObjectOutputStream oos = new ObjectOutputStream(bos))
- {
- if (!verify())
- {
- throw new IOException("Inconsistent key file");
- }
- // don't need to synchronize, since the underlying
- // collection makes a copy
- for (Map.Entry<K, int[]> entry : keyHash.entrySet())
- {
- BlockDiskElementDescriptor<K> descriptor = new BlockDiskElementDescriptor<>();
- descriptor.setKey(entry.getKey());
- descriptor.setBlocks(entry.getValue());
- // stream these out in the loop.
- oos.writeUnshared(descriptor);
- }
- }
- }
-
- log.info("{0}: Finished saving keys. It took {1} to store {2} keys. Key file length [{3}]",
- () -> logCacheName, () -> timer.getElapsedTimeString(), () -> numKeys,
- () -> keyFile.length());
- }
- catch (IOException e)
- {
- log.error("{0}: Problem storing keys.", logCacheName, e);
- }
- }
-
- /**
- * Resets the file and creates a new key map.
- */
- protected void reset()
- {
- synchronized (keyFile)
- {
- clearMemoryMap();
- saveKeys();
- }
- }
-
- /**
- * This is mainly used for testing. It leave the disk in tact, and just
- * clears memory.
- */
- protected void clearMemoryMap()
- {
- this.keyHash.clear();
- }
-
- /**
- * Create the map for keys that contain the index position on disk.
- */
- private void initKeyMap()
- {
- keyHash = null;
- if (maxKeySize >= 0)
- {
- if (this.diskLimitType == DiskLimitType.SIZE)
- {
- keyHash = new LRUMapSizeLimited(maxKeySize);
- }
- else
- {
- keyHash = new LRUMapCountLimited(maxKeySize);
- }
- log.info("{0}: Set maxKeySize to: \"{1}\"", logCacheName, maxKeySize);
- }
- else
- {
- // If no max size, use a plain map for memory and processing
- // efficiency.
- keyHash = new HashMap<>();
- // keyHash = Collections.synchronizedMap( new HashMap() );
- log.info("{0}: Set maxKeySize to unlimited", logCacheName);
- }
- }
-
- /**
- * Loads the keys from the .key file. The keys are stored individually on
- * disk. They are added one by one to an LRUMap..
- */
- protected void loadKeys()
- {
- log.info("{0}: Loading keys for {1}", () -> logCacheName, () -> keyFile.toString());
-
- try
- {
- // create a key map to use.
- initKeyMap();
-
- HashMap<K, int[]> keys = new HashMap<>();
-
- synchronized (keyFile)
- {
- FileInputStream fis = new FileInputStream(keyFile);
- BufferedInputStream bis = new BufferedInputStream(fis, 65536);
-
- try (ObjectInputStream ois = new ObjectInputStreamClassLoaderAware(bis, null))
- {
- while (true)
- {
- @SuppressWarnings("unchecked")
- // Need to cast from Object
- BlockDiskElementDescriptor<K> descriptor = (BlockDiskElementDescriptor<K>) ois.readObject();
- if (descriptor != null)
- {
- keys.put(descriptor.getKey(), descriptor.getBlocks());
- }
- }
- }
- catch (EOFException eof)
- {
- // nothing
- }
- }
-
- if (!keys.isEmpty())
- {
- keyHash.putAll(keys);
-
- log.debug("{0}: Found {1} in keys file.", logCacheName, keys.size());
- log.info("{0}: Loaded keys from [{1}], key count: {2}; up to {3} will be available.",
- () -> logCacheName, () -> fileName, () -> keyHash.size(),
- () -> maxKeySize);
- }
- }
- catch (Exception e)
- {
- log.error("{0}: Problem loading keys for file {1}", logCacheName, fileName, e);
- }
- }
-
- /**
- * Gets the entry set.
- * <p>
- *
- * @return entry set.
- */
- public Set<Map.Entry<K, int[]>> entrySet()
- {
- return this.keyHash.entrySet();
- }
-
- /**
- * Gets the key set.
- * <p>
- *
- * @return key set.
- */
- public Set<K> keySet()
- {
- return this.keyHash.keySet();
- }
-
- /**
- * Gets the size of the key hash.
- * <p>
- *
- * @return the number of keys.
- */
- public int size()
- {
- return this.keyHash.size();
- }
-
- /**
- * gets the object for the key.
- * <p>
- *
- * @param key
- * @return Object
- */
- public int[] get(K key)
- {
- return this.keyHash.get(key);
- }
-
- /**
- * Puts a int[] in the keyStore.
- * <p>
- *
- * @param key
- * @param value
- */
- public void put(K key, int[] value)
- {
- this.keyHash.put(key, value);
- }
-
- /**
- * Remove by key.
- * <p>
- *
- * @param key
- * @return BlockDiskElementDescriptor if it was present, else null
- */
- public int[] remove(K key)
- {
- return this.keyHash.remove(key);
- }
-
- /**
- * Verify key store integrity
- *
- * @return true if key store is valid
- */
- private boolean verify()
- {
- Map<Integer, Set<K>> blockAllocationMap = new TreeMap<>();
- for (Entry<K, int[]> e : keyHash.entrySet())
- {
- for (int block : e.getValue())
- {
- Set<K> keys = blockAllocationMap.get(block);
- if (keys == null)
- {
- keys = new HashSet<>();
- blockAllocationMap.put(block, keys);
- }
- else if (!log.isTraceEnabled())
- {
- // keys are not null, and no debug - fail fast
- return false;
- }
- keys.add(e.getKey());
- }
- }
- boolean ok = true;
- if (log.isTraceEnabled())
- {
- for (Entry<Integer, Set<K>> e : blockAllocationMap.entrySet())
- {
- log.trace("Block {0}: {1}", e.getKey(), e.getValue());
- if (e.getValue().size() > 1)
- {
- ok = false;
- }
- }
- return ok;
- }
- else
- {
- return ok;
- }
- }
-
- /**
- * Class for recycling and lru. This implements the LRU size overflow
- * callback, so we can mark the blocks as free.
- */
- public class LRUMapSizeLimited extends AbstractLRUMap<K, int[]>
- {
- /**
- * <code>tag</code> tells us which map we are working on.
- */
- public final static String TAG = "orig-lru-size";
-
- // size of the content in kB
- private AtomicInteger contentSize;
- private int maxSize;
-
- /**
- * Default
- */
- public LRUMapSizeLimited()
- {
- this(-1);
- }
-
- /**
- * @param maxSize
- * maximum cache size in kB
- */
- public LRUMapSizeLimited(int maxSize)
- {
- super();
- this.maxSize = maxSize;
- this.contentSize = new AtomicInteger(0);
- }
-
- // keep the content size in kB, so 2^31 kB is reasonable value
- private void subLengthFromCacheSize(int[] value)
- {
- contentSize.addAndGet(value.length * blockSize / -1024 - 1);
- }
-
- // keep the content size in kB, so 2^31 kB is reasonable value
- private void addLengthToCacheSize(int[] value)
- {
- contentSize.addAndGet(value.length * blockSize / 1024 + 1);
- }
-
- @Override
- public int[] put(K key, int[] value)
- {
- int[] oldValue = null;
-
- try
- {
- oldValue = super.put(key, value);
- }
- finally
- {
- if (value != null)
- {
- addLengthToCacheSize(value);
- }
- if (oldValue != null)
- {
- subLengthFromCacheSize(oldValue);
- }
- }
-
- return oldValue;
- }
-
- @Override
- public int[] remove(Object key)
- {
- int[] value = null;
-
- try
- {
- value = super.remove(key);
- return value;
- }
- finally
- {
- if (value != null)
- {
- subLengthFromCacheSize(value);
- }
- }
- }
-
- /**
- * This is called when the may key size is reached. The least recently
- * used item will be passed here. We will store the position and size of
- * the spot on disk in the recycle bin.
- * <p>
- *
- * @param key
- * @param value
- */
- @Override
- protected void processRemovedLRU(K key, int[] value)
- {
- blockDiskCache.freeBlocks(value);
- if (log.isDebugEnabled())
- {
- log.debug("{0}: Removing key: [{1}] from key store.", logCacheName, key);
- log.debug("{0}: Key store size: [{1}].", logCacheName, super.size());
- }
-
- if (value != null)
- {
- subLengthFromCacheSize(value);
- }
- }
-
- @Override
- protected boolean shouldRemove()
- {
- return maxSize > 0 && contentSize.get() > maxSize && this.size() > 1;
- }
- }
-
- /**
- * Class for recycling and lru. This implements the LRU overflow callback,
- * so we can mark the blocks as free.
- */
- public class LRUMapCountLimited extends LRUMap<K, int[]>
- {
- /**
- * <code>tag</code> tells us which map we are working on.
- */
- public final static String TAG = "orig-lru-count";
-
- public LRUMapCountLimited(int maxKeySize)
- {
- super(maxKeySize);
- }
-
- /**
- * This is called when the may key size is reached. The least recently
- * used item will be passed here. We will store the position and size of
- * the spot on disk in the recycle bin.
- * <p>
- *
- * @param key
- * @param value
- */
- @Override
- protected void processRemovedLRU(K key, int[] value)
- {
- blockDiskCache.freeBlocks(value);
- if (log.isDebugEnabled())
- {
- log.debug("{0}: Removing key: [{1}] from key store.", logCacheName, key);
- log.debug("{0}: Key store size: [{1}].", logCacheName, super.size());
- }
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDisk.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDisk.java
deleted file mode 100644
index 7df2a58..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDisk.java
+++ /dev/null
@@ -1,279 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.nio.file.StandardOpenOption;
-
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/** Provides thread safe access to the underlying random access file. */
-public class IndexedDisk implements AutoCloseable
-{
- /** The size of the header that indicates the amount of data stored in an occupied block. */
- public static final byte HEADER_SIZE_BYTES = 4;
-
- /** The serializer. */
- private final IElementSerializer elementSerializer;
-
- /** The logger */
- private static final Log log = LogManager.getLog(IndexedDisk.class);
-
- /** The path to the log directory. */
- private final String filepath;
-
- /** The data file. */
- private final FileChannel fc;
-
- /**
- * Constructor for the Disk object
- * <p>
- * @param file
- * @param elementSerializer
- * @throws IOException
- */
- public IndexedDisk(File file, IElementSerializer elementSerializer)
- throws IOException
- {
- this.filepath = file.getAbsolutePath();
- this.elementSerializer = elementSerializer;
- this.fc = FileChannel.open(file.toPath(),
- StandardOpenOption.CREATE,
- StandardOpenOption.READ,
- StandardOpenOption.WRITE);
- }
-
- /**
- * This reads an object from the given starting position on the file.
- * <p>
- * The first four bytes of the record should tell us how long it is. The data is read into a byte
- * array and then an object is constructed from the byte array.
- * <p>
- * @return Serializable
- * @param ded
- * @throws IOException
- * @throws ClassNotFoundException
- */
- protected <T> T readObject(IndexedDiskElementDescriptor ded)
- throws IOException, ClassNotFoundException
- {
- String message = null;
- boolean corrupted = false;
- long fileLength = fc.size();
- if (ded.pos > fileLength)
- {
- corrupted = true;
- message = "Record " + ded + " starts past EOF.";
- }
- else
- {
- ByteBuffer datalength = ByteBuffer.allocate(HEADER_SIZE_BYTES);
- fc.read(datalength, ded.pos);
- datalength.flip();
- int datalen = datalength.getInt();
- if (ded.len != datalen)
- {
- corrupted = true;
- message = "Record " + ded + " does not match data length on disk (" + datalen + ")";
- }
- else if (ded.pos + ded.len > fileLength)
- {
- corrupted = true;
- message = "Record " + ded + " exceeds file length.";
- }
- }
-
- if (corrupted)
- {
- log.warn("\n The file is corrupt: \n {0}", message);
- throw new IOException("The File Is Corrupt, need to reset");
- }
-
- ByteBuffer data = ByteBuffer.allocate(ded.len);
- fc.read(data, ded.pos + HEADER_SIZE_BYTES);
- data.flip();
-
- return elementSerializer.deSerialize(data.array(), null);
- }
-
- /**
- * Moves the data stored from one position to another. The descriptor's position is updated.
- * <p>
- * @param ded
- * @param newPosition
- * @throws IOException
- */
- protected void move(final IndexedDiskElementDescriptor ded, final long newPosition)
- throws IOException
- {
- ByteBuffer datalength = ByteBuffer.allocate(HEADER_SIZE_BYTES);
- fc.read(datalength, ded.pos);
- datalength.flip();
- int length = datalength.getInt();
-
- if (length != ded.len)
- {
- throw new IOException("Mismatched memory and disk length (" + length + ") for " + ded);
- }
-
- // TODO: more checks?
-
- long readPos = ded.pos;
- long writePos = newPosition;
-
- // header len + data len
- int remaining = HEADER_SIZE_BYTES + length;
- ByteBuffer buffer = ByteBuffer.allocate(16384);
-
- while (remaining > 0)
- {
- // chunk it
- int chunkSize = Math.min(remaining, buffer.capacity());
- buffer.limit(chunkSize);
- fc.read(buffer, readPos);
- buffer.flip();
- fc.write(buffer, writePos);
- buffer.clear();
-
- writePos += chunkSize;
- readPos += chunkSize;
- remaining -= chunkSize;
- }
-
- ded.pos = newPosition;
- }
-
- /**
- * Writes the given byte array to the Disk at the specified position.
- * <p>
- * @param data
- * @param ded
- * @return true if we wrote successfully
- * @throws IOException
- */
- protected boolean write(IndexedDiskElementDescriptor ded, byte[] data)
- throws IOException
- {
- long pos = ded.pos;
- if (log.isTraceEnabled())
- {
- log.trace("write> pos={0}", pos);
- log.trace("{0} -- data.length = {1}", fc, data.length);
- }
-
- if (data.length != ded.len)
- {
- throw new IOException("Mismatched descriptor and data lengths");
- }
-
- ByteBuffer headerBuffer = ByteBuffer.allocate(HEADER_SIZE_BYTES);
- headerBuffer.putInt(data.length);
- // write the header
- headerBuffer.flip();
- int written = fc.write(headerBuffer, pos);
- assert written == HEADER_SIZE_BYTES;
-
- //write the data
- ByteBuffer dataBuffer = ByteBuffer.wrap(data);
- written = fc.write(dataBuffer, pos + HEADER_SIZE_BYTES);
-
- return written == data.length;
- }
-
- /**
- * Serializes the object and write it out to the given position.
- * <p>
- * TODO: make this take a ded as well.
- * @param obj
- * @param pos
- * @throws IOException
- */
- protected <T> void writeObject(T obj, long pos)
- throws IOException
- {
- byte[] data = elementSerializer.serialize(obj);
- write(new IndexedDiskElementDescriptor(pos, data.length), data);
- }
-
- /**
- * Returns the raf length.
- * <p>
- * @return the length of the file.
- * @throws IOException
- */
- protected long length()
- throws IOException
- {
- return fc.size();
- }
-
- /**
- * Closes the raf.
- * <p>
- * @throws IOException
- */
- @Override
- public void close()
- throws IOException
- {
- fc.close();
- }
-
- /**
- * Sets the raf to empty.
- * <p>
- * @throws IOException
- */
- protected synchronized void reset()
- throws IOException
- {
- log.debug("Resetting Indexed File [{0}]", filepath);
- fc.truncate(0);
- fc.force(true);
- }
-
- /**
- * Truncates the file to a given length.
- * <p>
- * @param length the new length of the file
- * @throws IOException
- */
- protected void truncate(long length)
- throws IOException
- {
- log.info("Truncating file [{0}] to {1}", filepath, length);
- fc.truncate(length);
- }
-
- /**
- * This is used for debugging.
- * <p>
- * @return the file path.
- */
- protected String getFilePath()
- {
- return filepath;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCache.java
deleted file mode 100644
index 68d9eef..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCache.java
+++ /dev/null
@@ -1,1680 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import java.io.File;
-import java.io.IOException;
-import java.io.Serializable;
-import java.nio.file.Files;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentSkipListSet;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache;
-import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.control.group.GroupAttrName;
-import org.apache.commons.jcs.engine.control.group.GroupId;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.engine.stats.StatElement;
-import org.apache.commons.jcs.engine.stats.Stats;
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.struct.AbstractLRUMap;
-import org.apache.commons.jcs.utils.struct.LRUMap;
-import org.apache.commons.jcs.utils.timing.ElapsedTimer;
-
-/**
- * Disk cache that uses a RandomAccessFile with keys stored in memory. The maximum number of keys
- * stored in memory is configurable. The disk cache tries to recycle spots on disk to limit file
- * expansion.
- */
-public class IndexedDiskCache<K, V> extends AbstractDiskCache<K, V>
-{
- /** The logger */
- private static final Log log = LogManager.getLog(IndexedDiskCache.class);
-
- /** Cache name used in log messages */
- protected final String logCacheName;
-
- /** The name of the file where the data is stored */
- private final String fileName;
-
- /** The IndexedDisk manages reads and writes to the data file. */
- private IndexedDisk dataFile;
-
- /** The IndexedDisk manages reads and writes to the key file. */
- private IndexedDisk keyFile;
-
- /** Map containing the keys and disk offsets. */
- private final Map<K, IndexedDiskElementDescriptor> keyHash;
-
- /** The maximum number of keys that we will keep in memory. */
- private final int maxKeySize;
-
- /** A handle on the data file. */
- private File rafDir;
-
- /** Should we keep adding to the recycle bin. False during optimization. */
- private boolean doRecycle = true;
-
- /** Should we optimize real time */
- private boolean isRealTimeOptimizationEnabled = true;
-
- /** Should we optimize on shutdown. */
- private boolean isShutdownOptimizationEnabled = true;
-
- /** are we currently optimizing the files */
- private boolean isOptimizing = false;
-
- /** The number of times the file has been optimized. */
- private int timesOptimized = 0;
-
- /** The thread optimizing the file. */
- private volatile Thread currentOptimizationThread;
-
- /** used for counting the number of requests */
- private int removeCount = 0;
-
- /** Should we queue puts. True when optimizing. We write the queue post optimization. */
- private boolean queueInput = false;
-
- /** list where puts made during optimization are made */
- private final ConcurrentSkipListSet<IndexedDiskElementDescriptor> queuedPutList;
-
- /** RECYLCE BIN -- array of empty spots */
- private final ConcurrentSkipListSet<IndexedDiskElementDescriptor> recycle;
-
- /** User configurable parameters */
- private final IndexedDiskCacheAttributes cattr;
-
- /** How many slots have we recycled. */
- private int recycleCnt = 0;
-
- /** How many items were there on startup. */
- private int startupSize = 0;
-
- /** the number of bytes free on disk. */
- private AtomicLong bytesFree = new AtomicLong(0);
-
- /** mode we are working on (size or count limited **/
- private DiskLimitType diskLimitType = DiskLimitType.COUNT;
-
- /** simple stat */
- private AtomicInteger hitCount = new AtomicInteger(0);
-
- /**
- * Use this lock to synchronize reads and writes to the underlying storage mechanism.
- */
- protected ReentrantReadWriteLock storageLock = new ReentrantReadWriteLock();
-
- /**
- * Constructor for the DiskCache object.
- * <p>
- *
- * @param cacheAttributes
- */
- public IndexedDiskCache(IndexedDiskCacheAttributes cacheAttributes)
- {
- this(cacheAttributes, null);
- }
-
- /**
- * Constructor for the DiskCache object.
- * <p>
- *
- * @param cattr
- * @param elementSerializer
- * used if supplied, the super's super will not set a null
- */
- public IndexedDiskCache(IndexedDiskCacheAttributes cattr, IElementSerializer elementSerializer)
- {
- super(cattr);
-
- setElementSerializer(elementSerializer);
-
- this.cattr = cattr;
- this.maxKeySize = cattr.getMaxKeySize();
- this.isRealTimeOptimizationEnabled = cattr.getOptimizeAtRemoveCount() > 0;
- this.isShutdownOptimizationEnabled = cattr.isOptimizeOnShutdown();
- this.logCacheName = "Region [" + getCacheName() + "] ";
- this.diskLimitType = cattr.getDiskLimitType();
- // Make a clean file name
- this.fileName = getCacheName().replaceAll("[^a-zA-Z0-9-_\\.]", "_");
- this.keyHash = createInitialKeyMap();
- this.queuedPutList = new ConcurrentSkipListSet<>(new PositionComparator());
- this.recycle = new ConcurrentSkipListSet<>();
-
- try
- {
- initializeFileSystem(cattr);
- initializeKeysAndData(cattr);
-
- // Initialization finished successfully, so set alive to true.
- setAlive(true);
- log.info("{0}: Indexed Disk Cache is alive.", logCacheName);
-
- // TODO: Should we improve detection of whether or not the file should be optimized.
- if (isRealTimeOptimizationEnabled && keyHash.size() > 0)
- {
- // Kick off a real time optimization, in case we didn't do a final optimization.
- doOptimizeRealTime();
- }
- }
- catch (IOException e)
- {
- log.error("{0}: Failure initializing for fileName: {1} and directory: {2}",
- logCacheName, fileName, this.rafDir.getAbsolutePath(), e);
- }
- }
-
- /**
- * Tries to create the root directory if it does not already exist.
- * <p>
- *
- * @param cattr
- */
- private void initializeFileSystem(IndexedDiskCacheAttributes cattr)
- {
- this.rafDir = cattr.getDiskPath();
- log.info("{0}: Cache file root directory: {1}", logCacheName, rafDir);
- }
-
- /**
- * Creates the key and data disk caches.
- * <p>
- * Loads any keys if they are present and ClearDiskOnStartup is false.
- * <p>
- *
- * @param cattr
- * @throws IOException
- */
- private void initializeKeysAndData(IndexedDiskCacheAttributes cattr) throws IOException
- {
- this.dataFile = new IndexedDisk(new File(rafDir, fileName + ".data"), getElementSerializer());
- this.keyFile = new IndexedDisk(new File(rafDir, fileName + ".key"), getElementSerializer());
-
- if (cattr.isClearDiskOnStartup())
- {
- log.info("{0}: ClearDiskOnStartup is set to true. Ingnoring any persisted data.",
- logCacheName);
- initializeEmptyStore();
- }
- else if (keyFile.length() > 0)
- {
- // If the key file has contents, try to initialize the keys
- // from it. In no keys are loaded reset the data file.
- initializeStoreFromPersistedData();
- }
- else
- {
- // Otherwise start with a new empty map for the keys, and reset
- // the data file if it has contents.
- initializeEmptyStore();
- }
- }
-
- /**
- * Initializes an empty disk cache.
- * <p>
- *
- * @throws IOException
- */
- private void initializeEmptyStore() throws IOException
- {
- this.keyHash.clear();
-
- if (dataFile.length() > 0)
- {
- dataFile.reset();
- }
- }
-
- /**
- * Loads any persisted data and checks for consistency. If there is a consistency issue, the
- * files are cleared.
- * <p>
- *
- * @throws IOException
- */
- private void initializeStoreFromPersistedData() throws IOException
- {
- loadKeys();
-
- if (keyHash.isEmpty())
- {
- dataFile.reset();
- }
- else
- {
- boolean isOk = checkKeyDataConsistency(false);
- if (!isOk)
- {
- keyHash.clear();
- keyFile.reset();
- dataFile.reset();
- log.warn("{0}: Corruption detected. Resetting data and keys files.", logCacheName);
- }
- else
- {
- synchronized (this)
- {
- startupSize = keyHash.size();
- }
- }
- }
- }
-
- /**
- * Loads the keys from the .key file. The keys are stored in a HashMap on disk. This is
- * converted into a LRUMap.
- */
- protected void loadKeys()
- {
- log.debug("{0}: Loading keys for {1}", () -> logCacheName, () -> keyFile.toString());
-
- storageLock.writeLock().lock();
-
- try
- {
- // clear a key map to use.
- keyHash.clear();
-
- HashMap<K, IndexedDiskElementDescriptor> keys = keyFile.readObject(
- new IndexedDiskElementDescriptor(0, (int) keyFile.length() - IndexedDisk.HEADER_SIZE_BYTES));
-
- if (keys != null)
- {
- log.debug("{0}: Found {1} in keys file.", logCacheName, keys.size());
-
- keyHash.putAll(keys);
-
- log.info("{0}: Loaded keys from [{1}], key count: {2}; up to {3} will be available.",
- () -> logCacheName, () -> fileName, () -> keyHash.size(), () -> maxKeySize);
- }
-
- if (log.isTraceEnabled())
- {
- dump(false);
- }
- }
- catch (Exception e)
- {
- log.error("{0}: Problem loading keys for file {1}", logCacheName, fileName, e);
- }
- finally
- {
- storageLock.writeLock().unlock();
- }
- }
-
- /**
- * Check for minimal consistency between the keys and the datafile. Makes sure no starting
- * positions in the keys exceed the file length.
- * <p>
- * The caller should take the appropriate action if the keys and data are not consistent.
- *
- * @param checkForDedOverlaps
- * if <code>true</code>, do a more thorough check by checking for
- * data overlap
- * @return <code>true</code> if the test passes
- */
- private boolean checkKeyDataConsistency(boolean checkForDedOverlaps)
- {
- ElapsedTimer timer = new ElapsedTimer();
- log.debug("{0}: Performing inital consistency check", logCacheName);
-
- boolean isOk = true;
- long fileLength = 0;
- try
- {
- fileLength = dataFile.length();
-
- for (Map.Entry<K, IndexedDiskElementDescriptor> e : keyHash.entrySet())
- {
- IndexedDiskElementDescriptor ded = e.getValue();
-
- isOk = ded.pos + IndexedDisk.HEADER_SIZE_BYTES + ded.len <= fileLength;
-
- if (!isOk)
- {
- log.warn("{0}: The dataFile is corrupted!\n raf.length() = {1}\n ded.pos = {2}",
- logCacheName, fileLength, ded.pos);
- break;
- }
- }
-
- if (isOk && checkForDedOverlaps)
- {
- isOk = checkForDedOverlaps(createPositionSortedDescriptorList());
- }
- }
- catch (IOException e)
- {
- log.error(e);
- isOk = false;
- }
-
- log.info("{0}: Finished inital consistency check, isOk = {1} in {2}",
- logCacheName, isOk, timer.getElapsedTimeString());
-
- return isOk;
- }
-
- /**
- * Detects any overlapping elements. This expects a sorted list.
- * <p>
- * The total length of an item is IndexedDisk.RECORD_HEADER + ded.len.
- * <p>
- *
- * @param sortedDescriptors
- * @return false if there are overlaps.
- */
- protected boolean checkForDedOverlaps(IndexedDiskElementDescriptor[] sortedDescriptors)
- {
- ElapsedTimer timer = new ElapsedTimer();
- boolean isOk = true;
- long expectedNextPos = 0;
- for (int i = 0; i < sortedDescriptors.length; i++)
- {
- IndexedDiskElementDescriptor ded = sortedDescriptors[i];
- if (expectedNextPos > ded.pos)
- {
- log.error("{0}: Corrupt file: overlapping deds {1}", logCacheName, ded);
- isOk = false;
- break;
- }
- else
- {
- expectedNextPos = ded.pos + IndexedDisk.HEADER_SIZE_BYTES + ded.len;
- }
- }
- log.debug("{0}: Check for DED overlaps took {1} ms.", () -> logCacheName,
- () -> timer.getElapsedTime());
-
- return isOk;
- }
-
- /**
- * Saves key file to disk. This converts the LRUMap to a HashMap for deserialization.
- */
- protected void saveKeys()
- {
- try
- {
- log.info("{0}: Saving keys to: {1}, key count: {2}",
- () -> logCacheName, () -> fileName, () -> keyHash.size());
-
- keyFile.reset();
-
- HashMap<K, IndexedDiskElementDescriptor> keys = new HashMap<>();
- keys.putAll(keyHash);
-
- if (keys.size() > 0)
- {
- keyFile.writeObject(keys, 0);
- }
-
- log.info("{0}: Finished saving keys.", logCacheName);
- }
- catch (IOException e)
- {
- log.error("{0}: Problem storing keys.", logCacheName, e);
- }
- }
-
- /**
- * Update the disk cache. Called from the Queue. Makes sure the Item has not been retrieved from
- * purgatory while in queue for disk. Remove items from purgatory when they go to disk.
- * <p>
- *
- * @param ce
- * The ICacheElement<K, V> to put to disk.
- */
- @Override
- protected void processUpdate(ICacheElement<K, V> ce)
- {
- if (!isAlive())
- {
- log.error("{0}: No longer alive; aborting put of key = {1}",
- () -> logCacheName, () -> ce.getKey());
- return;
- }
-
- log.debug("{0}: Storing element on disk, key: {1}",
- () -> logCacheName, () -> ce.getKey());
-
- IndexedDiskElementDescriptor ded = null;
-
- // old element with same key
- IndexedDiskElementDescriptor old = null;
-
- try
- {
- byte[] data = getElementSerializer().serialize(ce);
-
- // make sure this only locks for one particular cache region
- storageLock.writeLock().lock();
- try
- {
- old = keyHash.get(ce.getKey());
-
- // Item with the same key already exists in file.
- // Try to reuse the location if possible.
- if (old != null && data.length <= old.len)
- {
- // Reuse the old ded. The defrag relies on ded updates by reference, not
- // replacement.
- ded = old;
- ded.len = data.length;
- }
- else
- {
- // we need this to compare in the recycle bin
- ded = new IndexedDiskElementDescriptor(dataFile.length(), data.length);
-
- if (doRecycle)
- {
- IndexedDiskElementDescriptor rep = recycle.ceiling(ded);
- if (rep != null)
- {
- // remove element from recycle bin
- recycle.remove(rep);
- ded = rep;
- ded.len = data.length;
- recycleCnt++;
- this.adjustBytesFree(ded, false);
- log.debug("{0}: using recycled ded {1} rep.len = {2} ded.len = {3}",
- logCacheName, ded.pos, rep.len, ded.len);
- }
- }
-
- // Put it in the map
- keyHash.put(ce.getKey(), ded);
-
- if (queueInput)
- {
- queuedPutList.add(ded);
- log.debug("{0}: added to queued put list. {1}",
- () -> logCacheName, () -> queuedPutList.size());
- }
-
- // add the old slot to the recycle bin
- if (old != null)
- {
- addToRecycleBin(old);
- }
- }
-
- dataFile.write(ded, data);
- }
- finally
- {
- storageLock.writeLock().unlock();
- }
-
- log.debug("{0}: Put to file: {1}, key: {2}, position: {3}, size: {4}",
- logCacheName, fileName, ce.getKey(), ded.pos, ded.len);
- }
- catch (IOException e)
- {
- log.error("{0}: Failure updating element, key: {1} old: {2}",
- logCacheName, ce.getKey(), old, e);
- }
- }
-
- /**
- * Gets the key, then goes to disk to get the object.
- * <p>
- *
- * @param key
- * @return ICacheElement<K, V> or null
- * @see AbstractDiskCache#doGet
- */
- @Override
- protected ICacheElement<K, V> processGet(K key)
- {
- if (!isAlive())
- {
- log.error("{0}: No longer alive so returning null for key = {1}",
- logCacheName, key);
- return null;
- }
-
- log.debug("{0}: Trying to get from disk: {1}", logCacheName, key);
-
- ICacheElement<K, V> object = null;
- try
- {
- storageLock.readLock().lock();
- try
- {
- object = readElement(key);
- }
- finally
- {
- storageLock.readLock().unlock();
- }
-
- if (object != null)
- {
- hitCount.incrementAndGet();
- }
- }
- catch (IOException ioe)
- {
- log.error("{0}: Failure getting from disk, key = {1}", logCacheName, key, ioe);
- reset();
- }
- return object;
- }
-
- /**
- * Gets matching items from the cache.
- * <p>
- *
- * @param pattern
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache matching keys
- */
- @Override
- public Map<K, ICacheElement<K, V>> processGetMatching(String pattern)
- {
- Map<K, ICacheElement<K, V>> elements = new HashMap<>();
- Set<K> keyArray = null;
- storageLock.readLock().lock();
- try
- {
- keyArray = new HashSet<>(keyHash.keySet());
- }
- finally
- {
- storageLock.readLock().unlock();
- }
-
- Set<K> matchingKeys = getKeyMatcher().getMatchingKeysFromArray(pattern, keyArray);
-
- for (K key : matchingKeys)
- {
- ICacheElement<K, V> element = processGet(key);
- if (element != null)
- {
- elements.put(key, element);
- }
- }
- return elements;
- }
-
- /**
- * Reads the item from disk.
- * <p>
- *
- * @param key
- * @return ICacheElement
- * @throws IOException
- */
- private ICacheElement<K, V> readElement(K key) throws IOException
- {
- ICacheElement<K, V> object = null;
-
- IndexedDiskElementDescriptor ded = keyHash.get(key);
-
- if (ded != null)
- {
- log.debug("{0}: Found on disk, key: ", logCacheName, key);
-
- try
- {
- ICacheElement<K, V> readObject = dataFile.readObject(ded);
- object = readObject;
- // TODO consider checking key equality and throwing if there is a failure
- }
- catch (IOException e)
- {
- log.error("{0}: IO Exception, Problem reading object from file", logCacheName, e);
- throw e;
- }
- catch (Exception e)
- {
- log.error("{0}: Exception, Problem reading object from file", logCacheName, e);
- throw new IOException(logCacheName + "Problem reading object from disk.", e);
- }
- }
-
- return object;
- }
-
- /**
- * Return the keys in this cache.
- * <p>
- *
- * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#getKeySet()
- */
- @Override
- public Set<K> getKeySet() throws IOException
- {
- HashSet<K> keys = new HashSet<>();
-
- storageLock.readLock().lock();
-
- try
- {
- keys.addAll(this.keyHash.keySet());
- }
- finally
- {
- storageLock.readLock().unlock();
- }
-
- return keys;
- }
-
- /**
- * Returns true if the removal was successful; or false if there is nothing to remove. Current
- * implementation always result in a disk orphan.
- * <p>
- *
- * @return true if at least one item was removed.
- * @param key
- */
- @Override
- protected boolean processRemove(K key)
- {
- if (!isAlive())
- {
- log.error("{0}: No longer alive so returning false for key = {1}", logCacheName, key);
- return false;
- }
-
- if (key == null)
- {
- return false;
- }
-
- boolean reset = false;
- boolean removed = false;
- try
- {
- storageLock.writeLock().lock();
-
- if (key instanceof String && key.toString().endsWith(NAME_COMPONENT_DELIMITER))
- {
- removed = performPartialKeyRemoval((String) key);
- }
- else if (key instanceof GroupAttrName && ((GroupAttrName<?>) key).attrName == null)
- {
- removed = performGroupRemoval(((GroupAttrName<?>) key).groupId);
- }
- else
- {
- removed = performSingleKeyRemoval(key);
- }
- }
- finally
- {
- storageLock.writeLock().unlock();
- }
-
- if (reset)
- {
- reset();
- }
-
- // this increments the remove count.
- // there is no reason to call this if an item was not removed.
- if (removed)
- {
- doOptimizeRealTime();
- }
-
- return removed;
- }
-
- /**
- * Iterates over the keyset. Builds a list of matches. Removes all the keys in the list. Does
- * not remove via the iterator, since the map impl may not support it.
- * <p>
- * This operates under a lock obtained in doRemove().
- * <p>
- *
- * @param key
- * @return true if there was a match
- */
- private boolean performPartialKeyRemoval(String key)
- {
- boolean removed = false;
-
- // remove all keys of the same name hierarchy.
- List<K> itemsToRemove = new LinkedList<>();
-
- for (K k : keyHash.keySet())
- {
- if (k instanceof String && k.toString().startsWith(key))
- {
- itemsToRemove.add(k);
- }
- }
-
- // remove matches.
- for (K fullKey : itemsToRemove)
- {
- // Don't add to recycle bin here
- // https://issues.apache.org/jira/browse/JCS-67
- performSingleKeyRemoval(fullKey);
- removed = true;
- // TODO this needs to update the remove count separately
- }
-
- return removed;
- }
-
- /**
- * Remove all elements from the group. This does not use the iterator to remove. It builds a
- * list of group elements and then removes them one by one.
- * <p>
- * This operates under a lock obtained in doRemove().
- * <p>
- *
- * @param key
- * @return true if an element was removed
- */
- private boolean performGroupRemoval(GroupId key)
- {
- boolean removed = false;
-
- // remove all keys of the same name group.
- List<K> itemsToRemove = new LinkedList<>();
-
- // remove all keys of the same name hierarchy.
- for (K k : keyHash.keySet())
- {
- if (k instanceof GroupAttrName && ((GroupAttrName<?>) k).groupId.equals(key))
- {
- itemsToRemove.add(k);
- }
- }
-
- // remove matches.
- for (K fullKey : itemsToRemove)
- {
- // Don't add to recycle bin here
- // https://issues.apache.org/jira/browse/JCS-67
- performSingleKeyRemoval(fullKey);
- removed = true;
- // TODO this needs to update the remove count separately
- }
-
- return removed;
- }
-
- /**
- * Removes an individual key from the cache.
- * <p>
- * This operates under a lock obtained in doRemove().
- * <p>
- *
- * @param key
- * @return true if an item was removed.
- */
- private boolean performSingleKeyRemoval(K key)
- {
- boolean removed;
- // remove single item.
- IndexedDiskElementDescriptor ded = keyHash.remove(key);
- removed = ded != null;
- addToRecycleBin(ded);
-
- log.debug("{0}: Disk removal: Removed from key hash, key [{1}] removed = {2}",
- logCacheName, key, removed);
- return removed;
- }
-
- /**
- * Remove all the items from the disk cache by reseting everything.
- */
- @Override
- public void processRemoveAll()
- {
- ICacheEvent<String> cacheEvent =
- createICacheEvent(getCacheName(), "all", ICacheEventLogger.REMOVEALL_EVENT);
- try
- {
- reset();
- }
- finally
- {
- logICacheEvent(cacheEvent);
- }
- }
-
- /**
- * Reset effectively clears the disk cache, creating new files, recycle bins, and keymaps.
- * <p>
- * It can be used to handle errors by last resort, force content update, or removeall.
- */
- private void reset()
- {
- log.info("{0}: Resetting cache", logCacheName);
-
- try
- {
- storageLock.writeLock().lock();
-
- if (dataFile != null)
- {
- dataFile.close();
- }
-
- File dataFileTemp = new File(rafDir, fileName + ".data");
- Files.delete(dataFileTemp.toPath());
-
- if (keyFile != null)
- {
- keyFile.close();
- }
- File keyFileTemp = new File(rafDir, fileName + ".key");
- Files.delete(keyFileTemp.toPath());
-
- dataFile = new IndexedDisk(dataFileTemp, getElementSerializer());
- keyFile = new IndexedDisk(keyFileTemp, getElementSerializer());
-
- this.recycle.clear();
- this.keyHash.clear();
- }
- catch (IOException e)
- {
- log.error("{0}: Failure resetting state", logCacheName, e);
- }
- finally
- {
- storageLock.writeLock().unlock();
- }
- }
-
- /**
- * Create the map for keys that contain the index position on disk.
- *
- * @return a new empty Map for keys and IndexedDiskElementDescriptors
- */
- private Map<K, IndexedDiskElementDescriptor> createInitialKeyMap()
- {
- Map<K, IndexedDiskElementDescriptor> keyMap = null;
- if (maxKeySize >= 0)
- {
- if (this.diskLimitType == DiskLimitType.COUNT)
- {
- keyMap = new LRUMapCountLimited(maxKeySize);
- }
- else
- {
- keyMap = new LRUMapSizeLimited(maxKeySize);
- }
-
- log.info("{0}: Set maxKeySize to: \"{1}\"", logCacheName, maxKeySize);
- }
- else
- {
- // If no max size, use a plain map for memory and processing efficiency.
- keyMap = new HashMap<>();
- // keyHash = Collections.synchronizedMap( new HashMap() );
- log.info("{0}: Set maxKeySize to unlimited", logCacheName);
- }
-
- return keyMap;
- }
-
- /**
- * Dispose of the disk cache in a background thread. Joins against this thread to put a cap on
- * the disposal time.
- * <p>
- * TODO make dispose window configurable.
- */
- @Override
- public void processDispose()
- {
- ICacheEvent<String> cacheEvent = createICacheEvent(getCacheName(), "none", ICacheEventLogger.DISPOSE_EVENT);
- try
- {
- Thread t = new Thread(this::disposeInternal, "IndexedDiskCache-DisposalThread");
- t.start();
- // wait up to 60 seconds for dispose and then quit if not done.
- try
- {
- t.join(60 * 1000);
- }
- catch (InterruptedException ex)
- {
- log.error("{0}: Interrupted while waiting for disposal thread to finish.",
- logCacheName, ex);
- }
- }
- finally
- {
- logICacheEvent(cacheEvent);
- }
- }
-
- /**
- * Internal method that handles the disposal.
- */
- protected void disposeInternal()
- {
- if (!isAlive())
- {
- log.error("{0}: Not alive and dispose was called, filename: {1}",
- logCacheName, fileName);
- return;
- }
-
- // Prevents any interaction with the cache while we're shutting down.
- setAlive(false);
-
- Thread optimizationThread = currentOptimizationThread;
- if (isRealTimeOptimizationEnabled && optimizationThread != null)
- {
- // Join with the current optimization thread.
- log.debug("{0}: In dispose, optimization already in progress; waiting for completion.",
- logCacheName);
-
- try
- {
- optimizationThread.join();
- }
- catch (InterruptedException e)
- {
- log.error("{0}: Unable to join current optimization thread.",
- logCacheName, e);
- }
- }
- else if (isShutdownOptimizationEnabled && this.getBytesFree() > 0)
- {
- optimizeFile();
- }
-
- saveKeys();
-
- try
- {
- log.debug("{0}: Closing files, base filename: {1}", logCacheName,
- fileName);
- dataFile.close();
- dataFile = null;
- keyFile.close();
- keyFile = null;
- }
- catch (IOException e)
- {
- log.error("{0}: Failure closing files in dispose, filename: {1}",
- logCacheName, fileName, e);
- }
-
- log.info("{0}: Shutdown complete.", logCacheName);
- }
-
- /**
- * Add descriptor to recycle bin if it is not null. Adds the length of the item to the bytes
- * free.
- * <p>
- * This is called in three places: (1) When an item is removed. All item removals funnel down to the removeSingleItem method.
- * (2) When an item on disk is updated with a value that will not fit in the previous slot. (3) When the max key size is
- * reached, the freed slot will be added.
- * <p>
- *
- * @param ded
- */
- protected void addToRecycleBin(IndexedDiskElementDescriptor ded)
- {
- // reuse the spot
- if (ded != null)
- {
- storageLock.readLock().lock();
-
- try
- {
- adjustBytesFree(ded, true);
-
- if (doRecycle)
- {
- recycle.add(ded);
- log.debug("{0}: recycled ded {1}", logCacheName, ded);
- }
- }
- finally
- {
- storageLock.readLock().unlock();
- }
- }
- }
-
- /**
- * Performs the check for optimization, and if it is required, do it.
- */
- protected void doOptimizeRealTime()
- {
- if (isRealTimeOptimizationEnabled && !isOptimizing
- && removeCount++ >= cattr.getOptimizeAtRemoveCount())
- {
- isOptimizing = true;
-
- log.info("{0}: Optimizing file. removeCount [{1}] OptimizeAtRemoveCount [{2}]",
- logCacheName, removeCount, cattr.getOptimizeAtRemoveCount());
-
- if (currentOptimizationThread == null)
- {
- storageLock.writeLock().lock();
-
- try
- {
- if (currentOptimizationThread == null)
- {
- currentOptimizationThread = new Thread(() -> {
- optimizeFile();
- currentOptimizationThread = null;
- }, "IndexedDiskCache-OptimizationThread");
- }
- }
- finally
- {
- storageLock.writeLock().unlock();
- }
-
- if (currentOptimizationThread != null)
- {
- currentOptimizationThread.start();
- }
- }
- }
- }
-
- /**
- * File optimization is handled by this method. It works as follows:
- * <ol>
- * <li>Shutdown recycling and turn on queuing of puts.</li>
- * <li>Take a snapshot of the current descriptors. If there are any removes, ignore them, as they will be compacted during the
- * next optimization.</li>
- * <li>Optimize the snapshot. For each descriptor:
- * <ol>
- * <li>Obtain the write-lock.</li>
- * <li>Shift the element on the disk, in order to compact out the free space.</li>
- * <li>Release the write-lock. This allows elements to still be accessible during optimization.</li>
- * </ol>
- * </li>
- * <li>Obtain the write-lock.</li>
- * <li>All queued puts are made at the end of the file. Optimize these under a single write-lock.</li>
- * <li>Truncate the file.</li>
- * <li>Release the write-lock.</li>
- * <li>Restore system to standard operation.</li>
- * </ol>
- */
- protected void optimizeFile()
- {
- ElapsedTimer timer = new ElapsedTimer();
- timesOptimized++;
- log.info("{0}: Beginning Optimization #{1}", logCacheName, timesOptimized);
-
- // CREATE SNAPSHOT
- IndexedDiskElementDescriptor[] defragList = null;
-
- storageLock.writeLock().lock();
-
- try
- {
- queueInput = true;
- // shut off recycle while we're optimizing,
- doRecycle = false;
- defragList = createPositionSortedDescriptorList();
- }
- finally
- {
- storageLock.writeLock().unlock();
- }
-
- // Defrag the file outside of the write lock. This allows a move to be made,
- // and yet have the element still accessible for reading or writing.
- long expectedNextPos = defragFile(defragList, 0);
-
- // ADD THE QUEUED ITEMS to the end and then truncate
- storageLock.writeLock().lock();
-
- try
- {
- try
- {
- if (!queuedPutList.isEmpty())
- {
- defragList = queuedPutList.toArray(new IndexedDiskElementDescriptor[queuedPutList.size()]);
-
- // pack them at the end
- expectedNextPos = defragFile(defragList, expectedNextPos);
- }
- // TRUNCATE THE FILE
- dataFile.truncate(expectedNextPos);
- }
- catch (IOException e)
- {
- log.error("{0}: Error optimizing queued puts.", logCacheName, e);
- }
-
- // RESTORE NORMAL OPERATION
- removeCount = 0;
- resetBytesFree();
- this.recycle.clear();
- queuedPutList.clear();
- queueInput = false;
- // turn recycle back on.
- doRecycle = true;
- isOptimizing = false;
- }
- finally
- {
- storageLock.writeLock().unlock();
- }
-
- log.info("{0}: Finished #{1}, Optimization took {2}",
- logCacheName, timesOptimized, timer.getElapsedTimeString());
- }
-
- /**
- * Defragments the file in place by compacting out the free space (i.e., moving records
- * forward). If there were no gaps the resulting file would be the same size as the previous
- * file. This must be supplied an ordered defragList.
- * <p>
- *
- * @param defragList
- * sorted list of descriptors for optimization
- * @param startingPos
- * the start position in the file
- * @return this is the potential new file end
- */
- private long defragFile(IndexedDiskElementDescriptor[] defragList, long startingPos)
- {
- ElapsedTimer timer = new ElapsedTimer();
- long preFileSize = 0;
- long postFileSize = 0;
- long expectedNextPos = 0;
- try
- {
- preFileSize = this.dataFile.length();
- // find the first gap in the disk and start defragging.
- expectedNextPos = startingPos;
- for (int i = 0; i < defragList.length; i++)
- {
- storageLock.writeLock().lock();
- try
- {
- if (expectedNextPos != defragList[i].pos)
- {
- dataFile.move(defragList[i], expectedNextPos);
- }
- expectedNextPos = defragList[i].pos + IndexedDisk.HEADER_SIZE_BYTES + defragList[i].len;
- }
- finally
- {
- storageLock.writeLock().unlock();
- }
- }
-
- postFileSize = this.dataFile.length();
-
- // this is the potential new file end
- return expectedNextPos;
- }
- catch (IOException e)
- {
- log.error("{0}: Error occurred during defragmentation.", logCacheName, e);
- }
- finally
- {
- log.info("{0}: Defragmentation took {1}. File Size (before={2}) (after={3}) (truncating to {4})",
- logCacheName, timer.getElapsedTimeString(), preFileSize, postFileSize, expectedNextPos);
- }
-
- return 0;
- }
-
- /**
- * Creates a snapshot of the IndexedDiskElementDescriptors in the keyHash and returns them
- * sorted by position in the dataFile.
- * <p>
- *
- * @return IndexedDiskElementDescriptor[]
- */
- private IndexedDiskElementDescriptor[] createPositionSortedDescriptorList()
- {
- List<IndexedDiskElementDescriptor> defragList = new ArrayList<>(keyHash.values());
- Collections.sort(defragList, new PositionComparator());
-
- return defragList.toArray(new IndexedDiskElementDescriptor[0]);
- }
-
- /**
- * Returns the current cache size.
- * <p>
- *
- * @return The size value
- */
- @Override
- public int getSize()
- {
- return keyHash.size();
- }
-
- /**
- * Returns the size of the recycle bin in number of elements.
- * <p>
- *
- * @return The number of items in the bin.
- */
- protected int getRecyleBinSize()
- {
- return this.recycle.size();
- }
-
- /**
- * Returns the number of times we have used spots from the recycle bin.
- * <p>
- *
- * @return The number of spots used.
- */
- protected int getRecyleCount()
- {
- return this.recycleCnt;
- }
-
- /**
- * Returns the number of bytes that are free. When an item is removed, its length is recorded.
- * When a spot is used form the recycle bin, the length of the item stored is recorded.
- * <p>
- *
- * @return The number bytes free on the disk file.
- */
- protected long getBytesFree()
- {
- return this.bytesFree.get();
- }
-
- /**
- * Resets the number of bytes that are free.
- */
- private void resetBytesFree()
- {
- this.bytesFree.set(0);
- }
-
- /**
- * To subtract you can pass in false for add..
- * <p>
- *
- * @param ded
- * @param add
- */
- private void adjustBytesFree(IndexedDiskElementDescriptor ded, boolean add)
- {
- if (ded != null)
- {
- int amount = ded.len + IndexedDisk.HEADER_SIZE_BYTES;
-
- if (add)
- {
- this.bytesFree.addAndGet(amount);
- }
- else
- {
- this.bytesFree.addAndGet(-amount);
- }
- }
- }
-
- /**
- * This is for debugging and testing.
- * <p>
- *
- * @return the length of the data file.
- * @throws IOException
- */
- protected long getDataFileSize() throws IOException
- {
- long size = 0;
-
- storageLock.readLock().lock();
-
- try
- {
- if (dataFile != null)
- {
- size = dataFile.length();
- }
- }
- finally
- {
- storageLock.readLock().unlock();
- }
-
- return size;
- }
-
- /**
- * For debugging. This dumps the values by default.
- */
- public void dump()
- {
- dump(true);
- }
-
- /**
- * For debugging.
- * <p>
- *
- * @param dumpValues
- * A boolean indicating if values should be dumped.
- */
- public void dump(boolean dumpValues)
- {
- if (log.isTraceEnabled())
- {
- log.trace("{0}: [dump] Number of keys: {1}", logCacheName, keyHash.size());
-
- for (Map.Entry<K, IndexedDiskElementDescriptor> e : keyHash.entrySet())
- {
- K key = e.getKey();
- IndexedDiskElementDescriptor ded = e.getValue();
-
- log.trace("{0}: [dump] Disk element, key: {1}, pos: {2}, len: {3}" +
- (dumpValues ? ", val: " + get(key) : ""),
- logCacheName, key, ded.pos, ded.len);
- }
- }
- }
-
- /**
- * @return Returns the AuxiliaryCacheAttributes.
- */
- @Override
- public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
- {
- return this.cattr;
- }
-
- /**
- * Returns info about the disk cache.
- * <p>
- *
- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getStatistics()
- */
- @Override
- public synchronized IStats getStatistics()
- {
- IStats stats = new Stats();
- stats.setTypeName("Indexed Disk Cache");
-
- ArrayList<IStatElement<?>> elems = new ArrayList<>();
-
- elems.add(new StatElement<>("Is Alive", Boolean.valueOf(isAlive())));
- elems.add(new StatElement<>("Key Map Size", Integer.valueOf(this.keyHash != null ? this.keyHash.size() : -1)));
- try
- {
- elems.add(
- new StatElement<>("Data File Length", Long.valueOf(this.dataFile != null ? this.dataFile.length() : -1L)));
- }
- catch (IOException e)
- {
- log.error(e);
- }
- elems.add(new StatElement<>("Max Key Size", this.maxKeySize));
- elems.add(new StatElement<>("Hit Count", this.hitCount));
- elems.add(new StatElement<>("Bytes Free", this.bytesFree));
- elems.add(new StatElement<>("Optimize Operation Count", Integer.valueOf(this.removeCount)));
- elems.add(new StatElement<>("Times Optimized", Integer.valueOf(this.timesOptimized)));
- elems.add(new StatElement<>("Recycle Count", Integer.valueOf(this.recycleCnt)));
- elems.add(new StatElement<>("Recycle Bin Size", Integer.valueOf(this.recycle.size())));
- elems.add(new StatElement<>("Startup Size", Integer.valueOf(this.startupSize)));
-
- // get the stats from the super too
- IStats sStats = super.getStatistics();
- elems.addAll(sStats.getStatElements());
-
- stats.setStatElements(elems);
-
- return stats;
- }
-
- /**
- * This is exposed for testing.
- * <p>
- *
- * @return Returns the timesOptimized.
- */
- protected int getTimesOptimized()
- {
- return timesOptimized;
- }
-
- /**
- * This is used by the event logging.
- * <p>
- *
- * @return the location of the disk, either path or ip.
- */
- @Override
- protected String getDiskLocation()
- {
- return dataFile.getFilePath();
- }
-
- /**
- * Compares IndexedDiskElementDescriptor based on their position.
- * <p>
- */
- protected static final class PositionComparator implements Comparator<IndexedDiskElementDescriptor>, Serializable
- {
- /** serialVersionUID */
- private static final long serialVersionUID = -8387365338590814113L;
-
- /**
- * Compares two descriptors based on position.
- * <p>
- *
- * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
- */
- @Override
- public int compare(IndexedDiskElementDescriptor ded1, IndexedDiskElementDescriptor ded2)
- {
- if (ded1.pos < ded2.pos)
- {
- return -1;
- }
- else if (ded1.pos == ded2.pos)
- {
- return 0;
- }
- else
- {
- return 1;
- }
- }
- }
-
- /**
- * Class for recycling and lru. This implements the LRU overflow callback, so we can add items
- * to the recycle bin. This class counts the size element to decide, when to throw away an element
- */
- public class LRUMapSizeLimited extends AbstractLRUMap<K, IndexedDiskElementDescriptor>
- {
- /**
- * <code>tag</code> tells us which map we are working on.
- */
- public static final String TAG = "orig";
-
- // size of the content in kB
- private AtomicInteger contentSize;
- private int maxSize;
-
- /**
- * Default
- */
- public LRUMapSizeLimited()
- {
- this(-1);
- }
-
- /**
- * @param maxKeySize
- */
- public LRUMapSizeLimited(int maxKeySize)
- {
- super();
- this.maxSize = maxKeySize;
- this.contentSize = new AtomicInteger(0);
- }
-
- // keep the content size in kB, so 2^31 kB is reasonable value
- private void subLengthFromCacheSize(IndexedDiskElementDescriptor value)
- {
- contentSize.addAndGet((value.len + IndexedDisk.HEADER_SIZE_BYTES) / -1024 - 1);
- }
-
- // keep the content size in kB, so 2^31 kB is reasonable value
- private void addLengthToCacheSize(IndexedDiskElementDescriptor value)
- {
- contentSize.addAndGet((value.len + IndexedDisk.HEADER_SIZE_BYTES) / 1024 + 1);
- }
-
- @Override
- public IndexedDiskElementDescriptor put(K key, IndexedDiskElementDescriptor value)
- {
- IndexedDiskElementDescriptor oldValue = null;
-
- try
- {
- oldValue = super.put(key, value);
- }
- finally
- {
- // keep the content size in kB, so 2^31 kB is reasonable value
- if (value != null)
- {
- addLengthToCacheSize(value);
- }
- if (oldValue != null)
- {
- subLengthFromCacheSize(oldValue);
- }
- }
-
- return oldValue;
- }
-
- @Override
- public IndexedDiskElementDescriptor remove(Object key)
- {
- IndexedDiskElementDescriptor value = null;
-
- try
- {
- value = super.remove(key);
- return value;
- }
- finally
- {
- if (value != null)
- {
- subLengthFromCacheSize(value);
- }
- }
- }
-
- /**
- * This is called when the may key size is reached. The least recently used item will be
- * passed here. We will store the position and size of the spot on disk in the recycle bin.
- * <p>
- *
- * @param key
- * @param value
- */
- @Override
- protected void processRemovedLRU(K key, IndexedDiskElementDescriptor value)
- {
- if (value != null)
- {
- subLengthFromCacheSize(value);
- }
-
- addToRecycleBin(value);
-
- log.debug("{0}: Removing key: [{1}] from key store.", logCacheName, key);
- log.debug("{0}: Key store size: [{1}].", logCacheName, this.size());
-
- doOptimizeRealTime();
- }
-
- @Override
- protected boolean shouldRemove()
- {
- return maxSize > 0 && contentSize.get() > maxSize && this.size() > 0;
- }
- }
-
- /**
- * Class for recycling and lru. This implements the LRU overflow callback, so we can add items
- * to the recycle bin. This class counts the elements to decide, when to throw away an element
- */
-
- public class LRUMapCountLimited extends LRUMap<K, IndexedDiskElementDescriptor>
- // implements Serializable
- {
- public LRUMapCountLimited(int maxKeySize)
- {
- super(maxKeySize);
- }
-
- /**
- * This is called when the may key size is reached. The least recently used item will be
- * passed here. We will store the position and size of the spot on disk in the recycle bin.
- * <p>
- *
- * @param key
- * @param value
- */
- @Override
- protected void processRemovedLRU(K key, IndexedDiskElementDescriptor value)
- {
- addToRecycleBin(value);
- log.debug("{0}: Removing key: [{1}] from key store.", logCacheName, key);
- log.debug("{0}: Key store size: [{1}].", logCacheName, this.size());
-
- doOptimizeRealTime();
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheAttributes.java
deleted file mode 100644
index fffaadb..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheAttributes.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.disk.AbstractDiskCacheAttributes;
-
-/**
- * Configuration class for the Indexed Disk Cache
- */
-public class IndexedDiskCacheAttributes
- extends AbstractDiskCacheAttributes
-{
- /** Don't change. */
- private static final long serialVersionUID = -2190863599358782950L;
-
- /** default value */
- private static final int DEFAULT_maxKeySize = 5000;
-
- /** -1 means no limit. */
- private int maxKeySize = DEFAULT_maxKeySize;
-
- /** default to -1, i.e., don't optimize until shutdown */
- private int optimizeAtRemoveCount = -1;
-
- /** Should we optimize on shutdown. */
- public static final boolean DEFAULT_OPTIMIZE_ON_SHUTDOWN = true;
-
- /** Should we optimize on shutdown. */
- private boolean optimizeOnShutdown = DEFAULT_OPTIMIZE_ON_SHUTDOWN;
-
- /** Should we clear the disk on startup. */
- public static final boolean DEFAULT_CLEAR_DISK_ON_STARTUP = false;
-
- /** Should we clear the disk on startup. If true the contents of disk are cleared. */
- private boolean clearDiskOnStartup = DEFAULT_CLEAR_DISK_ON_STARTUP;
-
- /**
- * Constructor for the DiskCacheAttributes object
- */
- public IndexedDiskCacheAttributes()
- {
- super();
- }
-
- /**
- * Gets the maxKeySize attribute of the DiskCacheAttributes object
- * <p>
- * @return The maxKeySize value
- */
- public int getMaxKeySize()
- {
- return this.maxKeySize;
- }
-
- /**
- * Sets the maxKeySize attribute of the DiskCacheAttributes object
- * <p>
- * @param maxKeySize The new maxKeySize value
- */
- public void setMaxKeySize( int maxKeySize )
- {
- this.maxKeySize = maxKeySize;
- }
-
- /**
- * Gets the optimizeAtRemoveCount attribute of the DiskCacheAttributes object
- * <p>
- * @return The optimizeAtRemoveCount value
- */
- public int getOptimizeAtRemoveCount()
- {
- return this.optimizeAtRemoveCount;
- }
-
- /**
- * Sets the optimizeAtRemoveCount attribute of the DiskCacheAttributes object This number
- * determines how often the disk cache should run real time optimizations.
- * <p>
- * @param cnt The new optimizeAtRemoveCount value
- */
- public void setOptimizeAtRemoveCount( int cnt )
- {
- this.optimizeAtRemoveCount = cnt;
- }
-
- /**
- * @param optimizeOnShutdown The optimizeOnShutdown to set.
- */
- public void setOptimizeOnShutdown( boolean optimizeOnShutdown )
- {
- this.optimizeOnShutdown = optimizeOnShutdown;
- }
-
- /**
- * @return Returns the optimizeOnShutdown.
- */
- public boolean isOptimizeOnShutdown()
- {
- return optimizeOnShutdown;
- }
-
- /**
- * @param clearDiskOnStartup the clearDiskOnStartup to set
- */
- public void setClearDiskOnStartup( boolean clearDiskOnStartup )
- {
- this.clearDiskOnStartup = clearDiskOnStartup;
- }
-
- /**
- * @return the clearDiskOnStartup
- */
- public boolean isClearDiskOnStartup()
- {
- return clearDiskOnStartup;
- }
-
- /**
- * Write out the values for debugging purposes.
- * <p>
- * @return String
- */
- @Override
- public String toString()
- {
- StringBuilder str = new StringBuilder();
- str.append( "IndexedDiskCacheAttributes " );
- str.append( "\n diskPath = " + super.getDiskPath() );
- str.append( "\n maxPurgatorySize = " + super.getMaxPurgatorySize() );
- str.append( "\n maxKeySize = " + maxKeySize );
- str.append( "\n optimizeAtRemoveCount = " + optimizeAtRemoveCount );
- str.append( "\n shutdownSpoolTimeLimit = " + super.getShutdownSpoolTimeLimit() );
- str.append( "\n optimizeOnShutdown = " + optimizeOnShutdown );
- str.append( "\n clearDiskOnStartup = " + clearDiskOnStartup );
- return str.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheFactory.java
deleted file mode 100644
index 7d0822f..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheFactory.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * Creates disk cache instances.
- */
-public class IndexedDiskCacheFactory
- extends AbstractAuxiliaryCacheFactory
-{
- /** The logger. */
- private static final Log log = LogManager.getLog( IndexedDiskCacheFactory.class );
-
- /**
- * Create an instance of an IndexedDiskCache.
- * <p>
- * @param iaca cache attributes of this cache instance
- * @param cacheMgr This allows auxiliaries to reference the manager without assuming that it is
- * a singleton. This will allow JCS to be a non-singleton. Also, it makes it easier to
- * test.
- * @param cacheEventLogger
- * @param elementSerializer
- * @return IndexedDiskCache
- */
- @Override
- public <K, V> IndexedDiskCache<K, V> createCache( AuxiliaryCacheAttributes iaca, ICompositeCacheManager cacheMgr,
- ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
- {
- IndexedDiskCacheAttributes idca = (IndexedDiskCacheAttributes) iaca;
- log.debug( "Creating DiskCache for attributes = {0}", idca );
-
- IndexedDiskCache<K, V> cache = new IndexedDiskCache<>( idca, elementSerializer );
- cache.setCacheEventLogger( cacheEventLogger );
-
- return cache;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskDumper.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskDumper.java
deleted file mode 100644
index a6ab077..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskDumper.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-
-
-/**
- * Used to dump out a Disk cache from disk for debugging. This is meant to be
- * run as a command line utility for
- */
-public class IndexedDiskDumper
-{
- /**
- * The main program for the DiskDumper class
- * <p>
- * Creates a disk cache and then calls dump, which write out the contents to
- * a debug log.
- * <p>
- * @param args
- * The command line arguments
- */
- public static void main( String[] args )
- {
- if ( args.length != 1 )
- {
- System.out.println( "Usage: java org.apache.commons.jcs.auxiliary.disk.DiskDump <cache_name>" );
- System.exit( 0 );
- }
-
- IndexedDiskCacheAttributes attr = new IndexedDiskCacheAttributes();
-
- attr.setCacheName( args[0] );
- attr.setDiskPath( args[0] );
-
- IndexedDiskCache<Serializable, Serializable> dc = new IndexedDiskCache<>( attr );
- dc.dump( true );
- System.exit( 0 );
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskElementDescriptor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskElementDescriptor.java
deleted file mode 100644
index 5f5af18..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskElementDescriptor.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-
-/**
- * Disk objects are located by descriptor entries. These are saved on shutdown and loaded into
- * memory on startup.
- */
-public class IndexedDiskElementDescriptor
- implements Serializable, Comparable<IndexedDiskElementDescriptor>
-{
- /** Don't change */
- private static final long serialVersionUID = -3029163572847659450L;
-
- /** Position of the cache data entry on disk. */
- long pos;
-
- /** Number of bytes the serialized form of the cache data takes. */
- int len;
-
- /**
- * Constructs a usable disk element descriptor.
- * <p>
- * @param pos
- * @param len
- */
- public IndexedDiskElementDescriptor( long pos, int len )
- {
- this.pos = pos;
- this.len = len;
- }
-
- /**
- * @return debug string
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "[DED: " );
- buf.append( " pos = " + pos );
- buf.append( " len = " + len );
- buf.append( "]" );
- return buf.toString();
- }
-
- /**
- * @see java.lang.Object#hashCode()
- */
- @Override
- public int hashCode()
- {
- return Long.valueOf(this.pos).hashCode() ^ Integer.valueOf(len).hashCode();
- }
-
- /**
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals(Object o)
- {
- if (o == null)
- {
- return false;
- }
- else if (o instanceof IndexedDiskElementDescriptor)
- {
- IndexedDiskElementDescriptor ided = (IndexedDiskElementDescriptor)o;
- return pos == ided.pos && len == ided.len;
- }
-
- return false;
- }
-
- /**
- * Compares based on length, then on pos descending.
- * <p>
- * @param o Object
- * @return int
- */
- @Override
- public int compareTo( IndexedDiskElementDescriptor o )
- {
- if ( o == null )
- {
- return 1;
- }
-
- if ( o.len == len )
- {
- if ( o.pos == pos )
- {
- return 0;
- }
- else if ( o.pos < pos )
- {
- return -1;
- }
- else
- {
- return 1;
- }
- }
- else if ( o.len > len )
- {
- return -1;
- }
- else
- {
- return 1;
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCache.java
deleted file mode 100644
index a60b81d..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCache.java
+++ /dev/null
@@ -1,878 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Timestamp;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.sql.DataSource;
-
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.engine.stats.StatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.serialization.StandardSerializer;
-
-/**
- * This is the jdbc disk cache plugin.
- * <p>
- * It expects a table created by the following script. The table name is configurable.
- * <p>
- *
- * <pre>
- * drop TABLE JCS_STORE;
- * CREATE TABLE JCS_STORE
- * (
- * CACHE_KEY VARCHAR(250) NOT NULL,
- * REGION VARCHAR(250) NOT NULL,
- * ELEMENT BLOB,
- * CREATE_TIME TIMESTAMP,
- * UPDATE_TIME_SECONDS BIGINT,
- * MAX_LIFE_SECONDS BIGINT,
- * SYSTEM_EXPIRE_TIME_SECONDS BIGINT,
- * IS_ETERNAL CHAR(1),
- * PRIMARY KEY (CACHE_KEY, REGION)
- * );
- * </pre>
- * <p>
- * The cleanup thread will delete non eternal items where (now - create time) > max life seconds *
- * 1000
- * <p>
- * To speed up the deletion the SYSTEM_EXPIRE_TIME_SECONDS is used instead. It is recommended that
- * an index be created on this column is you will have over a million records.
- * <p>
- * @author Aaron Smuts
- */
-public class JDBCDiskCache<K, V>
- extends AbstractDiskCache<K, V>
-{
- /** The local logger. */
- private static final Log log = LogManager.getLog( JDBCDiskCache.class );
-
- /** custom serialization */
- private IElementSerializer elementSerializer = new StandardSerializer();
-
- /** configuration */
- private JDBCDiskCacheAttributes jdbcDiskCacheAttributes;
-
- /** # of times update was called */
- private AtomicInteger updateCount = new AtomicInteger(0);
-
- /** # of times get was called */
- private AtomicInteger getCount = new AtomicInteger(0);
-
- /** # of times getMatching was called */
- private AtomicInteger getMatchingCount = new AtomicInteger(0);
-
- /** if count % interval == 0 then log */
- private static final int LOG_INTERVAL = 100;
-
- /** db connection pool */
- private DataSourceFactory dsFactory = null;
-
- /** tracks optimization */
- private TableState tableState;
-
- /**
- * Constructs a JDBC Disk Cache for the provided cache attributes. The table state object is
- * used to mark deletions.
- * <p>
- * @param cattr the configuration object for this cache
- * @param dsFactory the DataSourceFactory for this cache
- * @param tableState an object to track table operations
- * @param compositeCacheManager the global cache manager
- */
- public JDBCDiskCache( JDBCDiskCacheAttributes cattr, DataSourceFactory dsFactory, TableState tableState,
- ICompositeCacheManager compositeCacheManager )
- {
- super( cattr );
-
- setTableState( tableState );
- setJdbcDiskCacheAttributes( cattr );
-
- log.info( "jdbcDiskCacheAttributes = {0}", () -> getJdbcDiskCacheAttributes() );
-
- // This initializes the pool access.
- this.dsFactory = dsFactory;
-
- // Initialization finished successfully, so set alive to true.
- setAlive(true);
- }
-
- /**
- * Inserts or updates. By default it will try to insert. If the item exists we will get an
- * error. It will then update. This behavior is configurable. The cache can be configured to
- * check before inserting.
- * <p>
- * @param ce
- */
- @Override
- protected void processUpdate( ICacheElement<K, V> ce )
- {
- updateCount.incrementAndGet();
-
- log.debug( "updating, ce = {0}", ce );
-
- try (Connection con = getDataSource().getConnection())
- {
- log.debug( "Putting [{0}] on disk.", () -> ce.getKey());
-
- byte[] element;
-
- try
- {
- element = getElementSerializer().serialize( ce );
- }
- catch ( IOException e )
- {
- log.error( "Could not serialize element", e );
- return;
- }
-
- insertOrUpdate( ce, con, element );
- }
- catch ( SQLException e )
- {
- log.error( "Problem getting connection.", e );
- }
-
- if ( log.isInfoEnabled() )
- {
- if ( updateCount.get() % LOG_INTERVAL == 0 )
- {
- // TODO make a log stats method
- log.info( "Update Count [{0}]", updateCount);
- }
- }
- }
-
- /**
- * If test before insert it true, we check to see if the element exists. If the element exists
- * we will update. Otherwise, we try inserting. If this fails because the item exists, we will
- * update.
- * <p>
- * @param ce
- * @param con
- * @param element
- */
- private void insertOrUpdate( ICacheElement<K, V> ce, Connection con, byte[] element )
- {
- boolean exists = false;
-
- // First do a query to determine if the element already exists
- if ( this.getJdbcDiskCacheAttributes().isTestBeforeInsert() )
- {
- exists = doesElementExist( ce, con );
- }
-
- // If it doesn't exist, insert it, otherwise update
- if ( !exists )
- {
- exists = insertRow( ce, con, element );
- }
-
- // update if it exists.
- if ( exists )
- {
- updateRow( ce, con, element );
- }
- }
-
- /**
- * This inserts a new row in the database.
- * <p>
- * @param ce
- * @param con
- * @param element
- * @return true if the insertion fails because the record exists.
- */
- private boolean insertRow( ICacheElement<K, V> ce, Connection con, byte[] element )
- {
- boolean exists = false;
- String sqlI = "insert into "
- + getJdbcDiskCacheAttributes().getTableName()
- + " (CACHE_KEY, REGION, ELEMENT, MAX_LIFE_SECONDS, IS_ETERNAL, CREATE_TIME, UPDATE_TIME_SECONDS, SYSTEM_EXPIRE_TIME_SECONDS) "
- + " values (?, ?, ?, ?, ?, ?, ?, ?)";
-
- try (PreparedStatement psInsert = con.prepareStatement( sqlI ))
- {
- psInsert.setString( 1, (String) ce.getKey() );
- psInsert.setString( 2, this.getCacheName() );
- psInsert.setBytes( 3, element );
- psInsert.setLong( 4, ce.getElementAttributes().getMaxLife() );
- if ( ce.getElementAttributes().getIsEternal() )
- {
- psInsert.setString( 5, "T" );
- }
- else
- {
- psInsert.setString( 5, "F" );
- }
- Timestamp createTime = new Timestamp( ce.getElementAttributes().getCreateTime() );
- psInsert.setTimestamp( 6, createTime );
-
- long now = System.currentTimeMillis() / 1000;
- psInsert.setLong( 7, now );
-
- long expireTime = now + ce.getElementAttributes().getMaxLife();
- psInsert.setLong( 8, expireTime );
-
- psInsert.execute();
- }
- catch ( SQLException e )
- {
- if ("23000".equals(e.getSQLState()))
- {
- exists = true;
- }
- else
- {
- log.error( "Could not insert element", e );
- }
-
- // see if it exists, if we didn't already
- if ( !exists && !this.getJdbcDiskCacheAttributes().isTestBeforeInsert() )
- {
- exists = doesElementExist( ce, con );
- }
- }
-
- return exists;
- }
-
- /**
- * This updates a row in the database.
- * <p>
- * @param ce
- * @param con
- * @param element
- */
- private void updateRow( ICacheElement<K, V> ce, Connection con, byte[] element )
- {
- String sqlU = "update " + getJdbcDiskCacheAttributes().getTableName()
- + " set ELEMENT = ?, CREATE_TIME = ?, UPDATE_TIME_SECONDS = ?, " + " SYSTEM_EXPIRE_TIME_SECONDS = ? "
- + " where CACHE_KEY = ? and REGION = ?";
-
- try (PreparedStatement psUpdate = con.prepareStatement( sqlU ))
- {
- psUpdate.setBytes( 1, element );
-
- Timestamp createTime = new Timestamp( ce.getElementAttributes().getCreateTime() );
- psUpdate.setTimestamp( 2, createTime );
-
- long now = System.currentTimeMillis() / 1000;
- psUpdate.setLong( 3, now );
-
- long expireTime = now + ce.getElementAttributes().getMaxLife();
- psUpdate.setLong( 4, expireTime );
-
- psUpdate.setString( 5, (String) ce.getKey() );
- psUpdate.setString( 6, this.getCacheName() );
- psUpdate.execute();
-
- log.debug( "ran update {0}", sqlU );
- }
- catch ( SQLException e )
- {
- log.error( "Error executing update sql [{0}]", sqlU, e );
- }
- }
-
- /**
- * Does an element exist for this key?
- * <p>
- * @param ce the cache element
- * @param con a database connection
- * @return boolean
- */
- protected boolean doesElementExist( ICacheElement<K, V> ce, Connection con )
- {
- boolean exists = false;
- // don't select the element, since we want this to be fast.
- String sqlS = "select CACHE_KEY from " + getJdbcDiskCacheAttributes().getTableName()
- + " where REGION = ? and CACHE_KEY = ?";
-
- try (PreparedStatement psSelect = con.prepareStatement( sqlS ))
- {
- psSelect.setString( 1, this.getCacheName() );
- psSelect.setString( 2, (String) ce.getKey() );
-
- try (ResultSet rs = psSelect.executeQuery())
- {
- exists = rs.next();
- }
-
- log.debug( "[{0}] existing status is {1}", ce.getKey(), exists );
- }
- catch ( SQLException e )
- {
- log.error( "Problem looking for item before insert.", e );
- }
-
- return exists;
- }
-
- /**
- * Queries the database for the value. If it gets a result, the value is deserialized.
- * <p>
- * @param key
- * @return ICacheElement
- * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#get(Object)
- */
- @Override
- protected ICacheElement<K, V> processGet( K key )
- {
- getCount.incrementAndGet();
-
- log.debug( "Getting [{0}] from disk", key );
-
- if ( !isAlive() )
- {
- return null;
- }
-
- ICacheElement<K, V> obj = null;
-
- byte[] data = null;
- try
- {
- // region, key
- String selectString = "select ELEMENT from " + getJdbcDiskCacheAttributes().getTableName()
- + " where REGION = ? and CACHE_KEY = ?";
-
- try (Connection con = getDataSource().getConnection())
- {
- try (PreparedStatement psSelect = con.prepareStatement( selectString ))
- {
- psSelect.setString( 1, this.getCacheName() );
- psSelect.setString( 2, key.toString() );
-
- try (ResultSet rs = psSelect.executeQuery())
- {
- if ( rs.next() )
- {
- data = rs.getBytes( 1 );
- }
- if ( data != null )
- {
- try
- {
- // USE THE SERIALIZER
- obj = getElementSerializer().deSerialize( data, null );
- }
- catch ( Exception e )
- {
- log.error( "Problem getting item for key [{0}]", key, e );
- }
- }
- }
- }
- }
- }
- catch ( SQLException sqle )
- {
- log.error( "Caught a SQL exception trying to get the item for key [{0}]",
- key, sqle );
- }
-
- if ( log.isInfoEnabled() )
- {
- if ( getCount.get() % LOG_INTERVAL == 0 )
- {
- // TODO make a log stats method
- log.info( "Get Count [{0}]", getCount );
- }
- }
- return obj;
- }
-
- /**
- * This will run a like query. It will try to construct a usable query but different
- * implementations will be needed to adjust the syntax.
- * <p>
- * @param pattern
- * @return key,value map
- */
- @Override
- protected Map<K, ICacheElement<K, V>> processGetMatching( String pattern )
- {
- getMatchingCount.incrementAndGet();
-
- log.debug( "Getting [{0}] from disk", pattern);
-
- if ( !isAlive() )
- {
- return null;
- }
-
- Map<K, ICacheElement<K, V>> results = new HashMap<>();
-
- try
- {
- // region, key
- String selectString = "select CACHE_KEY, ELEMENT from " + getJdbcDiskCacheAttributes().getTableName()
- + " where REGION = ? and CACHE_KEY like ?";
-
- try (Connection con = getDataSource().getConnection())
- {
- try (PreparedStatement psSelect = con.prepareStatement( selectString ))
- {
- psSelect.setString( 1, this.getCacheName() );
- psSelect.setString( 2, constructLikeParameterFromPattern( pattern ) );
-
- try (ResultSet rs = psSelect.executeQuery())
- {
- while ( rs.next() )
- {
- String key = rs.getString( 1 );
- byte[] data = rs.getBytes( 2 );
- if ( data != null )
- {
- try
- {
- // USE THE SERIALIZER
- ICacheElement<K, V> value = getElementSerializer().deSerialize( data, null );
- results.put( (K) key, value );
- }
- catch ( Exception e )
- {
- log.error( "Problem getting items for pattern [{0}]", pattern, e );
- }
- }
- }
- }
- }
- }
- }
- catch ( SQLException sqle )
- {
- log.error( "Caught a SQL exception trying to get items for pattern [{0}]",
- pattern, sqle );
- }
-
- if ( log.isInfoEnabled() )
- {
- if ( getMatchingCount.get() % LOG_INTERVAL == 0 )
- {
- // TODO make a log stats method
- log.info( "Get Matching Count [{0}]", getMatchingCount);
- }
- }
- return results;
- }
-
- /**
- * @param pattern
- * @return String to use in the like query.
- */
- public String constructLikeParameterFromPattern( String pattern )
- {
- String likePattern = pattern.replaceAll( "\\.\\+", "%" );
- likePattern = likePattern.replaceAll( "\\.", "_" );
-
- log.debug( "pattern = [{0}]", likePattern );
-
- return likePattern;
- }
-
- /**
- * Returns true if the removal was successful; or false if there is nothing to remove. Current
- * implementation always results in a disk orphan.
- * <p>
- * @param key
- * @return boolean
- */
- @Override
- protected boolean processRemove( K key )
- {
- // remove single item.
- String sql = "delete from " + getJdbcDiskCacheAttributes().getTableName()
- + " where REGION = ? and CACHE_KEY = ?";
-
- try (Connection con = getDataSource().getConnection())
- {
- boolean partial = false;
- if ( key instanceof String && key.toString().endsWith( NAME_COMPONENT_DELIMITER ) )
- {
- // remove all keys of the same name group.
- sql = "delete from " + getJdbcDiskCacheAttributes().getTableName()
- + " where REGION = ? and CACHE_KEY like ?";
- partial = true;
- }
-
- try (PreparedStatement psSelect = con.prepareStatement( sql ))
- {
- psSelect.setString( 1, this.getCacheName() );
- if ( partial )
- {
- psSelect.setString( 2, key.toString() + "%" );
- }
- else
- {
- psSelect.setString( 2, key.toString() );
- }
-
- psSelect.executeUpdate();
-
- setAlive(true);
- }
- catch ( SQLException e )
- {
- log.error( "Problem creating statement. sql [{0}]", sql, e );
- setAlive(false);
- }
- }
- catch ( SQLException e )
- {
- log.error( "Problem updating cache.", e );
- reset();
- }
- return false;
- }
-
- /**
- * This should remove all elements. The auxiliary can be configured to forbid this behavior. If
- * remove all is not allowed, the method balks.
- */
- @Override
- protected void processRemoveAll()
- {
- // it should never get here from the abstract disk cache.
- if ( this.jdbcDiskCacheAttributes.isAllowRemoveAll() )
- {
- try (Connection con = getDataSource().getConnection())
- {
- String sql = "delete from " + getJdbcDiskCacheAttributes().getTableName() + " where REGION = ?";
-
- try (PreparedStatement psDelete = con.prepareStatement( sql ))
- {
- psDelete.setString( 1, this.getCacheName() );
- setAlive(true);
- psDelete.executeUpdate();
- }
- catch ( SQLException e )
- {
- log.error( "Problem creating statement.", e );
- setAlive(false);
- }
- }
- catch ( SQLException e )
- {
- log.error( "Problem removing all.", e );
- reset();
- }
- }
- else
- {
- log.info( "RemoveAll was requested but the request was not fulfilled: "
- + "allowRemoveAll is set to false." );
- }
- }
-
- /**
- * Removed the expired. (now - create time) > max life seconds * 1000
- * <p>
- * @return the number deleted
- */
- protected int deleteExpired()
- {
- int deleted = 0;
-
- try (Connection con = getDataSource().getConnection())
- {
- // The shrinker thread might kick in before the table is created
- // So check if the table exists first
- DatabaseMetaData dmd = con.getMetaData();
- ResultSet result = dmd.getTables(null, null,
- getJdbcDiskCacheAttributes().getTableName(), null);
-
- if (result.next())
- {
- getTableState().setState( TableState.DELETE_RUNNING );
- long now = System.currentTimeMillis() / 1000;
-
- String sql = "delete from " + getJdbcDiskCacheAttributes().getTableName()
- + " where IS_ETERNAL = ? and REGION = ? and ? > SYSTEM_EXPIRE_TIME_SECONDS";
-
- try (PreparedStatement psDelete = con.prepareStatement( sql ))
- {
- psDelete.setString( 1, "F" );
- psDelete.setString( 2, this.getCacheName() );
- psDelete.setLong( 3, now );
-
- setAlive(true);
-
- deleted = psDelete.executeUpdate();
- }
- catch ( SQLException e )
- {
- log.error( "Problem creating statement.", e );
- setAlive(false);
- }
-
- logApplicationEvent( getAuxiliaryCacheAttributes().getName(), "deleteExpired",
- "Deleted expired elements. URL: " + getDiskLocation() );
- }
- else
- {
- log.warn( "Trying to shrink non-existing table [{0}]",
- getJdbcDiskCacheAttributes().getTableName() );
- }
- }
- catch ( SQLException e )
- {
- logError( getAuxiliaryCacheAttributes().getName(), "deleteExpired",
- e.getMessage() + " URL: " + getDiskLocation() );
- log.error( "Problem removing expired elements from the table.", e );
- reset();
- }
- finally
- {
- getTableState().setState( TableState.FREE );
- }
-
- return deleted;
- }
-
- /**
- * Typically this is used to handle errors by last resort, force content update, or removeall
- */
- public void reset()
- {
- // nothing
- }
-
- /** Shuts down the pool */
- @Override
- public void processDispose()
- {
- ICacheEvent<K> cacheEvent = createICacheEvent( getCacheName(), (K)"none", ICacheEventLogger.DISPOSE_EVENT );
-
- try
- {
- dsFactory.close();
- }
- catch ( SQLException e )
- {
- log.error( "Problem shutting down.", e );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Returns the current cache size. Just does a count(*) for the region.
- * <p>
- * @return The size value
- */
- @Override
- public int getSize()
- {
- int size = 0;
-
- // region, key
- String selectString = "select count(*) from " + getJdbcDiskCacheAttributes().getTableName()
- + " where REGION = ?";
-
- try (Connection con = getDataSource().getConnection())
- {
- try (PreparedStatement psSelect = con.prepareStatement( selectString ))
- {
- psSelect.setString( 1, this.getCacheName() );
-
- try (ResultSet rs = psSelect.executeQuery())
- {
- if ( rs.next() )
- {
- size = rs.getInt( 1 );
- }
- }
- }
- }
- catch ( SQLException e )
- {
- log.error( "Problem getting size.", e );
- }
-
- return size;
- }
-
- /**
- * Return the keys in this cache.
- * <p>
- * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#getKeySet()
- */
- @Override
- public Set<K> getKeySet() throws IOException
- {
- throw new UnsupportedOperationException( "Groups not implemented." );
- // return null;
- }
-
- /**
- * @param elementSerializer The elementSerializer to set.
- */
- @Override
- public void setElementSerializer( IElementSerializer elementSerializer )
- {
- this.elementSerializer = elementSerializer;
- }
-
- /**
- * @return Returns the elementSerializer.
- */
- @Override
- public IElementSerializer getElementSerializer()
- {
- return elementSerializer;
- }
-
- /**
- * @param jdbcDiskCacheAttributes The jdbcDiskCacheAttributes to set.
- */
- protected void setJdbcDiskCacheAttributes( JDBCDiskCacheAttributes jdbcDiskCacheAttributes )
- {
- this.jdbcDiskCacheAttributes = jdbcDiskCacheAttributes;
- }
-
- /**
- * @return Returns the jdbcDiskCacheAttributes.
- */
- protected JDBCDiskCacheAttributes getJdbcDiskCacheAttributes()
- {
- return jdbcDiskCacheAttributes;
- }
-
- /**
- * @return Returns the AuxiliaryCacheAttributes.
- */
- @Override
- public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
- {
- return this.getJdbcDiskCacheAttributes();
- }
-
- /**
- * Extends the parent stats.
- * <p>
- * @return IStats
- */
- @Override
- public IStats getStatistics()
- {
- IStats stats = super.getStatistics();
- stats.setTypeName( "JDBC/Abstract Disk Cache" );
-
- List<IStatElement<?>> elems = stats.getStatElements();
-
- elems.add(new StatElement<>( "Update Count", updateCount ) );
- elems.add(new StatElement<>( "Get Count", getCount ) );
- elems.add(new StatElement<>( "Get Matching Count", getMatchingCount ) );
- elems.add(new StatElement<>( "DB URL", getJdbcDiskCacheAttributes().getUrl()) );
-
- stats.setStatElements( elems );
-
- return stats;
- }
-
- /**
- * Returns the name of the table.
- * <p>
- * @return the table name or UNDEFINED
- */
- protected String getTableName()
- {
- String name = "UNDEFINED";
- if ( this.getJdbcDiskCacheAttributes() != null )
- {
- name = this.getJdbcDiskCacheAttributes().getTableName();
- }
- return name;
- }
-
- /**
- * @param tableState The tableState to set.
- */
- public void setTableState( TableState tableState )
- {
- this.tableState = tableState;
- }
-
- /**
- * @return Returns the tableState.
- */
- public TableState getTableState()
- {
- return tableState;
- }
-
- /**
- * This is used by the event logging.
- * <p>
- * @return the location of the disk, either path or ip.
- */
- @Override
- protected String getDiskLocation()
- {
- return this.jdbcDiskCacheAttributes.getUrl();
- }
-
- /**
- * Public so managers can access it.
- * @return the dsFactory
- * @throws SQLException if getting a data source fails
- */
- public DataSource getDataSource() throws SQLException
- {
- return dsFactory.getDataSource();
- }
-
- /**
- * For debugging.
- * <p>
- * @return this.getStats();
- */
- @Override
- public String toString()
- {
- return this.getStats();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheAttributes.java
deleted file mode 100644
index d14202a..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheAttributes.java
+++ /dev/null
@@ -1,331 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.disk.AbstractDiskCacheAttributes;
-
-/**
- * The configurator will set these values based on what is in the cache.ccf file.
- * <p>
- * @author Aaron Smuts
- */
-public class JDBCDiskCacheAttributes
- extends AbstractDiskCacheAttributes
-{
- /** Don't change */
- private static final long serialVersionUID = -6535808344813320062L;
-
- /** default */
- private static final String DEFAULT_TABLE_NAME = "JCS_STORE";
-
- /** DB username */
- private String userName;
-
- /** DB password */
- private String password;
-
- /** URL for the db */
- private String url;
-
- /** The name of the database. */
- private String database = "";
-
- /** The driver */
- private String driverClassName;
-
- /** The JNDI path. */
- private String jndiPath;
-
- /** The time between two JNDI lookups */
- private long jndiTTL = 0L;
-
- /** The table name */
- private String tableName = DEFAULT_TABLE_NAME;
-
- /** If false we will insert and if it fails we will update. */
- private boolean testBeforeInsert = true;
-
- /** This is the default limit on the maximum number of active connections. */
- public static final int DEFAULT_MAX_TOTAL = 10;
-
- /** Max connections allowed */
- private int maxTotal = DEFAULT_MAX_TOTAL;
-
- /** This is the default setting for the cleanup routine. */
- public static final int DEFAULT_SHRINKER_INTERVAL_SECONDS = 300;
-
- /** How often should we remove expired. */
- private int shrinkerIntervalSeconds = DEFAULT_SHRINKER_INTERVAL_SECONDS;
-
- /** Should we remove expired in the background. */
- private boolean useDiskShrinker = true;
-
- /** The default Pool Name to which the connection pool will be keyed. */
- public static final String DEFAULT_POOL_NAME = "jcs";
-
- /**
- * If a pool name is supplied, the manager will attempt to load it. It should be configured in a
- * separate section as follows. Assuming the name is "MyPool":
- *
- * <pre>
- * jcs.jdbcconnectionpool.MyPool.attributes.userName=MyUserName
- * jcs.jdbcconnectionpool.MyPool.attributes.password=MyPassword
- * jcs.jdbcconnectionpool.MyPool.attributes.url=MyUrl
- * jcs.jdbcconnectionpool.MyPool.attributes.maxActive=MyMaxActive
- * jcs.jdbcconnectionpool.MyPool.attributes.driverClassName=MyDriverClassName
- * </pre>
- */
- private String connectionPoolName;
-
- /**
- * @param userName The userName to set.
- */
- public void setUserName( String userName )
- {
- this.userName = userName;
- }
-
- /**
- * @return Returns the userName.
- */
- public String getUserName()
- {
- return userName;
- }
-
- /**
- * @param password The password to set.
- */
- public void setPassword( String password )
- {
- this.password = password;
- }
-
- /**
- * @return Returns the password.
- */
- public String getPassword()
- {
- return password;
- }
-
- /**
- * @param url The url to set.
- */
- public void setUrl( String url )
- {
- this.url = url;
- }
-
- /**
- * @return Returns the url.
- */
- public String getUrl()
- {
- return url;
- }
-
- /**
- * This is appended to the url.
- * @param database The database to set.
- */
- public void setDatabase( String database )
- {
- this.database = database;
- }
-
- /**
- * @return Returns the database.
- */
- public String getDatabase()
- {
- return database;
- }
-
- /**
- * @param driverClassName The driverClassName to set.
- */
- public void setDriverClassName( String driverClassName )
- {
- this.driverClassName = driverClassName;
- }
-
- /**
- * @return Returns the driverClassName.
- */
- public String getDriverClassName()
- {
- return driverClassName;
- }
-
- /**
- * @return the jndiPath
- */
- public String getJndiPath()
- {
- return jndiPath;
- }
-
- /**
- * @param jndiPath the jndiPath to set
- */
- public void setJndiPath(String jndiPath)
- {
- this.jndiPath = jndiPath;
- }
-
- /**
- * @return the jndiTTL
- */
- public long getJndiTTL()
- {
- return jndiTTL;
- }
-
- /**
- * @param jndiTTL the jndiTTL to set
- */
- public void setJndiTTL(long jndiTTL)
- {
- this.jndiTTL = jndiTTL;
- }
-
- /**
- * @param tableName The tableName to set.
- */
- public void setTableName( String tableName )
- {
- this.tableName = tableName;
- }
-
- /**
- * @return Returns the tableName.
- */
- public String getTableName()
- {
- return tableName;
- }
-
- /**
- * If this is true then the disk cache will check to see if the item already exists in the
- * database. If it is false, it will try to insert. If the insert fails it will try to update.
- * <p>
- * @param testBeforeInsert The testBeforeInsert to set.
- */
- public void setTestBeforeInsert( boolean testBeforeInsert )
- {
- this.testBeforeInsert = testBeforeInsert;
- }
-
- /**
- * @return Returns the testBeforeInsert.
- */
- public boolean isTestBeforeInsert()
- {
- return testBeforeInsert;
- }
-
- /**
- * @param maxTotal The maxTotal to set.
- */
- public void setMaxTotal( int maxActive )
- {
- this.maxTotal = maxActive;
- }
-
- /**
- * @return Returns the maxTotal.
- */
- public int getMaxTotal()
- {
- return maxTotal;
- }
-
- /**
- * @param shrinkerIntervalSecondsArg The shrinkerIntervalSeconds to set.
- */
- public void setShrinkerIntervalSeconds( int shrinkerIntervalSecondsArg )
- {
- this.shrinkerIntervalSeconds = shrinkerIntervalSecondsArg;
- }
-
- /**
- * @return Returns the shrinkerIntervalSeconds.
- */
- public int getShrinkerIntervalSeconds()
- {
- return shrinkerIntervalSeconds;
- }
-
- /**
- * @param useDiskShrinker The useDiskShrinker to set.
- */
- public void setUseDiskShrinker( boolean useDiskShrinker )
- {
- this.useDiskShrinker = useDiskShrinker;
- }
-
- /**
- * @return Returns the useDiskShrinker.
- */
- public boolean isUseDiskShrinker()
- {
- return useDiskShrinker;
- }
-
- /**
- * @param connectionPoolName the connectionPoolName to set
- */
- public void setConnectionPoolName( String connectionPoolName )
- {
- this.connectionPoolName = connectionPoolName;
- }
-
- /**
- * @return the connectionPoolName
- */
- public String getConnectionPoolName()
- {
- return connectionPoolName;
- }
-
- /**
- * For debugging.
- * <p>
- * @return debug string with most of the properties.
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\nJDBCCacheAttributes" );
- buf.append( "\n UserName [" + getUserName() + "]" );
- buf.append( "\n Url [" + getUrl() + "]" );
- buf.append( "\n Database [" + getDatabase() + "]" );
- buf.append( "\n DriverClassName [" + getDriverClassName() + "]" );
- buf.append( "\n TableName [" + getTableName() + "]" );
- buf.append( "\n TestBeforeInsert [" + isTestBeforeInsert() + "]" );
- buf.append( "\n MaxActive [" + getMaxTotal() + "]" );
- buf.append( "\n AllowRemoveAll [" + isAllowRemoveAll() + "]" );
- buf.append( "\n ShrinkerIntervalSeconds [" + getShrinkerIntervalSeconds() + "]" );
- buf.append( "\n useDiskShrinker [" + isUseDiskShrinker() + "]" );
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheFactory.java
deleted file mode 100644
index 2868e82..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheFactory.java
+++ /dev/null
@@ -1,266 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc;
-
-/*
- * 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.
- */
-
-import java.sql.SQLException;
-import java.util.Properties;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.JndiDataSourceFactory;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.SharedPoolDataSourceFactory;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.behavior.IRequireScheduler;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.config.PropertySetter;
-
-/**
- * This factory should create JDBC auxiliary caches.
- * <p>
- * @author Aaron Smuts
- */
-public class JDBCDiskCacheFactory
- extends AbstractAuxiliaryCacheFactory
- implements IRequireScheduler
-{
- /** The logger */
- private static final Log log = LogManager.getLog( JDBCDiskCacheFactory.class );
-
- /**
- * A map of TableState objects to table names. Each cache has a table state object, which is
- * used to determine if any long processes such as deletes or optimizations are running.
- */
- private ConcurrentMap<String, TableState> tableStates;
-
- /** The background scheduler, one for all regions. Injected by the configurator */
- protected ScheduledExecutorService scheduler;
-
- /**
- * A map of table name to shrinker threads. This allows each table to have a different setting.
- * It assumes that there is only one jdbc disk cache auxiliary defined per table.
- */
- private ConcurrentMap<String, ShrinkerThread> shrinkerThreadMap;
-
- /** Pool name to DataSourceFactories */
- private ConcurrentMap<String, DataSourceFactory> dsFactories;
-
- /** props prefix */
- protected static final String POOL_CONFIGURATION_PREFIX = "jcs.jdbcconnectionpool.";
-
- /** .attributes */
- protected static final String ATTRIBUTE_PREFIX = ".attributes";
-
- /**
- * This factory method should create an instance of the jdbc cache.
- * <p>
- * @param rawAttr specific cache configuration attributes
- * @param compositeCacheManager the global cache manager
- * @param cacheEventLogger a specific logger for cache events
- * @param elementSerializer a serializer for cache elements
- * @return JDBCDiskCache the cache instance
- * @throws SQLException if the cache instance could not be created
- */
- @Override
- public <K, V> JDBCDiskCache<K, V> createCache( AuxiliaryCacheAttributes rawAttr,
- ICompositeCacheManager compositeCacheManager,
- ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
- throws SQLException
- {
- JDBCDiskCacheAttributes cattr = (JDBCDiskCacheAttributes) rawAttr;
- TableState tableState = getTableState( cattr.getTableName() );
- DataSourceFactory dsFactory = getDataSourceFactory(cattr, compositeCacheManager.getConfigurationProperties());
-
- JDBCDiskCache<K, V> cache = new JDBCDiskCache<>( cattr, dsFactory, tableState, compositeCacheManager );
- cache.setCacheEventLogger( cacheEventLogger );
- cache.setElementSerializer( elementSerializer );
-
- // create a shrinker if we need it.
- createShrinkerWhenNeeded( cattr, cache );
-
- return cache;
- }
-
- /**
- * Initialize this factory
- */
- @Override
- public void initialize()
- {
- super.initialize();
- this.tableStates = new ConcurrentHashMap<>();
- this.shrinkerThreadMap = new ConcurrentHashMap<>();
- this.dsFactories = new ConcurrentHashMap<>();
- }
-
- /**
- * Dispose of this factory, clean up shared resources
- */
- @Override
- public void dispose()
- {
- this.tableStates.clear();
-
- for (DataSourceFactory dsFactory : this.dsFactories.values())
- {
- try
- {
- dsFactory.close();
- }
- catch (SQLException e)
- {
- log.error("Could not close data source factory {0}", dsFactory.getName(), e);
- }
- }
-
- this.dsFactories.clear();
- this.shrinkerThreadMap.clear();
- super.dispose();
- }
-
- /**
- * Get a table state for a given table name
- *
- * @param tableName
- * @return a cached instance of the table state
- */
- protected TableState getTableState(String tableName)
- {
- return tableStates.computeIfAbsent(tableName, key -> new TableState(key));
- }
-
- /**
- * @see org.apache.commons.jcs.engine.behavior.IRequireScheduler#setScheduledExecutorService(java.util.concurrent.ScheduledExecutorService)
- */
- @Override
- public void setScheduledExecutorService(ScheduledExecutorService scheduledExecutor)
- {
- this.scheduler = scheduledExecutor;
- }
-
- /**
- * Get the scheduler service
- *
- * @return the scheduler
- */
- protected ScheduledExecutorService getScheduledExecutorService()
- {
- return scheduler;
- }
-
- /**
- * If UseDiskShrinker is true then we will create a shrinker daemon if necessary.
- * <p>
- * @param cattr
- * @param raf
- */
- protected void createShrinkerWhenNeeded( JDBCDiskCacheAttributes cattr, JDBCDiskCache<?, ?> raf )
- {
- // add cache to shrinker.
- if ( cattr.isUseDiskShrinker() )
- {
- ScheduledExecutorService shrinkerService = getScheduledExecutorService();
- ShrinkerThread shrinkerThread = shrinkerThreadMap.computeIfAbsent(cattr.getTableName(), key -> {
- ShrinkerThread newShrinkerThread = new ShrinkerThread();
-
- long intervalMillis = Math.max( 999, cattr.getShrinkerIntervalSeconds() * 1000 );
- log.info( "Setting the shrinker to run every [{0}] ms. for table [{1}]",
- intervalMillis, key );
- shrinkerService.scheduleAtFixedRate(newShrinkerThread, 0, intervalMillis, TimeUnit.MILLISECONDS);
-
- return newShrinkerThread;
- });
-
- shrinkerThread.addDiskCacheToShrinkList( raf );
- }
- }
-
- /**
- * manages the DataSourceFactories.
- * <p>
- * @param cattr the cache configuration
- * @param configProps the configuration properties object
- * @return a DataSourceFactory
- * @throws SQLException if a database access error occurs
- */
- protected DataSourceFactory getDataSourceFactory( JDBCDiskCacheAttributes cattr,
- Properties configProps ) throws SQLException
- {
- String poolName = null;
-
- if (cattr.getConnectionPoolName() == null)
- {
- poolName = cattr.getCacheName() + "." + JDBCDiskCacheAttributes.DEFAULT_POOL_NAME;
- }
- else
- {
- poolName = cattr.getConnectionPoolName();
- }
-
-
- DataSourceFactory dsFactory = this.dsFactories.computeIfAbsent(poolName, key -> {
- DataSourceFactory newDsFactory;
- JDBCDiskCacheAttributes dsConfig = null;
-
- if (cattr.getConnectionPoolName() == null)
- {
- dsConfig = cattr;
- }
- else
- {
- dsConfig = new JDBCDiskCacheAttributes();
- String dsConfigAttributePrefix = POOL_CONFIGURATION_PREFIX + key + ATTRIBUTE_PREFIX;
- PropertySetter.setProperties( dsConfig,
- configProps,
- dsConfigAttributePrefix + "." );
-
- dsConfig.setConnectionPoolName(key);
- }
-
- if ( dsConfig.getJndiPath() != null )
- {
- newDsFactory = new JndiDataSourceFactory();
- }
- else
- {
- newDsFactory = new SharedPoolDataSourceFactory();
- }
-
- try
- {
- newDsFactory.initialize(dsConfig);
- }
- catch (SQLException e)
- {
- throw new RuntimeException(e);
- }
- return newDsFactory;
- });
-
- return dsFactory;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/ShrinkerThread.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/ShrinkerThread.java
deleted file mode 100644
index 4e0a5d6..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/ShrinkerThread.java
+++ /dev/null
@@ -1,149 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc;
-
-import java.util.Iterator;
-import java.util.concurrent.CopyOnWriteArraySet;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.timing.ElapsedTimer;
-
-/**
- * Calls delete expired on the disk caches. The shrinker is run by a clock daemon. The shrinker
- * calls delete on each region. It pauses between calls.
- * <p>
- * @author Aaron Smuts
- */
-public class ShrinkerThread
- implements Runnable
-{
- /** The logger. */
- private static final Log log = LogManager.getLog( ShrinkerThread.class );
-
- /** A set of JDBCDiskCache objects to call deleteExpired on. */
- private final CopyOnWriteArraySet<JDBCDiskCache<?, ?>> shrinkSet =
- new CopyOnWriteArraySet<>();
-
- /** Default time period to use. */
- private static final long DEFAULT_PAUSE_BETWEEN_REGION_CALLS_MILLIS = 5000;
-
- /**
- * How long should we wait between calls to deleteExpired when we are iterating through the list
- * of regions. Delete can lock the table. We want to give clients a chance to get some work
- * done.
- */
- private long pauseBetweenRegionCallsMillis = DEFAULT_PAUSE_BETWEEN_REGION_CALLS_MILLIS;
-
- /**
- * Does nothing special.
- */
- protected ShrinkerThread()
- {
- super();
- }
-
- /**
- * Adds a JDBC disk cache to the set of disk cache to shrink.
- * <p>
- * @param diskCache
- */
- public void addDiskCacheToShrinkList( JDBCDiskCache<?, ?> diskCache )
- {
- // the set will prevent dupes.
- // we could also just add these to a hashmap by region name
- // but that might cause a problem if you wanted to use two different
- // jbdc disk caches for the same region.
- shrinkSet.add( diskCache );
- }
-
- /**
- * Calls deleteExpired on each item in the set. It pauses between each call.
- */
- @Override
- public void run()
- {
- try
- {
- deleteExpiredFromAllRegisteredRegions();
- }
- catch ( Throwable e )
- {
- log.error( "Caught an exception while trying to delete expired items.", e );
- }
- }
-
- /**
- * Deletes the expired items from all the registered regions.
- */
- private void deleteExpiredFromAllRegisteredRegions()
- {
- log.info( "Running JDBC disk cache shrinker. Number of regions [{0}]",
- () -> shrinkSet.size() );
-
- for (Iterator<JDBCDiskCache<?, ?>> i = shrinkSet.iterator(); i.hasNext();)
- {
- JDBCDiskCache<?, ?> cache = i.next();
- ElapsedTimer timer = new ElapsedTimer();
- int deleted = cache.deleteExpired();
-
- log.info( "Deleted [{0}] expired for region [{1}] for table [{2}] in {3} ms.",
- deleted, cache.getCacheName(), cache.getTableName(), timer.getElapsedTime() );
-
- // don't pause after the last call to delete expired.
- if ( i.hasNext() )
- {
- log.info( "Pausing for [{0}] ms before shrinking the next region.",
- this.getPauseBetweenRegionCallsMillis() );
-
- try
- {
- Thread.sleep( this.getPauseBetweenRegionCallsMillis() );
- }
- catch ( InterruptedException e )
- {
- log.warn( "Interrupted while waiting to delete expired for the next region." );
- }
- }
- }
- }
-
- /**
- * How long should we wait between calls to deleteExpired when we are iterating through the list
- * of regions.
- * <p>
- * @param pauseBetweenRegionCallsMillis The pauseBetweenRegionCallsMillis to set.
- */
- public void setPauseBetweenRegionCallsMillis( long pauseBetweenRegionCallsMillis )
- {
- this.pauseBetweenRegionCallsMillis = pauseBetweenRegionCallsMillis;
- }
-
- /**
- * How long should we wait between calls to deleteExpired when we are iterating through the list
- * of regions.
- * <p>
- * @return Returns the pauseBetweenRegionCallsMillis.
- */
- public long getPauseBetweenRegionCallsMillis()
- {
- return pauseBetweenRegionCallsMillis;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/TableState.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/TableState.java
deleted file mode 100644
index a862660..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/TableState.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-
-/**
- * This is used by various elements of the JDBC disk cache to indicate the
- * status of a table. The MySQL disk cache, for instance, marks the status as
- * optimizing when a scheduled optimization is taking place. This allows the
- * cache to balk rather than block during long running optimizations.
- * <p>
- * @author Aaron Smuts
- */
-public class TableState
- implements Serializable
-{
- /** Don't change. */
- private static final long serialVersionUID = -6625081552084964885L;
-
- /** Name of the table whose state this reflects. */
- private String tableName;
-
- /**
- * The table is free. It can be accessed and no potentially table locking
- * jobs are running.
- */
- public static final int FREE = 0;
-
- /** A potentially table locking deletion is running */
- public static final int DELETE_RUNNING = 1;
-
- /** A table locking optimization is running. */
- public static final int OPTIMIZATION_RUNNING = 2;
-
- /** we might want to add error */
- private int state = FREE;
-
- /**
- * Construct a usable table state.
- * <p>
- * @param tableName
- */
- public TableState( String tableName )
- {
- this.setTableName( tableName );
- }
-
- /**
- * @param tableName
- * The tableName to set.
- */
- public void setTableName( String tableName )
- {
- this.tableName = tableName;
- }
-
- /**
- * @return Returns the tableName.
- */
- public String getTableName()
- {
- return tableName;
- }
-
- /**
- * @param state
- * The state to set.
- */
- public void setState( int state )
- {
- this.state = state;
- }
-
- /**
- * @return Returns the state.
- */
- public int getState()
- {
- return state;
- }
-
- /**
- * Write out the values for debugging purposes.
- * <p>
- * @return String
- */
- @Override
- public String toString()
- {
- StringBuilder str = new StringBuilder();
- str.append( "TableState " );
- str.append( "\n TableName = " + getTableName() );
- str.append( "\n State = " + getState() );
- return str.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/dsfactory/DataSourceFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/dsfactory/DataSourceFactory.java
deleted file mode 100644
index 73b57e1..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/dsfactory/DataSourceFactory.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory;
-
-/*
- * 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.
- */
-
-import java.sql.SQLException;
-
-import javax.sql.DataSource;
-
-import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes;
-
-
-/**
- * A factory that returns a DataSource.
- * Borrowed from Apache DB Torque
- *
- * @author <a href="mailto:jmcnally@apache.org">John McNally</a>
- * @author <a href="mailto:fischer@seitenbau.de">Thomas Fischer</a>
- * @version $Id: DataSourceFactory.java 1336091 2012-05-09 11:09:40Z tfischer $
- */
-public interface DataSourceFactory
-{
- /**
- * Key for the configuration which contains DataSourceFactories
- */
- String DSFACTORY_KEY = "dsfactory";
-
- /**
- * Key for the configuration which contains the fully qualified name
- * of the factory implementation class
- */
- String FACTORY_KEY = "factory";
-
- /**
- * @return the name of the factory.
- */
- String getName();
-
- /**
- * @return the <code>DataSource</code> configured by the factory.
- * @throws SQLException if the source can't be returned
- */
- DataSource getDataSource() throws SQLException;
-
- /**
- * Initialize the factory.
- *
- * @param config the factory settings
- * @throws SQLException Any exceptions caught during processing will be
- * rethrown wrapped into a SQLException.
- */
- void initialize(JDBCDiskCacheAttributes config)
- throws SQLException;
-
- /**
- * A hook which is called when the resources of the associated DataSource
- * can be released.
- * After close() is called, the other methods may not work any more
- * (e.g. getDataSource() might return null).
- * It is not guaranteed that this method does anything. For example,
- * we do not want to close connections retrieved via JNDI, so the
- * JndiDataSouurceFactory does not close these connections
- *
- * @throws SQLException Any exceptions caught during processing will be
- * rethrown wrapped into a SQLException.
- */
- void close()
- throws SQLException;
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/dsfactory/JndiDataSourceFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/dsfactory/JndiDataSourceFactory.java
deleted file mode 100644
index ce84aef..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/dsfactory/JndiDataSourceFactory.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory;
-
-/*
- * 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.
- */
-
-import java.sql.SQLException;
-import java.util.Hashtable;
-import java.util.Map;
-
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-import javax.sql.DataSource;
-
-import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * A factory that looks up the DataSource from JNDI. It is also able
- * to deploy the DataSource based on properties found in the
- * configuration.
- *
- * This factory tries to avoid excessive context lookups to improve speed.
- * The time between two lookups can be configured. The default is 0 (no cache).
- *
- * Borrowed and adapted from Apache DB Torque
- *
- * @author <a href="mailto:jmcnally@apache.org">John McNally</a>
- * @author <a href="mailto:thomas@vandahl.org">Thomas Vandahl</a>
- */
-public class JndiDataSourceFactory implements DataSourceFactory
-{
- /** The log. */
- private static Log log = LogManager.getLog(JndiDataSourceFactory.class);
-
- /** The name of the factory. */
- private String name;
-
- /** The path to get the resource from. */
- private String path;
-
- /** The context to get the resource from. */
- private Context ctx;
-
- /** A locally cached copy of the DataSource */
- private DataSource ds = null;
-
- /** Time of last actual lookup action */
- private long lastLookup = 0;
-
- /** Time between two lookups */
- private long ttl = 0; // ms
-
- /**
- * @return the name of the factory.
- */
- @Override
- public String getName()
- {
- return name;
- }
-
- /**
- * @see org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#getDataSource()
- */
- @Override
- public DataSource getDataSource() throws SQLException
- {
- long time = System.currentTimeMillis();
-
- if (ds == null || time - lastLookup > ttl)
- {
- try
- {
- synchronized (ctx)
- {
- ds = ((DataSource) ctx.lookup(path));
- }
- lastLookup = time;
- }
- catch (NamingException e)
- {
- throw new SQLException(e);
- }
- }
-
- return ds;
- }
-
- /**
- * @see org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#initialize(JDBCDiskCacheAttributes)
- */
- @Override
- public void initialize(JDBCDiskCacheAttributes config) throws SQLException
- {
- this.name = config.getConnectionPoolName();
- initJNDI(config);
- }
-
- /**
- * Initializes JNDI.
- *
- * @param config where to read the settings from
- * @throws SQLException if a property set fails
- */
- private void initJNDI(JDBCDiskCacheAttributes config) throws SQLException
- {
- log.debug("Starting initJNDI");
-
- try
- {
- this.path = config.getJndiPath();
- log.debug("JNDI path: {0}", path);
-
- this.ttl = config.getJndiTTL();
- log.debug("Time between context lookups: {0}", ttl);
-
- Hashtable<String, Object> env = new Hashtable<>();
- ctx = new InitialContext(env);
-
- if (log.isTraceEnabled())
- {
- log.trace("Created new InitialContext");
- debugCtx(ctx);
- }
- }
- catch (NamingException e)
- {
- throw new SQLException(e);
- }
- }
-
- /**
- * Does nothing. We do not want to close a dataSource retrieved from Jndi,
- * because other applications might use it as well.
- */
- @Override
- public void close()
- {
- // do nothing
- }
-
- /**
- *
- * @param ctx the context
- * @throws NamingException
- */
- private void debugCtx(Context ctx) throws NamingException
- {
- log.trace("InitialContext -------------------------------");
- Map<?, ?> env = ctx.getEnvironment();
- log.trace("Environment properties: {0}", env.size());
- env.forEach((key, value) -> log.trace(" {0}: {1}", key, value));
- log.trace("----------------------------------------------");
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/dsfactory/SharedPoolDataSourceFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/dsfactory/SharedPoolDataSourceFactory.java
deleted file mode 100644
index 1104f96..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/dsfactory/SharedPoolDataSourceFactory.java
+++ /dev/null
@@ -1,152 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory;
-
-/*
- * 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.
- */
-
-import java.sql.SQLException;
-
-import javax.sql.ConnectionPoolDataSource;
-import javax.sql.DataSource;
-
-import org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS;
-import org.apache.commons.dbcp2.datasources.InstanceKeyDataSource;
-import org.apache.commons.dbcp2.datasources.SharedPoolDataSource;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * A factory that looks up the DataSource using the JDBC2 pool methods.
- *
- * Borrowed and adapted from Apache DB Torque
- *
- * @author <a href="mailto:jmcnally@apache.org">John McNally</a>
- * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
- */
-public class SharedPoolDataSourceFactory implements DataSourceFactory
-{
- /** The log. */
- private static Log log = LogManager.getLog(SharedPoolDataSourceFactory.class);
-
- /** The name of the factory. */
- private String name;
-
- /** The wrapped <code>DataSource</code>. */
- private SharedPoolDataSource ds = null;
-
- /**
- * @return the name of the factory.
- */
- @Override
- public String getName()
- {
- return name;
- }
-
- /**
- * @see org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#getDataSource()
- */
- @Override
- public DataSource getDataSource()
- {
- return ds;
- }
-
- /**
- * @see org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#initialize(JDBCDiskCacheAttributes)
- */
- @Override
- public void initialize(JDBCDiskCacheAttributes config) throws SQLException
- {
- this.name = config.getConnectionPoolName();
- ConnectionPoolDataSource cpds = initCPDS(config);
- SharedPoolDataSource dataSource = new SharedPoolDataSource();
- initJdbc2Pool(dataSource, config);
- dataSource.setConnectionPoolDataSource(cpds);
- dataSource.setMaxTotal(config.getMaxTotal());
- this.ds = dataSource;
- }
-
- /**
- * Closes the pool associated with this factory and releases it.
- * @throws SQLException if the pool cannot be closed properly
- */
- @Override
- public void close() throws SQLException
- {
- try
- {
- if (ds != null)
- {
- ds.close();
- }
- }
- catch (Exception e)
- {
- throw new SQLException("Exception caught closing data source", e);
- }
- ds = null;
- }
-
- /**
- * Initializes the ConnectionPoolDataSource.
- *
- * @param config where to read the settings from
- * @throws SQLException if a property set fails
- * @return a configured <code>ConnectionPoolDataSource</code>
- */
- private ConnectionPoolDataSource initCPDS(final JDBCDiskCacheAttributes config)
- throws SQLException
- {
- log.debug("Starting initCPDS");
-
- DriverAdapterCPDS cpds = new DriverAdapterCPDS();
-
- try
- {
- cpds.setDriver(config.getDriverClassName());
- }
- catch (ClassNotFoundException e)
- {
- throw new SQLException("Driver class not found " + config.getDriverClassName(), e);
- }
-
- cpds.setUrl(config.getUrl());
- cpds.setUser(config.getUserName());
- cpds.setPassword(config.getPassword());
-
- return cpds;
- }
-
- /**
- * Initializes the Jdbc2PoolDataSource.
- *
- * @param dataSource the dataSource to initialize, not null.
- * @param config where to read the settings from, not null.
- *
- * @throws SQLException if a property set fails.
- */
- private void initJdbc2Pool(final InstanceKeyDataSource dataSource, final JDBCDiskCacheAttributes config)
- throws SQLException
- {
- log.debug("Starting initJdbc2Pool");
-
- dataSource.setDescription(config.getConnectionPoolName());
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/hsql/HSQLDiskCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/hsql/HSQLDiskCacheFactory.java
deleted file mode 100644
index 8a50305..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/hsql/HSQLDiskCacheFactory.java
+++ /dev/null
@@ -1,129 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc.hsql;
-
-/*
- * 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.
- */
-
-import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-
-import javax.sql.DataSource;
-
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCache;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheFactory;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This factory should create hsql disk caches.
- * <p>
- * @author Aaron Smuts
- */
-public class HSQLDiskCacheFactory
- extends JDBCDiskCacheFactory
-{
- /** The logger */
- private static final Log log = LogManager.getLog( HSQLDiskCacheFactory.class );
-
- /**
- * This factory method should create an instance of the hsqlcache.
- * <p>
- * @param rawAttr
- * @param compositeCacheManager
- * @param cacheEventLogger
- * @param elementSerializer
- * @return JDBCDiskCache
- * @throws SQLException if the creation of the cache instance fails
- */
- @Override
- public <K, V> JDBCDiskCache<K, V> createCache( AuxiliaryCacheAttributes rawAttr,
- ICompositeCacheManager compositeCacheManager,
- ICacheEventLogger cacheEventLogger,
- IElementSerializer elementSerializer )
- throws SQLException
- {
- // TODO get this from the attributes.
- System.setProperty( "hsqldb.cache_scale", "8" );
-
- JDBCDiskCache<K, V> cache = super.createCache(rawAttr, compositeCacheManager,
- cacheEventLogger, elementSerializer);
- setupDatabase( cache.getDataSource(), (JDBCDiskCacheAttributes) rawAttr );
-
- return cache;
- }
-
- /**
- * Creates the table if it doesn't exist
- * <p>
- * @param ds Data Source
- * @param attributes Cache region configuration
- * @throws SQLException
- */
- protected void setupDatabase( DataSource ds, JDBCDiskCacheAttributes attributes )
- throws SQLException
- {
- try (Connection cConn = ds.getConnection())
- {
- setupTable( cConn, attributes.getTableName() );
- log.info( "Finished setting up table [{0}]", attributes.getTableName());
- }
- }
-
- /**
- * SETUP TABLE FOR CACHE
- * <p>
- * @param cConn
- * @param tableName
- */
- protected synchronized void setupTable( Connection cConn, String tableName ) throws SQLException
- {
- DatabaseMetaData dmd = cConn.getMetaData();
- ResultSet result = dmd.getTables(null, null, tableName, null);
-
- if (!result.next())
- {
- // TODO make the cached nature of the table configurable
- StringBuilder createSql = new StringBuilder();
- createSql.append( "CREATE CACHED TABLE ").append( tableName );
- createSql.append( "( " );
- createSql.append( "CACHE_KEY VARCHAR(250) NOT NULL, " );
- createSql.append( "REGION VARCHAR(250) NOT NULL, " );
- createSql.append( "ELEMENT BINARY, " );
- createSql.append( "CREATE_TIME TIMESTAMP, " );
- createSql.append( "UPDATE_TIME_SECONDS BIGINT, " );
- createSql.append( "MAX_LIFE_SECONDS BIGINT, " );
- createSql.append( "SYSTEM_EXPIRE_TIME_SECONDS BIGINT, " );
- createSql.append( "IS_ETERNAL CHAR(1), " );
- createSql.append( "PRIMARY KEY (CACHE_KEY, REGION) " );
- createSql.append( ");" );
-
- try (Statement sStatement = cConn.createStatement())
- {
- sStatement.execute( createSql.toString() );
- }
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCache.java
deleted file mode 100644
index b1fe59a..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCache.java
+++ /dev/null
@@ -1,165 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc.mysql;
-
-/*
- * 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.
- */
-
-import java.sql.SQLException;
-import java.util.Map;
-
-import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCache;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.TableState;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * The MySQLDiskCache extends the core JDBCDiskCache.
- * <p>
- * Although the generic JDBC Disk Cache can be used for MySQL, the MySQL JDBC Disk Cache has
- * additional features, such as table optimization that are particular to MySQL.
- * <p>
- * @author Aaron Smuts
- */
-public class MySQLDiskCache<K, V>
- extends JDBCDiskCache<K, V>
-{
- /** local logger */
- private static final Log log = LogManager.getLog( MySQLDiskCache.class );
-
- /** config attributes */
- private final MySQLDiskCacheAttributes mySQLDiskCacheAttributes;
-
- /**
- * Delegates to the super and makes use of the MySQL specific parameters used for scheduled
- * optimization.
- * <p>
- * @param attributes the configuration object for this cache
- * @param dsFactory the DataSourceFactory for this cache
- * @param tableState an object to track table operations
- * @param compositeCacheManager the global cache manager
- * @throws SQLException if the pool access could not be set up
- */
- public MySQLDiskCache( MySQLDiskCacheAttributes attributes, DataSourceFactory dsFactory,
- TableState tableState, ICompositeCacheManager compositeCacheManager ) throws SQLException
- {
- super( attributes, dsFactory, tableState, compositeCacheManager );
-
- mySQLDiskCacheAttributes = attributes;
-
- log.debug( "MySQLDiskCacheAttributes = {0}", attributes );
- }
-
- /**
- * This delegates to the generic JDBC disk cache. If we are currently optimizing, then this
- * method will balk and return null.
- * <p>
- * @param key Key to locate value for.
- * @return An object matching key, or null.
- */
- @Override
- protected ICacheElement<K, V> processGet( K key )
- {
- if ( this.getTableState().getState() == TableState.OPTIMIZATION_RUNNING )
- {
- if ( this.mySQLDiskCacheAttributes.isBalkDuringOptimization() )
- {
- return null;
- }
- }
- return super.processGet( key );
- }
-
- /**
- * This delegates to the generic JDBC disk cache. If we are currently optimizing, then this
- * method will balk and return null.
- * <p>
- * @param pattern used for like query.
- * @return An object matching key, or null.
- */
- @Override
- protected Map<K, ICacheElement<K, V>> processGetMatching( String pattern )
- {
- if ( this.getTableState().getState() == TableState.OPTIMIZATION_RUNNING )
- {
- if ( this.mySQLDiskCacheAttributes.isBalkDuringOptimization() )
- {
- return null;
- }
- }
- return super.processGetMatching( pattern );
- }
-
- /**
- * @param pattern
- * @return String to use in the like query.
- */
- @Override
- public String constructLikeParameterFromPattern( String pattern )
- {
- String likePattern = pattern.replaceAll( "\\.\\+", "%" );
- likePattern = likePattern.replaceAll( "\\.", "_" );
-
- log.debug( "pattern = [{0}]", likePattern );
-
- return likePattern;
- }
-
- /**
- * This delegates to the generic JDBC disk cache. If we are currently optimizing, then this
- * method will balk and do nothing.
- * <p>
- * @param element
- */
- @Override
- protected void processUpdate( ICacheElement<K, V> element )
- {
- if ( this.getTableState().getState() == TableState.OPTIMIZATION_RUNNING )
- {
- if ( this.mySQLDiskCacheAttributes.isBalkDuringOptimization() )
- {
- return;
- }
- }
- super.processUpdate( element );
- }
-
- /**
- * Removed the expired. (now - create time) > max life seconds * 1000
- * <p>
- * If we are currently optimizing, then this method will balk and do nothing.
- * <p>
- * TODO consider blocking and trying again.
- * <p>
- * @return the number deleted
- */
- @Override
- protected int deleteExpired()
- {
- if ( this.getTableState().getState() == TableState.OPTIMIZATION_RUNNING )
- {
- if ( this.mySQLDiskCacheAttributes.isBalkDuringOptimization() )
- {
- return -1;
- }
- }
- return super.deleteExpired();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCacheAttributes.java
deleted file mode 100644
index fca9702..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCacheAttributes.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc.mysql;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes;
-
-/**
- * This has additional attributes that are particular to the MySQL disk cache.
- * <p>
- * @author Aaron Smuts
- */
-public class MySQLDiskCacheAttributes
- extends JDBCDiskCacheAttributes
-{
- /** Don't change. */
- private static final long serialVersionUID = -6535808344813320061L;
-
- /**
- * For now this is a simple comma delimited list of HH:MM:SS times to optimize
- * the table. If none is supplied, then no optimizations will be performed.
- * <p>
- * In the future we can add a chron like scheduling system. This is to meet
- * a pressing current need.
- * <p>
- * 03:01,15:00 will cause the optimizer to run at 3 am and at 3 pm.
- */
- private String optimizationSchedule = null;
-
- /**
- * If true, we will balk, that is return null during optimization rather than block.
- */
- public static final boolean DEFAULT_BALK_DURING_OPTIMIZATION = true;
-
- /**
- * If true, we will balk, that is return null during optimization rather than block.
- * <p>
- * <a href="http://en.wikipedia.org/wiki/Balking_pattern">Balking</a>
- */
- private boolean balkDuringOptimization = DEFAULT_BALK_DURING_OPTIMIZATION;
-
- /**
- * @param optimizationSchedule The optimizationSchedule to set.
- */
- public void setOptimizationSchedule( String optimizationSchedule )
- {
- this.optimizationSchedule = optimizationSchedule;
- }
-
- /**
- * @return Returns the optimizationSchedule.
- */
- public String getOptimizationSchedule()
- {
- return optimizationSchedule;
- }
-
- /**
- * @param balkDuringOptimization The balkDuringOptimization to set.
- */
- public void setBalkDuringOptimization( boolean balkDuringOptimization )
- {
- this.balkDuringOptimization = balkDuringOptimization;
- }
-
- /**
- * Should we return null while optimizing the table.
- * <p>
- * @return Returns the balkDuringOptimization.
- */
- public boolean isBalkDuringOptimization()
- {
- return balkDuringOptimization;
- }
-
- /**
- * For debugging.
- * <p>
- * @return debug string
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\nMySQLDiskCacheAttributes" );
- buf.append( "\n OptimizationSchedule [" + getOptimizationSchedule() + "]" );
- buf.append( "\n BalkDuringOptimization [" + isBalkDuringOptimization() + "]" );
- buf.append( super.toString() );
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCacheFactory.java
deleted file mode 100644
index 728201c..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCacheFactory.java
+++ /dev/null
@@ -1,162 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc.mysql;
-
-/*
- * 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.
- */
-
-import java.sql.SQLException;
-import java.text.ParseException;
-import java.util.Date;
-import java.util.concurrent.TimeUnit;
-
-import javax.sql.DataSource;
-
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheFactory;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.TableState;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.mysql.util.ScheduleParser;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This factory should create mysql disk caches.
- * <p>
- * @author Aaron Smuts
- */
-public class MySQLDiskCacheFactory
- extends JDBCDiskCacheFactory
-{
- /** The logger */
- private static final Log log = LogManager.getLog( MySQLDiskCacheFactory.class );
-
- /**
- * This factory method should create an instance of the mysqlcache.
- * <p>
- * @param rawAttr specific cache configuration attributes
- * @param compositeCacheManager the global cache manager
- * @param cacheEventLogger a specific logger for cache events
- * @param elementSerializer a serializer for cache elements
- * @return MySQLDiskCache the cache instance
- * @throws SQLException if the cache instance could not be created
- */
- @Override
- public <K, V> MySQLDiskCache<K, V> createCache( AuxiliaryCacheAttributes rawAttr,
- ICompositeCacheManager compositeCacheManager,
- ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
- throws SQLException
- {
- MySQLDiskCacheAttributes cattr = (MySQLDiskCacheAttributes) rawAttr;
- TableState tableState = getTableState( cattr.getTableName() );
- DataSourceFactory dsFactory = getDataSourceFactory(cattr, compositeCacheManager.getConfigurationProperties());
-
- MySQLDiskCache<K, V> cache = new MySQLDiskCache<>( cattr, dsFactory, tableState, compositeCacheManager );
- cache.setCacheEventLogger( cacheEventLogger );
- cache.setElementSerializer( elementSerializer );
-
- // create a shrinker if we need it.
- createShrinkerWhenNeeded( cattr, cache );
- scheduleOptimizations( cattr, tableState, cache.getDataSource() );
-
- return cache;
-
- }
-
- /**
- * For each time in the optimization schedule, this calls schedule Optimization.
- * <p>
- * @param attributes configuration properties.
- * @param tableState for noting optimization in progress, etc.
- * @param ds the DataSource
- */
- protected void scheduleOptimizations( MySQLDiskCacheAttributes attributes, TableState tableState, DataSource ds )
- {
- if ( attributes != null )
- {
- if ( attributes.getOptimizationSchedule() != null )
- {
- log.info( "Will try to configure optimization for table [{0}] on schedule [{1}]",
- () -> attributes.getTableName(), () -> attributes.getOptimizationSchedule());
-
- MySQLTableOptimizer optimizer = new MySQLTableOptimizer( attributes, tableState, ds );
-
- // loop through the dates.
- try
- {
- Date[] dates = ScheduleParser.createDatesForSchedule( attributes.getOptimizationSchedule() );
- if ( dates != null )
- {
- for ( int i = 0; i < dates.length; i++ )
- {
- this.scheduleOptimization( dates[i], optimizer );
- }
- }
- }
- catch ( ParseException e )
- {
- log.warn( "Problem creating optimization schedule for table [{0}]",
- attributes.getTableName(), e );
- }
- }
- else
- {
- log.info( "Optimization is not configured for table [{0}]",
- attributes.getTableName());
- }
- }
- }
-
- /**
- * This takes in a single time and schedules the optimizer to be called at that time every day.
- * <p>
- * @param startTime -- HH:MM:SS format
- * @param optimizer
- */
- protected void scheduleOptimization( Date startTime, MySQLTableOptimizer optimizer )
- {
- log.info( "startTime [{0}] for optimizer {1}", startTime, optimizer );
-
- Date now = new Date();
- long initialDelay = startTime.getTime() - now.getTime();
-
- // have the daemon execute the optimization
- getScheduledExecutorService().scheduleAtFixedRate(() -> optimizeTable(optimizer),
- initialDelay, 86400L, TimeUnit.SECONDS );
- }
-
- /**
- * This calls the optimizers' optimize table method. This is used by the timer.
- * <p>
- * @author Aaron Smuts
- */
- private void optimizeTable(MySQLTableOptimizer optimizer)
- {
- if ( optimizer != null )
- {
- boolean success = optimizer.optimizeTable();
- log.info( "Optimization success status [{0}]", success );
- }
- else
- {
- log.warn( "OptimizerRunner: The optimizer is null. Could not optimize table." );
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLTableOptimizer.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLTableOptimizer.java
deleted file mode 100644
index 585947f..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLTableOptimizer.java
+++ /dev/null
@@ -1,278 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc.mysql;
-
-/*
- * 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.
- */
-
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-
-import javax.sql.DataSource;
-
-import org.apache.commons.jcs.auxiliary.disk.jdbc.TableState;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.timing.ElapsedTimer;
-
-/**
- * The MySQL Table Optimizer can optimize MySQL tables. It knows how to optimize for MySQL databases
- * in particular and how to repair the table if it is corrupted in the process.
- * <p>
- * We will probably be able to abstract out a generic optimizer interface from this class in the
- * future.
- * <p>
- * @author Aaron Smuts
- */
-public class MySQLTableOptimizer
-{
- /** The logger */
- private static final Log log = LogManager.getLog( MySQLTableOptimizer.class );
-
- /** The data source */
- private DataSource dataSource = null;
-
- /** The name of the table. */
- private String tableName = null;
-
- /** optimizing, etc. */
- private TableState tableState;
-
- /**
- * This constructs an optimizer with the disk cacn properties.
- * <p>
- * @param attributes
- * @param tableState We mark the table status as optimizing when this is happening.
- * @param dataSource access to the database
- */
- public MySQLTableOptimizer( MySQLDiskCacheAttributes attributes, TableState tableState, DataSource dataSource )
- {
- setTableName( attributes.getTableName() );
-
- this.tableState = tableState;
- this.dataSource = dataSource;
- }
-
- /**
- * A scheduler will call this method. When it is called the table state is marked as optimizing.
- * TODO we need to verify that no deletions are running before we call optimize. We should wait
- * if a deletion is in progress.
- * <p>
- * This restores when there is an optimization error. The error output looks like this:
- *
- * <pre>
- * mysql> optimize table JCS_STORE_FLIGHT_OPTION_ITINERARY;
- * +---------------------------------------------+----------+----------+---------------------+
- * | Table | Op | Msg_type | Msg_text |
- * +---------------------------------------------+----------+----------+---------------------+
- * | jcs_cache.JCS_STORE_FLIGHT_OPTION_ITINERARY | optimize | error | 2 when fixing table |
- * | jcs_cache.JCS_STORE_FLIGHT_OPTION_ITINERARY | optimize | status | Operation failed |
- * +---------------------------------------------+----------+----------+---------------------+
- * 2 rows in set (51.78 sec)
- * </pre>
- *
- * A successful repair response looks like this:
- *
- * <pre>
- * mysql> REPAIR TABLE JCS_STORE_FLIGHT_OPTION_ITINERARY;
- * +---------------------------------------------+--------+----------+----------------------------------------------+
- * | Table | Op | Msg_type | Msg_text |
- * +---------------------------------------------+--------+----------+----------------------------------------------+
- * | jcs_cache.JCS_STORE_FLIGHT_OPTION_ITINERARY | repair | error | 2 when fixing table |
- * | jcs_cache.JCS_STORE_FLIGHT_OPTION_ITINERARY | repair | warning | Number of rows changed from 131276 to 260461 |
- * | jcs_cache.JCS_STORE_FLIGHT_OPTION_ITINERARY | repair | status | OK |
- * +---------------------------------------------+--------+----------+----------------------------------------------+
- * 3 rows in set (3 min 5.94 sec)
- * </pre>
- *
- * A successful optimization looks like this:
- *
- * <pre>
- * mysql> optimize table JCS_STORE_DEFAULT;
- * +-----------------------------+----------+----------+----------+
- * | Table | Op | Msg_type | Msg_text |
- * +-----------------------------+----------+----------+----------+
- * | jcs_cache.JCS_STORE_DEFAULT | optimize | status | OK |
- * +-----------------------------+----------+----------+----------+
- * 1 row in set (1.10 sec)
- * </pre>
- * @return true if it worked
- */
- public boolean optimizeTable()
- {
- ElapsedTimer timer = new ElapsedTimer();
- boolean success = false;
-
- if ( tableState.getState() == TableState.OPTIMIZATION_RUNNING )
- {
- log.warn( "Skipping optimization. Optimize was called, but the "
- + "table state indicates that an optimization is currently running." );
- return false;
- }
-
- try
- {
- tableState.setState( TableState.OPTIMIZATION_RUNNING );
- log.info( "Optimizing table [{0}]", this.getTableName());
-
- try (Connection con = dataSource.getConnection())
- {
- // TEST
-
- try (Statement sStatement = con.createStatement())
- {
- ResultSet rs = sStatement.executeQuery( "optimize table " + this.getTableName() );
-
- // first row is error, then status
- // if there is only one row in the result set, everything
- // should be fine.
- // This may be mysql version specific.
- if ( rs.next() )
- {
- String status = rs.getString( "Msg_type" );
- String message = rs.getString( "Msg_text" );
-
- log.info( "Message Type: {0}", status );
- log.info( "Message: {0}", message );
-
- if ( "error".equals( status ) )
- {
- log.warn( "Optimization was in error. Will attempt "
- + "to repair the table. Message: {0}", message);
-
- // try to repair the table.
- success = repairTable( sStatement );
- }
- else
- {
- success = true;
- }
- }
-
- // log the table status
- String statusString = getTableStatus( sStatement );
- log.info( "Table status after optimizing table [{0}]: {1}",
- this.getTableName(), statusString );
- }
- catch ( SQLException e )
- {
- log.error( "Problem optimizing table [{0}]",
- this.getTableName(), e );
- return false;
- }
- }
- catch ( SQLException e )
- {
- log.error( "Problem getting connection.", e );
- }
- }
- finally
- {
- tableState.setState( TableState.FREE );
-
- log.info( "Optimization of table [{0}] took {1} ms.",
- () -> this.getTableName(), () -> timer.getElapsedTime() );
- }
-
- return success;
- }
-
- /**
- * This calls show table status and returns the result as a String.
- * <p>
- * @param sStatement
- * @return String
- * @throws SQLException
- */
- protected String getTableStatus( Statement sStatement )
- throws SQLException
- {
- ResultSet statusResultSet = sStatement.executeQuery( "show table status" );
- StringBuilder statusString = new StringBuilder();
- int numColumns = statusResultSet.getMetaData().getColumnCount();
- while ( statusResultSet.next() )
- {
- statusString.append( "\n" );
- for ( int i = 1; i <= numColumns; i++ )
- {
- statusString.append( statusResultSet.getMetaData().getColumnLabel( i ) + " ["
- + statusResultSet.getString( i ) + "] | " );
- }
- }
- return statusString.toString();
- }
-
- /**
- * This is called if the optimization is in error.
- * <p>
- * It looks for "OK" in response. If it find "OK" as a message in any result set row, it returns
- * true. Otherwise we assume that the repair failed.
- * <p>
- * @param sStatement
- * @return true if successful
- * @throws SQLException
- */
- protected boolean repairTable( Statement sStatement )
- throws SQLException
- {
- boolean success = false;
-
- // if( message != null && message.indexOf( ) )
- ResultSet repairResult = sStatement.executeQuery( "repair table " + this.getTableName() );
- StringBuilder repairString = new StringBuilder();
- int numColumns = repairResult.getMetaData().getColumnCount();
- while ( repairResult.next() )
- {
- for ( int i = 1; i <= numColumns; i++ )
- {
- repairString.append( repairResult.getMetaData().getColumnLabel( i ) + " [" + repairResult.getString( i )
- + "] | " );
- }
-
- String message = repairResult.getString( "Msg_text" );
- if ( "OK".equals( message ) )
- {
- success = true;
- }
- }
- log.info("{0}", repairString);
-
- if ( !success )
- {
- log.warn( "Failed to repair the table. {0}", repairString );
- }
- return success;
- }
-
- /**
- * @param tableName The tableName to set.
- */
- public void setTableName( String tableName )
- {
- this.tableName = tableName;
- }
-
- /**
- * @return Returns the tableName.
- */
- public String getTableName()
- {
- return tableName;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/util/ScheduleParser.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/util/ScheduleParser.java
deleted file mode 100644
index 4e973e2..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/util/ScheduleParser.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc.mysql.util;
-
-/*
- * 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.
- */
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.StringTokenizer;
-
-/**
- * Parses the very simple schedule format.
- * <p>
- * @author Aaron Smuts
- */
-public class ScheduleParser
-{
- /**
- * For each date time that is separated by a comma in the
- * OptimizationSchedule, create a date and add it to an array of dates.
- * <p>
- * @param schedule
- * @return Date[]
- * @throws ParseException
- */
- public static Date[] createDatesForSchedule( String schedule )
- throws ParseException
- {
- if ( schedule == null )
- {
- throw new ParseException( "Cannot create schedules for a null String.", 0 );
- }
-
- StringTokenizer toker = new StringTokenizer( schedule, "," );
- Date[] dates = new Date[toker.countTokens()];
- int cnt = 0;
- while ( toker.hasMoreTokens() )
- {
- String time = toker.nextToken();
- dates[cnt] = getDateForSchedule( time );
- cnt++;
- }
- return dates;
- }
-
- /**
- * For a single string it creates a date that is the next time this hh:mm:ss
- * combo will be seen.
- * <p>
- * @param startTime
- * @return Date
- * @throws ParseException
- */
- public static Date getDateForSchedule( String startTime )
- throws ParseException
- {
- if ( startTime == null )
- {
- throw new ParseException( "Cannot create date for a null String.", 0 );
- }
-
- SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
- Date date = sdf.parse(startTime);
- Calendar cal = Calendar.getInstance();
- // This will result in a date of 1/1/1970
- cal.setTime(date);
-
- Calendar now = Calendar.getInstance();
- cal.set(now.get(Calendar.YEAR), now.get(Calendar.MONTH), now.get(Calendar.DAY_OF_MONTH));
-
- // if the date is less than now, add a day.
- if ( cal.before( now ) )
- {
- cal.add( Calendar.DAY_OF_MONTH, 1 );
- }
-
- return cal.getTime();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCache.java
deleted file mode 100644
index 44e7a5d..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCache.java
+++ /dev/null
@@ -1,417 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheEventLogging;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheAttributes;
-import org.apache.commons.jcs.engine.CacheInfo;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.ZombieCacheServiceNonLocal;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-import org.apache.commons.jcs.engine.behavior.IZombie;
-import org.apache.commons.jcs.engine.stats.Stats;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * Lateral distributor. Returns null on get by default. Net search not implemented.
- */
-public class LateralCache<K, V>
- extends AbstractAuxiliaryCacheEventLogging<K, V>
-{
- /** The logger. */
- private static final Log log = LogManager.getLog( LateralCache.class );
-
- /** generalize this, use another interface */
- private final ILateralCacheAttributes lateralCacheAttributes;
-
- /** The region name */
- final String cacheName;
-
- /** either http, socket.udp, or socket.tcp can set in config */
- private ICacheServiceNonLocal<K, V> lateralCacheService;
-
- /** Monitors the connection. */
- private LateralCacheMonitor monitor;
-
- /**
- * Constructor for the LateralCache object
- * <p>
- * @param cattr
- * @param lateral
- * @param monitor
- */
- public LateralCache( ILateralCacheAttributes cattr, ICacheServiceNonLocal<K, V> lateral, LateralCacheMonitor monitor )
- {
- this.cacheName = cattr.getCacheName();
- this.lateralCacheAttributes = cattr;
- this.lateralCacheService = lateral;
- this.monitor = monitor;
- }
-
- /**
- * Constructor for the LateralCache object
- * <p>
- * @param cattr
- */
- public LateralCache( ILateralCacheAttributes cattr )
- {
- this.cacheName = cattr.getCacheName();
- this.lateralCacheAttributes = cattr;
- }
-
- /**
- * Update lateral.
- * <p>
- * @param ce
- * @throws IOException
- */
- @Override
- protected void processUpdate( ICacheElement<K, V> ce )
- throws IOException
- {
- try
- {
- if (ce != null)
- {
- log.debug( "update: lateral = [{0}], CacheInfo.listenerId = {1}",
- lateralCacheService, CacheInfo.listenerId );
- lateralCacheService.update( ce, CacheInfo.listenerId );
- }
- }
- catch ( IOException ex )
- {
- handleException( ex, "Failed to put [" + ce.getKey() + "] to " + ce.getCacheName() + "@" + lateralCacheAttributes );
- }
- }
-
- /**
- * The performance costs are too great. It is not recommended that you enable lateral gets.
- * <p>
- * @param key
- * @return ICacheElement<K, V> or null
- * @throws IOException
- */
- @Override
- protected ICacheElement<K, V> processGet( K key )
- throws IOException
- {
- ICacheElement<K, V> obj = null;
-
- if ( this.lateralCacheAttributes.getPutOnlyMode() )
- {
- return null;
- }
- try
- {
- obj = lateralCacheService.get( cacheName, key );
- }
- catch ( Exception e )
- {
- log.error( e );
- handleException( e, "Failed to get [" + key + "] from " + lateralCacheAttributes.getCacheName() + "@" + lateralCacheAttributes );
- }
- return obj;
- }
-
- /**
- * @param pattern
- * @return A map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- * @throws IOException
- */
- @Override
- protected Map<K, ICacheElement<K, V>> processGetMatching( String pattern )
- throws IOException
- {
- if ( this.lateralCacheAttributes.getPutOnlyMode() )
- {
- return Collections.emptyMap();
- }
- try
- {
- return lateralCacheService.getMatching( cacheName, pattern );
- }
- catch ( IOException e )
- {
- log.error( e );
- handleException( e, "Failed to getMatching [" + pattern + "] from " + lateralCacheAttributes.getCacheName() + "@" + lateralCacheAttributes );
- return Collections.emptyMap();
- }
- }
-
- /**
- * Return the keys in this cache.
- * <p>
- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet()
- */
- @Override
- public Set<K> getKeySet() throws IOException
- {
- try
- {
- return lateralCacheService.getKeySet( cacheName );
- }
- catch ( IOException ex )
- {
- handleException( ex, "Failed to get key set from " + lateralCacheAttributes.getCacheName() + "@"
- + lateralCacheAttributes );
- }
- return Collections.emptySet();
- }
-
- /**
- * Synchronously remove from the remote cache; if failed, replace the remote handle with a
- * zombie.
- * <p>
- * @param key
- * @return false always
- * @throws IOException
- */
- @Override
- protected boolean processRemove( K key )
- throws IOException
- {
- log.debug( "removing key: {0}", key );
-
- try
- {
- lateralCacheService.remove( cacheName, key, CacheInfo.listenerId );
- }
- catch ( IOException ex )
- {
- handleException( ex, "Failed to remove " + key + " from " + lateralCacheAttributes.getCacheName() + "@" + lateralCacheAttributes );
- }
- return false;
- }
-
- /**
- * Synchronously removeAll from the remote cache; if failed, replace the remote handle with a
- * zombie.
- * <p>
- * @throws IOException
- */
- @Override
- protected void processRemoveAll()
- throws IOException
- {
- try
- {
- lateralCacheService.removeAll( cacheName, CacheInfo.listenerId );
- }
- catch ( IOException ex )
- {
- handleException( ex, "Failed to remove all from " + lateralCacheAttributes.getCacheName() + "@" + lateralCacheAttributes );
- }
- }
-
- /**
- * Synchronously dispose the cache. Not sure we want this.
- * <p>
- * @throws IOException
- */
- @Override
- protected void processDispose()
- throws IOException
- {
- log.debug( "Disposing of lateral cache" );
-
- ///* HELP: This section did nothing but generate compilation warnings.
- // TODO: may limit this functionality. It is dangerous.
- // asmuts -- Added functionality to help with warnings. I'm not getting
- // any.
- try
- {
- lateralCacheService.dispose( this.lateralCacheAttributes.getCacheName() );
- // Should remove connection
- }
- catch ( IOException ex )
- {
- log.error( "Couldn't dispose", ex );
- handleException( ex, "Failed to dispose " + lateralCacheAttributes.getCacheName() );
- }
- }
-
- /**
- * Returns the cache status.
- * <p>
- * @return The status value
- */
- @Override
- public CacheStatus getStatus()
- {
- return this.lateralCacheService instanceof IZombie ? CacheStatus.ERROR : CacheStatus.ALIVE;
- }
-
- /**
- * Returns the current cache size.
- * <p>
- * @return The size value
- */
- @Override
- public int getSize()
- {
- return 0;
- }
-
- /**
- * Gets the cacheType attribute of the LateralCache object
- * <p>
- * @return The cacheType value
- */
- @Override
- public CacheType getCacheType()
- {
- return CacheType.LATERAL_CACHE;
- }
-
- /**
- * Gets the cacheName attribute of the LateralCache object
- * <p>
- * @return The cacheName value
- */
- @Override
- public String getCacheName()
- {
- return cacheName;
- }
-
- /**
- * Not yet sure what to do here.
- * <p>
- * @param ex
- * @param msg
- * @throws IOException
- */
- private void handleException( Exception ex, String msg )
- throws IOException
- {
- log.error( "Disabling lateral cache due to error {0}", msg, ex );
-
- lateralCacheService = new ZombieCacheServiceNonLocal<>( lateralCacheAttributes.getZombieQueueMaxSize() );
- // may want to flush if region specifies
- // Notify the cache monitor about the error, and kick off the recovery
- // process.
- monitor.notifyError();
-
- // could stop the net search if it is built and try to reconnect?
- if ( ex instanceof IOException )
- {
- throw (IOException) ex;
- }
- throw new IOException( ex.getMessage() );
- }
-
- /**
- * Replaces the current remote cache service handle with the given handle.
- * <p>
- * @param restoredLateral
- */
- public void fixCache( ICacheServiceNonLocal<K, V> restoredLateral )
- {
- if ( this.lateralCacheService != null && this.lateralCacheService instanceof ZombieCacheServiceNonLocal )
- {
- ZombieCacheServiceNonLocal<K, V> zombie = (ZombieCacheServiceNonLocal<K, V>) this.lateralCacheService;
- this.lateralCacheService = restoredLateral;
- try
- {
- zombie.propagateEvents( restoredLateral );
- }
- catch ( Exception e )
- {
- try
- {
- handleException( e, "Problem propagating events from Zombie Queue to new Lateral Service." );
- }
- catch ( IOException e1 )
- {
- // swallow, since this is just expected kick back. Handle always throws
- }
- }
- }
- else
- {
- this.lateralCacheService = restoredLateral;
- }
- }
-
- /**
- * getStats
- * <p>
- * @return String
- */
- @Override
- public String getStats()
- {
- return "";
- }
-
- /**
- * @return Returns the AuxiliaryCacheAttributes.
- */
- @Override
- public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
- {
- return lateralCacheAttributes;
- }
-
- /**
- * @return debugging data.
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\n LateralCache " );
- buf.append( "\n Cache Name [" + lateralCacheAttributes.getCacheName() + "]" );
- buf.append( "\n cattr = [" + lateralCacheAttributes + "]" );
- return buf.toString();
- }
-
- /**
- * @return extra data.
- */
- @Override
- public String getEventLoggingExtraInfo()
- {
- return null;
- }
-
- /**
- * The NoWait on top does not call out to here yet.
- * <p>
- * @return almost nothing
- */
- @Override
- public IStats getStatistics()
- {
- IStats stats = new Stats();
- stats.setTypeName( "LateralCache" );
- return stats;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheAttributes.java
deleted file mode 100644
index fba67f3..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheAttributes.java
+++ /dev/null
@@ -1,292 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheAttributes;
-
-/**
- * This class stores attributes for all of the available lateral cache auxiliaries.
- */
-public class LateralCacheAttributes
- extends AbstractAuxiliaryCacheAttributes
- implements ILateralCacheAttributes
-{
- /** Don't change */
- private static final long serialVersionUID = -3408449508837393660L;
-
- /** Default receive setting */
- private static final boolean DEFAULT_RECEIVE = true;
-
- /** THe type of lateral */
- private String transmissionTypeName = "UDP";
-
- /** indicates the lateral type, this needs to change */
- private Type transmissionType = Type.UDP;
-
- /** The http servers */
- private String httpServers;
-
- /** used to identify the service that this manager will be operating on */
- private String httpServer = "";
-
- /** this needs to change */
- private String udpMulticastAddr = "228.5.6.7";
-
- /** this needs to change */
- private int udpMulticastPort = 6789;
-
- /** this needs to change */
- private int httpListenerPort = 8080;
-
- /** disables gets from laterals */
- private boolean putOnlyMode = true;
-
- /**
- * do we receive and broadcast or only broadcast this is useful when you don't want to get any
- * notifications
- */
- private boolean receive = DEFAULT_RECEIVE;
-
- /** If the primary fails, we will queue items before reconnect. This limits the number of items that can be queued. */
- private int zombieQueueMaxSize = DEFAULT_ZOMBIE_QUEUE_MAX_SIZE;
-
- /**
- * Sets the httpServer attribute of the LateralCacheAttributes object
- * <P>
- * @param val The new httpServer value
- */
- @Override
- public void setHttpServer( String val )
- {
- httpServer = val;
- }
-
- /**
- * Gets the httpServer attribute of the LateralCacheAttributes object
- * @return The httpServer value
- */
- @Override
- public String getHttpServer()
- {
- return httpServer;
- }
-
- /**
- * Sets the httpServers attribute of the LateralCacheAttributes object
- * @param val The new httpServers value
- */
- @Override
- public void setHttpServers( String val )
- {
- httpServers = val;
- }
-
- /**
- * Gets the httpSrvers attribute of the LateralCacheAttributes object
- * @return The httpServers value
- */
- @Override
- public String getHttpServers()
- {
- return httpServers;
- }
-
- /**
- * Sets the httpListenerPort attribute of the ILateralCacheAttributes object
- * @param val The new tcpListenerPort value
- */
- @Override
- public void setHttpListenerPort( int val )
- {
- this.httpListenerPort = val;
- }
-
- /**
- * Gets the httpListenerPort attribute of the ILateralCacheAttributes object
- * @return The httpListenerPort value
- */
- @Override
- public int getHttpListenerPort()
- {
- return this.httpListenerPort;
- }
-
- /**
- * Sets the udpMulticastAddr attribute of the LateralCacheAttributes object
- * @param val The new udpMulticastAddr value
- */
- @Override
- public void setUdpMulticastAddr( String val )
- {
- udpMulticastAddr = val;
- }
-
- /**
- * Gets the udpMulticastAddr attribute of the LateralCacheAttributes object
- * @return The udpMulticastAddr value
- */
- @Override
- public String getUdpMulticastAddr()
- {
- return udpMulticastAddr;
- }
-
- /**
- * Sets the udpMulticastPort attribute of the LateralCacheAttributes object
- * @param val The new udpMulticastPort value
- */
- @Override
- public void setUdpMulticastPort( int val )
- {
- udpMulticastPort = val;
- }
-
- /**
- * Gets the udpMulticastPort attribute of the LateralCacheAttributes object
- * @return The udpMulticastPort value
- */
- @Override
- public int getUdpMulticastPort()
- {
- return udpMulticastPort;
- }
-
- /**
- * Sets the transmissionType attribute of the LateralCacheAttributes object
- * @param val The new transmissionType value
- */
- @Override
- public void setTransmissionType( Type val )
- {
- this.transmissionType = val;
- this.transmissionTypeName = val.toString();
- }
-
- /**
- * Gets the transmissionType attribute of the LateralCacheAttributes object
- * @return The transmissionType value
- */
- @Override
- public Type getTransmissionType()
- {
- return this.transmissionType;
- }
-
- /**
- * Sets the transmissionTypeName attribute of the LateralCacheAttributes object
- * @param val The new transmissionTypeName value
- */
- @Override
- public void setTransmissionTypeName( String val )
- {
- this.transmissionTypeName = val;
- this.transmissionType = Type.valueOf(val);
- }
-
- /**
- * Gets the transmissionTypeName attribute of the LateralCacheAttributes object
- * @return The transmissionTypeName value
- */
- @Override
- public String getTransmissionTypeName()
- {
- return this.transmissionTypeName;
- }
-
- /**
- * Sets the outgoingOnlyMode attribute of the ILateralCacheAttributes. When this is true the
- * lateral cache will only issue put and remove order and will not try to retrieve elements from
- * other lateral caches.
- * @param val The new transmissionTypeName value
- */
- @Override
- public void setPutOnlyMode( boolean val )
- {
- this.putOnlyMode = val;
- }
-
- /**
- * @return The outgoingOnlyMode value. Stops gets from going remote.
- */
- @Override
- public boolean getPutOnlyMode()
- {
- return putOnlyMode;
- }
-
- /**
- * @param receive The receive to set.
- */
- @Override
- public void setReceive( boolean receive )
- {
- this.receive = receive;
- }
-
- /**
- * @return Returns the receive.
- */
- @Override
- public boolean isReceive()
- {
- return receive;
- }
-
- /**
- * The number of elements the zombie queue will hold. This queue is used to store events if we
- * loose our connection with the server.
- * <p>
- * @param zombieQueueMaxSize The zombieQueueMaxSize to set.
- */
- @Override
- public void setZombieQueueMaxSize( int zombieQueueMaxSize )
- {
- this.zombieQueueMaxSize = zombieQueueMaxSize;
- }
-
- /**
- * The number of elements the zombie queue will hold. This queue is used to store events if we
- * loose our connection with the server.
- * <p>
- * @return Returns the zombieQueueMaxSize.
- */
- @Override
- public int getZombieQueueMaxSize()
- {
- return zombieQueueMaxSize;
- }
-
- /**
- * @return debug string.
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- //buf.append( "cacheName=" + cacheName + "\n" );
- //buf.append( "putOnlyMode=" + putOnlyMode + "\n" );
- //buf.append( "transmissionTypeName=" + transmissionTypeName + "\n" );
- //buf.append( "transmissionType=" + transmissionType + "\n" );
- //buf.append( "tcpServer=" + tcpServer + "\n" );
- buf.append( transmissionTypeName + httpServer + udpMulticastAddr + String.valueOf( udpMulticastPort ) );
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheMonitor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheMonitor.java
deleted file mode 100644
index c78916b..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheMonitor.java
+++ /dev/null
@@ -1,136 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral;
-
-/*
- * 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.
- */
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheMonitor;
-import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory;
-import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.ZombieCacheServiceNonLocal;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-
-/**
- * Used to monitor and repair any failed connection for the lateral cache service. By default the
- * monitor operates in a failure driven mode. That is, it goes into a wait state until there is an
- * error. Upon the notification of a connection error, the monitor changes to operate in a time
- * driven mode. That is, it attempts to recover the connections on a periodic basis. When all failed
- * connections are restored, it changes back to the failure driven mode.
- */
-public class LateralCacheMonitor extends AbstractAuxiliaryCacheMonitor
-{
- /**
- * Map of caches to monitor
- */
- private ConcurrentHashMap<String, LateralCacheNoWait<?, ?>> caches;
-
- /**
- * Reference to the factory
- */
- private LateralTCPCacheFactory factory;
-
- /**
- * Allows close classes, ie testers to set the idle period to something testable.
- * <p>
- * @param idlePeriod
- */
- protected static void forceShortIdlePeriod( long idlePeriod )
- {
- LateralCacheMonitor.idlePeriod = idlePeriod;
- }
-
- /**
- * Constructor for the LateralCacheMonitor object
- * <p>
- * It's the clients responsibility to decide how many of these there will be.
- *
- * @param factory a reference to the factory that manages the service instances
- */
- public LateralCacheMonitor(LateralTCPCacheFactory factory)
- {
- super("JCS-LateralCacheMonitor");
- this.factory = factory;
- this.caches = new ConcurrentHashMap<>();
- setIdlePeriod(20000L);
- }
-
- /**
- * Add a cache to be monitored
- *
- * @param cache the cache
- */
- public void addCache(LateralCacheNoWait<?, ?> cache)
- {
- this.caches.put(cache.getCacheName(), cache);
-
- // if not yet started, go ahead
- if (this.getState() == Thread.State.NEW)
- {
- this.start();
- }
- }
-
- /**
- * Clean up all resources before shutdown
- */
- @Override
- public void dispose()
- {
- this.caches.clear();
- }
-
- /**
- * Main processing method for the LateralCacheMonitor object
- */
- @Override
- public void doWork()
- {
- // Monitor each cache instance one after the other.
- log.info( "Number of caches to monitor = " + caches.size() );
- //for
- for (Map.Entry<String, LateralCacheNoWait<?, ?>> entry : caches.entrySet())
- {
- String cacheName = entry.getKey();
-
- @SuppressWarnings("unchecked") // Downcast to match service
- LateralCacheNoWait<Object, Object> c = (LateralCacheNoWait<Object, Object>) entry.getValue();
- if ( c.getStatus() == CacheStatus.ERROR )
- {
- log.info( "Found LateralCacheNoWait in error, " + cacheName );
-
- ITCPLateralCacheAttributes lca = (ITCPLateralCacheAttributes)c.getAuxiliaryCacheAttributes();
-
- // Get service instance
- ICacheServiceNonLocal<Object, Object> cacheService = factory.getCSNLInstance(lca);
-
- // If we can't fix them, just skip and re-try in the
- // next round.
- if (cacheService instanceof ZombieCacheServiceNonLocal)
- {
- continue;
- }
-
- c.fixCache(cacheService);
- }
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheNoWait.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheNoWait.java
deleted file mode 100644
index 3ac2bfd..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheNoWait.java
+++ /dev/null
@@ -1,433 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral;
-
-import java.io.IOException;
-import java.rmi.UnmarshalException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.engine.CacheAdaptor;
-import org.apache.commons.jcs.engine.CacheEventQueueFactory;
-import org.apache.commons.jcs.engine.CacheInfo;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheEventQueue;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-import org.apache.commons.jcs.engine.stats.StatElement;
-import org.apache.commons.jcs.engine.stats.Stats;
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * Used to queue up update requests to the underlying cache. These requests will be processed in
- * their order of arrival via the cache event queue processor.
- */
-public class LateralCacheNoWait<K, V>
- extends AbstractAuxiliaryCache<K, V>
-{
- /** The logger. */
- private static final Log log = LogManager.getLog( LateralCacheNoWait.class );
-
- /** The cache */
- private final LateralCache<K, V> cache;
-
- /** The event queue */
- private ICacheEventQueue<K, V> eventQueue;
-
- /** times get called */
- private int getCount = 0;
-
- /** times remove called */
- private int removeCount = 0;
-
- /** times put called */
- private int putCount = 0;
-
- /**
- * Constructs with the given lateral cache, and fires up an event queue for asynchronous
- * processing.
- * <p>
- * @param cache
- */
- public LateralCacheNoWait( LateralCache<K, V> cache )
- {
- this.cache = cache;
-
- log.debug( "Constructing LateralCacheNoWait, LateralCache = [{0}]", cache );
-
- CacheEventQueueFactory<K, V> fact = new CacheEventQueueFactory<>();
- this.eventQueue = fact.createCacheEventQueue( new CacheAdaptor<>( cache ), CacheInfo.listenerId, cache
- .getCacheName(), cache.getAuxiliaryCacheAttributes().getEventQueuePoolName(), cache
- .getAuxiliaryCacheAttributes().getEventQueueType() );
-
- // need each no wait to handle each of its real updates and removes,
- // since there may
- // be more than one per cache? alternative is to have the cache
- // perform updates using a different method that specifies the listener
- // this.q = new CacheEventQueue(new CacheAdaptor(this),
- // LateralCacheInfo.listenerId, cache.getCacheName());
- if ( cache.getStatus() == CacheStatus.ERROR )
- {
- eventQueue.destroy();
- }
- }
-
- /**
- * @param ce
- * @throws IOException
- */
- @Override
- public void update( ICacheElement<K, V> ce )
- throws IOException
- {
- putCount++;
- try
- {
- eventQueue.addPutEvent( ce );
- }
- catch ( IOException ex )
- {
- log.error( ex );
- eventQueue.destroy();
- }
- }
-
- /**
- * Synchronously reads from the lateral cache.
- * <p>
- * @param key
- * @return ICacheElement<K, V> if found, else null
- */
- @Override
- public ICacheElement<K, V> get( K key )
- {
- getCount++;
- if ( this.getStatus() != CacheStatus.ERROR )
- {
- try
- {
- return cache.get( key );
- }
- catch ( UnmarshalException ue )
- {
- log.debug( "Retrying the get owing to UnmarshalException..." );
- try
- {
- return cache.get( key );
- }
- catch ( IOException ex )
- {
- log.error( "Failed in retrying the get for the second time." );
- eventQueue.destroy();
- }
- }
- catch ( IOException ex )
- {
- eventQueue.destroy();
- }
- }
- return null;
- }
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
- {
- if ( keys != null && !keys.isEmpty() )
- {
- Map<K, ICacheElement<K, V>> elements = keys.stream()
- .collect(Collectors.toMap(
- key -> key,
- key -> get(key))).entrySet().stream()
- .filter(entry -> entry.getValue() != null)
- .collect(Collectors.toMap(
- entry -> entry.getKey(),
- entry -> entry.getValue()));
-
- return elements;
- }
-
- return new HashMap<>();
- }
-
- /**
- * Synchronously reads from the lateral cache.
- * <p>
- * @param pattern
- * @return ICacheElement<K, V> if found, else empty
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching(String pattern)
- {
- getCount++;
- if ( this.getStatus() != CacheStatus.ERROR )
- {
- try
- {
- return cache.getMatching( pattern );
- }
- catch ( UnmarshalException ue )
- {
- log.debug( "Retrying the get owing to UnmarshalException." );
- try
- {
- return cache.getMatching( pattern );
- }
- catch ( IOException ex )
- {
- log.error( "Failed in retrying the get for the second time." );
- eventQueue.destroy();
- }
- }
- catch ( IOException ex )
- {
- eventQueue.destroy();
- }
- }
- return Collections.emptyMap();
- }
-
- /**
- * Return the keys in this cache.
- * <p>
- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet()
- */
- @Override
- public Set<K> getKeySet() throws IOException
- {
- try
- {
- return cache.getKeySet();
- }
- catch ( IOException ex )
- {
- log.error( ex );
- eventQueue.destroy();
- }
- return Collections.emptySet();
- }
-
- /**
- * Adds a remove request to the lateral cache.
- * <p>
- * @param key
- * @return always false
- */
- @Override
- public boolean remove( K key )
- {
- removeCount++;
- try
- {
- eventQueue.addRemoveEvent( key );
- }
- catch ( IOException ex )
- {
- log.error( ex );
- eventQueue.destroy();
- }
- return false;
- }
-
- /** Adds a removeAll request to the lateral cache. */
- @Override
- public void removeAll()
- {
- try
- {
- eventQueue.addRemoveAllEvent();
- }
- catch ( IOException ex )
- {
- log.error( ex );
- eventQueue.destroy();
- }
- }
-
- /** Adds a dispose request to the lateral cache. */
- @Override
- public void dispose()
- {
- try
- {
- eventQueue.addDisposeEvent();
- }
- catch ( IOException ex )
- {
- log.error( ex );
- eventQueue.destroy();
- }
- }
-
- /**
- * No lateral invocation.
- * <p>
- * @return The size value
- */
- @Override
- public int getSize()
- {
- return cache.getSize();
- }
-
- /**
- * No lateral invocation.
- * <p>
- * @return The cacheType value
- */
- @Override
- public CacheType getCacheType()
- {
- return cache.getCacheType();
- }
-
- /**
- * Returns the asyn cache status. An error status indicates either the lateral connection is not
- * available, or the asyn queue has been unexpectedly destroyed. No lateral invocation.
- * <p>
- * @return The status value
- */
- @Override
- public CacheStatus getStatus()
- {
- return eventQueue.isWorking() ? cache.getStatus() : CacheStatus.ERROR;
- }
-
- /**
- * Gets the cacheName attribute of the LateralCacheNoWait object
- * <p>
- * @return The cacheName value
- */
- @Override
- public String getCacheName()
- {
- return cache.getCacheName();
- }
-
- /**
- * Replaces the lateral cache service handle with the given handle and reset the queue by
- * starting up a new instance.
- * <p>
- * @param lateral
- */
- public void fixCache( ICacheServiceNonLocal<K, V> lateral )
- {
- cache.fixCache( lateral );
- resetEventQ();
- }
-
- /**
- * Resets the event q by first destroying the existing one and starting up new one.
- */
- public void resetEventQ()
- {
- if ( eventQueue.isWorking() )
- {
- eventQueue.destroy();
- }
- CacheEventQueueFactory<K, V> fact = new CacheEventQueueFactory<>();
- this.eventQueue = fact.createCacheEventQueue( new CacheAdaptor<>( cache ), CacheInfo.listenerId, cache
- .getCacheName(), cache.getAuxiliaryCacheAttributes().getEventQueuePoolName(), cache
- .getAuxiliaryCacheAttributes().getEventQueueType() );
- }
-
- /**
- * @return Returns the AuxiliaryCacheAttributes.
- */
- @Override
- public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
- {
- return cache.getAuxiliaryCacheAttributes();
- }
-
- /**
- * getStats
- * @return String
- */
- @Override
- public String getStats()
- {
- return getStatistics().toString();
- }
-
- /**
- * this won't be called since we don't do ICache logging here.
- * <p>
- * @return String
- */
- @Override
- public String getEventLoggingExtraInfo()
- {
- return "Lateral Cache No Wait";
- }
-
- /**
- * @return statistics about this communication
- */
- @Override
- public IStats getStatistics()
- {
- IStats stats = new Stats();
- stats.setTypeName( "Lateral Cache No Wait" );
-
- ArrayList<IStatElement<?>> elems = new ArrayList<>();
-
- // get the stats from the event queue too
- IStats eqStats = this.eventQueue.getStatistics();
- elems.addAll(eqStats.getStatElements());
-
- elems.add(new StatElement<>( "Get Count", Integer.valueOf(this.getCount) ) );
- elems.add(new StatElement<>( "Remove Count", Integer.valueOf(this.removeCount) ) );
- elems.add(new StatElement<>( "Put Count", Integer.valueOf(this.putCount) ) );
- elems.add(new StatElement<>( "Attributes", cache.getAuxiliaryCacheAttributes() ) );
-
- stats.setStatElements( elems );
-
- return stats;
- }
-
- /**
- * @return debugging info.
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( " LateralCacheNoWait " );
- buf.append( " Status = " + this.getStatus() );
- buf.append( " cache = [" + cache.toString() + "]" );
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheNoWaitFacade.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheNoWaitFacade.java
deleted file mode 100644
index 4d15a3e..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheNoWaitFacade.java
+++ /dev/null
@@ -1,467 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheAttributes;
-import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheListener;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.stats.StatElement;
-import org.apache.commons.jcs.engine.stats.Stats;
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * Used to provide access to multiple services under nowait protection. Composite factory should
- * construct LateralCacheNoWaitFacade to give to the composite cache out of caches it constructs
- * from the varies manager to lateral services. Perhaps the lateralcache factory should be able to
- * do this.
- */
-public class LateralCacheNoWaitFacade<K, V>
- extends AbstractAuxiliaryCache<K, V>
-{
- /** The logger */
- private static final Log log = LogManager.getLog( LateralCacheNoWaitFacade.class );
-
- /** The queuing facade to the client. */
- public LateralCacheNoWait<K, V>[] noWaits;
-
- /** The region name */
- private final String cacheName;
-
- /** A cache listener */
- private ILateralCacheListener<K, V> listener;
-
- /** User configurable attributes. */
- private final ILateralCacheAttributes lateralCacheAttributes;
-
- /** Disposed state of this facade */
- private boolean disposed = false;
-
- /**
- * Constructs with the given lateral cache, and fires events to any listeners.
- * <p>
- * @param noWaits
- * @param cattr
- */
- public LateralCacheNoWaitFacade(ILateralCacheListener<K, V> listener, LateralCacheNoWait<K, V>[] noWaits, ILateralCacheAttributes cattr )
- {
- log.debug( "CONSTRUCTING NO WAIT FACADE" );
- this.listener = listener;
- this.noWaits = noWaits;
- this.cacheName = cattr.getCacheName();
- this.lateralCacheAttributes = cattr;
- }
-
- /**
- * Tells you if the no wait is in the list or not.
- * <p>
- * @param noWait
- * @return true if the noWait is in the list.
- */
- public boolean containsNoWait( LateralCacheNoWait<K, V> noWait )
- {
- Optional<LateralCacheNoWait<K, V>> optional = Arrays.stream(noWaits)
- // we know noWait isn't null
- .filter(nw -> noWait.equals( nw ))
- .findFirst();
-
- return optional.isPresent();
- }
-
- /**
- * Adds a no wait to the list if it isn't already in the list.
- * <p>
- * @param noWait
- * @return true if it wasn't already contained
- */
- public synchronized boolean addNoWait( LateralCacheNoWait<K, V> noWait )
- {
- if ( noWait == null )
- {
- return false;
- }
-
- if ( containsNoWait( noWait ) )
- {
- log.debug( "No Wait already contained, [{0}]", noWait );
- return false;
- }
-
- @SuppressWarnings("unchecked") // No generic arrays in java
- LateralCacheNoWait<K, V>[] newArray = new LateralCacheNoWait[noWaits.length + 1];
-
- System.arraycopy( noWaits, 0, newArray, 0, noWaits.length );
-
- // set the last position to the new noWait
- newArray[noWaits.length] = noWait;
-
- noWaits = newArray;
-
- return true;
- }
-
- /**
- * Removes a no wait from the list if it is already there.
- * <p>
- * @param noWait
- * @return true if it was already in the array
- */
- public synchronized boolean removeNoWait( LateralCacheNoWait<K, V> noWait )
- {
- if ( noWait == null )
- {
- return false;
- }
-
- int position = -1;
- for ( int i = 0; i < noWaits.length; i++ )
- {
- // we know noWait isn't null
- if ( noWait.equals( noWaits[i] ) )
- {
- position = i;
- break;
- }
- }
-
- if ( position == -1 )
- {
- return false;
- }
-
- @SuppressWarnings("unchecked") // No generic arrays in java
- LateralCacheNoWait<K, V>[] newArray = new LateralCacheNoWait[noWaits.length - 1];
-
- System.arraycopy( noWaits, 0, newArray, 0, position );
- if ( noWaits.length != position )
- {
- System.arraycopy( noWaits, position + 1, newArray, position, noWaits.length - position - 1 );
- }
- noWaits = newArray;
-
- return true;
- }
-
- /**
- * @param ce
- * @throws IOException
- */
- @Override
- public void update( ICacheElement<K, V> ce )
- throws IOException
- {
- log.debug( "updating through lateral cache facade, noWaits.length = {0}",
- noWaits.length );
-
- for (LateralCacheNoWait<K, V> nw : noWaits)
- {
- nw.update( ce );
- }
- }
-
- /**
- * Synchronously reads from the lateral cache.
- * <p>
- * @param key
- * @return ICacheElement
- */
- @Override
- public ICacheElement<K, V> get( K key )
- {
- Optional<ICacheElement<K, V>> optional = Arrays.stream(noWaits)
- .map(nw -> nw.get( key ))
- .filter(obj -> obj != null)
- .findFirst();
-
- if (optional.isPresent())
- {
- return optional.get();
- }
-
- return null;
- }
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
- {
- if ( keys != null && !keys.isEmpty() )
- {
- Map<K, ICacheElement<K, V>> elements = keys.stream()
- .collect(Collectors.toMap(
- key -> key,
- key -> get(key))).entrySet().stream()
- .filter(entry -> entry.getValue() != null)
- .collect(Collectors.toMap(
- entry -> entry.getKey(),
- entry -> entry.getValue()));
-
- return elements;
- }
-
- return new HashMap<>();
- }
-
- /**
- * Synchronously reads from the lateral cache. Get a response from each! This will be slow.
- * Merge them.
- * <p>
- * @param pattern
- * @return ICacheElement
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching(String pattern)
- {
- Map<K, ICacheElement<K, V>> elements = new HashMap<>();
- for (LateralCacheNoWait<K, V> nw : noWaits)
- {
- elements.putAll( nw.getMatching( pattern ) );
- }
- return elements;
- }
-
- /**
- * Return the keys in this cache.
- * <p>
- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet()
- */
- @Override
- public Set<K> getKeySet() throws IOException
- {
- HashSet<K> allKeys = new HashSet<>();
- for (LateralCacheNoWait<K, V> nw : noWaits)
- {
- if ( nw != null )
- {
- Set<K> keys = nw.getKeySet();
- if (keys != null)
- {
- allKeys.addAll( keys );
- }
- }
- }
- return allKeys;
- }
-
- /**
- * Adds a remove request to the lateral cache.
- * <p>
- * @param key
- * @return always false.
- */
- @Override
- public boolean remove( K key )
- {
- Arrays.stream(noWaits).forEach(nw -> nw.remove( key ));
- return false;
- }
-
- /**
- * Adds a removeAll request to the lateral cache.
- */
- @Override
- public void removeAll()
- {
- Arrays.stream(noWaits).forEach(nw -> nw.removeAll());
- }
-
- /** Adds a dispose request to the lateral cache. */
- @Override
- public void dispose()
- {
- try
- {
- if ( listener != null )
- {
- listener.dispose();
- listener = null;
- }
-
- Arrays.stream(noWaits).forEach(nw -> nw.dispose());
- }
- finally
- {
- disposed = true;
- }
- }
-
- /**
- * No lateral invocation.
- * @return The size value
- */
- @Override
- public int getSize()
- {
- return 0;
- //cache.getSize();
- }
-
- /**
- * Gets the cacheType attribute of the LateralCacheNoWaitFacade object.
- * <p>
- * @return The cacheType value
- */
- @Override
- public CacheType getCacheType()
- {
- return CacheType.LATERAL_CACHE;
- }
-
- /**
- * Gets the cacheName attribute of the LateralCacheNoWaitFacade object.
- * <p>
- * @return The cacheName value
- */
- @Override
- public String getCacheName()
- {
- return "";
- //cache.getCacheName();
- }
-
- /**
- * Gets the status attribute of the LateralCacheNoWaitFacade object
- * @return The status value
- */
- @Override
- public CacheStatus getStatus()
- {
- if (disposed)
- {
- return CacheStatus.DISPOSED;
- }
-
- if (noWaits.length == 0 || listener != null)
- {
- return CacheStatus.ALIVE;
- }
-
- List<CacheStatus> statii = Arrays.stream(noWaits)
- .map(nw -> nw.getStatus())
- .collect(Collectors.toList());
-
- // It's alive if ANY of its nowaits is alive
- if (statii.contains(CacheStatus.ALIVE))
- {
- return CacheStatus.ALIVE;
- }
- // It's alive if ANY of its nowaits is in error, but
- // none are alive, then it's in error
- if (statii.contains(CacheStatus.ERROR))
- {
- return CacheStatus.ERROR;
- }
-
- // Otherwise, it's been disposed, since it's the only status left
- return CacheStatus.DISPOSED;
- }
-
- /**
- * @return Returns the AuxiliaryCacheAttributes.
- */
- @Override
- public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
- {
- return this.lateralCacheAttributes;
- }
-
- /**
- * @return "LateralCacheNoWaitFacade: " + cacheName;
- */
- @Override
- public String toString()
- {
- return "LateralCacheNoWaitFacade: " + cacheName;
- }
-
- /**
- * this won't be called since we don't do ICache logging here.
- * <p>
- * @return String
- */
- @Override
- public String getEventLoggingExtraInfo()
- {
- return "Lateral Cache No Wait";
- }
-
- /**
- * getStats
- * @return String
- */
- @Override
- public String getStats()
- {
- return getStatistics().toString();
- }
-
- /**
- * @return IStats
- */
- @Override
- public IStats getStatistics()
- {
- IStats stats = new Stats();
- stats.setTypeName( "Lateral Cache No Wait Facade" );
-
- ArrayList<IStatElement<?>> elems = new ArrayList<>();
-
- if ( noWaits != null )
- {
- elems.add(new StatElement<>( "Number of No Waits", Integer.valueOf(noWaits.length) ) );
-
- for ( LateralCacheNoWait<K, V> lcnw : noWaits )
- {
- if ( lcnw != null )
- {
- // get the stats from the super too
- IStats sStats = lcnw.getStatistics();
- elems.addAll(sStats.getStatElements());
- }
- }
- }
-
- stats.setStatElements( elems );
-
- return stats;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCommand.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCommand.java
deleted file mode 100644
index 5c4ff57..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralCommand.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral;
-
-/*
- * 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.
- */
-
-/**
- * Enumeration of the available lateral commands
- */
-public enum LateralCommand
-{
- /** The command for updates */
- UPDATE,
-
- /** The command for removes */
- REMOVE,
-
- /** The command instructing us to remove all */
- REMOVEALL,
-
- /** The command for disposing the cache. */
- DISPOSE,
-
- /** Command to return an object. */
- GET,
-
- /** Command to return an object. */
- GET_MATCHING,
-
- /** Command to get all keys */
- GET_KEYSET
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralElementDescriptor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralElementDescriptor.java
deleted file mode 100644
index 55ef04b..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/LateralElementDescriptor.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-import java.io.Serializable;
-
-/**
- * This class wraps command to other laterals. It is essentially a
- * JCS-TCP-Lateral packet. The headers specify the action the receiver should
- * take.
- */
-public class LateralElementDescriptor<K, V>
- implements Serializable
-{
- /** Don't change */
- private static final long serialVersionUID = 5268222498076063575L;
-
- /** The Cache Element that we are distributing. */
- public ICacheElement<K, V> ce;
-
- /**
- * The id of the the source of the request. This is used to prevent infinite
- * loops.
- */
- public long requesterId;
-
- /** The operation has been requested by the client. */
- public LateralCommand command = LateralCommand.UPDATE;
-
- /**
- * The hashcode value for this element.
- */
- public int valHashCode = -1;
-
- /** Constructor for the LateralElementDescriptor object */
- public LateralElementDescriptor()
- {
- super();
- }
-
- /**
- * Constructor for the LateralElementDescriptor object
- * <p>
- * @param ce ICacheElement<K, V> payload
- */
- public LateralElementDescriptor( ICacheElement<K, V> ce )
- {
- this.ce = ce;
- }
-
- /**
- * @return String, all the important values that can be configured
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\n LateralElementDescriptor " );
- buf.append( "\n command = [" + this.command + "]" );
- buf.append( "\n valHashCode = [" + this.valHashCode + "]" );
- buf.append( "\n ICacheElement = [" + this.ce + "]" );
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/behavior/ILateralCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/behavior/ILateralCacheAttributes.java
deleted file mode 100644
index 07b0183..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/behavior/ILateralCacheAttributes.java
+++ /dev/null
@@ -1,200 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral.behavior;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-
-/**
- * This interface defines configuration options common to lateral cache plugins.
- * <p>
- * TODO it needs to be trimmed down. The old version had features for every lateral. Now, the
- * individual laterals have their own specific attributes interfaces.
- */
-public interface ILateralCacheAttributes
- extends AuxiliaryCacheAttributes
-{
- enum Type
- {
- /** HTTP type */
- HTTP, // 1
-
- /** UDP type */
- UDP, // 2
-
- /** TCP type */
- TCP, // 3
-
- /** XMLRPC type */
- XMLRPC // 4
- }
-
- /**
- * The number of elements the zombie queue will hold. This queue is used to store events if we
- * loose our connection with the server.
- */
- int DEFAULT_ZOMBIE_QUEUE_MAX_SIZE = 1000;
-
- /**
- * Sets the httpServer attribute of the ILateralCacheAttributes object
- * <p>
- * @param val The new httpServer value
- */
- void setHttpServer( String val );
-
- /**
- * Gets the httpServer attribute of the ILateralCacheAttributes object
- * <p>
- * @return The httpServer value
- */
- String getHttpServer();
-
- /**
- * Sets the httpListenerPort attribute of the ILateralCacheAttributes object
- * <p>
- * @param val The new tcpListenerPort value
- */
- void setHttpListenerPort( int val );
-
- /**
- * Gets the httpListenerPort attribute of the ILateralCacheAttributes object
- * <p>
- * @return The httpListenerPort value
- */
- int getHttpListenerPort();
-
- /**
- * Sets the httpServers attribute of the LateralCacheAttributes object
- * <p>
- * @param val The new httpServers value
- */
- void setHttpServers( String val );
-
- /**
- * Gets the httpSrvers attribute of the LateralCacheAttributes object
- * <p>
- * @return The httpServers value
- */
- String getHttpServers();
-
- /**
- * Sets the udpMulticastAddr attribute of the ILateralCacheAttributes object
- * <p>
- * @param val The new udpMulticastAddr value
- */
- void setUdpMulticastAddr( String val );
-
- /**
- * Gets the udpMulticastAddr attribute of the ILateralCacheAttributes object
- * <p>
- * @return The udpMulticastAddr value
- */
- String getUdpMulticastAddr();
-
- /**
- * Sets the udpMulticastPort attribute of the ILateralCacheAttributes object
- * <p>
- * @param val The new udpMulticastPort value
- */
- void setUdpMulticastPort( int val );
-
- /**
- * Gets the udpMulticastPort attribute of the ILateralCacheAttributes object
- * <p>
- * @return The udpMulticastPort value
- */
- int getUdpMulticastPort();
-
- /**
- * Sets the transmissionType attribute of the ILateralCacheAttributes object
- * <p>
- * @param val The new transmissionType value
- */
- void setTransmissionType( Type val );
-
- /**
- * Gets the transmissionType attribute of the ILateralCacheAttributes object
- * <p>
- * @return The transmissionType value
- */
- Type getTransmissionType();
-
- /**
- * Sets the transmissionTypeName attribute of the ILateralCacheAttributes object
- * <p>
- * @param val The new transmissionTypeName value
- */
- void setTransmissionTypeName( String val );
-
- /**
- * Gets the transmissionTypeName attribute of the ILateralCacheAttributes object
- * <p>
- * @return The transmissionTypeName value
- */
- String getTransmissionTypeName();
-
- /**
- * Sets the putOnlyMode attribute of the ILateralCacheAttributes. When this is true the lateral
- * cache will only issue put and remove order and will not try to retrieve elements from other
- * lateral caches.
- * <p>
- * @param val The new transmissionTypeName value
- */
- void setPutOnlyMode( boolean val );
-
- /**
- * @return The outgoingOnlyMode value. Stops gets from going remote.
- */
- boolean getPutOnlyMode();
-
- /**
- * @param receive The receive to set.
- */
- void setReceive( boolean receive );
-
- /**
- * Should a listener be created. By default this is true.
- * <p>
- * If this is false the lateral will connect to others but it will not create a listener to
- * receive.
- * <p>
- * It is possible if two laterals are misconfigured that lateral A may have a region R1 that is
- * not configured for the lateral but another is. And if cache B has region R1 configured for
- * lateral distribution, A will get messages for R1 but not send them.
- * <p>
- * @return true if we should have a listener connection
- */
- boolean isReceive();
-
- /**
- * The number of elements the zombie queue will hold. This queue is used to store events if we
- * loose our connection with the server.
- * <p>
- * @param zombieQueueMaxSize The zombieQueueMaxSize to set.
- */
- void setZombieQueueMaxSize( int zombieQueueMaxSize );
-
- /**
- * The number of elements the zombie queue will hold. This queue is used to store events if we
- * loose our connection with the server.
- * <p>
- * @return Returns the zombieQueueMaxSize.
- */
- int getZombieQueueMaxSize();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/behavior/ILateralCacheListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/behavior/ILateralCacheListener.java
deleted file mode 100644
index 581f593..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/behavior/ILateralCacheListener.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral.behavior;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICacheListener;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-
-/**
- * Listens for lateral cache event notification.
- */
-public interface ILateralCacheListener<K, V>
- extends ICacheListener<K, V>
-{
- /**
- * Initialize this listener
- */
- void init();
-
- /**
- * @param cacheMgr
- * The cacheMgr to set.
- */
- void setCacheManager( ICompositeCacheManager cacheMgr );
-
- /**
- * @return Returns the cacheMgr.
- */
- ICompositeCacheManager getCacheManager();
-
- /**
- * Dispose this listener
- */
- void dispose();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPCacheFactory.java
deleted file mode 100644
index 5374043..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPCacheFactory.java
+++ /dev/null
@@ -1,404 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral.socket.tcp;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.StringTokenizer;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.lateral.LateralCache;
-import org.apache.commons.jcs.auxiliary.lateral.LateralCacheMonitor;
-import org.apache.commons.jcs.auxiliary.lateral.LateralCacheNoWait;
-import org.apache.commons.jcs.auxiliary.lateral.LateralCacheNoWaitFacade;
-import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheListener;
-import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes;
-import org.apache.commons.jcs.engine.CacheWatchRepairable;
-import org.apache.commons.jcs.engine.ZombieCacheServiceNonLocal;
-import org.apache.commons.jcs.engine.ZombieCacheWatch;
-import org.apache.commons.jcs.engine.behavior.ICache;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.behavior.IShutdownObserver;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.discovery.UDPDiscoveryManager;
-import org.apache.commons.jcs.utils.discovery.UDPDiscoveryService;
-
-/**
- * Constructs a LateralCacheNoWaitFacade for the given configuration. Each lateral service / local
- * relationship is managed by one manager. This manager can have multiple caches. The remote
- * relationships are consolidated and restored via these managers.
- * <p>
- * The facade provides a front to the composite cache so the implementation is transparent.
- */
-public class LateralTCPCacheFactory
- extends AbstractAuxiliaryCacheFactory
-{
- /** The logger */
- private static final Log log = LogManager.getLog( LateralTCPCacheFactory.class );
-
- /** Address to service map. */
- private ConcurrentHashMap<String, ICacheServiceNonLocal<?, ?>> csnlInstances;
-
- /** Map of available discovery listener instances, keyed by port. */
- private ConcurrentHashMap<String, LateralTCPDiscoveryListener> lTCPDLInstances;
-
- /** Monitor thread */
- private LateralCacheMonitor monitor;
-
- /**
- * Wrapper of the lateral cache watch service; or wrapper of a zombie
- * service if failed to connect.
- */
- private CacheWatchRepairable lateralWatch;
-
- /**
- * Creates a TCP lateral.
- * <p>
- * @param iaca
- * @param cacheMgr
- * @param cacheEventLogger
- * @param elementSerializer
- * @return LateralCacheNoWaitFacade
- */
- @Override
- public <K, V> LateralCacheNoWaitFacade<K, V> createCache(
- AuxiliaryCacheAttributes iaca, ICompositeCacheManager cacheMgr,
- ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
- {
- ITCPLateralCacheAttributes lac = (ITCPLateralCacheAttributes) iaca;
- ArrayList<ICache<K, V>> noWaits = new ArrayList<>();
-
- // pairs up the tcp servers and set the tcpServer value and
- // get the manager and then get the cache
- // no servers are required.
- if ( lac.getTcpServers() != null )
- {
- StringTokenizer it = new StringTokenizer( lac.getTcpServers(), "," );
- log.debug( "Configured for [{0}] servers.", () -> it.countTokens() );
-
- while ( it.hasMoreElements() )
- {
- String server = (String) it.nextElement();
- log.debug( "tcp server = {0}", server );
- ITCPLateralCacheAttributes lacC = (ITCPLateralCacheAttributes) lac.clone();
- lacC.setTcpServer( server );
-
- LateralCacheNoWait<K, V> lateralNoWait = createCacheNoWait(lacC, cacheEventLogger, elementSerializer);
-
- addListenerIfNeeded( lacC, cacheMgr );
- monitor.addCache(lateralNoWait);
- noWaits.add( lateralNoWait );
- }
- }
-
- ILateralCacheListener<K, V> listener = createListener( lac, cacheMgr );
-
- // create the no wait facade.
- @SuppressWarnings("unchecked") // No generic arrays in java
- LateralCacheNoWait<K, V>[] lcnwArray = noWaits.toArray( new LateralCacheNoWait[0] );
- LateralCacheNoWaitFacade<K, V> lcnwf =
- new LateralCacheNoWaitFacade<>(listener, lcnwArray, lac );
-
- // create udp discovery if available.
- createDiscoveryService( lac, lcnwf, cacheMgr, cacheEventLogger, elementSerializer );
-
- return lcnwf;
- }
-
- protected <K, V> LateralCacheNoWait<K, V> createCacheNoWait( ITCPLateralCacheAttributes lca,
- ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
- {
- ICacheServiceNonLocal<K, V> lateralService = getCSNLInstance(lca);
-
- LateralCache<K, V> cache = new LateralCache<>( lca, lateralService, this.monitor );
- cache.setCacheEventLogger( cacheEventLogger );
- cache.setElementSerializer( elementSerializer );
-
- log.debug( "Created cache for noWait, cache [{0}]", cache );
-
- LateralCacheNoWait<K, V> lateralNoWait = new LateralCacheNoWait<>( cache );
- lateralNoWait.setCacheEventLogger( cacheEventLogger );
- lateralNoWait.setElementSerializer( elementSerializer );
-
- log.info( "Created LateralCacheNoWait for [{0}] LateralCacheNoWait = [{1}]",
- lca, lateralNoWait );
-
- return lateralNoWait;
- }
-
- /**
- * Initialize this factory
- */
- @Override
- public void initialize()
- {
- this.csnlInstances = new ConcurrentHashMap<>();
- this.lTCPDLInstances = new ConcurrentHashMap<>();
-
- // Create the monitoring daemon thread
- this.monitor = new LateralCacheMonitor(this);
- this.monitor.setDaemon( true );
- this.monitor.start();
-
- this.lateralWatch = new CacheWatchRepairable();
- this.lateralWatch.setCacheWatch( new ZombieCacheWatch() );
- }
-
- /**
- * Dispose of this factory, clean up shared resources
- */
- @Override
- public void dispose()
- {
- for (ICacheServiceNonLocal<?, ?> service : this.csnlInstances.values())
- {
- try
- {
- service.dispose("");
- }
- catch (IOException e)
- {
- log.error("Could not dispose service " + service, e);
- }
- }
-
- this.csnlInstances.clear();
-
- // TODO: shut down discovery listeners
- this.lTCPDLInstances.clear();
-
- if (this.monitor != null)
- {
- this.monitor.notifyShutdown();
- try
- {
- this.monitor.join(5000);
- }
- catch (InterruptedException e)
- {
- // swallow
- }
- this.monitor = null;
- }
- }
-
- /**
- * Returns an instance of the cache service.
- * <p>
- * @param lca configuration for the creation of a new service instance
- *
- * @return ICacheServiceNonLocal<K, V>
- */
- // Need to cast because of common map for all cache services
- @SuppressWarnings("unchecked")
- public <K, V> ICacheServiceNonLocal<K, V> getCSNLInstance( ITCPLateralCacheAttributes lca )
- {
- String key = lca.getTcpServer();
-
- csnlInstances.computeIfPresent(key, (name, service) -> {
- // If service creation did not succeed last time, force retry
- if (service instanceof ZombieCacheServiceNonLocal)
- {
- log.info("Disposing of zombie service instance for [{0}]", name);
- return null;
- }
-
- return service;
- });
-
- ICacheServiceNonLocal<K, V> service =
- (ICacheServiceNonLocal<K, V>) csnlInstances.computeIfAbsent(key, name -> {
-
- log.info( "Instance for [{0}] is null, creating", name );
-
- // Create the service
- try
- {
- log.info( "Creating TCP service, lca = {0}", lca );
-
- return new LateralTCPService<>( lca );
- }
- catch ( IOException ex )
- {
- // Failed to connect to the lateral server.
- // Configure this LateralCacheManager instance to use the
- // "zombie" services.
- log.error( "Failure, lateral instance will use zombie service", ex );
-
- ICacheServiceNonLocal<K, V> zombieService =
- new ZombieCacheServiceNonLocal<>( lca.getZombieQueueMaxSize() );
-
- // Notify the cache monitor about the error, and kick off
- // the recovery process.
- monitor.notifyError();
-
- return zombieService;
- }
- });
-
- return service;
- }
-
- /**
- * Gets the instance attribute of the LateralCacheTCPListener class.
- * <p>
- * @param ilca ITCPLateralCacheAttributes
- * @param cacheManager a reference to the global cache manager
- *
- * @return The instance value
- */
- private LateralTCPDiscoveryListener getDiscoveryListener(ITCPLateralCacheAttributes ilca, ICompositeCacheManager cacheManager)
- {
- String key = ilca.getUdpDiscoveryAddr() + ":" + ilca.getUdpDiscoveryPort();
-
- LateralTCPDiscoveryListener ins = lTCPDLInstances.computeIfAbsent(key, key1 -> {
- log.info("Created new discovery listener for cacheName {0} for request {1}",
- key1, ilca.getCacheName());
- return new LateralTCPDiscoveryListener( this.getName(), cacheManager);
- });
-
- return ins;
- }
-
- /**
- * Add listener for receivers
- * <p>
- * @param iaca cache configuration attributes
- * @param cacheMgr the composite cache manager
- */
- private void addListenerIfNeeded( ITCPLateralCacheAttributes iaca, ICompositeCacheManager cacheMgr )
- {
- // don't create a listener if we are not receiving.
- if ( iaca.isReceive() )
- {
- try
- {
- addLateralCacheListener( iaca.getCacheName(),
- LateralTCPListener.getInstance( iaca, cacheMgr ) );
- }
- catch ( IOException ioe )
- {
- log.error("Problem creating lateral listener", ioe);
- }
- }
- else
- {
- log.debug( "Not creating a listener since we are not receiving." );
- }
- }
-
- /**
- * Adds the lateral cache listener to the underlying cache-watch service.
- * <p>
- * @param cacheName The feature to be added to the LateralCacheListener attribute
- * @param listener The feature to be added to the LateralCacheListener attribute
- * @throws IOException
- */
- private <K, V> void addLateralCacheListener( String cacheName, ILateralCacheListener<K, V> listener )
- throws IOException
- {
- synchronized ( this.lateralWatch )
- {
- lateralWatch.addCacheListener( cacheName, listener );
- }
- }
-
- /**
- * Makes sure a listener gets created. It will get monitored as soon as it
- * is used.
- * <p>
- * This should be called by create cache.
- * <p>
- * @param attr ITCPLateralCacheAttributes
- * @param cacheMgr
- *
- * @return the listener if created, else null
- */
- private <K, V> ILateralCacheListener<K, V> createListener( ITCPLateralCacheAttributes attr,
- ICompositeCacheManager cacheMgr )
- {
- ILateralCacheListener<K, V> listener = null;
-
- // don't create a listener if we are not receiving.
- if ( attr.isReceive() )
- {
- log.info( "Getting listener for {0}", attr );
-
- // make a listener. if one doesn't exist
- listener = LateralTCPListener.getInstance( attr, cacheMgr );
-
- // register for shutdown notification
- cacheMgr.registerShutdownObserver( (IShutdownObserver) listener );
- }
- else
- {
- log.debug( "Not creating a listener since we are not receiving." );
- }
-
- return listener;
- }
-
- /**
- * Creates the discovery service. Only creates this for tcp laterals right now.
- * <p>
- * @param lac ITCPLateralCacheAttributes
- * @param lcnwf
- * @param cacheMgr
- * @param cacheEventLogger
- * @param elementSerializer
- * @return null if none is created.
- */
- private synchronized <K, V> UDPDiscoveryService createDiscoveryService(
- ITCPLateralCacheAttributes lac,
- LateralCacheNoWaitFacade<K, V> lcnwf,
- ICompositeCacheManager cacheMgr,
- ICacheEventLogger cacheEventLogger,
- IElementSerializer elementSerializer )
- {
- UDPDiscoveryService discovery = null;
-
- // create the UDP discovery for the TCP lateral
- if ( lac.isUdpDiscoveryEnabled() )
- {
- // One can be used for all regions
- LateralTCPDiscoveryListener discoveryListener = getDiscoveryListener( lac, cacheMgr );
- discoveryListener.addNoWaitFacade( lac.getCacheName(), lcnwf );
-
- // need a factory for this so it doesn't
- // get dereferenced, also we don't want one for every region.
- discovery = UDPDiscoveryManager.getInstance().getService( lac.getUdpDiscoveryAddr(),
- lac.getUdpDiscoveryPort(),
- lac.getTcpListenerPort(), cacheMgr);
-
- discovery.addParticipatingCacheName( lac.getCacheName() );
- discovery.addDiscoveryListener( discoveryListener );
-
- log.info( "Registered TCP lateral cache [{0}] with UDPDiscoveryService.",
- () -> lac.getCacheName() );
- }
- return discovery;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPDiscoveryListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPDiscoveryListener.java
deleted file mode 100644
index 6816ab2..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPDiscoveryListener.java
+++ /dev/null
@@ -1,315 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral.socket.tcp;
-
-import java.util.ArrayList;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes;
-import org.apache.commons.jcs.auxiliary.lateral.LateralCacheNoWait;
-import org.apache.commons.jcs.auxiliary.lateral.LateralCacheNoWaitFacade;
-import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.discovery.DiscoveredService;
-import org.apache.commons.jcs.utils.discovery.behavior.IDiscoveryListener;
-
-/**
- * This knows how to add and remove discovered services. It observes UDP discovery events.
- * <p>
- * We can have one listener per region, or one shared by all regions.
- */
-public class LateralTCPDiscoveryListener
- implements IDiscoveryListener
-{
- /** The log factory */
- private static final Log log = LogManager.getLog( LateralTCPDiscoveryListener.class );
-
- /**
- * Map of no wait facades. these are used to determine which regions are locally configured to
- * use laterals.
- */
- private final ConcurrentMap<String, LateralCacheNoWaitFacade<?, ?>> facades =
- new ConcurrentHashMap<>();
-
- /**
- * List of regions that are configured differently here than on another server. We keep track of
- * this to limit the amount of info logging.
- */
- private final CopyOnWriteArrayList<String> knownDifferentlyConfiguredRegions =
- new CopyOnWriteArrayList<>();
-
- /** The name of the cache factory */
- private String factoryName;
-
- /** Reference to the cache manager for auxiliary cache access */
- private ICompositeCacheManager cacheManager;
-
- /**
- * This plugs into the udp discovery system. It will receive add and remove events.
- * <p>
- * @param factoryName the name of the related cache factory
- * @param cacheManager the global cache manager
- */
- protected LateralTCPDiscoveryListener( String factoryName, ICompositeCacheManager cacheManager )
- {
- this.factoryName = factoryName;
- this.cacheManager = cacheManager;
- }
-
- /**
- * Adds a nowait facade under this cachename. If one already existed, it will be overridden.
- * <p>
- * This adds nowaits to a facade for the region name. If the region has no facade, then it is
- * not configured to use the lateral cache, and no facade will be created.
- * <p>
- * @param cacheName - the region name
- * @param facade - facade (for region) => multiple lateral clients.
- * @return true if the facade was not already registered.
- */
- public boolean addNoWaitFacade( String cacheName, LateralCacheNoWaitFacade<?, ?> facade )
- {
- boolean isNew = !containsNoWaitFacade( cacheName );
-
- // override or put anew, it doesn't matter
- facades.put( cacheName, facade );
- knownDifferentlyConfiguredRegions.remove( cacheName );
-
- return isNew;
- }
-
- /**
- * Allows us to see if the facade is present.
- * <p>
- * @param cacheName - facades are for a region
- * @return do we contain the no wait. true if so
- */
- public boolean containsNoWaitFacade( String cacheName )
- {
- return facades.containsKey( cacheName );
- }
-
- /**
- * Allows us to see if the facade is present and if it has the no wait.
- * <p>
- * @param cacheName - facades are for a region
- * @param noWait - is this no wait in the facade
- * @return do we contain the no wait. true if so
- */
- public <K, V> boolean containsNoWait( String cacheName, LateralCacheNoWait<K, V> noWait )
- {
- @SuppressWarnings("unchecked") // Need to cast because of common map for all facades
- LateralCacheNoWaitFacade<K, V> facade =
- (LateralCacheNoWaitFacade<K, V>)facades.get( noWait.getCacheName() );
-
- if ( facade == null )
- {
- return false;
- }
-
- return facade.containsNoWait( noWait );
- }
-
- /**
- * When a broadcast is received from the UDP Discovery receiver, for each cacheName in the
- * message, the add no wait will be called here. To add a no wait, the facade is looked up for
- * this cache name.
- * <p>
- * Each region has a facade. The facade contains a list of end points--the other tcp lateral
- * services.
- * <p>
- * @param noWait
- * @return true if we found the no wait and added it. False if the no wait was not present or if
- * we already had it.
- */
- protected <K, V> boolean addNoWait( LateralCacheNoWait<K, V> noWait )
- {
- @SuppressWarnings("unchecked") // Need to cast because of common map for all facades
- LateralCacheNoWaitFacade<K, V> facade =
- (LateralCacheNoWaitFacade<K, V>)facades.get( noWait.getCacheName() );
- log.debug( "addNoWait > Got facade for {0} = {1}", noWait.getCacheName(), facade );
-
- if ( facade != null )
- {
- boolean isNew = facade.addNoWait( noWait );
- log.debug( "Called addNoWait, isNew = {0}", isNew );
- return isNew;
- }
- else
- {
- if ( knownDifferentlyConfiguredRegions.addIfAbsent( noWait.getCacheName() ) )
- {
- log.info( "addNoWait > Different nodes are configured differently "
- + "or region [{0}] is not yet used on this side.",
- () -> noWait.getCacheName() );
- }
- return false;
- }
- }
-
- /**
- * Look up the facade for the name. If it doesn't exist, then the region is not configured for
- * use with the lateral cache. If it is present, remove the item from the no wait list.
- * <p>
- * @param noWait
- * @return true if we found the no wait and removed it. False if the no wait was not present.
- */
- protected <K, V> boolean removeNoWait( LateralCacheNoWait<K, V> noWait )
- {
- @SuppressWarnings("unchecked") // Need to cast because of common map for all facades
- LateralCacheNoWaitFacade<K, V> facade =
- (LateralCacheNoWaitFacade<K, V>)facades.get( noWait.getCacheName() );
- log.debug( "removeNoWait > Got facade for {0} = {1}", noWait.getCacheName(), facade);
-
- if ( facade != null )
- {
- boolean removed = facade.removeNoWait( noWait );
- log.debug( "Called removeNoWait, removed {0}", removed );
- return removed;
- }
- else
- {
- if ( knownDifferentlyConfiguredRegions.addIfAbsent( noWait.getCacheName() ) )
- {
- log.info( "addNoWait > Different nodes are configured differently "
- + "or region [{0}] is not yet used on this side.",
- () -> noWait.getCacheName() );
- }
- return false;
- }
- }
-
- /**
- * Creates the lateral cache if needed.
- * <p>
- * We could go to the composite cache manager and get the the cache for the region. This would
- * force a full configuration of the region. One advantage of this would be that the creation of
- * the later would go through the factory, which would add the item to the no wait list. But we
- * don't want to do this. This would force this client to have all the regions as the other.
- * This might not be desired. We don't want to send or receive for a region here that is either
- * not used or not configured to use the lateral.
- * <p>
- * Right now, I'm afraid that the region will get puts if another instance has the region
- * configured to use the lateral and our address is configured. This might be a bug, but it
- * shouldn't happen with discovery.
- * <p>
- * @param service
- */
- @Override
- public void addDiscoveredService( DiscoveredService service )
- {
- // get a cache and add it to the no waits
- // the add method should not add the same.
- // we need the listener port from the original config.
- ArrayList<String> regions = service.getCacheNames();
- String serverAndPort = service.getServiceAddress() + ":" + service.getServicePort();
-
- if ( regions != null )
- {
- // for each region get the cache
- for (String cacheName : regions)
- {
- AuxiliaryCache<?, ?> ic = cacheManager.getAuxiliaryCache(factoryName, cacheName);
-
- log.debug( "Got cache, ic = {0}", ic );
-
- // add this to the nowaits for this cachename
- if ( ic != null )
- {
- AuxiliaryCacheAttributes aca = ic.getAuxiliaryCacheAttributes();
- if (aca instanceof ITCPLateralCacheAttributes)
- {
- ITCPLateralCacheAttributes lca = (ITCPLateralCacheAttributes)aca;
- if (lca.getTransmissionType() != LateralCacheAttributes.Type.TCP
- || !serverAndPort.equals(lca.getTcpServer()) )
- {
- // skip caches not belonging to this service
- continue;
- }
- }
-
- addNoWait( (LateralCacheNoWait<?, ?>) ic );
- log.debug( "Called addNoWait for cacheName [{0}]", cacheName );
- }
- }
- }
- else
- {
- log.warn( "No cache names found in message {0}", service );
- }
- }
-
- /**
- * Removes the lateral cache.
- * <p>
- * We need to tell the manager that this instance is bad, so it will reconnect the sender if it
- * comes back.
- * <p>
- * @param service
- */
- @Override
- public void removeDiscoveredService( DiscoveredService service )
- {
- // get a cache and add it to the no waits
- // the add method should not add the same.
- // we need the listener port from the original config.
- ArrayList<String> regions = service.getCacheNames();
- String serverAndPort = service.getServiceAddress() + ":" + service.getServicePort();
-
- if ( regions != null )
- {
- // for each region get the cache
- for (String cacheName : regions)
- {
- AuxiliaryCache<?, ?> ic = cacheManager.getAuxiliaryCache(factoryName, cacheName);
-
- log.debug( "Got cache, ic = {0}", ic );
-
- // remove this to the nowaits for this cachename
- if ( ic != null )
- {
- AuxiliaryCacheAttributes aca = ic.getAuxiliaryCacheAttributes();
- if (aca instanceof ITCPLateralCacheAttributes)
- {
- ITCPLateralCacheAttributes lca = (ITCPLateralCacheAttributes)aca;
- if (lca.getTransmissionType() != LateralCacheAttributes.Type.TCP
- || !serverAndPort.equals(lca.getTcpServer()) )
- {
- // skip caches not belonging to this service
- continue;
- }
- }
-
- removeNoWait( (LateralCacheNoWait<?, ?>) ic );
- log.debug( "Called removeNoWait for cacheName [{0}]", cacheName );
- }
- }
- }
- else
- {
- log.warn( "No cache names found in message {0}", service );
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPListener.java
deleted file mode 100644
index e33e82e..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPListener.java
+++ /dev/null
@@ -1,677 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral.socket.tcp;
-
-/*
- * 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.
- */
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.net.SocketException;
-import java.net.SocketTimeoutException;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.commons.jcs.auxiliary.lateral.LateralElementDescriptor;
-import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheListener;
-import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes;
-import org.apache.commons.jcs.engine.CacheInfo;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IShutdownObserver;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.io.ObjectInputStreamClassLoaderAware;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.threadpool.DaemonThreadFactory;
-
-/**
- * Listens for connections from other TCP lateral caches and handles them. The initialization method
- * starts a listening thread, which creates a socket server. When messages are received they are
- * passed to a pooled executor which then calls the appropriate handle method.
- */
-public class LateralTCPListener<K, V>
- implements ILateralCacheListener<K, V>, IShutdownObserver
-{
- /** The logger */
- private static final Log log = LogManager.getLog( LateralTCPListener.class );
-
- /** How long the server will block on an accept(). 0 is infinite. */
- private static final int acceptTimeOut = 1000;
-
- /** The CacheHub this listener is associated with */
- private transient ICompositeCacheManager cacheManager;
-
- /** Map of available instances, keyed by port */
- private static final ConcurrentHashMap<String, ILateralCacheListener<?, ?>> instances =
- new ConcurrentHashMap<>();
-
- /** The socket listener */
- private ListenerThread receiver;
-
- /** Configuration attributes */
- private ITCPLateralCacheAttributes tcpLateralCacheAttributes;
-
- /** The processor. We should probably use an event queue here. */
- private ExecutorService pooledExecutor;
-
- /** put count */
- private int putCnt = 0;
-
- /** remove count */
- private int removeCnt = 0;
-
- /** get count */
- private int getCnt = 0;
-
- /**
- * Use the vmid by default. This can be set for testing. If we ever need to run more than one
- * per vm, then we need a new technique.
- */
- private long listenerId = CacheInfo.listenerId;
-
- /** is this shut down? */
- private AtomicBoolean shutdown;
-
- /** is this terminated? */
- private AtomicBoolean terminated;
-
- /**
- * Gets the instance attribute of the LateralCacheTCPListener class.
- * <p>
- * @param ilca ITCPLateralCacheAttributes
- * @param cacheMgr
- * @return The instance value
- */
- public static <K, V> LateralTCPListener<K, V>
- getInstance( ITCPLateralCacheAttributes ilca, ICompositeCacheManager cacheMgr )
- {
- @SuppressWarnings("unchecked") // Need to cast because of common map for all instances
- LateralTCPListener<K, V> ins = (LateralTCPListener<K, V>) instances.computeIfAbsent(
- String.valueOf( ilca.getTcpListenerPort() ),
- k -> {
- LateralTCPListener<K, V> newIns = new LateralTCPListener<>( ilca );
-
- newIns.init();
- newIns.setCacheManager( cacheMgr );
-
- log.info( "Created new listener {0}",
- () -> ilca.getTcpListenerPort() );
-
- return newIns;
- });
-
- return ins;
- }
-
- /**
- * Only need one since it does work for all regions, just reference by multiple region names.
- * <p>
- * @param ilca
- */
- protected LateralTCPListener( ITCPLateralCacheAttributes ilca )
- {
- this.setTcpLateralCacheAttributes( ilca );
- }
-
- /**
- * This starts the ListenerThread on the specified port.
- */
- @Override
- public synchronized void init()
- {
- try
- {
- int port = getTcpLateralCacheAttributes().getTcpListenerPort();
- String host = getTcpLateralCacheAttributes().getTcpListenerHost();
-
- pooledExecutor = Executors.newCachedThreadPool(
- new DaemonThreadFactory("JCS-LateralTCPListener-"));
- terminated = new AtomicBoolean(false);
- shutdown = new AtomicBoolean(false);
-
- ServerSocket serverSocket;
- if (host != null && host.length() > 0)
- {
- log.info( "Listening on {0}:{1}", host, port );
- // Resolve host name
- InetAddress inetAddress = InetAddress.getByName(host);
- //Bind the SocketAddress with inetAddress and port
- SocketAddress endPoint = new InetSocketAddress(inetAddress, port);
-
- serverSocket = new ServerSocket();
- serverSocket.bind(endPoint);
- }
- else
- {
- log.info( "Listening on port {0}", port );
- serverSocket = new ServerSocket( port );
- }
- serverSocket.setSoTimeout( acceptTimeOut );
-
- receiver = new ListenerThread(serverSocket);
- receiver.setDaemon( true );
- receiver.start();
- }
- catch ( IOException ex )
- {
- throw new IllegalStateException( ex );
- }
- }
-
- /**
- * Let the lateral cache set a listener_id. Since there is only one listener for all the
- * regions and every region gets registered? the id shouldn't be set if it isn't zero. If it is
- * we assume that it is a reconnect.
- * <p>
- * By default, the listener id is the vmid.
- * <p>
- * The service should set this value. This value will never be changed by a server we connect
- * to. It needs to be non static, for unit tests.
- * <p>
- * The service will use the value it sets in all send requests to the sender.
- * <p>
- * @param id The new listenerId value
- * @throws IOException
- */
- @Override
- public void setListenerId( long id )
- throws IOException
- {
- this.listenerId = id;
- log.debug( "set listenerId = {0}", id );
- }
-
- /**
- * Gets the listenerId attribute of the LateralCacheTCPListener object
- * <p>
- * @return The listenerId value
- * @throws IOException
- */
- @Override
- public long getListenerId()
- throws IOException
- {
- return this.listenerId;
- }
-
- /**
- * Increments the put count. Gets the cache that was injected by the lateral factory. Calls put
- * on the cache.
- * <p>
- * @see org.apache.commons.jcs.engine.behavior.ICacheListener#handlePut(org.apache.commons.jcs.engine.behavior.ICacheElement)
- */
- @Override
- public void handlePut( ICacheElement<K, V> element )
- throws IOException
- {
- putCnt++;
- if ( log.isInfoEnabled() && getPutCnt() % 100 == 0 )
- {
- log.info( "Put Count (port {0}) = {1}",
- () -> getTcpLateralCacheAttributes().getTcpListenerPort(),
- () -> getPutCnt() );
- }
-
- log.debug( "handlePut> cacheName={0}, key={1}",
- () -> element.getCacheName(), () -> element.getKey() );
-
- getCache( element.getCacheName() ).localUpdate( element );
- }
-
- /**
- * Increments the remove count. Gets the cache that was injected by the lateral factory. Calls
- * remove on the cache.
- * <p>
- * @see org.apache.commons.jcs.engine.behavior.ICacheListener#handleRemove(java.lang.String,
- * Object)
- */
- @Override
- public void handleRemove( String cacheName, K key )
- throws IOException
- {
- removeCnt++;
- if ( log.isInfoEnabled() && getRemoveCnt() % 100 == 0 )
- {
- log.info( "Remove Count = {0}", () -> getRemoveCnt() );
- }
-
- log.debug( "handleRemove> cacheName={0}, key={1}", cacheName, key );
-
- getCache( cacheName ).localRemove( key );
- }
-
- /**
- * Gets the cache that was injected by the lateral factory. Calls removeAll on the cache.
- * <p>
- * @see org.apache.commons.jcs.engine.behavior.ICacheListener#handleRemoveAll(java.lang.String)
- */
- @Override
- public void handleRemoveAll( String cacheName )
- throws IOException
- {
- log.debug( "handleRemoveAll> cacheName={0}", cacheName );
-
- getCache( cacheName ).localRemoveAll();
- }
-
- /**
- * Gets the cache that was injected by the lateral factory. Calls get on the cache.
- * <p>
- * @param cacheName
- * @param key
- * @return a ICacheElement
- * @throws IOException
- */
- public ICacheElement<K, V> handleGet( String cacheName, K key )
- throws IOException
- {
- getCnt++;
- if ( log.isInfoEnabled() && getGetCnt() % 100 == 0 )
- {
- log.info( "Get Count (port {0}) = {1}",
- () -> getTcpLateralCacheAttributes().getTcpListenerPort(),
- () -> getGetCnt() );
- }
-
- log.debug( "handleGet> cacheName={0}, key={1}", cacheName, key );
-
- return getCache( cacheName ).localGet( key );
- }
-
- /**
- * Gets the cache that was injected by the lateral factory. Calls get on the cache.
- * <p>
- * @param cacheName the name of the cache
- * @param pattern the matching pattern
- * @return Map
- * @throws IOException
- */
- public Map<K, ICacheElement<K, V>> handleGetMatching( String cacheName, String pattern )
- throws IOException
- {
- getCnt++;
- if ( log.isInfoEnabled() && getGetCnt() % 100 == 0 )
- {
- log.info( "GetMatching Count (port {0}) = {1}",
- () -> getTcpLateralCacheAttributes().getTcpListenerPort(),
- () -> getGetCnt() );
- }
-
- log.debug( "handleGetMatching> cacheName={0}, pattern={1}", cacheName, pattern );
-
- return getCache( cacheName ).localGetMatching( pattern );
- }
-
- /**
- * Gets the cache that was injected by the lateral factory. Calls getKeySet on the cache.
- * <p>
- * @param cacheName the name of the cache
- * @return a set of keys
- * @throws IOException
- */
- public Set<K> handleGetKeySet( String cacheName ) throws IOException
- {
- return getCache( cacheName ).getKeySet(true);
- }
-
- /**
- * This marks this instance as terminated.
- * <p>
- * @see org.apache.commons.jcs.engine.behavior.ICacheListener#handleDispose(java.lang.String)
- */
- @Override
- public void handleDispose( String cacheName )
- throws IOException
- {
- log.info( "handleDispose > cacheName={0} | Ignoring message. "
- + "Do not dispose from remote.", cacheName );
-
- // TODO handle active deregistration, rather than passive detection
- terminated.set(true);
- }
-
- @Override
- public synchronized void dispose()
- {
- terminated.set(true);
- notify();
-
- pooledExecutor.shutdownNow();
- }
-
- /**
- * Gets the cacheManager attribute of the LateralCacheTCPListener object.
- * <p>
- * Normally this is set by the factory. If it wasn't set the listener defaults to the expected
- * singleton behavior of the cache manager.
- * <p>
- * @param name
- * @return CompositeCache
- */
- protected CompositeCache<K, V> getCache( String name )
- {
- return getCacheManager().getCache( name );
- }
-
- /**
- * This is roughly the number of updates the lateral has received.
- * <p>
- * @return Returns the putCnt.
- */
- public int getPutCnt()
- {
- return putCnt;
- }
-
- /**
- * @return Returns the getCnt.
- */
- public int getGetCnt()
- {
- return getCnt;
- }
-
- /**
- * @return Returns the removeCnt.
- */
- public int getRemoveCnt()
- {
- return removeCnt;
- }
-
- /**
- * @param cacheMgr The cacheMgr to set.
- */
- @Override
- public void setCacheManager( ICompositeCacheManager cacheMgr )
- {
- this.cacheManager = cacheMgr;
- }
-
- /**
- * @return Returns the cacheMgr.
- */
- @Override
- public ICompositeCacheManager getCacheManager()
- {
- return cacheManager;
- }
-
- /**
- * @param tcpLateralCacheAttributes The tcpLateralCacheAttributes to set.
- */
- public void setTcpLateralCacheAttributes( ITCPLateralCacheAttributes tcpLateralCacheAttributes )
- {
- this.tcpLateralCacheAttributes = tcpLateralCacheAttributes;
- }
-
- /**
- * @return Returns the tcpLateralCacheAttributes.
- */
- public ITCPLateralCacheAttributes getTcpLateralCacheAttributes()
- {
- return tcpLateralCacheAttributes;
- }
-
- /**
- * Processes commands from the server socket. There should be one listener for each configured
- * TCP lateral.
- */
- public class ListenerThread
- extends Thread
- {
- /** The socket listener */
- private final ServerSocket serverSocket;
-
- /**
- * Constructor
- *
- * @param serverSocket
- */
- public ListenerThread(ServerSocket serverSocket)
- {
- super();
- this.serverSocket = serverSocket;
- }
-
- /** Main processing method for the ListenerThread object */
- @SuppressWarnings("synthetic-access")
- @Override
- public void run()
- {
- try (ServerSocket ssck = serverSocket)
- {
- ConnectionHandler handler;
-
- outer: while ( true )
- {
- log.debug( "Waiting for clients to connect " );
-
- Socket socket = null;
- inner: while (true)
- {
- // Check to see if we've been asked to exit, and exit
- if (terminated.get())
- {
- log.debug("Thread terminated, exiting gracefully");
- break outer;
- }
-
- try
- {
- socket = ssck.accept();
- break inner;
- }
- catch (SocketTimeoutException e)
- {
- // No problem! We loop back up!
- continue inner;
- }
- }
-
- if ( socket != null && log.isDebugEnabled() )
- {
- InetAddress inetAddress = socket.getInetAddress();
- log.debug( "Connected to client at {0}", inetAddress );
- }
-
- handler = new ConnectionHandler( socket );
- pooledExecutor.execute( handler );
- }
- }
- catch ( IOException e )
- {
- log.error( "Exception caught in TCP listener", e );
- }
- }
- }
-
- /**
- * A Separate thread that runs when a command comes into the LateralTCPReceiver.
- */
- public class ConnectionHandler
- implements Runnable
- {
- /** The socket connection, passed in via constructor */
- private final Socket socket;
-
- /**
- * Construct for a given socket
- * @param socket
- */
- public ConnectionHandler( Socket socket )
- {
- this.socket = socket;
- }
-
- /**
- * Main processing method for the LateralTCPReceiverConnection object
- */
- @Override
- @SuppressWarnings({"unchecked", // Need to cast from Object
- "synthetic-access" })
- public void run()
- {
- try (ObjectInputStream ois =
- new ObjectInputStreamClassLoaderAware( socket.getInputStream(), null ))
- {
- while ( true )
- {
- LateralElementDescriptor<K, V> led =
- (LateralElementDescriptor<K, V>) ois.readObject();
-
- if ( led == null )
- {
- log.debug( "LateralElementDescriptor is null" );
- continue;
- }
- if ( led.requesterId == getListenerId() )
- {
- log.debug( "from self" );
- }
- else
- {
- log.debug( "receiving LateralElementDescriptor from another led = {0}",
- led );
-
- handle( led );
- }
- }
- }
- catch ( EOFException e )
- {
- log.info( "Caught EOFException, closing connection.", e );
- }
- catch ( SocketException e )
- {
- log.info( "Caught SocketException, closing connection.", e );
- }
- catch ( Exception e )
- {
- log.error( "Unexpected exception.", e );
- }
- }
-
- /**
- * This calls the appropriate method, based on the command sent in the Lateral element
- * descriptor.
- * <p>
- * @param led
- * @throws IOException
- */
- @SuppressWarnings("synthetic-access")
- private void handle( LateralElementDescriptor<K, V> led )
- throws IOException
- {
- String cacheName = led.ce.getCacheName();
- K key = led.ce.getKey();
- Serializable obj = null;
-
- switch (led.command)
- {
- case UPDATE:
- handlePut( led.ce );
- break;
-
- case REMOVE:
- // if a hashcode was given and filtering is on
- // check to see if they are the same
- // if so, then don't remove, otherwise issue a remove
- if ( led.valHashCode != -1 )
- {
- if ( getTcpLateralCacheAttributes().isFilterRemoveByHashCode() )
- {
- ICacheElement<K, V> test = getCache( cacheName ).localGet( key );
- if ( test != null )
- {
- if ( test.getVal().hashCode() == led.valHashCode )
- {
- log.debug( "Filtering detected identical hashCode [{0}], "
- + "not issuing a remove for led {1}",
- led.valHashCode, led );
- return;
- }
- else
- {
- log.debug( "Different hashcodes, in cache [{0}] sent [{1}]",
- test.getVal().hashCode(), led.valHashCode );
- }
- }
- }
- }
- handleRemove( cacheName, key );
- break;
-
- case REMOVEALL:
- handleRemoveAll( cacheName );
- break;
-
- case GET:
- obj = handleGet( cacheName, key );
- break;
-
- case GET_MATCHING:
- obj = (Serializable) handleGetMatching( cacheName, (String) key );
- break;
-
- case GET_KEYSET:
- obj = (Serializable) handleGetKeySet(cacheName);
- break;
-
- default: break;
- }
-
- if (obj != null)
- {
- ObjectOutputStream oos = new ObjectOutputStream( socket.getOutputStream() );
- oos.writeObject( obj );
- oos.flush();
- }
- }
- }
-
- /**
- * Shuts down the receiver.
- */
- @Override
- public void shutdown()
- {
- if ( shutdown.compareAndSet(false, true) )
- {
- log.info( "Shutting down TCP Lateral receiver." );
-
- receiver.interrupt();
- }
- else
- {
- log.debug( "Shutdown already called." );
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPSender.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPSender.java
deleted file mode 100644
index 69b23b2..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPSender.java
+++ /dev/null
@@ -1,259 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral.socket.tcp;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-
-import org.apache.commons.jcs.auxiliary.lateral.LateralElementDescriptor;
-import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes;
-import org.apache.commons.jcs.io.ObjectInputStreamClassLoaderAware;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This class is based on the log4j SocketAppender class. I'm using a different repair structure, so
- * it is significantly different.
- */
-public class LateralTCPSender
-{
- /** The logger */
- private static final Log log = LogManager.getLog( LateralTCPSender.class );
-
- /** Config */
- private int socketOpenTimeOut;
- private int socketSoTimeOut;
-
- /** The stream from the server connection. */
- private ObjectOutputStream oos;
-
- /** The socket connection with the server. */
- private Socket socket;
-
- /** how many messages sent */
- private int sendCnt = 0;
-
- /** Use to synchronize multiple threads that may be trying to get. */
- private final Object getLock = new int[0];
-
- /**
- * Constructor for the LateralTCPSender object.
- * <p>
- * @param lca
- * @throws IOException
- */
- public LateralTCPSender( ITCPLateralCacheAttributes lca )
- throws IOException
- {
- this.socketOpenTimeOut = lca.getOpenTimeOut();
- this.socketSoTimeOut = lca.getSocketTimeOut();
-
- String p1 = lca.getTcpServer();
- if ( p1 == null )
- {
- throw new IOException( "Invalid server (null)" );
- }
-
- String h2 = p1.substring( 0, p1.indexOf( ":" ) );
- int po = Integer.parseInt( p1.substring( p1.indexOf( ":" ) + 1 ) );
- log.debug( "h2 = {0}, po = {1}", h2, po );
-
- if ( h2.length() == 0 )
- {
- throw new IOException( "Cannot connect to invalid address [" + h2 + ":" + po + "]" );
- }
-
- init( h2, po );
- }
-
- /**
- * Creates a connection to a TCP server.
- * <p>
- * @param host
- * @param port
- * @throws IOException
- */
- protected void init( String host, int port )
- throws IOException
- {
- try
- {
- log.info( "Attempting connection to [{0}]", host );
-
- // have time out socket open do this for us
- try
- {
- socket = new Socket();
- socket.connect( new InetSocketAddress( host, port ), this.socketOpenTimeOut );
- }
- catch ( IOException ioe )
- {
- if (socket != null)
- {
- socket.close();
- }
-
- throw new IOException( "Cannot connect to " + host + ":" + port, ioe );
- }
-
- socket.setSoTimeout( socketSoTimeOut );
- synchronized ( this )
- {
- oos = new ObjectOutputStream( socket.getOutputStream() );
- }
- }
- catch ( java.net.ConnectException e )
- {
- log.debug( "Remote host [{0}] refused connection.", host );
- throw e;
- }
- catch ( IOException e )
- {
- log.debug( "Could not connect to [{0}]", host, e );
- throw e;
- }
- }
-
- /**
- * Sends commands to the lateral cache listener.
- * <p>
- * @param led
- * @throws IOException
- */
- public <K, V> void send( LateralElementDescriptor<K, V> led )
- throws IOException
- {
- sendCnt++;
- if ( log.isInfoEnabled() && sendCnt % 100 == 0 )
- {
- log.info( "Send Count (port {0}) = {1}", socket.getPort(), sendCnt );
- }
-
- log.debug( "sending LateralElementDescriptor" );
-
- if ( led == null )
- {
- return;
- }
-
- if ( oos == null )
- {
- throw new IOException( "No remote connection is available for LateralTCPSender." );
- }
-
- synchronized ( this.getLock )
- {
- oos.writeUnshared( led );
- oos.flush();
- }
- }
-
- /**
- * Sends commands to the lateral cache listener and gets a response. I'm afraid that we could
- * get into a pretty bad blocking situation here. This needs work. I just wanted to get some
- * form of get working. However, get is not recommended for performance reasons. If you have 10
- * laterals, then you have to make 10 failed gets to find out none of the caches have the item.
- * <p>
- * @param led
- * @return ICacheElement
- * @throws IOException
- */
- public <K, V> Object sendAndReceive( LateralElementDescriptor<K, V> led )
- throws IOException
- {
- if ( led == null )
- {
- return null;
- }
-
- if ( oos == null )
- {
- throw new IOException( "No remote connection is available for LateralTCPSender." );
- }
-
- Object response = null;
-
- // Synchronized to insure that the get requests to server from this
- // sender and the responses are processed in order, else you could
- // return the wrong item from the cache.
- // This is a big block of code. May need to re-think this strategy.
- // This may not be necessary.
- // Normal puts, etc to laterals do not have to be synchronized.
- synchronized ( this.getLock )
- {
- try
- {
- // clean up input stream, nothing should be there yet.
- if ( socket.getInputStream().available() > 0 )
- {
- socket.getInputStream().read( new byte[socket.getInputStream().available()] );
- }
- }
- catch ( IOException ioe )
- {
- log.error( "Problem cleaning socket before send {0}", socket, ioe );
- throw ioe;
- }
-
- // write object to listener
- oos.writeUnshared( led );
- oos.flush();
-
- try (ObjectInputStream ois = new ObjectInputStreamClassLoaderAware( socket.getInputStream(), null ))
- {
- socket.setSoTimeout( socketSoTimeOut );
- response = ois.readObject();
- }
- catch ( IOException ioe )
- {
- String message = "Could not open ObjectInputStream to " + socket +
- " SoTimeout [" + socket.getSoTimeout() +
- "] Connected [" + socket.isConnected() + "]";
- log.error( message, ioe );
- throw ioe;
- }
- catch ( Exception e )
- {
- log.error( e );
- }
- }
-
- return response;
- }
-
- /**
- * Closes connection used by all LateralTCPSenders for this lateral connection. Dispose request
- * should come into the facade and be sent to all lateral cache services. The lateral cache
- * service will then call this method.
- * <p>
- * @throws IOException
- */
- public void dispose()
- throws IOException
- {
- log.info( "Dispose called" );
- // WILL CLOSE CONNECTION USED BY ALL
- oos.close();
- socket.close();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPService.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPService.java
deleted file mode 100644
index 553ad95..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPService.java
+++ /dev/null
@@ -1,451 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral.socket.tcp;
-
-/*
- * 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.
- */
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.auxiliary.lateral.LateralCommand;
-import org.apache.commons.jcs.auxiliary.lateral.LateralElementDescriptor;
-import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.CacheInfo;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * A lateral cache service implementation. Does not implement getGroupKey
- * TODO: Remove generics
- */
-public class LateralTCPService<K, V>
- implements ICacheServiceNonLocal<K, V>
-{
- /** The logger. */
- private static final Log log = LogManager.getLog( LateralTCPService.class );
-
- /** special configuration */
- private boolean allowPut;
- private boolean allowGet;
- private boolean issueRemoveOnPut;
-
- /** Sends to another lateral. */
- private LateralTCPSender sender;
-
- /** use the vmid by default */
- private long listenerId = CacheInfo.listenerId;
-
- /**
- * Constructor for the LateralTCPService object
- * <p>
- * @param lca ITCPLateralCacheAttributes
- * @throws IOException
- */
- public LateralTCPService( ITCPLateralCacheAttributes lca )
- throws IOException
- {
- this.allowGet = lca.isAllowGet();
- this.allowPut = lca.isAllowPut();
- this.issueRemoveOnPut = lca.isIssueRemoveOnPut();
-
- try
- {
- sender = new LateralTCPSender( lca );
-
- log.debug( "Created sender to [{0}]", () -> lca.getTcpServer() );
- }
- catch ( IOException e )
- {
- // log.error( "Could not create sender", e );
- // This gets thrown over and over in recovery mode.
- // The stack trace isn't useful here.
- log.error( "Could not create sender to [{0}] -- {1}", lca.getTcpServer(), e.getMessage());
- throw e;
- }
- }
-
- /**
- * @param item
- * @throws IOException
- */
- @Override
- public void update( ICacheElement<K, V> item )
- throws IOException
- {
- update( item, getListenerId() );
- }
-
- /**
- * If put is allowed, we will issue a put. If issue put on remove is configured, we will issue a
- * remove. Either way, we create a lateral element descriptor, which is essentially a JCS TCP
- * packet. It describes what operation the receiver should take when it gets the packet.
- * <p>
- * @see org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal#update(org.apache.commons.jcs.engine.behavior.ICacheElement,
- * long)
- */
- @Override
- public void update( ICacheElement<K, V> item, long requesterId )
- throws IOException
- {
- // if we don't allow put, see if we should remove on put
- if ( !this.allowPut &&
- // if we can't remove on put, and we can't put then return
- !this.issueRemoveOnPut )
- {
- return;
- }
-
- // if we shouldn't remove on put, then put
- if ( !this.issueRemoveOnPut )
- {
- LateralElementDescriptor<K, V> led = new LateralElementDescriptor<>( item );
- led.requesterId = requesterId;
- led.command = LateralCommand.UPDATE;
- sender.send( led );
- }
- // else issue a remove with the hashcode for remove check on
- // on the other end, this will be a server config option
- else
- {
- log.debug( "Issuing a remove for a put" );
-
- // set the value to null so we don't send the item
- CacheElement<K, V> ce = new CacheElement<>( item.getCacheName(), item.getKey(), null );
- LateralElementDescriptor<K, V> led = new LateralElementDescriptor<>( ce );
- led.requesterId = requesterId;
- led.command = LateralCommand.REMOVE;
- led.valHashCode = item.getVal().hashCode();
- sender.send( led );
- }
- }
-
- /**
- * Uses the default listener id and calls the next remove method.
- * <p>
- * @see org.apache.commons.jcs.engine.behavior.ICacheService#remove(String, Object)
- */
- @Override
- public void remove( String cacheName, K key )
- throws IOException
- {
- remove( cacheName, key, getListenerId() );
- }
-
- /**
- * Wraps the key in a LateralElementDescriptor.
- * <p>
- * @see org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal#remove(String, Object, long)
- */
- @Override
- public void remove( String cacheName, K key, long requesterId )
- throws IOException
- {
- CacheElement<K, V> ce = new CacheElement<>( cacheName, key, null );
- LateralElementDescriptor<K, V> led = new LateralElementDescriptor<>( ce );
- led.requesterId = requesterId;
- led.command = LateralCommand.REMOVE;
- sender.send( led );
- }
-
- /**
- * Does nothing.
- * <p>
- * @throws IOException
- */
- @Override
- public void release()
- throws IOException
- {
- // nothing needs to be done
- }
-
- /**
- * Will close the connection.
- * <p>
- * @param cacheName
- * @throws IOException
- */
- @Override
- public void dispose( String cacheName )
- throws IOException
- {
- sender.dispose();
- }
-
- /**
- * @param cacheName
- * @param key
- * @return ICacheElement<K, V> if found.
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> get( String cacheName, K key )
- throws IOException
- {
- return get( cacheName, key, getListenerId() );
- }
-
- /**
- * If get is allowed, we will issues a get request.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @return ICacheElement<K, V> if found.
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> get( String cacheName, K key, long requesterId )
- throws IOException
- {
- // if get is not allowed return
- if ( this.allowGet )
- {
- CacheElement<K, V> ce = new CacheElement<>( cacheName, key, null );
- LateralElementDescriptor<K, V> led = new LateralElementDescriptor<>( ce );
- // led.requesterId = requesterId; // later
- led.command = LateralCommand.GET;
- @SuppressWarnings("unchecked") // Need to cast from Object
- ICacheElement<K, V> response = (ICacheElement<K, V>)sender.sendAndReceive( led );
- if ( response != null )
- {
- return response;
- }
- return null;
- }
- else
- {
- // nothing needs to be done
- return null;
- }
- }
-
- /**
- * If allow get is true, we will issue a getmatching query.
- * <p>
- * @param cacheName
- * @param pattern
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache matching the pattern.
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern )
- throws IOException
- {
- return getMatching( cacheName, pattern, getListenerId() );
- }
-
- /**
- * If allow get is true, we will issue a getmatching query.
- * <p>
- * @param cacheName
- * @param pattern
- * @param requesterId - our identity
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache matching the pattern.
- * @throws IOException
- */
- @Override
- @SuppressWarnings("unchecked") // Need to cast from Object
- public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern, long requesterId )
- throws IOException
- {
- // if get is not allowed return
- if ( this.allowGet )
- {
- CacheElement<String, String> ce = new CacheElement<>( cacheName, pattern, null );
- LateralElementDescriptor<String, String> led = new LateralElementDescriptor<>( ce );
- // led.requesterId = requesterId; // later
- led.command = LateralCommand.GET_MATCHING;
-
- Object response = sender.sendAndReceive( led );
- if ( response != null )
- {
- return (Map<K, ICacheElement<K, V>>) response;
- }
- return Collections.emptyMap();
- }
- else
- {
- // nothing needs to be done
- return null;
- }
- }
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * @param cacheName
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys )
- throws IOException
- {
- return getMultiple( cacheName, keys, getListenerId() );
- }
-
- /**
- * This issues a separate get for each item.
- * <p>
- * TODO We should change this. It should issue one request.
- * <p>
- * @param cacheName
- * @param keys
- * @param requesterId
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys, long requesterId )
- throws IOException
- {
- Map<K, ICacheElement<K, V>> elements = new HashMap<>();
-
- if ( keys != null && !keys.isEmpty() )
- {
- for (K key : keys)
- {
- ICacheElement<K, V> element = get( cacheName, key );
-
- if ( element != null )
- {
- elements.put( key, element );
- }
- }
- }
- return elements;
- }
-
- /**
- * Return the keys in this cache.
- * <p>
- * @param cacheName the name of the cache region
- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet()
- */
- @Override
- @SuppressWarnings("unchecked") // Need cast from Object
- public Set<K> getKeySet(String cacheName) throws IOException
- {
- CacheElement<String, String> ce = new CacheElement<>(cacheName, null, null);
- LateralElementDescriptor<String, String> led = new LateralElementDescriptor<>(ce);
- // led.requesterId = requesterId; // later
- led.command = LateralCommand.GET_KEYSET;
- Object response = sender.sendAndReceive(led);
- if (response != null)
- {
- return (Set<K>) response;
- }
-
- return null;
- }
-
- /**
- * @param cacheName
- * @throws IOException
- */
- @Override
- public void removeAll( String cacheName )
- throws IOException
- {
- removeAll( cacheName, getListenerId() );
- }
-
- /**
- * @param cacheName
- * @param requesterId
- * @throws IOException
- */
- @Override
- public void removeAll( String cacheName, long requesterId )
- throws IOException
- {
- CacheElement<String, String> ce = new CacheElement<>( cacheName, "ALL", null );
- LateralElementDescriptor<String, String> led = new LateralElementDescriptor<>( ce );
- led.requesterId = requesterId;
- led.command = LateralCommand.REMOVEALL;
- sender.send( led );
- }
-
- /**
- * @param args
- */
- public static void main( String args[] )
- {
- try
- {
- LateralTCPSender sender = new LateralTCPSender( new TCPLateralCacheAttributes() );
-
- // process user input till done
- boolean notDone = true;
- String message = null;
- // wait to dispose
- BufferedReader br = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
-
- while ( notDone )
- {
- System.out.println( "enter message:" );
- message = br.readLine();
-
- if (message == null)
- {
- notDone = false;
- continue;
- }
-
- CacheElement<String, String> ce = new CacheElement<>( "test", "test", message );
- LateralElementDescriptor<String, String> led = new LateralElementDescriptor<>( ce );
- sender.send( led );
- }
- }
- catch ( IOException e )
- {
- System.out.println( e.toString() );
- }
- }
-
- /**
- * @param listernId The listernId to set.
- */
- protected void setListenerId( long listernId )
- {
- this.listenerId = listernId;
- }
-
- /**
- * @return Returns the listernId.
- */
- protected long getListenerId()
- {
- return listenerId;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/TCPLateralCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/TCPLateralCacheAttributes.java
deleted file mode 100644
index 26ed199..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/TCPLateralCacheAttributes.java
+++ /dev/null
@@ -1,407 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral.socket.tcp;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes;
-import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes;
-
-/**
- * This interface defines functions that are particular to the TCP Lateral Cache plugin. It extends
- * the generic LateralCacheAttributes interface which in turn extends the AuxiliaryCache interface.
- */
-public class TCPLateralCacheAttributes
- extends LateralCacheAttributes
- implements ITCPLateralCacheAttributes
-{
- /** Don't change. */
- private static final long serialVersionUID = 1077889204513905220L;
-
- /** default */
- private static final String DEFAULT_UDP_DISCOVERY_ADDRESS = "228.5.6.7";
-
- /** default */
- private static final int DEFAULT_UDP_DISCOVERY_PORT = 6789;
-
- /** default */
- private static final boolean DEFAULT_UDP_DISCOVERY_ENABLED = true;
-
- /** default */
- private static final boolean DEFAULT_ALLOW_GET = true;
-
- /** default */
- private static final boolean DEFAULT_ALLOW_PUT = true;
-
- /** default */
- private static final boolean DEFAULT_ISSUE_REMOVE_FOR_PUT = false;
-
- /** default */
- private static final boolean DEFAULT_FILTER_REMOVE_BY_HASH_CODE = true;
-
- /** default - Only block for 1 second before timing out on a read.*/
- private static final int DEFAULT_SOCKET_TIME_OUT = 1000;
-
- /** default - Only block for 2 seconds before timing out on startup.*/
- private static final int DEFAULT_OPEN_TIMEOUT = 2000;
-
- /** TCP -------------------------------------------- */
- private String tcpServers = "";
-
- /** used to identify the service that this manager will be operating on */
- private String tcpServer = "";
-
- /** The port */
- private int tcpListenerPort = 0;
-
- /** The host */
- private String tcpListenerHost = "";
-
- /** udp discovery for tcp server */
- private String udpDiscoveryAddr = DEFAULT_UDP_DISCOVERY_ADDRESS;
-
- /** discovery port */
- private int udpDiscoveryPort = DEFAULT_UDP_DISCOVERY_PORT;
-
- /** discovery switch */
- private boolean udpDiscoveryEnabled = DEFAULT_UDP_DISCOVERY_ENABLED;
-
- /** can we put */
- private boolean allowPut = DEFAULT_ALLOW_GET;
-
- /** can we go laterally for a get */
- private boolean allowGet = DEFAULT_ALLOW_PUT;
-
- /** call remove when there is a put */
- private boolean issueRemoveOnPut = DEFAULT_ISSUE_REMOVE_FOR_PUT;
-
- /** don't remove it the hashcode is the same */
- private boolean filterRemoveByHashCode = DEFAULT_FILTER_REMOVE_BY_HASH_CODE;
-
- /** Only block for socketTimeOut seconds before timing out on a read. */
- private int socketTimeOut = DEFAULT_SOCKET_TIME_OUT;
-
- /** Only block for openTimeOut seconds before timing out on startup. */
- private int openTimeOut = DEFAULT_OPEN_TIMEOUT;
-
- /**
- * Sets the tcpServer attribute of the ILateralCacheAttributes object
- * <p>
- * @param val The new tcpServer value
- */
- @Override
- public void setTcpServer( String val )
- {
- this.tcpServer = val;
- }
-
- /**
- * Gets the tcpServer attribute of the ILateralCacheAttributes object
- * <p>
- * @return The tcpServer value
- */
- @Override
- public String getTcpServer()
- {
- return this.tcpServer;
- }
-
- /**
- * Sets the tcpServers attribute of the ILateralCacheAttributes object
- * <p>
- * @param val The new tcpServers value
- */
- @Override
- public void setTcpServers( String val )
- {
- this.tcpServers = val;
- }
-
- /**
- * Gets the tcpServers attribute of the ILateralCacheAttributes object
- * <p>
- * @return The tcpServers value
- */
- @Override
- public String getTcpServers()
- {
- return this.tcpServers;
- }
-
- /**
- * Sets the tcpListenerPort attribute of the ILateralCacheAttributes object
- * <p>
- * @param val The new tcpListenerPort value
- */
- @Override
- public void setTcpListenerPort( int val )
- {
- this.tcpListenerPort = val;
- }
-
- /**
- * Gets the tcpListenerPort attribute of the ILateralCacheAttributes object
- * <p>
- * @return The tcpListenerPort value
- */
- @Override
- public int getTcpListenerPort()
- {
- return this.tcpListenerPort;
- }
-
- /**
- * Sets the tcpListenerHost attribute of the ILateralCacheAttributes object
- * <p>
- * @param val
- * The new tcpListenerHost value
- */
- @Override
- public void setTcpListenerHost( String val )
- {
- this.tcpListenerHost = val;
- }
-
- /**
- * Gets the tcpListenerHost attribute of the ILateralCacheAttributes object
- * <p>
- * @return The tcpListenerHost value
- */
- @Override
- public String getTcpListenerHost()
- {
- return this.tcpListenerHost;
- }
-
- /**
- * Can setup UDP Discovery. This only works for TCp laterals right now. It allows TCP laterals
- * to find each other by broadcasting to a multicast port.
- * <p>
- * @param udpDiscoveryEnabled The udpDiscoveryEnabled to set.
- */
- @Override
- public void setUdpDiscoveryEnabled( boolean udpDiscoveryEnabled )
- {
- this.udpDiscoveryEnabled = udpDiscoveryEnabled;
- }
-
- /**
- * Whether or not TCP laterals can try to find each other by multicast communication.
- * <p>
- * @return Returns the udpDiscoveryEnabled.
- */
- @Override
- public boolean isUdpDiscoveryEnabled()
- {
- return this.udpDiscoveryEnabled;
- }
-
- /**
- * The port to use if UDPDiscovery is enabled.
- * <p>
- * @return Returns the udpDiscoveryPort.
- */
- @Override
- public int getUdpDiscoveryPort()
- {
- return this.udpDiscoveryPort;
- }
-
- /**
- * Sets the port to use if UDPDiscovery is enabled.
- * <p>
- * @param udpDiscoveryPort The udpDiscoveryPort to set.
- */
- @Override
- public void setUdpDiscoveryPort( int udpDiscoveryPort )
- {
- this.udpDiscoveryPort = udpDiscoveryPort;
- }
-
- /**
- * The address to broadcast to if UDPDiscovery is enabled.
- * <p>
- * @return Returns the udpDiscoveryAddr.
- */
- @Override
- public String getUdpDiscoveryAddr()
- {
- return this.udpDiscoveryAddr;
- }
-
- /**
- * Sets the address to broadcast to if UDPDiscovery is enabled.
- * <p>
- * @param udpDiscoveryAddr The udpDiscoveryAddr to set.
- */
- @Override
- public void setUdpDiscoveryAddr( String udpDiscoveryAddr )
- {
- this.udpDiscoveryAddr = udpDiscoveryAddr;
- }
-
- /**
- * Is the lateral allowed to try and get from other laterals.
- * <p>
- * This replaces the old putOnlyMode
- * <p>
- * @param allowGet
- */
- @Override
- public void setAllowGet( boolean allowGet )
- {
- this.allowGet = allowGet;
- }
-
- /**
- * Is the lateral allowed to try and get from other laterals.
- * <p>
- * @return true if the lateral will try to get
- */
- @Override
- public boolean isAllowGet()
- {
- return this.allowGet;
- }
-
- /**
- * Is the lateral allowed to put objects to other laterals.
- * <p>
- * @param allowPut
- */
- @Override
- public void setAllowPut( boolean allowPut )
- {
- this.allowPut = allowPut;
- }
-
- /**
- * Is the lateral allowed to put objects to other laterals.
- * <p>
- * @return true if puts are allowed
- */
- @Override
- public boolean isAllowPut()
- {
- return this.allowPut;
- }
-
- /**
- * Should the client send a remove command rather than a put when update is called. This is a
- * client option, not a receiver option. This allows you to prevent the lateral from serializing
- * objects.
- * <p>
- * @param issueRemoveOnPut
- */
- @Override
- public void setIssueRemoveOnPut( boolean issueRemoveOnPut )
- {
- this.issueRemoveOnPut = issueRemoveOnPut;
- }
-
- /**
- * Should the client send a remove command rather than a put when update is called. This is a
- * client option, not a receiver option. This allows you to prevent the lateral from serializing
- * objects.
- * <p>
- * @return true if updates will result in a remove command being sent.
- */
- @Override
- public boolean isIssueRemoveOnPut()
- {
- return this.issueRemoveOnPut;
- }
-
- /**
- * Should the receiver try to match hashcodes. If true, the receiver will see if the client
- * supplied a hashcode. If it did, then it will try to get the item locally. If the item exists,
- * then it will compare the hashcode. if they are the same, it will not remove. This isn't
- * perfect since different objects can have the same hashcode, but it is unlikely of objects of
- * the same type.
- * <p>
- * @return boolean
- */
- @Override
- public boolean isFilterRemoveByHashCode()
- {
- return this.filterRemoveByHashCode;
- }
-
- /**
- * Should the receiver try to match hashcodes. If true, the receiver will see if the client
- * supplied a hashcode. If it did, then it will try to get the item locally. If the item exists,
- * then it will compare the hashcode. if they are the same, it will not remove. This isn't
- * perfect since different objects can have the same hashcode, but it is unlikely of objects of
- * the same type.
- * <p>
- * @param filter
- */
- @Override
- public void setFilterRemoveByHashCode( boolean filter )
- {
- this.filterRemoveByHashCode = filter;
- }
-
- /**
- * @param socketTimeOut the socketTimeOut to set
- */
- @Override
- public void setSocketTimeOut( int socketTimeOut )
- {
- this.socketTimeOut = socketTimeOut;
- }
-
- /**
- * @return the socketTimeOut
- */
- @Override
- public int getSocketTimeOut()
- {
- return socketTimeOut;
- }
-
- /**
- * @param openTimeOut the openTimeOut to set
- */
- @Override
- public void setOpenTimeOut( int openTimeOut )
- {
- this.openTimeOut = openTimeOut;
- }
-
- /**
- * @return the openTimeOut
- */
- @Override
- public int getOpenTimeOut()
- {
- return openTimeOut;
- }
-
- /**
- * Used to key the instance TODO create another method for this and use toString for debugging
- * only.
- * <p>
- * @return String
- */
- @Override
- public String toString()
- {
- return this.getTcpServer() + ":" + this.getTcpListenerPort();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/behavior/ITCPLateralCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/behavior/ITCPLateralCacheAttributes.java
deleted file mode 100644
index 7ffd3bc..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/behavior/ITCPLateralCacheAttributes.java
+++ /dev/null
@@ -1,233 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral.socket.tcp.behavior;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheAttributes;
-
-/**
- * This interface defines functions that are particular to the TCP Lateral Cache
- * plugin. It extends the generic LateralCacheAttributes interface which in turn
- * extends the AuxiliaryCache interface.
- * <p>
- * @author Aaron Smuts
- */
-public interface ITCPLateralCacheAttributes
- extends ILateralCacheAttributes
-{
- /**
- * Sets the tcpServer attribute of the ILateralCacheAttributes object
- * <p>
- * @param val
- * The new tcpServer value
- */
- void setTcpServer( String val );
-
- /**
- * Gets the tcpServer attribute of the ILateralCacheAttributes object
- * <p>
- * @return The tcpServer value
- */
- String getTcpServer();
-
- /**
- * Sets the tcpServers attribute of the ILateralCacheAttributes object
- * <p>
- * @param val
- * The new tcpServers value
- */
- void setTcpServers( String val );
-
- /**
- * Gets the tcpServers attribute of the ILateralCacheAttributes object
- * <p>
- * @return The tcpServers value
- */
- String getTcpServers();
-
- /**
- * Sets the tcpListenerPort attribute of the ILateralCacheAttributes object
- * <p>
- * @param val
- * The new tcpListenerPort value
- */
- void setTcpListenerPort( int val );
-
- /**
- * Gets the tcpListenerPort attribute of the ILateralCacheAttributes object
- * <p>
- * @return The tcpListenerPort value
- */
- int getTcpListenerPort();
-
- /**
- * Sets the tcpListenerHost attribute of the ILateralCacheAttributes object
- * <p>
- * @param val
- * The new tcpListenerHost value
- */
- void setTcpListenerHost( String val );
-
- /**
- * Gets the tcpListenerHost attribute of the ILateralCacheAttributes object
- * <p>
- * @return The tcpListenerHost value
- */
- String getTcpListenerHost();
-
- /**
- * Can setup UDP Discovery. This only works for TCp laterals right now. It
- * allows TCP laterals to find each other by broadcasting to a multicast
- * port.
- * <p>
- * @param udpDiscoveryEnabled
- * The udpDiscoveryEnabled to set.
- */
- void setUdpDiscoveryEnabled( boolean udpDiscoveryEnabled );
-
- /**
- * Whether or not TCP laterals can try to find each other by multicast
- * communication.
- * <p>
- * @return Returns the udpDiscoveryEnabled.
- */
- boolean isUdpDiscoveryEnabled();
-
- /**
- * The port to use if UDPDiscovery is enabled.
- * <p>
- * @return Returns the udpDiscoveryPort.
- */
- int getUdpDiscoveryPort();
-
- /**
- * Sets the port to use if UDPDiscovery is enabled.
- * <p>
- * @param udpDiscoveryPort
- * The udpDiscoveryPort to set.
- */
- void setUdpDiscoveryPort( int udpDiscoveryPort );
-
- /**
- * The address to broadcast to if UDPDiscovery is enabled.
- * <p>
- * @return Returns the udpDiscoveryAddr.
- */
- String getUdpDiscoveryAddr();
-
- /**
- * Sets the address to broadcast to if UDPDiscovery is enabled.
- * <p>
- * @param udpDiscoveryAddr
- * The udpDiscoveryAddr to set.
- */
- void setUdpDiscoveryAddr( String udpDiscoveryAddr );
-
- /**
- * Is the lateral allowed to try and get from other laterals.
- * <p>
- * This replaces the old putOnlyMode
- * <p>
- * @param allowGet
- */
- void setAllowGet( boolean allowGet );
-
- /**
- * Is the lateral allowed to try and get from other laterals.
- * <p>
- * @return true if the lateral will try to get
- */
- boolean isAllowGet();
-
- /**
- * Is the lateral allowed to put objects to other laterals.
- * <p>
- * @param allowPut
- */
- void setAllowPut( boolean allowPut );
-
- /**
- * Is the lateral allowed to put objects to other laterals.
- * <p>
- * @return true if puts are allowed
- */
- boolean isAllowPut();
-
- /**
- * Should the client send a remove command rather than a put when update is
- * called. This is a client option, not a receiver option. This allows you
- * to prevent the lateral from serializing objects.
- * <p>
- * @param issueRemoveOnPut
- */
- void setIssueRemoveOnPut( boolean issueRemoveOnPut );
-
- /**
- * Should the client send a remove command rather than a put when update is
- * called. This is a client option, not a receiver option. This allows you
- * to prevent the lateral from serializing objects.
- * <p>
- * @return true if updates will result in a remove command being sent.
- */
- boolean isIssueRemoveOnPut();
-
- /**
- * Should the receiver try to match hashcodes. If true, the receiver will
- * see if the client supplied a hashcode. If it did, then it will try to get
- * the item locally. If the item exists, then it will compare the hashcode.
- * if they are the same, it will not remove. This isn't perfect since
- * different objects can have the same hashcode, but it is unlikely of
- * objects of the same type.
- * <p>
- * @return boolean
- */
- boolean isFilterRemoveByHashCode();
-
- /**
- * Should the receiver try to match hashcodes. If true, the receiver will
- * see if the client supplied a hashcode. If it did, then it will try to get
- * the item locally. If the item exists, then it will compare the hashcode.
- * if they are the same, it will not remove. This isn't perfect since
- * different objects can have the same hashcode, but it is unlikely of
- * objects of the same type.
- * <p>
- * @param filter
- */
- void setFilterRemoveByHashCode( boolean filter );
-
- /**
- * @param socketTimeOut the socketTimeOut to set
- */
- void setSocketTimeOut( int socketTimeOut );
-
- /**
- * @return the socketTimeOut
- */
- int getSocketTimeOut();
-
- /**
- * @param openTimeOut the openTimeOut to set
- */
- void setOpenTimeOut( int openTimeOut );
-
- /**
- * @return the openTimeOut
- */
- int getOpenTimeOut();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteAuxiliaryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteAuxiliaryCache.java
deleted file mode 100644
index f599a43..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteAuxiliaryCache.java
+++ /dev/null
@@ -1,661 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheEventLogging;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheClient;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheListener;
-import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.ZombieCacheServiceNonLocal;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElementSerialized;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-import org.apache.commons.jcs.engine.behavior.IZombie;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.engine.stats.StatElement;
-import org.apache.commons.jcs.engine.stats.Stats;
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.serialization.SerializationConversionUtil;
-import org.apache.commons.jcs.utils.threadpool.ThreadPoolManager;
-
-/** Abstract base for remote caches. I'm trying to break out and reuse common functionality. */
-public abstract class AbstractRemoteAuxiliaryCache<K, V>
- extends AbstractAuxiliaryCacheEventLogging<K, V>
- implements IRemoteCacheClient<K, V>
-{
- /** The logger. */
- private static final Log log = LogManager.getLog( AbstractRemoteAuxiliaryCache.class );
-
- /**
- * This does the work. In an RMI instances, it will be a remote reference. In an http remote
- * cache it will be an http client. In zombie mode it is replaced with a balking facade.
- */
- private ICacheServiceNonLocal<K, V> remoteCacheService;
-
- /** The cacheName */
- protected final String cacheName;
-
- /** The listener. This can be null. */
- private IRemoteCacheListener<K, V> remoteCacheListener;
-
- /** The configuration values. TODO, we'll need a base here. */
- private IRemoteCacheAttributes remoteCacheAttributes;
-
- /** A thread pool for gets if configured. */
- private ExecutorService pool = null;
-
- /** Should we get asynchronously using a pool. */
- private boolean usePoolForGet = false;
-
- /**
- * Creates the base.
- * <p>
- * @param cattr
- * @param remote
- * @param listener
- */
- public AbstractRemoteAuxiliaryCache( IRemoteCacheAttributes cattr, ICacheServiceNonLocal<K, V> remote,
- IRemoteCacheListener<K, V> listener )
- {
- this.setRemoteCacheAttributes( cattr );
- this.cacheName = cattr.getCacheName();
- this.setRemoteCacheService( remote );
- this.setRemoteCacheListener( listener );
-
- if ( log.isDebugEnabled() )
- {
- log.debug( "Construct> cacheName={0}", () -> cattr.getCacheName() );
- log.debug( "irca = {0}", () -> getRemoteCacheAttributes() );
- log.debug( "remote = {0}", remote );
- log.debug( "listener = {0}", listener );
- }
-
- // use a pool if it is greater than 0
- log.debug( "GetTimeoutMillis() = {0}",
- () -> getRemoteCacheAttributes().getGetTimeoutMillis() );
-
- if ( getRemoteCacheAttributes().getGetTimeoutMillis() > 0 )
- {
- pool = ThreadPoolManager.getInstance().getExecutorService( getRemoteCacheAttributes().getThreadPoolName() );
- log.debug( "Thread Pool = {0}", pool );
- usePoolForGet = true;
- }
- }
-
- /**
- * Synchronously dispose the remote cache; if failed, replace the remote handle with a zombie.
- * <p>
- * @throws IOException
- */
- @Override
- protected void processDispose()
- throws IOException
- {
- log.info( "Disposing of remote cache." );
- try
- {
- if ( getRemoteCacheListener() != null )
- {
- getRemoteCacheListener().dispose();
- }
- }
- catch ( IOException ex )
- {
- log.error( "Couldn't dispose", ex );
- handleException( ex, "Failed to dispose [" + cacheName + "]", ICacheEventLogger.DISPOSE_EVENT );
- }
- }
-
- /**
- * Synchronously get from the remote cache; if failed, replace the remote handle with a zombie.
- * <p>
- * Use threadpool to timeout if a value is set for GetTimeoutMillis
- * <p>
- * If we are a cluster client, we need to leave the Element in its serialized form. Cluster
- * clients cannot deserialize objects. Cluster clients get ICacheElementSerialized objects from
- * other remote servers.
- * <p>
- * @param key
- * @return ICacheElement, a wrapper around the key, value, and attributes
- * @throws IOException
- */
- @Override
- protected ICacheElement<K, V> processGet( K key )
- throws IOException
- {
- ICacheElement<K, V> retVal = null;
- try
- {
- if ( usePoolForGet )
- {
- retVal = getUsingPool( key );
- }
- else
- {
- retVal = getRemoteCacheService().get( cacheName, key, getListenerId() );
- }
-
- // Eventually the instance of will not be necessary.
- if ( retVal instanceof ICacheElementSerialized )
- {
- // Never try to deserialize if you are a cluster client. Cluster
- // clients are merely intra-remote cache communicators. Remote caches are assumed
- // to have no ability to deserialize the objects.
- if ( this.getRemoteCacheAttributes().getRemoteType() != RemoteType.CLUSTER )
- {
- retVal = SerializationConversionUtil.getDeSerializedCacheElement( (ICacheElementSerialized<K, V>) retVal,
- super.getElementSerializer() );
- }
- }
- }
- catch ( Exception ex )
- {
- handleException( ex, "Failed to get [" + key + "] from [" + cacheName + "]", ICacheEventLogger.GET_EVENT );
- }
- return retVal;
- }
-
- /**
- * This allows gets to timeout in case of remote server machine shutdown.
- * <p>
- * @param key
- * @return ICacheElement
- * @throws IOException
- */
- public ICacheElement<K, V> getUsingPool( final K key )
- throws IOException
- {
- int timeout = getRemoteCacheAttributes().getGetTimeoutMillis();
-
- try
- {
- Callable<ICacheElement<K, V>> command = new Callable<ICacheElement<K, V>>()
- {
- @Override
- public ICacheElement<K, V> call()
- throws IOException
- {
- return getRemoteCacheService().get( cacheName, key, getListenerId() );
- }
- };
-
- // execute using the pool
- Future<ICacheElement<K, V>> future = pool.submit(command);
-
- // used timed get in order to timeout
- ICacheElement<K, V> ice = future.get(timeout, TimeUnit.MILLISECONDS);
-
- if ( ice == null )
- {
- log.debug( "nothing found in remote cache" );
- }
- else
- {
- log.debug( "found item in remote cache" );
- }
- return ice;
- }
- catch ( TimeoutException te )
- {
- log.warn( "TimeoutException, Get Request timed out after {0}", timeout );
- throw new IOException( "Get Request timed out after " + timeout );
- }
- catch ( InterruptedException ex )
- {
- log.warn( "InterruptedException, Get Request timed out after {0}", timeout );
- throw new IOException( "Get Request timed out after " + timeout );
- }
- catch (ExecutionException ex)
- {
- // assume that this is an IOException thrown by the callable.
- log.error( "ExecutionException, Assuming an IO exception thrown in the background.", ex );
- throw new IOException( "Get Request timed out after " + timeout );
- }
- }
-
- /**
- * Calls get matching on the server. Each entry in the result is unwrapped.
- * <p>
- * @param pattern
- * @return Map
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> processGetMatching( String pattern )
- throws IOException
- {
- Map<K, ICacheElement<K, V>> results = new HashMap<>();
- try
- {
- Map<K, ICacheElement<K, V>> rawResults = getRemoteCacheService().getMatching( cacheName, pattern, getListenerId() );
-
- // Eventually the instance of will not be necessary.
- if ( rawResults != null )
- {
- for (Map.Entry<K, ICacheElement<K, V>> entry : rawResults.entrySet())
- {
- ICacheElement<K, V> unwrappedResult = null;
- if ( entry.getValue() instanceof ICacheElementSerialized )
- {
- // Never try to deserialize if you are a cluster client. Cluster
- // clients are merely intra-remote cache communicators. Remote caches are assumed
- // to have no ability to deserialize the objects.
- if ( this.getRemoteCacheAttributes().getRemoteType() != RemoteType.CLUSTER )
- {
- unwrappedResult = SerializationConversionUtil
- .getDeSerializedCacheElement( (ICacheElementSerialized<K, V>) entry.getValue(),
- super.getElementSerializer() );
- }
- }
- else
- {
- unwrappedResult = entry.getValue();
- }
- results.put( entry.getKey(), unwrappedResult );
- }
- }
- }
- catch ( Exception ex )
- {
- handleException( ex, "Failed to getMatching [" + pattern + "] from [" + cacheName + "]",
- ICacheEventLogger.GET_EVENT );
- }
- return results;
- }
-
- /**
- * Synchronously remove from the remote cache; if failed, replace the remote handle with a
- * zombie.
- * <p>
- * @param key
- * @return boolean, whether or not the item was removed
- * @throws IOException
- */
- @Override
- protected boolean processRemove( K key )
- throws IOException
- {
- if ( !this.getRemoteCacheAttributes().getGetOnly() )
- {
- log.debug( "remove> key={0}", key );
- try
- {
- getRemoteCacheService().remove( cacheName, key, getListenerId() );
- }
- catch ( Exception ex )
- {
- handleException( ex, "Failed to remove " + key + " from " + cacheName, ICacheEventLogger.REMOVE_EVENT );
- }
- return true;
- }
- return false;
- }
-
- /**
- * Synchronously removeAll from the remote cache; if failed, replace the remote handle with a
- * zombie.
- * <p>
- * @throws IOException
- */
- @Override
- protected void processRemoveAll()
- throws IOException
- {
- if ( !this.getRemoteCacheAttributes().getGetOnly() )
- {
- try
- {
- getRemoteCacheService().removeAll( cacheName, getListenerId() );
- }
- catch ( Exception ex )
- {
- handleException( ex, "Failed to remove all from " + cacheName, ICacheEventLogger.REMOVEALL_EVENT );
- }
- }
- }
-
- /**
- * Serializes the object and then calls update on the remote server with the byte array. The
- * byte array is wrapped in a ICacheElementSerialized. This allows the remote server to operate
- * without any knowledge of caches classes.
- * <p>
- * @param ce
- * @throws IOException
- */
- @Override
- protected void processUpdate( ICacheElement<K, V> ce )
- throws IOException
- {
- if ( !getRemoteCacheAttributes().getGetOnly() )
- {
- ICacheElementSerialized<K, V> serialized = null;
- try
- {
- log.debug( "sending item to remote server" );
-
- // convert so we don't have to know about the object on the
- // other end.
- serialized = SerializationConversionUtil.getSerializedCacheElement( ce, super.getElementSerializer() );
-
- remoteCacheService.update( serialized, getListenerId() );
- }
- catch ( NullPointerException npe )
- {
- log.error( "npe for ce = {0} ce.attr = {1}", ce, ce.getElementAttributes(), npe );
- }
- catch ( Exception ex )
- {
- // event queue will wait and retry
- handleException( ex, "Failed to put [" + ce.getKey() + "] to " + ce.getCacheName(),
- ICacheEventLogger.UPDATE_EVENT );
- }
- }
- else
- {
- log.debug( "get only mode, not sending to remote server" );
- }
- }
-
- /**
- * Return the keys in this cache.
- * <p>
- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet()
- */
- @Override
- public Set<K> getKeySet()
- throws IOException
- {
- return getRemoteCacheService().getKeySet(cacheName);
- }
-
- /**
- * Allows other member of this package to access the listener. This is mainly needed for
- * deregistering a listener.
- * <p>
- * @return IRemoteCacheListener, the listener for this remote server
- */
- @Override
- public IRemoteCacheListener<K, V> getListener()
- {
- return getRemoteCacheListener();
- }
-
- /**
- * let the remote cache set a listener_id. Since there is only one listener for all the regions
- * and every region gets registered? the id shouldn't be set if it isn't zero. If it is we
- * assume that it is a reconnect.
- * <p>
- * @param id The new listenerId value
- */
- public void setListenerId( long id )
- {
- if ( getRemoteCacheListener() != null )
- {
- try
- {
- getRemoteCacheListener().setListenerId( id );
-
- log.debug( "set listenerId = {0}", id );
- }
- catch ( Exception e )
- {
- log.error( "Problem setting listenerId", e );
- }
- }
- }
-
- /**
- * Gets the listenerId attribute of the RemoteCacheListener object
- * <p>
- * @return The listenerId value
- */
- @Override
- public long getListenerId()
- {
- if ( getRemoteCacheListener() != null )
- {
- try
- {
- log.debug( "get listenerId = {0}", getRemoteCacheListener().getListenerId() );
- return getRemoteCacheListener().getListenerId();
- }
- catch ( IOException e )
- {
- log.error( "Problem getting listenerId", e );
- }
- }
- return -1;
- }
-
- /**
- * Returns the current cache size.
- * @return The size value
- */
- @Override
- public int getSize()
- {
- return 0;
- }
-
- /**
- * Custom exception handling some children. This should be used to initiate failover.
- * <p>
- * @param ex
- * @param msg
- * @param eventName
- * @throws IOException
- */
- protected abstract void handleException( Exception ex, String msg, String eventName )
- throws IOException;
-
- /**
- * Gets the stats attribute of the RemoteCache object.
- * <p>
- * @return The stats value
- */
- @Override
- public String getStats()
- {
- return getStatistics().toString();
- }
-
- /**
- * @return IStats object
- */
- @Override
- public IStats getStatistics()
- {
- IStats stats = new Stats();
- stats.setTypeName( "AbstractRemoteAuxiliaryCache" );
-
- ArrayList<IStatElement<?>> elems = new ArrayList<>();
-
- elems.add(new StatElement<>( "Remote Type", this.getRemoteCacheAttributes().getRemoteTypeName() ) );
-
-// if ( this.getRemoteCacheAttributes().getRemoteType() == RemoteType.CLUSTER )
-// {
-// // something cluster specific
-// }
-
- elems.add(new StatElement<>( "UsePoolForGet", Boolean.valueOf(usePoolForGet) ) );
-
- if ( pool != null )
- {
- elems.add(new StatElement<>( "Pool", pool ) );
- }
-
- if ( getRemoteCacheService() instanceof ZombieCacheServiceNonLocal )
- {
- elems.add(new StatElement<>( "Zombie Queue Size",
- Integer.valueOf(( (ZombieCacheServiceNonLocal<K, V>) getRemoteCacheService() ).getQueueSize()) ) );
- }
-
- stats.setStatElements( elems );
-
- return stats;
- }
-
- /**
- * Returns the cache status. An error status indicates the remote connection is not available.
- * <p>
- * @return The status value
- */
- @Override
- public CacheStatus getStatus()
- {
- return getRemoteCacheService() instanceof IZombie ? CacheStatus.ERROR : CacheStatus.ALIVE;
- }
-
- /**
- * Replaces the current remote cache service handle with the given handle. If the current remote
- * is a Zombie, then it propagates any events that are queued to the restored service.
- * <p>
- * @param restoredRemote ICacheServiceNonLocal -- the remote server or proxy to the remote server
- */
- @Override
- public void fixCache( ICacheServiceNonLocal<?, ?> restoredRemote )
- {
- @SuppressWarnings("unchecked") // Don't know how to do this properly
- ICacheServiceNonLocal<K, V> remote = (ICacheServiceNonLocal<K, V>)restoredRemote;
- ICacheServiceNonLocal<K, V> prevRemote = getRemoteCacheService();
- if ( prevRemote instanceof ZombieCacheServiceNonLocal )
- {
- ZombieCacheServiceNonLocal<K, V> zombie = (ZombieCacheServiceNonLocal<K, V>) prevRemote;
- setRemoteCacheService( remote );
- try
- {
- zombie.propagateEvents( remote );
- }
- catch ( Exception e )
- {
- try
- {
- handleException( e, "Problem propagating events from Zombie Queue to new Remote Service.",
- "fixCache" );
- }
- catch ( IOException e1 )
- {
- // swallow, since this is just expected kick back. Handle always throws
- }
- }
- }
- else
- {
- setRemoteCacheService( remote );
- }
- }
-
-
- /**
- * Gets the cacheType attribute of the RemoteCache object
- * @return The cacheType value
- */
- @Override
- public CacheType getCacheType()
- {
- return CacheType.REMOTE_CACHE;
- }
-
- /**
- * Gets the cacheName attribute of the RemoteCache object.
- * <p>
- * @return The cacheName value
- */
- @Override
- public String getCacheName()
- {
- return cacheName;
- }
-
- /**
- * @param remote the remote to set
- */
- protected void setRemoteCacheService( ICacheServiceNonLocal<K, V> remote )
- {
- this.remoteCacheService = remote;
- }
-
- /**
- * @return the remote
- */
- protected ICacheServiceNonLocal<K, V> getRemoteCacheService()
- {
- return remoteCacheService;
- }
-
- /**
- * @return Returns the AuxiliaryCacheAttributes.
- */
- @Override
- public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
- {
- return getRemoteCacheAttributes();
- }
-
- /**
- * @param remoteCacheAttributes the remoteCacheAttributes to set
- */
- protected void setRemoteCacheAttributes( IRemoteCacheAttributes remoteCacheAttributes )
- {
- this.remoteCacheAttributes = remoteCacheAttributes;
- }
-
- /**
- * @return the remoteCacheAttributes
- */
- protected IRemoteCacheAttributes getRemoteCacheAttributes()
- {
- return remoteCacheAttributes;
- }
-
- /**
- * @param remoteCacheListener the remoteCacheListener to set
- */
- protected void setRemoteCacheListener( IRemoteCacheListener<K, V> remoteCacheListener )
- {
- this.remoteCacheListener = remoteCacheListener;
- }
-
- /**
- * @return the remoteCacheListener
- */
- protected IRemoteCacheListener<K, V> getRemoteCacheListener()
- {
- return remoteCacheListener;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteCacheListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteCacheListener.java
deleted file mode 100644
index eafbc54..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteCacheListener.java
+++ /dev/null
@@ -1,266 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.net.UnknownHostException;
-
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheListener;
-import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElementSerialized;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.net.HostNameUtil;
-import org.apache.commons.jcs.utils.serialization.SerializationConversionUtil;
-
-/** Shared listener base. */
-public abstract class AbstractRemoteCacheListener<K, V>
- implements IRemoteCacheListener<K, V>
-{
- /** The logger */
- private static final Log log = LogManager.getLog( AbstractRemoteCacheListener.class );
-
- /** The cached name of the local host. The remote server gets this for logging purposes. */
- private static String localHostName = null;
-
- /**
- * The cache manager used to put items in different regions. This is set lazily and should not
- * be sent to the remote server.
- */
- private ICompositeCacheManager cacheMgr;
-
- /** The remote cache configuration object. */
- private final IRemoteCacheAttributes irca;
-
- /** This is set by the remote cache server. */
- private long listenerId = 0;
-
- /** Custom serializer. */
- private IElementSerializer elementSerializer;
-
- /**
- * Only need one since it does work for all regions, just reference by multiple region names.
- * <p>
- * The constructor exports this object, making it available to receive incoming calls. The
- * callback port is anonymous unless a local port value was specified in the configuration.
- * <p>
- * @param irca cache configuration
- * @param cacheMgr the cache hub
- * @param elementSerializer a custom serializer
- */
- public AbstractRemoteCacheListener( IRemoteCacheAttributes irca, ICompositeCacheManager cacheMgr, IElementSerializer elementSerializer )
- {
- this.irca = irca;
- this.cacheMgr = cacheMgr;
- this.elementSerializer = elementSerializer;
- }
-
- /**
- * Let the remote cache set a listener_id. Since there is only one listener for all the regions
- * and every region gets registered? the id shouldn't be set if it isn't zero. If it is we
- * assume that it is a reconnect.
- * <p>
- * @param id The new listenerId value
- * @throws IOException
- */
- @Override
- public void setListenerId( long id )
- throws IOException
- {
- listenerId = id;
- log.info( "set listenerId = [{0}]", id );
- }
-
- /**
- * Gets the listenerId attribute of the RemoteCacheListener object. This is stored in the
- * object. The RemoteCache object contains a reference to the listener and get the id this way.
- * <p>
- * @return The listenerId value
- * @throws IOException
- */
- @Override
- public long getListenerId()
- throws IOException
- {
- log.debug( "get listenerId = [{0}]", listenerId );
- return listenerId;
-
- }
-
- /**
- * Gets the remoteType attribute of the RemoteCacheListener object
- * <p>
- * @return The remoteType value
- * @throws IOException
- */
- @Override
- public RemoteType getRemoteType()
- throws IOException
- {
- log.debug( "getRemoteType = [{0}]", () -> irca.getRemoteType() );
- return irca.getRemoteType();
- }
-
- /**
- * If this is configured to remove on put, then remove the element since it has been updated
- * elsewhere. cd should be incomplete for faster transmission. We don't want to pass data only
- * invalidation. The next time it is used the local cache will get the new version from the
- * remote store.
- * <p>
- * If remove on put is not configured, then update the item.
- * @param cb
- * @throws IOException
- */
- @Override
- public void handlePut( ICacheElement<K, V> cb )
- throws IOException
- {
- if ( irca.getRemoveUponRemotePut() )
- {
- log.debug( "PUTTING ELEMENT FROM REMOTE, ( invalidating ) " );
- handleRemove( cb.getCacheName(), cb.getKey() );
- }
- else
- {
- log.debug( "PUTTING ELEMENT FROM REMOTE, ( updating ) " );
- log.debug( "cb = {0}", cb );
-
- // Eventually the instance of will not be necessary.
- if ( cb instanceof ICacheElementSerialized )
- {
- log.debug( "Object needs to be deserialized." );
- try
- {
- cb = SerializationConversionUtil.getDeSerializedCacheElement(
- (ICacheElementSerialized<K, V>) cb, this.elementSerializer );
- log.debug( "Deserialized result = {0}", cb );
- }
- catch ( IOException e )
- {
- throw e;
- }
- catch ( ClassNotFoundException e )
- {
- log.error( "Received a serialized version of a class that we don't know about.", e );
- }
- }
-
- getCacheManager().<K, V>getCache( cb.getCacheName() ).localUpdate( cb );
- }
- }
-
- /**
- * Calls localRemove on the CompositeCache.
- * <p>
- * @param cacheName
- * @param key
- * @throws IOException
- */
- @Override
- public void handleRemove( String cacheName, K key )
- throws IOException
- {
- log.debug( "handleRemove> cacheName={0}, key={1}", cacheName, key );
-
- getCacheManager().<K, V>getCache( cacheName ).localRemove( key );
- }
-
- /**
- * Calls localRemoveAll on the CompositeCache.
- * <p>
- * @param cacheName
- * @throws IOException
- */
- @Override
- public void handleRemoveAll( String cacheName )
- throws IOException
- {
- log.debug( "handleRemoveAll> cacheName={0}", cacheName );
-
- getCacheManager().<K, V>getCache( cacheName ).localRemoveAll();
- }
-
- /**
- * @param cacheName
- * @throws IOException
- */
- @Override
- public void handleDispose( String cacheName )
- throws IOException
- {
- log.debug( "handleDispose> cacheName={0}", cacheName );
- // TODO consider what to do here, we really don't want to
- // dispose, we just want to disconnect.
- // just allow the cache to go into error recovery mode.
- // getCacheManager().freeCache( cacheName, true );
- }
-
- /**
- * Gets the cacheManager attribute of the RemoteCacheListener object. This is one of the few
- * places that force the cache to be a singleton.
- */
- protected ICompositeCacheManager getCacheManager()
- {
- return cacheMgr;
- }
-
- /**
- * This is for debugging. It allows the remote server to log the address of clients.
- * <p>
- * @return String
- * @throws IOException
- */
- @Override
- public synchronized String getLocalHostAddress()
- throws IOException
- {
- if ( localHostName == null )
- {
- try
- {
- localHostName = HostNameUtil.getLocalHostAddress();
- }
- catch ( UnknownHostException uhe )
- {
- localHostName = "unknown";
- }
- }
- return localHostName;
- }
-
- /**
- * For easier debugging.
- * <p>
- * @return Basic info on this listener.
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\n AbstractRemoteCacheListener: " )
- .append( "\n RemoteHost = ").append(irca.getRemoteLocation())
- .append( "\n ListenerId = ").append(listenerId);
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteCacheNoWaitFacade.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteCacheNoWaitFacade.java
deleted file mode 100644
index 3c9650f..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteCacheNoWaitFacade.java
+++ /dev/null
@@ -1,434 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.engine.stats.StatElement;
-import org.apache.commons.jcs.engine.stats.Stats;
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/** An abstract base for the No Wait Facade. Different implementations will failover differently. */
-public abstract class AbstractRemoteCacheNoWaitFacade<K, V>
- extends AbstractAuxiliaryCache<K, V>
-{
- /** log instance */
- private static final Log log = LogManager.getLog( AbstractRemoteCacheNoWaitFacade.class );
-
- /** The connection to a remote server, or a zombie. */
- protected List<RemoteCacheNoWait<K, V>> noWaits;
-
- /** holds failover and cluster information */
- private IRemoteCacheAttributes remoteCacheAttributes;
-
- /**
- * Constructs with the given remote cache, and fires events to any listeners.
- * <p>
- * @param noWaits
- * @param rca
- * @param cacheEventLogger
- * @param elementSerializer
- */
- public AbstractRemoteCacheNoWaitFacade( List<RemoteCacheNoWait<K,V>> noWaits, IRemoteCacheAttributes rca,
- ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
- {
- log.debug( "CONSTRUCTING NO WAIT FACADE" );
- this.remoteCacheAttributes = rca;
- setCacheEventLogger( cacheEventLogger );
- setElementSerializer( elementSerializer );
- this.noWaits = new ArrayList<>(noWaits);
- for (RemoteCacheNoWait<K,V> nw : this.noWaits)
- {
- // FIXME: This cast is very brave. Remove this.
- ((RemoteCache<K, V>)nw.getRemoteCache()).setFacade(this);
- }
- }
-
- /**
- * Put an element in the cache.
- * <p>
- * @param ce
- * @throws IOException
- */
- @Override
- public void update( ICacheElement<K, V> ce )
- throws IOException
- {
- log.debug( "updating through cache facade, noWaits.length = {0}",
- () -> noWaits.size() );
-
- for (RemoteCacheNoWait<K, V> nw : noWaits)
- {
- try
- {
- nw.update( ce );
- // an initial move into a zombie will lock this to primary
- // recovery. will not discover other servers until primary
- // reconnect
- // and subsequent error
- }
- catch ( IOException ex )
- {
- String message = "Problem updating no wait. Will initiate failover if the noWait is in error.";
- log.error( message, ex );
-
- if ( getCacheEventLogger() != null )
- {
- getCacheEventLogger().logError( "RemoteCacheNoWaitFacade",
- ICacheEventLogger.UPDATE_EVENT,
- message + ":" + ex.getMessage() + " REGION: " + ce.getCacheName()
- + " ELEMENT: " + ce );
- }
-
- // can handle failover here? Is it safe to try the others?
- // check to see it the noWait is now a zombie
- // if it is a zombie, then move to the next in the failover list
- // will need to keep them in order or a count
- failover( nw );
- // should start a failover thread
- // should probably only failover if there is only one in the noWait
- // list
- // Should start a background thread to restore the original primary if we are in failover state.
- }
- }
- }
-
- /**
- * Synchronously reads from the remote cache.
- * <p>
- * @param key
- * @return Either an ICacheElement<K, V> or null if it is not found.
- */
- @Override
- public ICacheElement<K, V> get( K key )
- {
- for (RemoteCacheNoWait<K, V> nw : noWaits)
- {
- try
- {
- ICacheElement<K, V> obj = nw.get( key );
- if ( obj != null )
- {
- return obj;
- }
- }
- catch ( IOException ex )
- {
- log.debug( "Failed to get." );
- return null;
- }
- }
- return null;
- }
-
- /**
- * Synchronously read from the remote cache.
- * <p>
- * @param pattern
- * @return map
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching( String pattern )
- throws IOException
- {
- for (RemoteCacheNoWait<K, V> nw : noWaits)
- {
- try
- {
- return nw.getMatching( pattern );
- }
- catch ( IOException ex )
- {
- log.debug( "Failed to getMatching." );
- }
- }
- return Collections.emptyMap();
- }
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple( Set<K> keys )
- {
- if ( keys != null && !keys.isEmpty() )
- {
- for (RemoteCacheNoWait<K, V> nw : noWaits)
- {
- try
- {
- return nw.getMultiple( keys );
- }
- catch ( IOException ex )
- {
- log.debug( "Failed to get." );
- }
- }
- }
-
- return Collections.emptyMap();
- }
-
- /**
- * Return the keys in this cache.
- * <p>
- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet()
- */
- @Override
- public Set<K> getKeySet() throws IOException
- {
- HashSet<K> allKeys = new HashSet<>();
- for (RemoteCacheNoWait<K, V> nw : noWaits)
- {
- if ( nw != null )
- {
- Set<K> keys = nw.getKeySet();
- if(keys != null)
- {
- allKeys.addAll( keys );
- }
- }
- }
- return allKeys;
- }
-
- /**
- * Adds a remove request to the remote cache.
- * <p>
- * @param key
- * @return whether or not it was removed, right now it return false.
- */
- @Override
- public boolean remove( K key )
- {
- try
- {
- for (RemoteCacheNoWait<K, V> nw : noWaits)
- {
- nw.remove( key );
- }
- }
- catch ( IOException ex )
- {
- log.error( ex );
- }
- return false;
- }
-
- /**
- * Adds a removeAll request to the remote cache.
- */
- @Override
- public void removeAll()
- {
- try
- {
- for (RemoteCacheNoWait<K, V> nw : noWaits)
- {
- nw.removeAll();
- }
- }
- catch ( IOException ex )
- {
- log.error( ex );
- }
- }
-
- /** Adds a dispose request to the remote cache. */
- @Override
- public void dispose()
- {
- for (RemoteCacheNoWait<K, V> nw : noWaits)
- {
- nw.dispose();
- }
- }
-
- /**
- * No remote invocation.
- * <p>
- * @return The size value
- */
- @Override
- public int getSize()
- {
- return 0;
- // cache.getSize();
- }
-
- /**
- * Gets the cacheType attribute of the RemoteCacheNoWaitFacade object.
- * <p>
- * @return The cacheType value
- */
- @Override
- public CacheType getCacheType()
- {
- return CacheType.REMOTE_CACHE;
- }
-
- /**
- * Gets the cacheName attribute of the RemoteCacheNoWaitFacade object.
- * <p>
- * @return The cacheName value
- */
- @Override
- public String getCacheName()
- {
- return remoteCacheAttributes.getCacheName();
- }
-
- /**
- * Gets the status attribute of the RemoteCacheNoWaitFacade object
- * <p>
- * Return ALIVE if any are alive.
- * <p>
- * @return The status value
- */
- @Override
- public CacheStatus getStatus()
- {
- for (RemoteCacheNoWait<K, V> nw : noWaits)
- {
- if ( nw.getStatus() == CacheStatus.ALIVE )
- {
- return CacheStatus.ALIVE;
- }
- }
-
- return CacheStatus.DISPOSED;
- }
-
- /**
- * String form of some of the configuration information for the remote cache.
- * <p>
- * @return Some info for logging.
- */
- @Override
- public String toString()
- {
- return "RemoteCacheNoWaitFacade: " + remoteCacheAttributes.getCacheName() + ", rca = " + remoteCacheAttributes;
- }
-
- /**
- * Begin the failover process if this is a local cache. Clustered remote caches do not failover.
- * <p>
- * @param rcnw The no wait in error.
- */
- protected abstract void failover( RemoteCacheNoWait<K, V> rcnw );
-
- /**
- * Get the primary server from the list of failovers
- *
- * @return a no wait
- */
- public RemoteCacheNoWait<K, V> getPrimaryServer()
- {
- return noWaits.get(0);
- }
-
- /**
- * restore the primary server in the list of failovers
- *
- */
- public void restorePrimaryServer(RemoteCacheNoWait<K, V> rcnw)
- {
- noWaits.clear();
- noWaits.add(rcnw);
- }
-
- /**
- * @return Returns the AuxiliaryCacheAttributes.
- */
- @Override
- public IRemoteCacheAttributes getAuxiliaryCacheAttributes()
- {
- return this.remoteCacheAttributes;
- }
-
- /**
- * getStats
- * @return String
- */
- @Override
- public String getStats()
- {
- return getStatistics().toString();
- }
-
- /**
- * @return statistics about the cache region
- */
- @Override
- public IStats getStatistics()
- {
- IStats stats = new Stats();
- stats.setTypeName( "Remote Cache No Wait Facade" );
-
- ArrayList<IStatElement<?>> elems = new ArrayList<>();
-
- if ( noWaits != null )
- {
- elems.add(new StatElement<>( "Number of No Waits", Integer.valueOf(noWaits.size()) ) );
-
- for ( RemoteCacheNoWait<K, V> rcnw : noWaits )
- {
- // get the stats from the super too
- IStats sStats = rcnw.getStatistics();
- elems.addAll(sStats.getStatElements());
- }
- }
-
- stats.setStatElements( elems );
-
- return stats;
- }
-
- /**
- * This typically returns end point info .
- * <p>
- * @return the name
- */
- @Override
- public String getEventLoggingExtraInfo()
- {
- return "Remote Cache No Wait Facade";
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/CommonRemoteCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/CommonRemoteCacheAttributes.java
deleted file mode 100644
index 7ef69f9..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/CommonRemoteCacheAttributes.java
+++ /dev/null
@@ -1,295 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.remote.behavior.ICommonRemoteCacheAttributes;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheConstants;
-import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType;
-
-/**
- * Attributes common to remote cache client and server.
- */
-public class CommonRemoteCacheAttributes
- extends AbstractAuxiliaryCacheAttributes
- implements ICommonRemoteCacheAttributes
-{
- /** Don't change */
- private static final long serialVersionUID = -1555143736942374000L;
-
- /** The service name */
- private String remoteServiceName = IRemoteCacheConstants.REMOTE_CACHE_SERVICE_VAL;
-
- /** server host and port */
- private RemoteLocation location;
-
- /** Cluster chain */
- private String clusterServers = "";
-
- /** THe type of remote cache, local or cluster */
- private RemoteType remoteType = RemoteType.LOCAL;
-
- /** Should we issue a local remove if we get a put from a remote server */
- private boolean removeUponRemotePut = true;
-
- /** Can we receive from or put to the remote. this probably shouldn't be used. Use receive. */
- private boolean getOnly = false;
-
- /** Should we put and get from the clusters. */
- private boolean localClusterConsistency = false;
-
- /** read and connect timeout */
- private int rmiSocketFactoryTimeoutMillis = DEFAULT_RMI_SOCKET_FACTORY_TIMEOUT_MILLIS;
-
- /** Default constructor for the RemoteCacheAttributes object */
- public CommonRemoteCacheAttributes()
- {
- super();
- }
-
- /**
- * Gets the remoteTypeName attribute of the RemoteCacheAttributes object.
- * <p>
- * @return The remoteTypeName value
- */
- @Override
- public String getRemoteTypeName()
- {
- return remoteType != null ? remoteType.toString() : RemoteType.LOCAL.toString();
- }
-
- /**
- * Sets the remoteTypeName attribute of the RemoteCacheAttributes object.
- * <p>
- * @param s The new remoteTypeName value
- */
- @Override
- public void setRemoteTypeName( String s )
- {
- RemoteType rt = RemoteType.valueOf(s);
- if (rt != null)
- {
- this.remoteType = rt;
- }
- }
-
- /**
- * Gets the remoteType attribute of the RemoteCacheAttributes object.
- * <p>
- * @return The remoteType value
- */
- @Override
- public RemoteType getRemoteType()
- {
- return remoteType;
- }
-
- /**
- * Sets the remoteType attribute of the RemoteCacheAttributes object.
- * <p>
- * @param p The new remoteType value
- */
- @Override
- public void setRemoteType( RemoteType p )
- {
- this.remoteType = p;
- }
-
- /**
- * Gets the remoteServiceName attribute of the RemoteCacheAttributes object.
- * <p>
- * @return The remoteServiceName value
- */
- @Override
- public String getRemoteServiceName()
- {
- return this.remoteServiceName;
- }
-
- /**
- * Sets the remoteServiceName attribute of the RemoteCacheAttributes object.
- * <p>
- * @param s The new remoteServiceName value
- */
- @Override
- public void setRemoteServiceName( String s )
- {
- this.remoteServiceName = s;
- }
-
- /**
- * Sets the location attribute of the RemoteCacheAttributes object.
- * <p>
- * @param location The new location value
- */
- @Override
- public void setRemoteLocation( RemoteLocation location )
- {
- this.location = location;
- }
-
- /**
- * Sets the location attribute of the RemoteCacheAttributes object.
- * <p>
- * @param host The new remoteHost value
- * @param port The new remotePort value
- */
- @Override
- public void setRemoteLocation( String host, int port )
- {
- this.location = new RemoteLocation(host, port);
- }
-
- /**
- * Gets the location attribute of the RemoteCacheAttributes object.
- * <p>
- * @return The remote location value
- */
- @Override
- public RemoteLocation getRemoteLocation()
- {
- return this.location;
- }
-
- /**
- * Gets the clusterServers attribute of the RemoteCacheAttributes object.
- * <p>
- * @return The clusterServers value
- */
- @Override
- public String getClusterServers()
- {
- return this.clusterServers;
- }
-
- /**
- * Sets the clusterServers attribute of the RemoteCacheAttributes object.
- * <p>
- * @param s The new clusterServers value
- */
- @Override
- public void setClusterServers( String s )
- {
- this.clusterServers = s;
- }
-
- /**
- * Gets the removeUponRemotePut attribute of the RemoteCacheAttributes object.
- * <p>
- * @return The removeUponRemotePut value
- */
- @Override
- public boolean getRemoveUponRemotePut()
- {
- return this.removeUponRemotePut;
- }
-
- /**
- * Sets the removeUponRemotePut attribute of the RemoteCacheAttributes object.
- * <p>
- * @param r The new removeUponRemotePut value
- */
- @Override
- public void setRemoveUponRemotePut( boolean r )
- {
- this.removeUponRemotePut = r;
- }
-
- /**
- * Gets the getOnly attribute of the RemoteCacheAttributes object.
- * <p>
- * @return The getOnly value
- */
- @Override
- public boolean getGetOnly()
- {
- return this.getOnly;
- }
-
- /**
- * Sets the getOnly attribute of the RemoteCacheAttributes object
- * @param r The new getOnly value
- */
- @Override
- public void setGetOnly( boolean r )
- {
- this.getOnly = r;
- }
-
- /**
- * Should cluster updates be propagated to the locals.
- * <p>
- * @return The localClusterConsistency value
- */
- @Override
- public boolean isLocalClusterConsistency()
- {
- return localClusterConsistency;
- }
-
- /**
- * Should cluster updates be propagated to the locals.
- * <p>
- * @param r The new localClusterConsistency value
- */
- @Override
- public void setLocalClusterConsistency( boolean r )
- {
- this.localClusterConsistency = r;
- }
-
- /**
- * @param rmiSocketFactoryTimeoutMillis The rmiSocketFactoryTimeoutMillis to set.
- */
- @Override
- public void setRmiSocketFactoryTimeoutMillis( int rmiSocketFactoryTimeoutMillis )
- {
- this.rmiSocketFactoryTimeoutMillis = rmiSocketFactoryTimeoutMillis;
- }
-
- /**
- * @return Returns the rmiSocketFactoryTimeoutMillis.
- */
- @Override
- public int getRmiSocketFactoryTimeoutMillis()
- {
- return rmiSocketFactoryTimeoutMillis;
- }
-
- /**
- * @return String, all the important values that can be configured
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\n RemoteCacheAttributes " );
- if (this.location != null)
- {
- buf.append( "\n remoteHost = [" + this.location.getHost() + "]" );
- buf.append( "\n remotePort = [" + this.location.getPort() + "]" );
- }
- buf.append( "\n cacheName = [" + getCacheName() + "]" );
- buf.append( "\n remoteType = [" + remoteType + "]" );
- buf.append( "\n removeUponRemotePut = [" + this.removeUponRemotePut + "]" );
- buf.append( "\n getOnly = [" + getOnly + "]" );
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCache.java
deleted file mode 100644
index de06f59..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCache.java
+++ /dev/null
@@ -1,209 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.ArrayList;
-
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheListener;
-import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType;
-import org.apache.commons.jcs.engine.ZombieCacheServiceNonLocal;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-import org.apache.commons.jcs.engine.stats.StatElement;
-import org.apache.commons.jcs.engine.stats.Stats;
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * Client proxy for an RMI remote cache.
- * <p>
- * This handles gets, updates, and removes. It also initiates failover recovery when an error is
- * encountered.
- */
-public class RemoteCache<K, V>
- extends AbstractRemoteAuxiliaryCache<K, V>
-{
- /** The logger. */
- private static final Log log = LogManager.getLog( RemoteCache.class );
-
- /** for error notifications */
- private RemoteCacheMonitor monitor;
-
- /** back link for failover initiation */
- private AbstractRemoteCacheNoWaitFacade<K, V> facade;
-
- /**
- * Constructor for the RemoteCache object. This object communicates with a remote cache server.
- * One of these exists for each region. This also holds a reference to a listener. The same
- * listener is used for all regions for one remote server. Holding a reference to the listener
- * allows this object to know the listener id assigned by the remote cache.
- * <p>
- * @param cattr the cache configuration
- * @param remote the remote cache server handle
- * @param listener a listener
- * @param monitor the cache monitor
- */
- public RemoteCache( IRemoteCacheAttributes cattr,
- ICacheServiceNonLocal<K, V> remote,
- IRemoteCacheListener<K, V> listener,
- RemoteCacheMonitor monitor )
- {
- super( cattr, remote, listener );
- this.monitor = monitor;
-
- RemoteUtils.configureGlobalCustomSocketFactory( getRemoteCacheAttributes().getRmiSocketFactoryTimeoutMillis() );
- }
-
- /**
- * @return IStats object
- */
- @Override
- public IStats getStatistics()
- {
- IStats stats = new Stats();
- stats.setTypeName( "Remote Cache" );
-
- ArrayList<IStatElement<?>> elems = new ArrayList<>();
-
- elems.add(new StatElement<>( "Remote Host:Port", getIPAddressForService() ) );
- elems.add(new StatElement<>( "Remote Type", this.getRemoteCacheAttributes().getRemoteTypeName() ) );
-
-// if ( this.getRemoteCacheAttributes().getRemoteType() == RemoteType.CLUSTER )
-// {
-// // something cluster specific
-// }
-
- // get the stats from the super too
- IStats sStats = super.getStatistics();
- elems.addAll(sStats.getStatElements());
-
- stats.setStatElements( elems );
-
- return stats;
- }
-
- /**
- * Set facade
- *
- * @param facade the facade to set
- */
- protected void setFacade(AbstractRemoteCacheNoWaitFacade<K, V> facade)
- {
- this.facade = facade;
- }
-
- /**
- * Get facade
- *
- * @return the facade
- */
- protected AbstractRemoteCacheNoWaitFacade<K, V> getFacade()
- {
- return facade;
- }
-
- /**
- * Handles exception by disabling the remote cache service before re-throwing the exception in
- * the form of an IOException.
- * <p>
- * @param ex
- * @param msg
- * @param eventName
- * @throws IOException
- */
- @Override
- protected void handleException( Exception ex, String msg, String eventName )
- throws IOException
- {
- String message = "Disabling remote cache due to error: " + msg;
-
- logError( cacheName, "", message );
- log.error( message, ex );
-
- // we should not switch if the existing is a zombie.
- if ( getRemoteCacheService() == null || !( getRemoteCacheService() instanceof ZombieCacheServiceNonLocal ) )
- {
- // TODO make configurable
- setRemoteCacheService( new ZombieCacheServiceNonLocal<>( getRemoteCacheAttributes().getZombieQueueMaxSize() ) );
- }
- // may want to flush if region specifies
- // Notify the cache monitor about the error, and kick off the recovery
- // process.
- monitor.notifyError();
-
- log.debug( "Initiating failover, rcnwf = {0}", facade );
-
- if ( facade != null && facade.getAuxiliaryCacheAttributes().getRemoteType() == RemoteType.LOCAL )
- {
- log.debug( "Found facade, calling failover" );
- // may need to remove the noWait index here. It will be 0 if it is
- // local since there is only 1 possible listener.
- facade.failover( facade.getPrimaryServer() );
- }
-
- if ( ex instanceof IOException )
- {
- throw (IOException) ex;
- }
- throw new IOException( ex );
- }
-
- /**
- * Debugging info.
- * <p>
- * @return basic info about the RemoteCache
- */
- @Override
- public String toString()
- {
- return "RemoteCache: " + cacheName + " attributes = " + getRemoteCacheAttributes();
- }
-
- /**
- * Gets the extra info for the event log.
- * <p>
- * @return disk location
- */
- @Override
- public String getEventLoggingExtraInfo()
- {
- return getIPAddressForService();
- }
-
- /**
- * IP address for the service, if one is stored.
- * <p>
- * Protected for testing.
- * <p>
- * @return String
- */
- protected String getIPAddressForService()
- {
- String ipAddress = "(null)";
- if (this.getRemoteCacheAttributes().getRemoteLocation() != null)
- {
- ipAddress = this.getRemoteCacheAttributes().getRemoteLocation().toString();
- }
- return ipAddress;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheAttributes.java
deleted file mode 100644
index 7d1fad4..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheAttributes.java
+++ /dev/null
@@ -1,263 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import java.util.List;
-
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
-
-/**
- * These objects are used to configure the remote cache client.
- */
-public class RemoteCacheAttributes
- extends CommonRemoteCacheAttributes
- implements IRemoteCacheAttributes
-{
- /** Don't change */
- private static final long serialVersionUID = -1555143736942374000L;
-
- /**
- * Failover servers will be used by local caches one at a time. Listeners will be registered
- * with all cluster servers. If we add a get from cluster attribute we will have the ability to
- * chain clusters and have them get from each other.
- */
- private String failoverServers = "";
-
- /** callback */
- private int localPort = 0;
-
- /** what failover server we are connected to. */
- private int failoverIndex = 0;
-
- /** List of failover server addresses */
- private List<RemoteLocation> failovers;
-
- /** default name is remote_cache_client */
- private String threadPoolName = "remote_cache_client";
-
- /** must be greater than 0 for a pool to be used. */
- private int getTimeoutMillis = -1;
-
- /**
- * Can we receive from the server. You might have a 0 local store and keep everything on the
- * remote. If so, you don't want to be notified of updates.
- */
- private boolean receive = DEFAULT_RECEIVE;
-
- /** If the primary fails, we will queue items before reconnect. This limits the number of items that can be queued. */
- private int zombieQueueMaxSize = DEFAULT_ZOMBIE_QUEUE_MAX_SIZE;
-
- /** Default constructor for the RemoteCacheAttributes object */
- public RemoteCacheAttributes()
- {
- super();
- }
-
- /**
- * Gets the failoverIndex attribute of the RemoteCacheAttributes object.
- * <p>
- * @return The failoverIndex value
- */
- @Override
- public int getFailoverIndex()
- {
- return failoverIndex;
- }
-
- /**
- * Sets the failoverIndex attribute of the RemoteCacheAttributes object.
- * <p>
- * @param p The new failoverIndex value
- */
- @Override
- public void setFailoverIndex( int p )
- {
- this.failoverIndex = p;
- }
-
- /**
- * Gets the failovers attribute of the RemoteCacheAttributes object.
- * <p>
- * @return The failovers value
- */
- @Override
- public List<RemoteLocation> getFailovers()
- {
- return this.failovers;
- }
-
- /**
- * Sets the failovers attribute of the RemoteCacheAttributes object.
- * <p>
- * @param failovers The new failovers value
- */
- @Override
- public void setFailovers( List<RemoteLocation> failovers )
- {
- this.failovers = failovers;
- }
-
- /**
- * Gets the failoverServers attribute of the RemoteCacheAttributes object.
- * <p>
- * @return The failoverServers value
- */
- @Override
- public String getFailoverServers()
- {
- return this.failoverServers;
- }
-
- /**
- * Sets the failoverServers attribute of the RemoteCacheAttributes object.
- * <p>
- * @param s The new failoverServers value
- */
- @Override
- public void setFailoverServers( String s )
- {
- this.failoverServers = s;
- }
-
- /**
- * Gets the localPort attribute of the RemoteCacheAttributes object.
- * <p>
- * @return The localPort value
- */
- @Override
- public int getLocalPort()
- {
- return this.localPort;
- }
-
- /**
- * Sets the localPort attribute of the RemoteCacheAttributes object
- * @param p The new localPort value
- */
- @Override
- public void setLocalPort( int p )
- {
- this.localPort = p;
- }
-
- /**
- * @return the name of the pool
- */
- @Override
- public String getThreadPoolName()
- {
- return threadPoolName;
- }
-
- /**
- * @param name
- */
- @Override
- public void setThreadPoolName( String name )
- {
- threadPoolName = name;
- }
-
- /**
- * @return getTimeoutMillis
- */
- @Override
- public int getGetTimeoutMillis()
- {
- return getTimeoutMillis;
- }
-
- /**
- * @param millis
- */
- @Override
- public void setGetTimeoutMillis( int millis )
- {
- getTimeoutMillis = millis;
- }
-
- /**
- * By default this option is true. If you set it to false, you will not receive updates or
- * removes from the remote server.
- * <p>
- * @param receive
- */
- @Override
- public void setReceive( boolean receive )
- {
- this.receive = receive;
- }
-
- /**
- * If RECEIVE is false then the remote cache will not register a listener with the remote
- * server. This allows you to configure a remote server as a repository from which you can get
- * and to which you put, but from which you do not receive any notifications. That is, you will
- * not receive updates or removes.
- * <p>
- * If you set this option to false, you should set your local memory size to 0.
- * <p>
- * The remote cache manager uses this value to decide whether or not to register a listener.
- * @return the receive value.
- */
- @Override
- public boolean isReceive()
- {
- return this.receive;
- }
-
- /**
- * The number of elements the zombie queue will hold. This queue is used to store events if we
- * loose our connection with the server.
- * <p>
- * @param zombieQueueMaxSize The zombieQueueMaxSize to set.
- */
- @Override
- public void setZombieQueueMaxSize( int zombieQueueMaxSize )
- {
- this.zombieQueueMaxSize = zombieQueueMaxSize;
- }
-
- /**
- * The number of elements the zombie queue will hold. This queue is used to store events if we
- * loose our connection with the server.
- * <p>
- * @return Returns the zombieQueueMaxSize.
- */
- @Override
- public int getZombieQueueMaxSize()
- {
- return zombieQueueMaxSize;
- }
-
- /**
- * @return String, all the important values that can be configured
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder(super.toString());
- buf.append( "\n receive = [" + isReceive() + "]" );
- buf.append( "\n getTimeoutMillis = [" + getGetTimeoutMillis() + "]" );
- buf.append( "\n threadPoolName = [" + getThreadPoolName() + "]" );
- buf.append( "\n localClusterConsistency = [" + isLocalClusterConsistency() + "]" );
- buf.append( "\n zombieQueueMaxSize = [" + getZombieQueueMaxSize() + "]" );
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheFactory.java
deleted file mode 100644
index 25f18d6..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheFactory.java
+++ /dev/null
@@ -1,272 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import java.rmi.registry.Registry;
-import java.util.ArrayList;
-import java.util.StringTokenizer;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
-import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-
-/**
- * The RemoteCacheFactory creates remote caches for the cache hub. It returns a no wait facade which
- * is a wrapper around a no wait. The no wait object is either an active connection to a remote
- * cache or a balking zombie if the remote cache is not accessible. It should be transparent to the
- * clients.
- */
-public class RemoteCacheFactory
- extends AbstractAuxiliaryCacheFactory
-{
- /** Monitor thread */
- private RemoteCacheMonitor monitor;
-
- /** Contains mappings of RemoteLocation instance to RemoteCacheManager instance. */
- private ConcurrentMap<RemoteLocation, RemoteCacheManager> managers;
-
- /** Lock for initialization of manager instances */
- private Lock managerLock;
-
- /**
- * For LOCAL clients we get a handle to all the failovers, but we do not register a listener
- * with them. We create the RemoteCacheManager, but we do not get a cache.
- * <p>
- * The failover runner will get a cache from the manager. When the primary is restored it will
- * tell the manager for the failover to deregister the listener.
- * <p>
- * @param iaca
- * @param cacheMgr
- * @param cacheEventLogger
- * @param elementSerializer
- * @return AuxiliaryCache
- */
- @Override
- public <K, V> AuxiliaryCache<K, V> createCache(
- AuxiliaryCacheAttributes iaca, ICompositeCacheManager cacheMgr,
- ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
- {
- RemoteCacheAttributes rca = (RemoteCacheAttributes) iaca;
-
- ArrayList<RemoteCacheNoWait<K,V>> noWaits = new ArrayList<>();
-
- switch (rca.getRemoteType())
- {
- case LOCAL:
- // a list to be turned into an array of failover server information
- ArrayList<RemoteLocation> failovers = new ArrayList<>();
-
- // not necessary if a failover list is defined
- // REGISTER PRIMARY LISTENER
- // if it is a primary
- boolean primaryDefined = false;
- if ( rca.getRemoteLocation() != null )
- {
- primaryDefined = true;
-
- failovers.add( rca.getRemoteLocation() );
- RemoteCacheManager rcm = getManager( rca, cacheMgr, cacheEventLogger, elementSerializer );
- RemoteCacheNoWait<K,V> ic = rcm.getCache( rca );
- noWaits.add( ic );
- }
-
- // GET HANDLE BUT DONT REGISTER A LISTENER FOR FAILOVERS
- String failoverList = rca.getFailoverServers();
- if ( failoverList != null )
- {
- StringTokenizer fit = new StringTokenizer( failoverList, "," );
- int fCnt = 0;
- while ( fit.hasMoreTokens() )
- {
- fCnt++;
-
- String server = fit.nextToken();
- RemoteLocation location = RemoteLocation.parseServerAndPort(server);
-
- if (location != null)
- {
- failovers.add( location );
- rca.setRemoteLocation(location);
- RemoteCacheManager rcm = getManager( rca, cacheMgr, cacheEventLogger, elementSerializer );
-
- // add a listener if there are none, need to tell rca what
- // number it is at
- if ( ( !primaryDefined && fCnt == 1 ) || noWaits.size() <= 0 )
- {
- RemoteCacheNoWait<K,V> ic = rcm.getCache( rca );
- noWaits.add( ic );
- }
- }
- }
- // end while
- }
- // end if failoverList != null
-
- rca.setFailovers( failovers );
- break;
-
- case CLUSTER:
- // REGISTER LISTENERS FOR EACH SYSTEM CLUSTERED CACHEs
- StringTokenizer it = new StringTokenizer( rca.getClusterServers(), "," );
- while ( it.hasMoreElements() )
- {
- String server = (String) it.nextElement();
- RemoteLocation location = RemoteLocation.parseServerAndPort(server);
-
- if (location != null)
- {
- rca.setRemoteLocation(location);
- RemoteCacheManager rcm = getManager( rca, cacheMgr, cacheEventLogger, elementSerializer );
- rca.setRemoteType( RemoteType.CLUSTER );
- RemoteCacheNoWait<K,V> ic = rcm.getCache( rca );
- noWaits.add( ic );
- }
- }
- break;
- }
-
- RemoteCacheNoWaitFacade<K, V> rcnwf =
- new RemoteCacheNoWaitFacade<>(noWaits, rca, cacheEventLogger, elementSerializer, this );
-
- return rcnwf;
- }
-
- // end createCache
-
- /**
- * Returns an instance of RemoteCacheManager for the given connection parameters.
- * <p>
- * Host and Port uniquely identify a manager instance.
- * <p>
- * @param cattr
- *
- * @return The instance value or null if no such manager exists
- */
- public RemoteCacheManager getManager( IRemoteCacheAttributes cattr )
- {
- if ( cattr.getRemoteLocation() == null )
- {
- cattr.setRemoteLocation("", Registry.REGISTRY_PORT);
- }
-
- RemoteLocation loc = cattr.getRemoteLocation();
- RemoteCacheManager ins = managers.get( loc );
-
- return ins;
- }
-
- /**
- * Returns an instance of RemoteCacheManager for the given connection parameters.
- * <p>
- * Host and Port uniquely identify a manager instance.
- * <p>
- * If the connection cannot be established, zombie objects will be used for future recovery
- * purposes.
- * <p>
- * @param cattr
- * @param cacheMgr
- * @param cacheEventLogger
- * @param elementSerializer
- * @return The instance value, never null
- */
- public RemoteCacheManager getManager( IRemoteCacheAttributes cattr, ICompositeCacheManager cacheMgr,
- ICacheEventLogger cacheEventLogger,
- IElementSerializer elementSerializer )
- {
- RemoteCacheManager ins = getManager( cattr );
-
- if ( ins == null )
- {
- managerLock.lock();
-
- try
- {
- ins = managers.get( cattr.getRemoteLocation() );
-
- if (ins == null)
- {
- ins = new RemoteCacheManager( cattr, cacheMgr, monitor, cacheEventLogger, elementSerializer);
- managers.put( cattr.getRemoteLocation(), ins );
- monitor.addManager(ins);
- }
- }
- finally
- {
- managerLock.unlock();
- }
- }
-
- return ins;
- }
-
- /**
- * @see org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory#initialize()
- */
- @Override
- public void initialize()
- {
- super.initialize();
-
- managers = new ConcurrentHashMap<>();
- managerLock = new ReentrantLock();
-
- monitor = new RemoteCacheMonitor();
- monitor.setDaemon(true);
- }
-
- /**
- * @see org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory#dispose()
- */
- @Override
- public void dispose()
- {
- for (RemoteCacheManager manager : managers.values())
- {
- manager.release();
- }
-
- managers.clear();
-
- if (monitor != null)
- {
- monitor.notifyShutdown();
- try
- {
- monitor.join(5000);
- }
- catch (InterruptedException e)
- {
- // swallow
- }
- monitor = null;
- }
-
- super.dispose();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheFailoverRunner.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheFailoverRunner.java
deleted file mode 100644
index effc4fd..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheFailoverRunner.java
+++ /dev/null
@@ -1,389 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.List;
-import java.util.ListIterator;
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheMonitor;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.behavior.ICache;
-
-/**
- * The RemoteCacheFailoverRunner tries to establish a connection with a failover
- * server, if any are defined. Once a failover connection is made, it will
- * attempt to replace the failover with the primary remote server.
- * <p>
- * It works by switching out the RemoteCacheNoWait inside the Facade.
- * <p>
- * Client (i.e.) the CompositeCache has reference to a RemoteCacheNoWaitFacade.
- * This facade is created by the RemoteCacheFactory. The factory maintains a set
- * of managers, one for each remote server. Typically, there will only be one
- * manager.
- * <p>
- * If you use multiple remote servers, you may want to set one or more as
- * failovers. If a local cache cannot connect to the primary server, or looses
- * its connection to the primary server, it will attempt to restore that
- * Connection in the background. If failovers are defined, the Failover runner
- * will try to connect to a failover until the primary is restored.
- *
- */
-public class RemoteCacheFailoverRunner<K, V> extends AbstractAuxiliaryCacheMonitor
-{
- /** The facade returned to the composite cache. */
- private final RemoteCacheNoWaitFacade<K, V> facade;
-
- /** Factory instance */
- private final RemoteCacheFactory cacheFactory;
-
- /**
- * Constructor for the RemoteCacheFailoverRunner object. This allows the
- * FailoverRunner to modify the facade that the CompositeCache references.
- *
- * @param facade the facade the CompositeCache talks to.
- * @param cacheFactory the cache factory instance
- */
- public RemoteCacheFailoverRunner( RemoteCacheNoWaitFacade<K, V> facade, RemoteCacheFactory cacheFactory )
- {
- super("JCS-RemoteCacheFailoverRunner");
- this.facade = facade;
- this.cacheFactory = cacheFactory;
- setIdlePeriod(20000L);
- }
-
- /**
- * Clean up all resources before shutdown
- */
- @Override
- protected void dispose()
- {
- // empty
- }
-
- /**
- * do actual work
- */
- @Override
- protected void doWork()
- {
- // empty
- }
-
-
- /**
- * Main processing method for the RemoteCacheFailoverRunner object.
- * <p>
- * If we do not have a connection with any failover server, this will try to
- * connect one at a time. If no connection can be made, it goes to sleep for
- * a while (20 seconds).
- * <p>
- * Once a connection with a failover is made, we will try to reconnect to
- * the primary server.
- * <p>
- * The primary server is the first server defines in the FailoverServers
- * list.
- */
- @Override
- public void run()
- {
- // start the main work of connecting to a failover and then restoring
- // the primary.
- connectAndRestore();
-
- if ( log.isInfoEnabled() )
- {
- int failoverIndex = facade.getAuxiliaryCacheAttributes().getFailoverIndex();
- log.info( "Exiting failover runner. Failover index = {0}", failoverIndex);
-
- if ( failoverIndex <= 0 )
- {
- log.info( "Failover index is <= 0, meaning we are not connected to a failover server." );
- }
- else if ( failoverIndex > 0 )
- {
- log.info( "Failover index is > 0, meaning we are connected to a failover server." );
- }
- // log if we are allright or not.
- }
- }
-
- /**
- * This is the main loop. If there are failovers defined, then this will
- * continue until the primary is re-connected. If no failovers are defined,
- * this will exit automatically.
- */
- private void connectAndRestore()
- {
- IRemoteCacheAttributes rca0 = facade.getAuxiliaryCacheAttributes();
-
- do
- {
- log.info( "Remote cache FAILOVER RUNNING." );
-
- // there is no active listener
- if ( !allright.get() )
- {
- // Monitor each RemoteCacheManager instance one after the other.
- // Each RemoteCacheManager corresponds to one remote connection.
- List<RemoteLocation> failovers = rca0.getFailovers();
- // we should probably check to see if there are any failovers,
- // even though the caller
- // should have already.
-
- if ( failovers == null )
- {
- log.warn( "Remote is misconfigured, failovers was null." );
- return;
- }
- else if ( failovers.size() == 1 )
- {
- // if there is only the primary, return out of this
- log.info( "No failovers defined, exiting failover runner." );
- return;
- }
-
- int fidx = rca0.getFailoverIndex();
- log.debug( "fidx = {0} failovers.size = {1}", () -> fidx,
- () -> failovers.size() );
-
- // shouldn't we see if the primary is backup?
- // If we don't check the primary, if it gets connected in the
- // background,
- // we will disconnect it only to put it right back
- ListIterator<RemoteLocation> i = failovers.listIterator(fidx); // + 1; // +1 skips the primary
- log.debug( "starting at failover i = {0}", i );
-
- // try them one at a time until successful
- for ( ; i.hasNext() && !allright.get();)
- {
- RemoteLocation server = i.next();
- log.debug( "Trying server [{1}] at failover index i = {1}",
- server, i );
-
- RemoteCacheAttributes rca = (RemoteCacheAttributes) rca0.clone();
- rca.setRemoteLocation(server);
- RemoteCacheManager rcm = cacheFactory.getManager( rca );
-
- log.debug( "RemoteCacheAttributes for failover = {0}", rca );
-
- if (rcm != null)
- {
- // add a listener if there are none, need to tell rca
- // what number it is at
- ICache<K, V> ic = rcm.getCache( rca );
- if ( ic.getStatus() == CacheStatus.ALIVE )
- {
- // may need to do this more gracefully
- log.debug( "resetting no wait" );
- facade.restorePrimaryServer((RemoteCacheNoWait<K, V>) ic);
- rca0.setFailoverIndex( i.nextIndex() );
-
- log.debug( "setting ALLRIGHT to true" );
- if ( i.hasPrevious() )
- {
- log.debug( "Moving to Primary Recovery Mode, failover index = {0}", i );
- }
- else
- {
- log.debug( "No need to connect to failover, the primary server is back up." );
- }
-
- allright.set(true);
-
- log.info( "CONNECTED to host = [{0}]",
- () -> rca.getRemoteLocation() );
- }
- }
- }
- }
- // end if !allright
- // get here if while index >0 and allright, meaning that we are
- // connected to some backup server.
- else
- {
- log.debug( "ALLRIGHT is true " );
- log.info( "Failover runner is in primary recovery mode. "
- + "Failover index = {0} Will now try to reconnect to "
- + "primary server.", () -> rca0.getFailoverIndex() );
- }
-
- boolean primaryRestoredSuccessfully = false;
- // if we are not connected to the primary, try.
- if ( rca0.getFailoverIndex() > 0 )
- {
- primaryRestoredSuccessfully = restorePrimary();
- log.debug( "Primary recovery success state = {0}",
- primaryRestoredSuccessfully );
- }
-
- if ( !primaryRestoredSuccessfully )
- {
- // Time driven mode: sleep between each round of recovery
- // attempt.
- try
- {
- log.warn( "Failed to reconnect to primary server. "
- + "Cache failover runner is going to sleep for "
- + "{0} milliseconds.", idlePeriod );
- Thread.sleep( idlePeriod );
- }
- catch ( InterruptedException ex )
- {
- // ignore;
- }
- }
-
- // try to bring the listener back to the primary
- }
- while ( rca0.getFailoverIndex() > 0 || !allright.get() );
- // continue if the primary is not restored or if things are not allright.
- }
-
- /**
- * Try to restore the primary server.
- * <p>
- * Once primary is restored the failover listener must be deregistered.
- * <p>
- * The primary server is the first server defines in the FailoverServers
- * list.
- *
- * @return boolean value indicating whether the restoration was successful
- */
- private boolean restorePrimary()
- {
- IRemoteCacheAttributes rca0 = facade.getAuxiliaryCacheAttributes();
- // try to move back to the primary
- RemoteLocation server = rca0.getFailovers().get(0);
-
- log.info( "Trying to restore connection to primary remote server "
- + "[{0}]", server );
-
- RemoteCacheAttributes rca = (RemoteCacheAttributes) rca0.clone();
- rca.setRemoteLocation(server);
- RemoteCacheManager rcm = cacheFactory.getManager( rca );
-
- if (rcm != null)
- {
- // add a listener if there are none, need to tell rca what number it
- // is at
- ICache<K, V> ic = rcm.getCache( rca );
- // by default the listener id should be 0, else it will be the
- // listener
- // Originally associated with the remote cache. either way is fine.
- // We just don't want the listener id from a failover being used.
- // If the remote server was rebooted this could be a problem if new
- // locals were also added.
-
- if ( ic.getStatus() == CacheStatus.ALIVE )
- {
- try
- {
- // we could have more than one listener registered right
- // now.
- // this will not result in a loop, only duplication
- // stop duplicate listening.
- if ( facade.getPrimaryServer() != null && facade.getPrimaryServer().getStatus() == CacheStatus.ALIVE )
- {
- int fidx = rca0.getFailoverIndex();
-
- if ( fidx > 0 )
- {
- RemoteLocation serverOld = rca0.getFailovers().get(fidx);
-
- log.debug( "Failover Index = {0} the server at that "
- + "index is [{1}]", fidx, serverOld );
-
- if ( serverOld != null )
- {
- // create attributes that reflect the
- // previous failed over configuration.
- RemoteCacheAttributes rcaOld = (RemoteCacheAttributes) rca0.clone();
- rcaOld.setRemoteLocation(serverOld);
- RemoteCacheManager rcmOld = cacheFactory.getManager( rcaOld );
-
- if ( rcmOld != null )
- {
- // manager can remove by name if
- // necessary
- rcmOld.removeRemoteCacheListener( rcaOld );
- }
- log.info( "Successfully deregistered from "
- + "FAILOVER remote server = {0}", serverOld );
- }
- }
- else if ( fidx == 0 )
- {
- // this should never happen. If there are no
- // failovers this shouldn't get called.
- if ( log.isDebugEnabled() )
- {
- log.debug( "No need to restore primary, it is already restored." );
- return true;
- }
- }
- else if ( fidx < 0 )
- {
- // this should never happen
- log.warn( "Failover index is less than 0, this shouldn't happen" );
- }
- }
- }
- catch ( IOException e )
- {
- // TODO, should try again, or somehow stop the listener
- log.error("Trouble trying to deregister old failover "
- + "listener prior to restoring the primary = {0}",
- server, e );
- }
-
- // Restore primary
- // may need to do this more gracefully, letting the failover finish in the background
- RemoteCacheNoWait<K, V> failoverNoWait = facade.getPrimaryServer();
-
- // swap in a new one
- facade.restorePrimaryServer((RemoteCacheNoWait<K, V>) ic);
- rca0.setFailoverIndex( 0 );
-
- String message = "Successfully reconnected to PRIMARY "
- + "remote server. Substituted primary for "
- + "failoverNoWait [" + failoverNoWait + "]";
- log.info( message );
-
- if ( facade.getCacheEventLogger() != null )
- {
- facade.getCacheEventLogger().logApplicationEvent(
- "RemoteCacheFailoverRunner", "RestoredPrimary",
- message );
- }
- return true;
- }
- }
-
- // else all right
- // if the failover index was at 0 here, we would be in a bad
- // situation, unless there were just
- // no failovers configured.
- log.debug( "Primary server status in error, not connected." );
-
- return false;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheListener.java
deleted file mode 100644
index 29942fe..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheListener.java
+++ /dev/null
@@ -1,115 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.rmi.RemoteException;
-import java.rmi.server.UnicastRemoteObject;
-
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheConstants;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * Registered with RemoteCache server. The server updates the local caches via this listener. Each
- * server assigns a unique listener id for a listener.
- * <p>
- * One listener is used per remote cache server. The same listener is used for all the regions that
- * talk to a particular server.
- */
-public class RemoteCacheListener<K, V>
- extends AbstractRemoteCacheListener<K, V>
- implements IRemoteCacheConstants
-{
- /** The logger */
- private static final Log log = LogManager.getLog( RemoteCacheListener.class );
-
- /** Has this client been shutdown. */
- private boolean disposed = false;
-
- /**
- * Only need one since it does work for all regions, just reference by multiple region names.
- * <p>
- * The constructor exports this object, making it available to receive incoming calls. The
- * callback port is anonymous unless a local port value was specified in the configuration.
- * <p>
- * @param irca cache configuration
- * @param cacheMgr the cache hub
- * @param elementSerializer a custom serializer
- */
- public RemoteCacheListener( IRemoteCacheAttributes irca, ICompositeCacheManager cacheMgr, IElementSerializer elementSerializer )
- {
- super( irca, cacheMgr, elementSerializer );
-
- // Export this remote object to make it available to receive incoming
- // calls.
- try
- {
- UnicastRemoteObject.exportObject( this, irca.getLocalPort() );
- }
- catch ( RemoteException ex )
- {
- log.error( "Problem exporting object.", ex );
- throw new IllegalStateException( ex.getMessage() );
- }
- }
-
- /**
- * Deregister itself.
- * <p>
- * @throws IOException
- */
- @Override
- public synchronized void dispose()
- throws IOException
- {
- if ( !disposed )
- {
- log.info( "Unexporting listener." );
- try
- {
- UnicastRemoteObject.unexportObject( this, true );
- }
- catch ( RemoteException ex )
- {
- log.error( "Problem unexporting the listener.", ex );
- throw new IllegalStateException( ex.getMessage() );
- }
- disposed = true;
- }
- }
-
- /**
- * For easier debugging.
- * <p>
- * @return Basic info on this listener.
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\n RemoteCacheListener: " );
- buf.append( super.toString() );
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheManager.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheManager.java
deleted file mode 100644
index ac40eef..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheManager.java
+++ /dev/null
@@ -1,348 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.rmi.Naming;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheClient;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheListener;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.CacheWatchRepairable;
-import org.apache.commons.jcs.engine.ZombieCacheServiceNonLocal;
-import org.apache.commons.jcs.engine.ZombieCacheWatch;
-import org.apache.commons.jcs.engine.behavior.ICacheObserver;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * An instance of RemoteCacheManager corresponds to one remote connection of a specific host and
- * port. All RemoteCacheManager instances are monitored by the singleton RemoteCacheMonitor
- * monitoring daemon for error detection and recovery.
- * <p>
- * Getting an instance of the remote cache has the effect of getting a handle on the remote server.
- * Listeners are not registered with the server until a cache is requested from the manager.
- */
-public class RemoteCacheManager
-{
- /** The logger */
- private static final Log log = LogManager.getLog( RemoteCacheManager.class );
-
- /** Contains instances of RemoteCacheNoWait managed by a RemoteCacheManager instance. */
- private final ConcurrentMap<String, RemoteCacheNoWait<?, ?>> caches =
- new ConcurrentHashMap<>();
-
- /** The event logger. */
- private final ICacheEventLogger cacheEventLogger;
-
- /** The serializer. */
- private final IElementSerializer elementSerializer;
-
- /** Handle to the remote cache service; or a zombie handle if failed to connect. */
- private ICacheServiceNonLocal<?, ?> remoteService;
-
- /**
- * Wrapper of the remote cache watch service; or wrapper of a zombie service if failed to
- * connect.
- */
- private CacheWatchRepairable remoteWatch;
-
- /** The cache manager listeners will need to use to get a cache. */
- private final ICompositeCacheManager cacheMgr;
-
- /** For error notification */
- private final RemoteCacheMonitor monitor;
-
- /** The service found through lookup */
- private final String registry;
-
- /** can it be restored */
- private boolean canFix = true;
-
- /**
- * Constructs an instance to with the given remote connection parameters. If the connection
- * cannot be made, "zombie" services will be temporarily used until a successful re-connection
- * is made by the monitoring daemon.
- * <p>
- * @param cattr cache attributes
- * @param cacheMgr the cache hub
- * @param monitor the cache monitor thread for error notifications
- * @param cacheEventLogger
- * @param elementSerializer
- */
- protected RemoteCacheManager( IRemoteCacheAttributes cattr, ICompositeCacheManager cacheMgr,
- RemoteCacheMonitor monitor,
- ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer)
- {
- this.cacheMgr = cacheMgr;
- this.monitor = monitor;
- this.cacheEventLogger = cacheEventLogger;
- this.elementSerializer = elementSerializer;
- this.remoteWatch = new CacheWatchRepairable();
-
- this.registry = RemoteUtils.getNamingURL(cattr.getRemoteLocation(), cattr.getRemoteServiceName());
-
- try
- {
- lookupRemoteService();
- }
- catch (IOException e)
- {
- log.error("Could not find server", e);
- // Notify the cache monitor about the error, and kick off the
- // recovery process.
- monitor.notifyError();
- }
- }
-
- /**
- * Lookup remote service from registry
- * @throws IOException if the remote service could not be found
- *
- */
- protected void lookupRemoteService() throws IOException
- {
- log.info( "Looking up server [{0}]", registry );
- try
- {
- Object obj = Naming.lookup( registry );
- log.info( "Server found: {0}", obj );
-
- // Successful connection to the remote server.
- this.remoteService = (ICacheServiceNonLocal<?, ?>) obj;
- log.debug( "Remote Service = {0}", remoteService );
- remoteWatch.setCacheWatch( (ICacheObserver) remoteService );
- }
- catch ( Exception ex )
- {
- // Failed to connect to the remote server.
- // Configure this RemoteCacheManager instance to use the "zombie"
- // services.
- this.remoteService = new ZombieCacheServiceNonLocal<>();
- remoteWatch.setCacheWatch( new ZombieCacheWatch() );
- throw new IOException( "Problem finding server at [" + registry + "]", ex );
- }
- }
-
- /**
- * Adds the remote cache listener to the underlying cache-watch service.
- * <p>
- * @param cattr The feature to be added to the RemoteCacheListener attribute
- * @param listener The feature to be added to the RemoteCacheListener attribute
- * @throws IOException
- */
- public <K, V> void addRemoteCacheListener( IRemoteCacheAttributes cattr, IRemoteCacheListener<K, V> listener )
- throws IOException
- {
- if ( cattr.isReceive() )
- {
- log.info( "The remote cache is configured to receive events from the remote server. "
- + "We will register a listener. remoteWatch = {0} | IRemoteCacheListener = {1}"
- + " | cacheName ", remoteWatch, listener, cattr.getCacheName() );
-
- remoteWatch.addCacheListener( cattr.getCacheName(), listener );
- }
- else
- {
- log.info( "The remote cache is configured to NOT receive events from the remote server. "
- + "We will NOT register a listener." );
- }
- }
-
- /**
- * Removes a listener. When the primary recovers the failover must deregister itself for a
- * region. The failover runner will call this method to de-register. We do not want to deregister
- * all listeners to a remote server, in case a failover is a primary of another region. Having
- * one regions failover act as another servers primary is not currently supported.
- * <p>
- * @param cattr
- * @throws IOException
- */
- public void removeRemoteCacheListener( IRemoteCacheAttributes cattr )
- throws IOException
- {
- RemoteCacheNoWait<?, ?> cache = caches.get( cattr.getCacheName() );
- if ( cache != null )
- {
- removeListenerFromCache(cache);
- }
- else
- {
- if ( cattr.isReceive() )
- {
- log.warn( "Trying to deregister Cache Listener that was never registered." );
- }
- else
- {
- log.debug( "Since the remote cache is configured to not receive, "
- + "there is no listener to deregister." );
- }
- }
- }
-
- // common helper method
- private void removeListenerFromCache(RemoteCacheNoWait<?, ?> cache) throws IOException
- {
- IRemoteCacheClient<?, ?> rc = cache.getRemoteCache();
- log.debug( "Found cache for [{0}], deregistering listener.",
- () -> cache.getCacheName() );
- // could also store the listener for a server in the manager.
- IRemoteCacheListener<?, ?> listener = rc.getListener();
- remoteWatch.removeCacheListener( cache.getCacheName(), listener );
- }
-
- /**
- * Gets a RemoteCacheNoWait from the RemoteCacheManager. The RemoteCacheNoWait objects are
- * identified by the cache name value of the RemoteCacheAttributes object.
- * <p>
- * If the client is configured to register a listener, this call results on a listener being
- * created if one isn't already registered with the remote cache for this region.
- * <p>
- * @param cattr
- * @return The cache value
- */
- @SuppressWarnings("unchecked") // Need to cast because of common map for all caches
- public <K, V> RemoteCacheNoWait<K, V> getCache( IRemoteCacheAttributes cattr )
- {
- RemoteCacheNoWait<K, V> remoteCacheNoWait =
- (RemoteCacheNoWait<K, V>) caches.computeIfAbsent(cattr.getCacheName(), key -> {
- return newRemoteCacheNoWait(cattr);
- });
-
- // might want to do some listener sanity checking here.
- return remoteCacheNoWait;
- }
-
- /**
- * Create new RemoteCacheNoWait instance
- *
- * @param cattr the cache configuration
- * @return the instance
- */
- protected <K, V> RemoteCacheNoWait<K, V> newRemoteCacheNoWait(IRemoteCacheAttributes cattr)
- {
- RemoteCacheNoWait<K, V> remoteCacheNoWait;
- // create a listener first and pass it to the remotecache
- // sender.
- RemoteCacheListener<K, V> listener = null;
- try
- {
- listener = new RemoteCacheListener<>( cattr, cacheMgr, elementSerializer );
- addRemoteCacheListener( cattr, listener );
- }
- catch ( Exception e )
- {
- log.error( "Problem adding listener. RemoteCacheListener = {0}",
- listener, e );
- }
-
- IRemoteCacheClient<K, V> remoteCacheClient =
- new RemoteCache<>( cattr, (ICacheServiceNonLocal<K, V>) remoteService, listener, monitor );
- remoteCacheClient.setCacheEventLogger( cacheEventLogger );
- remoteCacheClient.setElementSerializer( elementSerializer );
-
- remoteCacheNoWait = new RemoteCacheNoWait<>( remoteCacheClient );
- remoteCacheNoWait.setCacheEventLogger( cacheEventLogger );
- remoteCacheNoWait.setElementSerializer( elementSerializer );
-
- return remoteCacheNoWait;
- }
-
- /** Shutdown all. */
- public void release()
- {
- for (RemoteCacheNoWait<?, ?> c : caches.values())
- {
- try
- {
- log.info( "freeCache [{0}]", () -> c.getCacheName() );
-
- removeListenerFromCache(c);
- c.dispose();
- }
- catch ( IOException ex )
- {
- log.error( "Problem releasing {0}", c.getCacheName(), ex );
- }
- }
-
- caches.clear();
- }
-
- /**
- * Fixes up all the caches managed by this cache manager.
- */
- public void fixCaches()
- {
- if ( !canFix )
- {
- return;
- }
-
- log.info( "Fixing caches. ICacheServiceNonLocal {0} | IRemoteCacheObserver {1}",
- remoteService, remoteWatch );
-
- for (RemoteCacheNoWait<?, ?> c : caches.values())
- {
- if (c.getStatus() == CacheStatus.ERROR)
- {
- c.fixCache( remoteService );
- }
- }
-
- if ( log.isInfoEnabled() )
- {
- String msg = "Remote connection to " + registry + " resumed.";
- if ( cacheEventLogger != null )
- {
- cacheEventLogger.logApplicationEvent( "RemoteCacheManager", "fix", msg );
- }
- log.info( msg );
- }
- }
-
- /**
- * Returns true if the connection to the remote host can be
- * successfully re-established.
- * <p>
- * @return true if we found a failover server
- */
- public boolean canFixCaches()
- {
- try
- {
- lookupRemoteService();
- }
- catch (IOException e)
- {
- log.error("Could not find server", e);
- canFix = false;
- }
-
- return canFix;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheMonitor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheMonitor.java
deleted file mode 100644
index d33ad53..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheMonitor.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheMonitor;
-
-/**
- * Used to monitor and repair any failed connection for the remote cache service. By default the
- * monitor operates in a failure driven mode. That is, it goes into a wait state until there is an
- * error.
- *
- * TODO consider moving this into an active monitoring mode. Upon the notification of a
- * connection error, the monitor changes to operate in a time driven mode. That is, it attempts to
- * recover the connections on a periodic basis. When all failed connections are restored, it changes
- * back to the failure driven mode.
- */
-public class RemoteCacheMonitor extends AbstractAuxiliaryCacheMonitor
-{
- /**
- * Map of managers to monitor
- */
- private ConcurrentHashMap<RemoteCacheManager, RemoteCacheManager> managers;
-
- /** Constructor for the RemoteCacheMonitor object */
- public RemoteCacheMonitor()
- {
- super("JCS-RemoteCacheMonitor");
- this.managers = new ConcurrentHashMap<>();
- setIdlePeriod(30000L);
- }
-
- /**
- * Add a manager to be monitored
- *
- * @param manager the remote cache manager
- */
- public void addManager(RemoteCacheManager manager)
- {
- this.managers.put(manager, manager);
-
- // if not yet started, go ahead
- if (this.getState() == Thread.State.NEW)
- {
- this.start();
- }
- }
-
- /**
- * Clean up all resources before shutdown
- */
- @Override
- public void dispose()
- {
- this.managers.clear();
- }
-
- // Avoid the use of any synchronization in the process of monitoring for
- // performance reason.
- // If exception is thrown owing to synchronization,
- // just skip the monitoring until the next round.
- /** Main processing method for the RemoteCacheMonitor object */
- @Override
- public void doWork()
- {
- // Monitor each RemoteCacheManager instance one after the other.
- // Each RemoteCacheManager corresponds to one remote connection.
- for (RemoteCacheManager mgr : managers.values())
- {
- // If we can't fix them, just skip and re-try in
- // the next round.
- if ( mgr.canFixCaches() )
- {
- mgr.fixCaches();
- }
- else
- {
- allright.set(false);
- }
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWait.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWait.java
deleted file mode 100644
index 8e13786..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWait.java
+++ /dev/null
@@ -1,517 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.rmi.UnmarshalException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheClient;
-import org.apache.commons.jcs.engine.CacheAdaptor;
-import org.apache.commons.jcs.engine.CacheEventQueueFactory;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheEventQueue;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-import org.apache.commons.jcs.engine.stats.StatElement;
-import org.apache.commons.jcs.engine.stats.Stats;
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * The RemoteCacheNoWait wraps the RemoteCacheClient. The client holds a handle on the
- * RemoteCacheService.
- * <p>
- * Used to queue up update requests to the underlying cache. These requests will be processed in
- * their order of arrival via the cache event queue processor.
- * <p>
- * Typically errors will be handled down stream. We only need to kill the queue if an error makes it
- * to this level from the queue. That can only happen if the queue is damaged, since the events are
- * Processed asynchronously.
- * <p>
- * There is no reason to create a queue on startup if the remote is not healthy.
- * <p>
- * If the remote cache encounters an error it will zombie--create a balking facade for the service.
- * The Zombie will queue up items until the connection is restored. An alternative way to accomplish
- * the same thing would be to stop, not destroy the queue at this level. That way items would be
- * added to the queue and then when the connection is restored, we could start the worker threads
- * again. This is a better long term solution, but it requires some significant changes to the
- * complicated worker queues.
- */
-public class RemoteCacheNoWait<K, V>
- extends AbstractAuxiliaryCache<K, V>
-{
- /** log instance */
- private static final Log log = LogManager.getLog( RemoteCacheNoWait.class );
-
- /** The remote cache client */
- private final IRemoteCacheClient<K, V> remoteCacheClient;
-
- /** Event queue for queuing up calls like put and remove. */
- private ICacheEventQueue<K, V> cacheEventQueue;
-
- /** how many times get has been called. */
- private int getCount = 0;
-
- /** how many times getMatching has been called. */
- private int getMatchingCount = 0;
-
- /** how many times getMultiple has been called. */
- private int getMultipleCount = 0;
-
- /** how many times remove has been called. */
- private int removeCount = 0;
-
- /** how many times put has been called. */
- private int putCount = 0;
-
- /**
- * Constructs with the given remote cache, and fires up an event queue for asynchronous
- * processing.
- * <p>
- * @param cache
- */
- public RemoteCacheNoWait( IRemoteCacheClient<K, V> cache )
- {
- remoteCacheClient = cache;
- this.cacheEventQueue = createCacheEventQueue(cache);
-
- if ( remoteCacheClient.getStatus() == CacheStatus.ERROR )
- {
- cacheEventQueue.destroy();
- }
- }
-
- /**
- * Create a cache event queue from the parameters of the remote client
- * @param client the remote client
- */
- private ICacheEventQueue<K, V> createCacheEventQueue( IRemoteCacheClient<K, V> client )
- {
- CacheEventQueueFactory<K, V> factory = new CacheEventQueueFactory<>();
- ICacheEventQueue<K, V> ceq = factory.createCacheEventQueue(
- new CacheAdaptor<>( client ),
- client.getListenerId(),
- client.getCacheName(),
- client.getAuxiliaryCacheAttributes().getEventQueuePoolName(),
- client.getAuxiliaryCacheAttributes().getEventQueueType() );
- return ceq;
- }
-
- /**
- * Adds a put event to the queue.
- * <p>
- * @param element
- * @throws IOException
- */
- @Override
- public void update( ICacheElement<K, V> element )
- throws IOException
- {
- putCount++;
- try
- {
- cacheEventQueue.addPutEvent( element );
- }
- catch ( IOException e )
- {
- log.error( "Problem adding putEvent to queue.", e );
- cacheEventQueue.destroy();
- throw e;
- }
- }
-
- /**
- * Synchronously reads from the remote cache.
- * <p>
- * @param key
- * @return element from the remote cache, or null if not present
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> get( K key )
- throws IOException
- {
- getCount++;
- try
- {
- return remoteCacheClient.get( key );
- }
- catch ( UnmarshalException ue )
- {
- log.debug( "Retrying the get owing to UnmarshalException." );
-
- try
- {
- return remoteCacheClient.get( key );
- }
- catch ( IOException ex )
- {
- log.info( "Failed in retrying the get for the second time. ", ex );
- }
- }
- catch ( IOException ex )
- {
- // We don't want to destroy the queue on a get failure.
- // The RemoteCache will Zombie and queue.
- // Since get does not use the queue, I don't want to kill the queue.
- throw ex;
- }
-
- return null;
- }
-
- /**
- * @param pattern
- * @return Map
- * @throws IOException
- *
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching( String pattern )
- throws IOException
- {
- getMatchingCount++;
- try
- {
- return remoteCacheClient.getMatching( pattern );
- }
- catch ( UnmarshalException ue )
- {
- log.debug( "Retrying the getMatching owing to UnmarshalException." );
-
- try
- {
- return remoteCacheClient.getMatching( pattern );
- }
- catch ( IOException ex )
- {
- log.info( "Failed in retrying the getMatching for the second time.", ex );
- }
- }
- catch ( IOException ex )
- {
- // We don't want to destroy the queue on a get failure.
- // The RemoteCache will Zombie and queue.
- // Since get does not use the queue, I don't want to kill the queue.
- throw ex;
- }
-
- return Collections.emptyMap();
- }
-
- /**
- * Gets multiple items from the cache based on the given set of keys. Sends the getMultiple
- * request on to the server rather than looping through the requested keys.
- * <p>
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple( Set<K> keys )
- throws IOException
- {
- getMultipleCount++;
- try
- {
- return remoteCacheClient.getMultiple( keys );
- }
- catch ( UnmarshalException ue )
- {
- log.debug( "Retrying the getMultiple owing to UnmarshalException..." );
-
- try
- {
- return remoteCacheClient.getMultiple( keys );
- }
- catch ( IOException ex )
- {
- log.info( "Failed in retrying the getMultiple for the second time.", ex );
- }
- }
- catch ( IOException ex )
- {
- // We don't want to destroy the queue on a get failure.
- // The RemoteCache will Zombie and queue.
- // Since get does not use the queue, I don't want to kill the queue.
- throw ex;
- }
-
- return new HashMap<>();
- }
-
- /**
- * Return the keys in this cache.
- * <p>
- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet()
- */
- @Override
- public Set<K> getKeySet() throws IOException
- {
- return remoteCacheClient.getKeySet();
- }
-
- /**
- * Adds a remove request to the remote cache.
- * <p>
- * @param key
- * @return if this was successful
- * @throws IOException
- */
- @Override
- public boolean remove( K key )
- throws IOException
- {
- removeCount++;
- try
- {
- cacheEventQueue.addRemoveEvent( key );
- }
- catch ( IOException e )
- {
- log.error( "Problem adding RemoveEvent to queue.", e );
- cacheEventQueue.destroy();
- throw e;
- }
- return false;
- }
-
- /**
- * Adds a removeAll request to the remote cache.
- * <p>
- * @throws IOException
- */
- @Override
- public void removeAll()
- throws IOException
- {
- try
- {
- cacheEventQueue.addRemoveAllEvent();
- }
- catch ( IOException e )
- {
- log.error( "Problem adding RemoveAllEvent to queue.", e );
- cacheEventQueue.destroy();
- throw e;
- }
- }
-
- /** Adds a dispose request to the remote cache. */
- @Override
- public void dispose()
- {
- try
- {
- cacheEventQueue.addDisposeEvent();
- }
- catch ( IOException e )
- {
- log.error( "Problem adding DisposeEvent to queue.", e );
- cacheEventQueue.destroy();
- }
- }
-
- /**
- * No remote invocation.
- * <p>
- * @return The size value
- */
- @Override
- public int getSize()
- {
- return remoteCacheClient.getSize();
- }
-
- /**
- * No remote invocation.
- * <p>
- * @return The cacheType value
- */
- @Override
- public CacheType getCacheType()
- {
- return CacheType.REMOTE_CACHE;
- }
-
- /**
- * Returns the asyn cache status. An error status indicates either the remote connection is not
- * available, or the asyn queue has been unexpectedly destroyed. No remote invocation.
- * <p>
- * @return The status value
- */
- @Override
- public CacheStatus getStatus()
- {
- return cacheEventQueue.isWorking() ? remoteCacheClient.getStatus() : CacheStatus.ERROR;
- }
-
- /**
- * Gets the cacheName attribute of the RemoteCacheNoWait object
- * <p>
- * @return The cacheName value
- */
- @Override
- public String getCacheName()
- {
- return remoteCacheClient.getCacheName();
- }
-
- /**
- * Replaces the remote cache service handle with the given handle and reset the event queue by
- * starting up a new instance.
- * <p>
- * @param remote
- */
- public void fixCache( ICacheServiceNonLocal<?, ?> remote )
- {
- remoteCacheClient.fixCache( remote );
- resetEventQ();
- }
-
- /**
- * Resets the event q by first destroying the existing one and starting up new one.
- * <p>
- * There may be no good reason to kill the existing queue. We will sometimes need to set a new
- * listener id, so we should create a new queue. We should let the old queue drain. If we were
- * Connected to the failover, it would be best to finish sending items.
- */
- public void resetEventQ()
- {
- ICacheEventQueue<K, V> previousQueue = cacheEventQueue;
-
- this.cacheEventQueue = createCacheEventQueue(this.remoteCacheClient);
-
- if ( previousQueue.isWorking() )
- {
- // we don't expect anything, it would have all gone to the zombie
- log.info( "resetEventQ, previous queue has [{0}] items queued up.",
- () -> previousQueue.size() );
- previousQueue.destroy();
- }
- }
-
- /**
- * This is temporary. It allows the manager to get the lister.
- * <p>
- * @return the instance of the remote cache client used by this object
- */
- protected IRemoteCacheClient<K, V> getRemoteCache()
- {
- return remoteCacheClient;
- }
-
- /**
- * @return Returns the AuxiliaryCacheAttributes.
- */
- @Override
- public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
- {
- return remoteCacheClient.getAuxiliaryCacheAttributes();
- }
-
- /**
- * This is for testing only. It allows you to take a look at the event queue.
- * <p>
- * @return ICacheEventQueue
- */
- protected ICacheEventQueue<K, V> getCacheEventQueue()
- {
- return this.cacheEventQueue;
- }
-
- /**
- * Returns the stats and the cache.toString().
- * <p>
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString()
- {
- return getStats() + "\n" + remoteCacheClient.toString();
- }
-
- /**
- * Returns the statistics in String form.
- * <p>
- * @return String
- */
- @Override
- public String getStats()
- {
- return getStatistics().toString();
- }
-
- /**
- * @return statistics about this communication
- */
- @Override
- public IStats getStatistics()
- {
- IStats stats = new Stats();
- stats.setTypeName( "Remote Cache No Wait" );
-
- ArrayList<IStatElement<?>> elems = new ArrayList<>();
-
- elems.add(new StatElement<>( "Status", getStatus() ) );
-
- // get the stats from the cache queue too
- IStats cStats = this.remoteCacheClient.getStatistics();
- if ( cStats != null )
- {
- elems.addAll(cStats.getStatElements());
- }
-
- // get the stats from the event queue too
- IStats eqStats = this.cacheEventQueue.getStatistics();
- elems.addAll(eqStats.getStatElements());
-
- elems.add(new StatElement<>( "Get Count", Integer.valueOf(this.getCount) ) );
- elems.add(new StatElement<>( "GetMatching Count", Integer.valueOf(this.getMatchingCount) ) );
- elems.add(new StatElement<>( "GetMultiple Count", Integer.valueOf(this.getMultipleCount) ) );
- elems.add(new StatElement<>( "Remove Count", Integer.valueOf(this.removeCount) ) );
- elems.add(new StatElement<>( "Put Count", Integer.valueOf(this.putCount) ) );
-
- stats.setStatElements( elems );
-
- return stats;
- }
-
- /**
- * this won't be called since we don't do ICache logging here.
- * <p>
- * @return String
- */
- @Override
- public String getEventLoggingExtraInfo()
- {
- return "Remote Cache No Wait";
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitFacade.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitFacade.java
deleted file mode 100644
index bdd7aa8..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitFacade.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import java.util.List;
-
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
-import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * Used to provide access to multiple services under nowait protection. Factory should construct
- * NoWaitFacade to give to the composite cache out of caches it constructs from the varies manager
- * to lateral services.
- * <p>
- * Typically, we only connect to one remote server per facade. We use a list of one
- * RemoteCacheNoWait.
- */
-public class RemoteCacheNoWaitFacade<K, V>
- extends AbstractRemoteCacheNoWaitFacade<K, V>
-{
- /** log instance */
- private static final Log log = LogManager.getLog( RemoteCacheNoWaitFacade.class );
-
- /** Provide factory instance to RemoteCacheFailoverRunner */
- private final RemoteCacheFactory cacheFactory;
-
- /**
- * Constructs with the given remote cache, and fires events to any listeners.
- * <p>
- * @param noWaits
- * @param rca
- * @param cacheEventLogger
- * @param elementSerializer
- * @param cacheFactory
- */
- public RemoteCacheNoWaitFacade( List<RemoteCacheNoWait<K,V>> noWaits,
- IRemoteCacheAttributes rca,
- ICacheEventLogger cacheEventLogger,
- IElementSerializer elementSerializer,
- RemoteCacheFactory cacheFactory)
- {
- super( noWaits, rca, cacheEventLogger, elementSerializer );
- this.cacheFactory = cacheFactory;
- }
-
- /**
- * Begin the failover process if this is a local cache. Clustered remote caches do not failover.
- * <p>
- * @param rcnw The no wait in error.
- */
- @Override
- protected void failover( RemoteCacheNoWait<K, V> rcnw )
- {
- log.debug( "in failover for {0}", rcnw );
-
- if ( getAuxiliaryCacheAttributes().getRemoteType() == RemoteType.LOCAL )
- {
- if ( rcnw.getStatus() == CacheStatus.ERROR )
- {
- // start failover, primary recovery process
- RemoteCacheFailoverRunner<K, V> runner = new RemoteCacheFailoverRunner<>( this, this.cacheFactory );
- runner.setDaemon( true );
- runner.start();
- runner.notifyError();
-
- if ( getCacheEventLogger() != null )
- {
- getCacheEventLogger().logApplicationEvent( "RemoteCacheNoWaitFacade", "InitiatedFailover",
- rcnw + " was in error." );
- }
- }
- else
- {
- log.info( "The noWait is not in error" );
- }
- }
- }
-
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteLocation.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteLocation.java
deleted file mode 100644
index 0ff1472..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteLocation.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/*
- * 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.
- */
-
-/**
- * Location of the RMI registry.
- */
-public final class RemoteLocation
-{
- /** The logger. */
- private static final Log log = LogManager.getLog( RemoteLocation.class );
-
- /** Pattern for parsing server:port */
- private static final Pattern SERVER_COLON_PORT = Pattern.compile("(\\S+)\\s*:\\s*(\\d+)");
-
- /** Host name */
- private final String host;
-
- /** Port */
- private final int port;
-
- /**
- * Constructor for the Location object
- * <p>
- * @param host
- * @param port
- */
- public RemoteLocation( String host, int port )
- {
- this.host = host;
- this.port = port;
- }
-
- /**
- * @return the host
- */
- public String getHost()
- {
- return host;
- }
-
- /**
- * @return the port
- */
- public int getPort()
- {
- return port;
- }
-
- /**
- * @param obj
- * @return true if the host and port are equal
- */
- @Override
- public boolean equals( Object obj )
- {
- if ( obj == this )
- {
- return true;
- }
- if ( obj == null || !( obj instanceof RemoteLocation ) )
- {
- return false;
- }
- RemoteLocation l = (RemoteLocation) obj;
- if ( this.host == null )
- {
- return l.host == null && port == l.port;
- }
- return host.equals( l.host ) && port == l.port;
- }
-
- /**
- * @return int
- */
- @Override
- public int hashCode()
- {
- return host == null ? port : host.hashCode() ^ port;
- }
-
- /**
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString()
- {
- StringBuilder sb = new StringBuilder();
- if (this.host != null)
- {
- sb.append(this.host);
- }
- sb.append(':').append(this.port);
-
- return sb.toString();
- }
-
- /**
- * Parse remote server and port from the string representation server:port and store them in
- * a RemoteLocation object
- *
- * @param server the input string
- * @return the remote location object
- */
- public static RemoteLocation parseServerAndPort(final String server)
- {
- Matcher match = SERVER_COLON_PORT.matcher(server);
-
- if (match.find() && match.groupCount() == 2)
- {
- RemoteLocation location = new RemoteLocation( match.group(1), Integer.parseInt( match.group(2) ) );
- return location;
- }
- else
- {
- log.error("Invalid server descriptor: {0}", server);
- }
-
- return null;
- }
-}
\ No newline at end of file
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteUtils.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteUtils.java
deleted file mode 100644
index b3075a6..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/RemoteUtils.java
+++ /dev/null
@@ -1,264 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.InetSocketAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.URL;
-import java.rmi.RemoteException;
-import java.rmi.registry.LocateRegistry;
-import java.rmi.registry.Registry;
-import java.rmi.server.RMISocketFactory;
-import java.util.Properties;
-
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This class provides some basic utilities for doing things such as starting
- * the registry properly.
- */
-public class RemoteUtils
-{
- /** The logger. */
- private static final Log log = LogManager.getLog(RemoteUtils.class);
-
- /** No instances please. */
- private RemoteUtils()
- {
- super();
- }
-
- /**
- * Creates and exports a registry on the specified port of the local host.
- * <p>
- *
- * @param port
- * @return the registry
- */
- public static Registry createRegistry(int port)
- {
- Registry registry = null;
-
- // if ( log.isInfoEnabled() )
- // {
- // log.info( "createRegistry> Setting security manager" );
- // }
- //
- // System.setSecurityManager( new RMISecurityManager() );
-
- if (port < 1024)
- {
- log.warn("createRegistry> Port chosen was less than 1024, will use default [{0}] instead.",
- Registry.REGISTRY_PORT);
- port = Registry.REGISTRY_PORT;
- }
-
- try
- {
- registry = LocateRegistry.createRegistry(port);
- log.info("createRegistry> Created the registry on port {0}", port);
- }
- catch (RemoteException e)
- {
- log.warn("createRegistry> Problem creating registry. It may already be started.",
- e);
- }
- catch (Throwable t)
- {
- log.error("createRegistry> Problem creating registry.", t);
- }
-
- if (registry == null)
- {
- try
- {
- registry = LocateRegistry.getRegistry(port);
- }
- catch (RemoteException e)
- {
- log.error("createRegistry> Problem getting a registry reference.", e);
- }
- }
-
- return registry;
- }
-
- /**
- * Loads properties for the named props file.
- * First tries class path, then file, then URL
- * <p>
- *
- * @param propFile
- * @return The properties object for the file
- * @throws IOException
- */
- public static Properties loadProps(String propFile)
- throws IOException
- {
- InputStream is = RemoteUtils.class.getResourceAsStream(propFile);
-
- if (null == is) // not found in class path
- {
- // Try root of class path
- if (propFile != null && !propFile.startsWith("/"))
- {
- is = RemoteUtils.class.getResourceAsStream("/" + propFile);
- }
- }
-
- if (null == is) // not found in class path
- {
- if (new File(propFile).exists())
- {
- // file found
- is = new FileInputStream(propFile);
- }
- else
- {
- // try URL
- is = new URL(propFile).openStream();
- }
- }
-
- Properties props = new Properties();
- try
- {
- props.load(is);
- log.debug("props.size={0}", () -> props.size());
-
- if (log.isTraceEnabled())
- {
- StringBuilder buf = new StringBuilder();
- props.forEach((key, value)
- -> buf.append('\n').append(key).append(" = ").append(value));
- log.trace(buf.toString());
- }
-
- }
- catch (IOException ex)
- {
- log.error("Error loading remote properties, for file name "
- + "[{0}]", propFile, ex);
- }
- finally
- {
- if (is != null)
- {
- is.close();
- }
- }
- return props;
- }
-
- /**
- * Configure a custom socket factory to set the timeout value. This sets the
- * global socket factory. It's used only if a custom factory is not
- * configured for the specific object.
- * <p>
- *
- * @param timeoutMillis
- */
- public static void configureGlobalCustomSocketFactory(final int timeoutMillis)
- {
- try
- {
- // Don't set a socket factory if the setting is -1
- if (timeoutMillis > 0)
- {
- log.info("RmiSocketFactoryTimeoutMillis [{0}]. "
- + " Configuring a custom socket factory.", timeoutMillis);
-
- // use this socket factory to add a timeout.
- RMISocketFactory.setSocketFactory(new RMISocketFactory()
- {
- @Override
- public Socket createSocket(String host, int port)
- throws IOException
- {
- Socket socket = new Socket();
- socket.setSoTimeout(timeoutMillis);
- socket.setSoLinger(false, 0);
- socket.connect(new InetSocketAddress(host, port), timeoutMillis);
- return socket;
- }
-
- @Override
- public ServerSocket createServerSocket(int port)
- throws IOException
- {
- return new ServerSocket(port);
- }
- });
- }
- }
- catch (IOException e)
- {
- // Only try to do it once. Otherwise we
- // Generate errors for each region on construction.
- RMISocketFactory factoryInUse = RMISocketFactory.getSocketFactory();
- if (factoryInUse != null && !factoryInUse.getClass().getName().startsWith("org.apache.commons.jcs"))
- {
- log.info("Could not create new custom socket factory. {0} Factory in use = {1}",
- () -> e.getMessage(), () -> RMISocketFactory.getSocketFactory());
- }
- }
- }
-
- /**
- * Get the naming url used for RMI registration
- *
- * @param location
- * the remote location
- * @param serviceName
- * the remote service name
- * @return the URL for RMI lookup
- */
- public static String getNamingURL(final RemoteLocation location, final String serviceName)
- {
- return getNamingURL(location.getHost(), location.getPort(), serviceName);
- }
-
- /**
- * Get the naming url used for RMI registration
- *
- * @param registryHost
- * the remote host
- * @param registryPort
- * the remote port
- * @param serviceName
- * the remote service name
- * @return the URL for RMI lookup
- */
- public static String getNamingURL(final String registryHost, final int registryPort, final String serviceName)
- {
- if (registryHost.contains(":"))
- { // TODO improve this check? See also JCS-133
- return "//[" + registryHost.replaceFirst("%", "%25") + "]:" + registryPort + "/" + serviceName;
- }
- final String registryURL = "//" + registryHost + ":" + registryPort + "/" + serviceName;
- return registryURL;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/behavior/ICommonRemoteCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/behavior/ICommonRemoteCacheAttributes.java
deleted file mode 100644
index 2b1e20e..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/behavior/ICommonRemoteCacheAttributes.java
+++ /dev/null
@@ -1,172 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.behavior;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.remote.RemoteLocation;
-import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType;
-
-/**
- * This specifies what a remote cache configuration object should look like.
- */
-public interface ICommonRemoteCacheAttributes
- extends AuxiliaryCacheAttributes
-{
- /** The default timeout for the custom RMI socket factory */
- int DEFAULT_RMI_SOCKET_FACTORY_TIMEOUT_MILLIS = 10000;
-
- /**
- * Gets the remoteTypeName attribute of the IRemoteCacheAttributes object
- * <p>
- * @return The remoteTypeName value
- */
- String getRemoteTypeName();
-
- /**
- * Sets the remoteTypeName attribute of the IRemoteCacheAttributes object
- * <p>
- * @param s The new remoteTypeName value
- */
- void setRemoteTypeName( String s );
-
- /**
- * Gets the remoteType attribute of the IRemoteCacheAttributes object
- * <p>
- * @return The remoteType value
- */
- RemoteType getRemoteType();
-
- /**
- * Sets the remoteType attribute of the IRemoteCacheAttributes object
- * <p>
- * @param p The new remoteType value
- */
- void setRemoteType( RemoteType p );
-
- /**
- * Gets the remoteServiceName attribute of the IRemoteCacheAttributes object
- * <p>
- * @return The remoteServiceName value
- */
- String getRemoteServiceName();
-
- /**
- * Sets the remoteServiceName attribute of the IRemoteCacheAttributes object
- * <p>
- * @param s The new remoteServiceName value
- */
- void setRemoteServiceName( String s );
-
- /**
- * Sets the location attribute of the RemoteCacheAttributes object.
- * <p>
- * @param location The new location value
- */
- void setRemoteLocation( RemoteLocation location );
-
- /**
- * Sets the location attribute of the RemoteCacheAttributes object.
- * <p>
- * @param host The new remoteHost value
- * @param port The new remotePort value
- */
- void setRemoteLocation( String host, int port );
-
- /**
- * Gets the location attribute of the RemoteCacheAttributes object.
- * <p>
- * @return The remote location value
- */
- public RemoteLocation getRemoteLocation();
-
- /**
- * Gets the clusterServers attribute of the IRemoteCacheAttributes object
- * <p>
- * @return The clusterServers value
- */
- String getClusterServers();
-
- /**
- * Sets the clusterServers attribute of the IRemoteCacheAttributes object
- * <p>
- * @param s The new clusterServers value
- */
- void setClusterServers( String s );
-
- /**
- * Gets the removeUponRemotePut attribute of the IRemoteCacheAttributes object
- * <p>
- * @return The removeUponRemotePut value
- */
- boolean getRemoveUponRemotePut();
-
- /**
- * Sets the removeUponRemotePut attribute of the IRemoteCacheAttributes object
- * <p>
- * @param r The new removeUponRemotePut value
- */
- void setRemoveUponRemotePut( boolean r );
-
- /**
- * Gets the getOnly attribute of the IRemoteCacheAttributes object
- * <p>
- * @return The getOnly value
- */
- boolean getGetOnly();
-
- /**
- * Sets the getOnly attribute of the IRemoteCacheAttributes object
- * <p>
- * @param r The new getOnly value
- */
- void setGetOnly( boolean r );
-
- /**
- * Should cluster updates be propagated to the locals
- * <p>
- * @return The localClusterConsistency value
- */
- boolean isLocalClusterConsistency();
-
- /**
- * Should cluster updates be propagated to the locals
- * <p>
- * @param r The new localClusterConsistency value
- */
- void setLocalClusterConsistency( boolean r );
-
- /**
- * This sets a general timeout on the rmi socket factory. By default the socket factory will
- * block forever.
- * <p>
- * We have a default setting. The default rmi behavior should never be used.
- * <p>
- * @return int milliseconds
- */
- int getRmiSocketFactoryTimeoutMillis();
-
- /**
- * This sets a general timeout on the RMI socket factory. By default the socket factory will
- * block forever.
- * <p>
- * @param rmiSocketFactoryTimeoutMillis
- */
- void setRmiSocketFactoryTimeoutMillis( int rmiSocketFactoryTimeoutMillis );
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheAttributes.java
deleted file mode 100644
index aa528ba..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheAttributes.java
+++ /dev/null
@@ -1,182 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.behavior;
-
-import java.util.List;
-
-import org.apache.commons.jcs.auxiliary.remote.RemoteLocation;
-
-/*
- * 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.
- */
-
-/**
- * This specifies what a remote cache configuration object should look like.
- */
-public interface IRemoteCacheAttributes
- extends ICommonRemoteCacheAttributes
-{
- /**
- * If RECEIVE is false then the remote cache will not register a listener with the remote
- * server. This allows you to configure a remote server as a repository from which you can get
- * and to which you put, but from which you do not receive any notifications. That is, you will
- * not receive updates or removes.
- * <p>
- * If you set this option to false, you should set your local memory size to 0.
- */
- boolean DEFAULT_RECEIVE = true;
-
- /**
- * The number of elements the zombie queue will hold. This queue is used to store events if we
- * loose our connection with the server.
- */
- int DEFAULT_ZOMBIE_QUEUE_MAX_SIZE = 1000;
-
- /**
- * Gets the failoverIndex attribute of the IRemoteCacheAttributes object.
- * <p>
- * This specifies which server in the list we are listening to if the number is greater than 0
- * we will try to move to 0 position the primary is added as position 1 if it is present
- * <p>
- * @return The failoverIndex value
- */
- int getFailoverIndex();
-
- /**
- * Sets the failoverIndex attribute of the IRemoteCacheAttributes object
- * <p>
- * @param p The new failoverIndex value
- */
- void setFailoverIndex( int p );
-
- /**
- * Gets the failovers attribute of the IRemoteCacheAttributes object
- * <p>
- * @return The failovers value
- */
- List<RemoteLocation> getFailovers();
-
- /**
- * Sets the failovers attribute of the IRemoteCacheAttributes object
- * <p>
- * @param failovers The new failovers value
- */
- void setFailovers( List<RemoteLocation> failovers );
-
- /**
- * Gets the localPort attribute of the IRemoteCacheAttributes object
- * <p>
- * @return The localPort value
- */
- int getLocalPort();
-
- /**
- * Sets the localPort attribute of the IRemoteCacheAttributes object
- * <p>
- * @param p The new localPort value
- */
- void setLocalPort( int p );
-
- /**
- * Gets the failoverServers attribute of the IRemoteCacheAttributes object
- * <p>
- * @return The failoverServers value
- */
- String getFailoverServers();
-
- /**
- * Sets the failoverServers attribute of the IRemoteCacheAttributes object
- * <p>
- * @param s The new failoverServers value
- */
- void setFailoverServers( String s );
-
- /**
- * The thread pool the remote cache should use. At first this will only be for gets.
- * <p>
- * The default name is "remote_cache_client"
- * <p>
- * @return the name of the pool
- */
- String getThreadPoolName();
-
- /**
- * Set the name of the pool to use. Pools should be defined in the cache.ccf.
- * <p>
- * @param name
- */
- void setThreadPoolName( String name );
-
- /**
- * -1 and 0 mean no timeout, this is the default if the timeout is -1 or 0, no threadpool will
- * be used.
- * <p>
- * @return the time in millis
- */
- int getGetTimeoutMillis();
-
- /**
- * -1 means no timeout, this is the default if the timeout is -1 or 0, no threadpool will be
- * used. If the timeout is greater than 0 a threadpool will be used for get requests.
- * <p>
- * @param millis
- */
- void setGetTimeoutMillis( int millis );
-
- /**
- * By default this option is true. If you set it to false, you will not receive updates or
- * removes from the remote server.
- * <p>
- * @param receive
- */
- void setReceive( boolean receive );
-
- /**
- * If RECEIVE is false then the remote cache will not register a listener with the remote
- * server. This allows you to configure a remote server as a repository from which you can get
- * and to which you put, but from which you do not receive any notifications. That is, you will
- * not receive updates or removes.
- * <p>
- * If you set this option to false, you should set your local memory size to 0.
- * <p>
- * The remote cache manager uses this value to decide whether or not to register a listener.
- * <p>
- * It makes no sense to configure a cluster remote cache to no receive.
- * <p>
- * Since a non-receiving remote cache client will not register a listener, it will not have a
- * listener id assigned from the server. As such the remote server cannot determine if it is a
- * cluster or a normal client. It will assume that it is a normal client.
- * <p>
- * @return the receive value.
- */
- boolean isReceive();
-
- /**
- * The number of elements the zombie queue will hold. This queue is used to store events if we
- * loose our connection with the server.
- * <p>
- * @param zombieQueueMaxSize The zombieQueueMaxSize to set.
- */
- void setZombieQueueMaxSize( int zombieQueueMaxSize );
-
- /**
- * The number of elements the zombie queue will hold. This queue is used to store events if we
- * loose our connection with the server.
- * <p>
- * @return Returns the zombieQueueMaxSize.
- */
- int getZombieQueueMaxSize();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheClient.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheClient.java
deleted file mode 100644
index acb68f6..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheClient.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.behavior;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-
-/**
- * This defines the behavior expected of a remote cache client. This extends Auxiliary cache which
- * in turn extends ICache.
- * <p>
- * I'd like generalize this a bit.
- * <p>
- * @author Aaron Smuts
- */
-public interface IRemoteCacheClient<K, V>
- extends AuxiliaryCache<K, V>
-{
- /**
- * Replaces the current remote cache service handle with the given handle. If the current remote
- * is a Zombie, the propagate the events that may be queued to the restored service.
- * <p>
- * @param remote ICacheServiceNonLocal -- the remote server or proxy to the remote server
- */
- void fixCache( ICacheServiceNonLocal<?, ?> remote );
-
- /**
- * Gets the listenerId attribute of the RemoteCacheListener object.
- * <p>
- * All requests to the remote cache must include a listener id. This allows the server to avoid
- * sending updates the the listener associated with this client.
- * <p>
- * @return The listenerId value
- */
- long getListenerId();
-
- /**
- * This returns the listener associated with this remote cache. TODO we should try to get this
- * out of the interface.
- * <p>
- * @return IRemoteCacheListener
- */
- IRemoteCacheListener<K, V> getListener();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheConstants.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheConstants.java
deleted file mode 100644
index 0dd06a9..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheConstants.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.behavior;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-
-
-/**
- * This holds constants that are used by the remote cache.
- */
-public interface IRemoteCacheConstants
-{
- /** Mapping to props file value */
- String REMOTE_CACHE_SERVICE_VAL = ICacheServiceNonLocal.class.getName();
-
- /** The prefix for cache server config. */
- String CACHE_SERVER_PREFIX = "jcs.remotecache";
-
- /**
- * I'm trying to migrate everything to use this prefix. All those below will be replaced. Any of
- * the RemoteCacheServerAttributes can be configured this way.
- */
- String CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX = CACHE_SERVER_PREFIX + ".serverattributes";
-
- /**
- * This is the name of the class that will be used for an object specific socket factory.
- */
- String CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX = CACHE_SERVER_PREFIX + ".customrmisocketfactory";
-
- /** Property prefix, should be jcs.remote but this would break existing config. */
- String PROPERTY_PREFIX = "remote";
-
- /** Mapping to props file value */
- String SOCKET_TIMEOUT_MILLIS = PROPERTY_PREFIX + ".cache.rmiSocketFactoryTimeoutMillis";
-
- /** Mapping to props file value */
- String REMOTE_CACHE_SERVICE_NAME = PROPERTY_PREFIX + ".cache.service.name";
-
- /** Mapping to props file value */
- String TOMCAT_XML = PROPERTY_PREFIX + ".tomcat.xml";
-
- /** Mapping to props file value */
- String TOMCAT_ON = PROPERTY_PREFIX + ".tomcat.on";
-
- /** Mapping to props file value */
- String REMOTE_CACHE_SERVICE_PORT = PROPERTY_PREFIX + ".cache.service.port";
-
- /** Mapping to props file value */
- String REMOTE_LOCAL_CLUSTER_CONSISTENCY = PROPERTY_PREFIX + ".cluster.LocalClusterConsistency";
-
- /** Mapping to props file value */
- String REMOTE_ALLOW_CLUSTER_GET = PROPERTY_PREFIX + ".cluster.AllowClusterGet";
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheDispatcher.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheDispatcher.java
deleted file mode 100644
index c5d0b0d..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheDispatcher.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.behavior;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheRequest;
-import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheResponse;
-
-import java.io.IOException;
-
-/**
- * In the future, this can be used as a generic dispatcher abstraction.
- * <p>
- * At the time of creation, only the http remote cache uses it. The RMI remote could be converted to
- * use it as well.
- */
-public interface IRemoteCacheDispatcher
-{
- /**
- * All requests will go through this method. The dispatcher implementation will send the request
- * remotely.
- * <p>
- * @param remoteCacheRequest
- * @return RemoteCacheResponse
- * @throws IOException
- */
- <K, V, T>
- RemoteCacheResponse<T> dispatchRequest( RemoteCacheRequest<K, V> remoteCacheRequest )
- throws IOException;
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheListener.java
deleted file mode 100644
index b673383..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/behavior/IRemoteCacheListener.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.behavior;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType;
-import org.apache.commons.jcs.engine.behavior.ICacheListener;
-
-import java.io.IOException;
-import java.rmi.Remote;
-
-/**
- * Listens for remote cache event notification ( rmi callback ).
- */
-public interface IRemoteCacheListener<K, V>
- extends ICacheListener<K, V>, Remote
-{
- /**
- * Get the id to be used by this manager.
- * <p>
- * @return long
- * @throws IOException
- */
- @Override
- long getListenerId()
- throws IOException;
-
- /**
- * Set the id to be used by this manager. The remote cache server identifies clients by this id.
- * The value will be set by the server through the remote cache listener.
- * <p>
- * @param id
- * @throws IOException
- */
- @Override
- void setListenerId( long id )
- throws IOException;
-
- /**
- * Gets the remoteType attribute of the IRemoteCacheListener object
- * <p>
- * @return The remoteType value
- * @throws IOException
- */
- RemoteType getRemoteType()
- throws IOException;
-
- /**
- * This is for debugging. It allows the remote cache server to log the address of any listeners
- * that register.
- * <p>
- * @return the local host address.
- * @throws IOException
- */
- String getLocalHostAddress()
- throws IOException;
-
- /**
- * Deregisters itself.
- * <p>
- * @throws IOException
- */
- void dispose()
- throws IOException;
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/behavior/IRemoteHttpCacheConstants.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/behavior/IRemoteHttpCacheConstants.java
deleted file mode 100644
index 49515f3..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/behavior/IRemoteHttpCacheConstants.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.behavior;
-
-/*
- * 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.
- */
-
-/** Constants used throughout the HTTP remote cache. */
-public interface IRemoteHttpCacheConstants
-{
- /** The prefix for cache server config. */
- String HTTP_CACHE_SERVER_PREFIX = "jcs.remotehttpcache";
-
- /** All of the RemoteHttpCacheServiceAttributes can be configured this way. */
- String HTTP_CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX = HTTP_CACHE_SERVER_PREFIX
- + ".serverattributes";
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/AbstractHttpClient.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/AbstractHttpClient.java
deleted file mode 100644
index 5b86fe1..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/AbstractHttpClient.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.client;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpVersion;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.config.CookieSpecs;
-import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.client.methods.RequestBuilder;
-import org.apache.http.impl.client.HttpClientBuilder;
-
-/**
- * This class simply configures the http multithreaded connection manager.
- * <p>
- * This is abstract because it can do anything. Child classes can overwrite whatever they want.
- */
-public abstract class AbstractHttpClient
-{
- /** The client */
- private HttpClient httpClient;
-
- /** The protocol version */
- private HttpVersion httpVersion;
-
- /** Configuration settings. */
- private RemoteHttpCacheAttributes remoteHttpCacheAttributes;
-
- /** The Logger. */
- private static final Log log = LogManager.getLog( AbstractHttpClient.class );
-
- /**
- * Sets the default Properties File and Heading, and creates the HttpClient and connection
- * manager.
- * <p>
- * @param remoteHttpCacheAttributes
- */
- public AbstractHttpClient( RemoteHttpCacheAttributes remoteHttpCacheAttributes )
- {
- this.remoteHttpCacheAttributes = remoteHttpCacheAttributes;
-
- String httpVersion = getRemoteHttpCacheAttributes().getHttpVersion();
- if ( "1.1".equals( httpVersion ) )
- {
- this.httpVersion = HttpVersion.HTTP_1_1;
- }
- else if ( "1.0".equals( httpVersion ) )
- {
- this.httpVersion = HttpVersion.HTTP_1_0;
- }
- else
- {
- log.warn( "Unrecognized value for 'httpVersion': [{0}], defaulting to 1.1",
- httpVersion );
- this.httpVersion = HttpVersion.HTTP_1_1;
- }
-
- HttpClientBuilder builder = HttpClientBuilder.create();
- configureClient(builder);
- this.httpClient = builder.build();
- }
-
- /**
- * Configures the http client.
- *
- * @param builder client builder to configure
- */
- protected void configureClient(HttpClientBuilder builder)
- {
- if ( getRemoteHttpCacheAttributes().getMaxConnectionsPerHost() > 0 )
- {
- builder.setMaxConnTotal(getRemoteHttpCacheAttributes().getMaxConnectionsPerHost());
- builder.setMaxConnPerRoute(getRemoteHttpCacheAttributes().getMaxConnectionsPerHost());
- }
-
- builder.setDefaultRequestConfig(RequestConfig.custom()
- .setConnectTimeout(getRemoteHttpCacheAttributes().getConnectionTimeoutMillis())
- .setSocketTimeout(getRemoteHttpCacheAttributes().getSocketTimeoutMillis())
- // By default we instruct HttpClient to ignore cookies.
- .setCookieSpec(CookieSpecs.IGNORE_COOKIES)
- .build());
- }
-
- /**
- * Execute the web service call
- * <p>
- * @param builder builder for the post request
- *
- * @return the call response
- *
- * @throws IOException on i/o error
- */
- protected final HttpResponse doWebserviceCall( RequestBuilder builder )
- throws IOException
- {
- preProcessWebserviceCall( builder.setVersion(httpVersion) );
- HttpUriRequest request = builder.build();
- HttpResponse httpResponse = this.httpClient.execute( request );
- postProcessWebserviceCall( request, httpResponse );
-
- return httpResponse;
- }
-
- /**
- * Called before the execute call on the client.
- * <p>
- * @param requestBuilder http method request builder
- *
- * @throws IOException
- */
- protected abstract void preProcessWebserviceCall( RequestBuilder requestBuilder )
- throws IOException;
-
- /**
- * Called after the execute call on the client.
- * <p>
- * @param request http request
- * @param httpState result of execution
- *
- * @throws IOException
- */
- protected abstract void postProcessWebserviceCall( HttpUriRequest request, HttpResponse httpState )
- throws IOException;
-
- /**
- * @return the remoteHttpCacheAttributes
- */
- protected RemoteHttpCacheAttributes getRemoteHttpCacheAttributes()
- {
- return remoteHttpCacheAttributes;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCache.java
deleted file mode 100644
index 8f884f8..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCache.java
+++ /dev/null
@@ -1,113 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.client;
-
-import java.io.IOException;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.remote.AbstractRemoteAuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheListener;
-import org.apache.commons.jcs.engine.ZombieCacheServiceNonLocal;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This uses an http client as the service.
- */
-public class RemoteHttpCache<K, V>
- extends AbstractRemoteAuxiliaryCache<K, V>
-{
- /** The logger. */
- private static final Log log = LogManager.getLog( RemoteHttpCache.class );
-
- /** for error notifications */
- private RemoteHttpCacheMonitor monitor;
-
- /** Keep the child copy here for the restore process. */
- private RemoteHttpCacheAttributes remoteHttpCacheAttributes;
-
- /**
- * Constructor for the RemoteCache object. This object communicates with a remote cache server.
- * One of these exists for each region. This also holds a reference to a listener. The same
- * listener is used for all regions for one remote server. Holding a reference to the listener
- * allows this object to know the listener id assigned by the remote cache.
- * <p>
- * @param remoteHttpCacheAttributes
- * @param remote
- * @param listener
- * @param monitor the cache monitor
- */
- public RemoteHttpCache( RemoteHttpCacheAttributes remoteHttpCacheAttributes, ICacheServiceNonLocal<K, V> remote,
- IRemoteCacheListener<K, V> listener, RemoteHttpCacheMonitor monitor )
- {
- super( remoteHttpCacheAttributes, remote, listener );
-
- this.remoteHttpCacheAttributes = remoteHttpCacheAttributes;
- this.monitor = monitor;
- }
-
- /**
- * Nothing right now. This should setup a zombie and initiate recovery.
- * <p>
- * @param ex
- * @param msg
- * @param eventName
- * @throws IOException
- */
- @Override
- protected void handleException( Exception ex, String msg, String eventName )
- throws IOException
- {
- // we should not switch if the existing is a zombie.
- if ( !( getRemoteCacheService() instanceof ZombieCacheServiceNonLocal ) )
- {
- String message = "Disabling remote cache due to error: " + msg;
- logError( cacheName, "", message );
- log.error( message, ex );
-
- setRemoteCacheService( new ZombieCacheServiceNonLocal<>( getRemoteCacheAttributes().getZombieQueueMaxSize() ) );
-
- monitor.notifyError( this );
- }
-
- if ( ex instanceof IOException )
- {
- throw (IOException) ex;
- }
- throw new IOException( ex.getMessage() );
- }
-
- /**
- * @return url of service
- */
- @Override
- public String getEventLoggingExtraInfo()
- {
- return null;
- }
-
- /**
- * @return the remoteHttpCacheAttributes
- */
- public RemoteHttpCacheAttributes getRemoteHttpCacheAttributes()
- {
- return remoteHttpCacheAttributes;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheAttributes.java
deleted file mode 100644
index c68670d..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheAttributes.java
+++ /dev/null
@@ -1,228 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.client;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes;
-
-/** Http client specific settings. */
-public class RemoteHttpCacheAttributes
- extends RemoteCacheAttributes
-{
- /** Don't change. */
- private static final long serialVersionUID = -5944327125140505212L;
-
- /** http verison to use. */
- private static final String DEFAULT_HTTP_VERSION = "1.1";
-
- /** The max connections allowed per host */
- private int maxConnectionsPerHost = 100;
-
- /** The socket timeout. */
- private int socketTimeoutMillis = 3000;
-
- /** The socket connections timeout */
- private int connectionTimeoutMillis = 5000;
-
- /** http verison to use. */
- private String httpVersion = DEFAULT_HTTP_VERSION;
-
- /** The cache name will be included on the parameters */
- private boolean includeCacheNameAsParameter = true;
-
- /** keys and patterns will be included in the parameters */
- private boolean includeKeysAndPatternsAsParameter = true;
-
- /** keys and patterns will be included in the parameters */
- private boolean includeRequestTypeasAsParameter = true;
-
- /** The complete URL to the service. */
- private String url;
-
- /** The default classname for the client. */
- public static final String DEFAULT_REMOTE_HTTP_CLIENT_CLASS_NAME = RemoteHttpCacheClient.class.getName();
-
- /** This allows users to inject their own client implementation. */
- private String remoteHttpClientClassName = DEFAULT_REMOTE_HTTP_CLIENT_CLASS_NAME;
-
- /**
- * @param maxConnectionsPerHost the maxConnectionsPerHost to set
- */
- public void setMaxConnectionsPerHost( int maxConnectionsPerHost )
- {
- this.maxConnectionsPerHost = maxConnectionsPerHost;
- }
-
- /**
- * @return the maxConnectionsPerHost
- */
- public int getMaxConnectionsPerHost()
- {
- return maxConnectionsPerHost;
- }
-
- /**
- * @param socketTimeoutMillis the socketTimeoutMillis to set
- */
- public void setSocketTimeoutMillis( int socketTimeoutMillis )
- {
- this.socketTimeoutMillis = socketTimeoutMillis;
- }
-
- /**
- * @return the socketTimeoutMillis
- */
- public int getSocketTimeoutMillis()
- {
- return socketTimeoutMillis;
- }
-
- /**
- * @param httpVersion the httpVersion to set
- */
- public void setHttpVersion( String httpVersion )
- {
- this.httpVersion = httpVersion;
- }
-
- /**
- * @return the httpVersion
- */
- public String getHttpVersion()
- {
- return httpVersion;
- }
-
- /**
- * @param connectionTimeoutMillis the connectionTimeoutMillis to set
- */
- public void setConnectionTimeoutMillis( int connectionTimeoutMillis )
- {
- this.connectionTimeoutMillis = connectionTimeoutMillis;
- }
-
- /**
- * @return the connectionTimeoutMillis
- */
- public int getConnectionTimeoutMillis()
- {
- return connectionTimeoutMillis;
- }
-
- /**
- * @param includeCacheNameInURL the includeCacheNameInURL to set
- */
- public void setIncludeCacheNameAsParameter( boolean includeCacheNameInURL )
- {
- this.includeCacheNameAsParameter = includeCacheNameInURL;
- }
-
- /**
- * @return the includeCacheNameInURL
- */
- public boolean isIncludeCacheNameAsParameter()
- {
- return includeCacheNameAsParameter;
- }
-
- /**
- * @param includeKeysAndPatternsInURL the includeKeysAndPatternsInURL to set
- */
- public void setIncludeKeysAndPatternsAsParameter( boolean includeKeysAndPatternsInURL )
- {
- this.includeKeysAndPatternsAsParameter = includeKeysAndPatternsInURL;
- }
-
- /**
- * @return the includeKeysAndPatternsInURL
- */
- public boolean isIncludeKeysAndPatternsAsParameter()
- {
- return includeKeysAndPatternsAsParameter;
- }
-
- /**
- * @param includeRequestTypeasAsParameter the includeRequestTypeasAsParameter to set
- */
- public void setIncludeRequestTypeasAsParameter( boolean includeRequestTypeasAsParameter )
- {
- this.includeRequestTypeasAsParameter = includeRequestTypeasAsParameter;
- }
-
- /**
- * @return the includeRequestTypeasAsParameter
- */
- public boolean isIncludeRequestTypeasAsParameter()
- {
- return includeRequestTypeasAsParameter;
- }
-
- /**
- * @param url the url to set
- */
- public void setUrl( String url )
- {
- this.url = url;
- }
-
- /**
- * @return the url
- */
- public String getUrl()
- {
- return url;
- }
-
- /**
- * @param remoteHttpClientClassName the remoteHttpClientClassName to set
- */
- public void setRemoteHttpClientClassName( String remoteHttpClientClassName )
- {
- this.remoteHttpClientClassName = remoteHttpClientClassName;
- }
-
- /**
- * @return the remoteHttpClientClassName
- */
- public String getRemoteHttpClientClassName()
- {
- return remoteHttpClientClassName;
- }
-
- /**
- * @return String details
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\n RemoteHttpCacheAttributes" );
- buf.append( "\n maxConnectionsPerHost = [" + getMaxConnectionsPerHost() + "]" );
- buf.append( "\n socketTimeoutMillis = [" + getSocketTimeoutMillis() + "]" );
- buf.append( "\n httpVersion = [" + getHttpVersion() + "]" );
- buf.append( "\n connectionTimeoutMillis = [" + getConnectionTimeoutMillis() + "]" );
- buf.append( "\n includeCacheNameAsParameter = [" + isIncludeCacheNameAsParameter() + "]" );
- buf.append( "\n includeKeysAndPatternsAsParameter = [" + isIncludeKeysAndPatternsAsParameter() + "]" );
- buf.append( "\n includeRequestTypeasAsParameter = [" + isIncludeRequestTypeasAsParameter() + "]" );
- buf.append( "\n url = [" + getUrl() + "]" );
- buf.append( "\n remoteHttpClientClassName = [" + getRemoteHttpClientClassName() + "]" );
- buf.append( super.toString() );
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheClient.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheClient.java
deleted file mode 100644
index 0f870d4..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheClient.java
+++ /dev/null
@@ -1,484 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.client;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheDispatcher;
-import org.apache.commons.jcs.auxiliary.remote.http.client.behavior.IRemoteHttpCacheClient;
-import org.apache.commons.jcs.auxiliary.remote.util.RemoteCacheRequestFactory;
-import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheRequest;
-import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheResponse;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/** This is the service used by the remote http auxiliary cache. */
-public class RemoteHttpCacheClient<K, V>
- implements IRemoteHttpCacheClient<K, V>
-{
- /** The Logger. */
- private static final Log log = LogManager.getLog( RemoteHttpCacheClient.class );
-
- /** The internal client. */
- private IRemoteCacheDispatcher remoteDispatcher;
-
- /** The remote attributes */
- private RemoteHttpCacheAttributes remoteHttpCacheAttributes;
-
- /** Set to true when initialize is called */
- private boolean initialized = false;
-
- /** For factory construction. */
- public RemoteHttpCacheClient()
- {
- // does nothing
- }
-
- /**
- * Constructs a client.
- * <p>
- * @param attributes
- */
- public RemoteHttpCacheClient( RemoteHttpCacheAttributes attributes )
- {
- setRemoteHttpCacheAttributes( attributes );
- initialize( attributes );
- }
-
- /**
- * The provides an extension point. If you want to extend this and use a special dispatcher,
- * here is the place to do it.
- * <p>
- * @param attributes
- */
- @Override
- public void initialize( RemoteHttpCacheAttributes attributes )
- {
- setRemoteDispatcher( new RemoteHttpCacheDispatcher( attributes ) );
-
- log.info( "Created remote Dispatcher. {0}", () -> getRemoteDispatcher() );
- setInitialized( true );
- }
-
- /**
- * Create a request, process, extract the payload.
- * <p>
- * @param cacheName
- * @param key
- * @return ICacheElement
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> get( String cacheName, K key )
- throws IOException
- {
- return get( cacheName, key, 0 );
- }
-
- /**
- * Create a request, process, extract the payload.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @return ICacheElement
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> get( String cacheName, K key, long requesterId )
- throws IOException
- {
- if ( !isInitialized() )
- {
- String message = "The Remote Http Client is not initialized. Cannot process request.";
- log.warn( message );
- throw new IOException( message );
- }
- RemoteCacheRequest<K, Serializable> remoteHttpCacheRequest =
- RemoteCacheRequestFactory.createGetRequest( cacheName, key, requesterId );
-
- RemoteCacheResponse<ICacheElement<K, V>> remoteHttpCacheResponse =
- getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest );
-
- log.debug( "Get [{0}] = {1}", key, remoteHttpCacheResponse );
-
- if ( remoteHttpCacheResponse != null)
- {
- return remoteHttpCacheResponse.getPayload();
- }
-
- return null;
- }
-
- /**
- * Gets multiple items from the cache matching the pattern.
- * <p>
- * @param cacheName
- * @param pattern
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache matching the pattern.
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern )
- throws IOException
- {
- return getMatching( cacheName, pattern, 0 );
- }
-
- /**
- * Gets multiple items from the cache matching the pattern.
- * <p>
- * @param cacheName
- * @param pattern
- * @param requesterId
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache matching the pattern.
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern, long requesterId )
- throws IOException
- {
- if ( !isInitialized() )
- {
- String message = "The Remote Http Client is not initialized. Cannot process request.";
- log.warn( message );
- throw new IOException( message );
- }
-
- RemoteCacheRequest<K, V> remoteHttpCacheRequest =
- RemoteCacheRequestFactory.createGetMatchingRequest( cacheName, pattern, requesterId );
-
- RemoteCacheResponse<Map<K, ICacheElement<K, V>>> remoteHttpCacheResponse =
- getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest );
-
- log.debug( "GetMatching [{0}] = {1}", pattern, remoteHttpCacheResponse );
-
- return remoteHttpCacheResponse.getPayload();
- }
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * @param cacheName
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys )
- throws IOException
- {
- return getMultiple( cacheName, keys, 0 );
- }
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * @param cacheName
- * @param keys
- * @param requesterId
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys, long requesterId )
- throws IOException
- {
- if ( !isInitialized() )
- {
- String message = "The Remote Http Client is not initialized. Cannot process request.";
- log.warn( message );
- throw new IOException( message );
- }
-
- RemoteCacheRequest<K, V> remoteHttpCacheRequest =
- RemoteCacheRequestFactory.createGetMultipleRequest( cacheName, keys, requesterId );
-
- RemoteCacheResponse<Map<K, ICacheElement<K, V>>> remoteHttpCacheResponse =
- getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest );
-
- log.debug( "GetMultiple [{0}] = {1}", keys, remoteHttpCacheResponse );
-
- return remoteHttpCacheResponse.getPayload();
- }
-
- /**
- * Removes the given key from the specified cache.
- * <p>
- * @param cacheName
- * @param key
- * @throws IOException
- */
- @Override
- public void remove( String cacheName, K key )
- throws IOException
- {
- remove( cacheName, key, 0 );
- }
-
- /**
- * Removes the given key from the specified cache.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @throws IOException
- */
- @Override
- public void remove( String cacheName, K key, long requesterId )
- throws IOException
- {
- if ( !isInitialized() )
- {
- String message = "The Remote Http Client is not initialized. Cannot process request.";
- log.warn( message );
- throw new IOException( message );
- }
-
- RemoteCacheRequest<K, V> remoteHttpCacheRequest =
- RemoteCacheRequestFactory.createRemoveRequest( cacheName, key, requesterId );
-
- getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest );
- }
-
- /**
- * Remove all keys from the specified cache.
- * <p>
- * @param cacheName
- * @throws IOException
- */
- @Override
- public void removeAll( String cacheName )
- throws IOException
- {
- removeAll( cacheName, 0 );
- }
-
- /**
- * Remove all keys from the sepcified cache.
- * <p>
- * @param cacheName
- * @param requesterId
- * @throws IOException
- */
- @Override
- public void removeAll( String cacheName, long requesterId )
- throws IOException
- {
- if ( !isInitialized() )
- {
- String message = "The Remote Http Client is not initialized. Cannot process request.";
- log.warn( message );
- throw new IOException( message );
- }
-
- RemoteCacheRequest<K, V> remoteHttpCacheRequest =
- RemoteCacheRequestFactory.createRemoveAllRequest( cacheName, requesterId );
-
- getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest );
- }
-
- /**
- * Puts a cache item to the cache.
- * <p>
- * @param item
- * @throws IOException
- */
- @Override
- public void update( ICacheElement<K, V> item )
- throws IOException
- {
- update( item, 0 );
- }
-
- /**
- * Puts a cache item to the cache.
- * <p>
- * @param cacheElement
- * @param requesterId
- * @throws IOException
- */
- @Override
- public void update( ICacheElement<K, V> cacheElement, long requesterId )
- throws IOException
- {
- if ( !isInitialized() )
- {
- String message = "The Remote Http Client is not initialized. Cannot process request.";
- log.warn( message );
- throw new IOException( message );
- }
-
- RemoteCacheRequest<K, V> remoteHttpCacheRequest =
- RemoteCacheRequestFactory.createUpdateRequest( cacheElement, requesterId );
-
- getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest );
- }
-
- /**
- * Frees the specified cache.
- * <p>
- * @param cacheName
- * @throws IOException
- */
- @Override
- public void dispose( String cacheName )
- throws IOException
- {
- if ( !isInitialized() )
- {
- String message = "The Remote Http Client is not initialized. Cannot process request.";
- log.warn( message );
- throw new IOException( message );
- }
-
- RemoteCacheRequest<K, V> remoteHttpCacheRequest =
- RemoteCacheRequestFactory.createDisposeRequest( cacheName, 0 );
-
- getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest );
- }
-
- /**
- * Frees the specified cache.
- * <p>
- * @throws IOException
- */
- @Override
- public void release()
- throws IOException
- {
- // noop
- }
-
- /**
- * Return the keys in this cache.
- * <p>
- * @param cacheName the name of the cache
- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet()
- */
- @Override
- public Set<K> getKeySet( String cacheName ) throws IOException
- {
- if ( !isInitialized() )
- {
- String message = "The Remote Http Client is not initialized. Cannot process request.";
- log.warn( message );
- throw new IOException( message );
- }
-
- RemoteCacheRequest<String, String> remoteHttpCacheRequest =
- RemoteCacheRequestFactory.createGetKeySetRequest(cacheName, 0 );
-
- RemoteCacheResponse<Set<K>> remoteHttpCacheResponse = getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest );
-
- if ( remoteHttpCacheResponse != null && remoteHttpCacheResponse.getPayload() != null )
- {
- return remoteHttpCacheResponse.getPayload();
- }
-
- return Collections.emptySet();
- }
-
- /**
- * Make and alive request.
- * <p>
- * @return true if we make a successful alive request.
- * @throws IOException
- */
- @Override
- public boolean isAlive()
- throws IOException
- {
- if ( !isInitialized() )
- {
- String message = "The Remote Http Client is not initialized. Cannot process request.";
- log.warn( message );
- throw new IOException( message );
- }
-
- RemoteCacheRequest<K, V> remoteHttpCacheRequest = RemoteCacheRequestFactory.createAliveCheckRequest( 0 );
- RemoteCacheResponse<String> remoteHttpCacheResponse =
- getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest );
-
- if ( remoteHttpCacheResponse != null )
- {
- return remoteHttpCacheResponse.isSuccess();
- }
-
- return false;
- }
-
- /**
- * @param remoteDispatcher the remoteDispatcher to set
- */
- public void setRemoteDispatcher( IRemoteCacheDispatcher remoteDispatcher )
- {
- this.remoteDispatcher = remoteDispatcher;
- }
-
- /**
- * @return the remoteDispatcher
- */
- public IRemoteCacheDispatcher getRemoteDispatcher()
- {
- return remoteDispatcher;
- }
-
- /**
- * @param remoteHttpCacheAttributes the remoteHttpCacheAttributes to set
- */
- public void setRemoteHttpCacheAttributes( RemoteHttpCacheAttributes remoteHttpCacheAttributes )
- {
- this.remoteHttpCacheAttributes = remoteHttpCacheAttributes;
- }
-
- /**
- * @return the remoteHttpCacheAttributes
- */
- public RemoteHttpCacheAttributes getRemoteHttpCacheAttributes()
- {
- return remoteHttpCacheAttributes;
- }
-
- /**
- * @param initialized the initialized to set
- */
- protected void setInitialized( boolean initialized )
- {
- this.initialized = initialized;
- }
-
- /**
- * @return the initialized
- */
- protected boolean isInitialized()
- {
- return initialized;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheDispatcher.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheDispatcher.java
deleted file mode 100644
index b6c9faf..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheDispatcher.java
+++ /dev/null
@@ -1,196 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.client;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheDispatcher;
-import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheRequest;
-import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheResponse;
-import org.apache.commons.jcs.utils.serialization.StandardSerializer;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.http.HttpException;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.client.methods.RequestBuilder;
-import org.apache.http.entity.ByteArrayEntity;
-import org.apache.http.util.EntityUtils;
-
-/** Calls the service. */
-public class RemoteHttpCacheDispatcher
- extends AbstractHttpClient
- implements IRemoteCacheDispatcher
-{
- /** Parameter encoding */
- private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
-
- /** Named of the parameter */
- private static final String PARAMETER_REQUEST_TYPE = "RequestType";
-
- /** Named of the parameter */
- private static final String PARAMETER_KEY = "Key";
-
- /** Named of the parameter */
- private static final String PARAMETER_CACHE_NAME = "CacheName";
-
- /** The Logger. */
- private static final Log log = LogManager.getLog( RemoteHttpCacheDispatcher.class );
-
- /** This needs to be standard, since the other side is standard */
- private StandardSerializer serializer = new StandardSerializer();
-
- /**
- * @param remoteHttpCacheAttributes
- */
- public RemoteHttpCacheDispatcher( RemoteHttpCacheAttributes remoteHttpCacheAttributes )
- {
- super( remoteHttpCacheAttributes );
- }
-
- /**
- * All requests will go through this method.
- * <p>
- * TODO consider taking in a URL instead of using the one in the configuration.
- * <p>
- * @param remoteCacheRequest
- * @return RemoteCacheResponse
- * @throws IOException
- */
- @Override
- public <K, V, T>
- RemoteCacheResponse<T> dispatchRequest( RemoteCacheRequest<K, V> remoteCacheRequest )
- throws IOException
- {
- try
- {
- byte[] requestAsByteArray = serializer.serialize( remoteCacheRequest );
-
- byte[] responseAsByteArray = processRequest( requestAsByteArray,
- remoteCacheRequest,
- getRemoteHttpCacheAttributes().getUrl());
-
- RemoteCacheResponse<T> remoteCacheResponse = null;
- try
- {
- remoteCacheResponse = serializer.deSerialize( responseAsByteArray, null );
- }
- catch ( ClassNotFoundException e )
- {
- log.error( "Couldn't deserialize the response.", e );
- }
- return remoteCacheResponse;
- }
- catch ( Exception e )
- {
- throw new IOException("Problem dispatching request.", e);
- }
- }
-
- /**
- * Process single request
- *
- * @param requestAsByteArray request body
- * @param remoteCacheRequest the cache request
- * @param url target url
- *
- * @return byte[] - the response
- *
- * @throws IOException
- * @throws HttpException
- */
- protected <K, V> byte[] processRequest( byte[] requestAsByteArray,
- RemoteCacheRequest<K, V> remoteCacheRequest, String url )
- throws IOException, HttpException
- {
- RequestBuilder builder = RequestBuilder.post( url ).setCharset( DEFAULT_ENCODING );
-
- if ( getRemoteHttpCacheAttributes().isIncludeCacheNameAsParameter()
- && remoteCacheRequest.getCacheName() != null )
- {
- builder.addParameter( PARAMETER_CACHE_NAME, remoteCacheRequest.getCacheName() );
- }
- if ( getRemoteHttpCacheAttributes().isIncludeKeysAndPatternsAsParameter() )
- {
- String keyValue = "";
- switch ( remoteCacheRequest.getRequestType() )
- {
- case GET:
- case REMOVE:
- case GET_KEYSET:
- keyValue = remoteCacheRequest.getKey().toString();
- break;
- case GET_MATCHING:
- keyValue = remoteCacheRequest.getPattern();
- break;
- case GET_MULTIPLE:
- keyValue = remoteCacheRequest.getKeySet().toString();
- break;
- case UPDATE:
- keyValue = remoteCacheRequest.getCacheElement().getKey().toString();
- break;
- default:
- break;
- }
- builder.addParameter( PARAMETER_KEY, keyValue );
- }
- if ( getRemoteHttpCacheAttributes().isIncludeRequestTypeasAsParameter() )
- {
- builder.addParameter( PARAMETER_REQUEST_TYPE,
- remoteCacheRequest.getRequestType().toString() );
- }
-
- builder.setEntity(new ByteArrayEntity( requestAsByteArray ));
- HttpResponse httpResponse = doWebserviceCall( builder );
- byte[] response = EntityUtils.toByteArray( httpResponse.getEntity() );
- return response;
- }
-
- /**
- * Called before the execute call on the client.
- * <p>
- * @param requestBuilder http method request builder
- *
- * @throws IOException
- */
- @Override
- protected void preProcessWebserviceCall( RequestBuilder requestBuilder )
- throws IOException
- {
- // do nothing. Child can override.
- }
-
- /**
- * Called after the execute call on the client.
- * <p>
- * @param request http request
- * @param httpState result of execution
- *
- * @throws IOException
- */
- @Override
- protected void postProcessWebserviceCall( HttpUriRequest request, HttpResponse httpState )
- throws IOException
- {
- // do nothing. Child can override.
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheFactory.java
deleted file mode 100644
index 476d176..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheFactory.java
+++ /dev/null
@@ -1,146 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.client;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.remote.RemoteCacheNoWait;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheClient;
-import org.apache.commons.jcs.auxiliary.remote.http.client.behavior.IRemoteHttpCacheClient;
-import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.config.OptionConverter;
-
-/**
- * The RemoteCacheFactory creates remote caches for the cache hub. It returns a no wait facade which
- * is a wrapper around a no wait. The no wait object is either an active connection to a remote
- * cache or a balking zombie if the remote cache is not accessible. It should be transparent to the
- * clients.
- */
-public class RemoteHttpCacheFactory
- extends AbstractAuxiliaryCacheFactory
-{
- /** The logger */
- private static final Log log = LogManager.getLog( RemoteHttpCacheFactory.class );
-
- /** Monitor thread instance */
- private RemoteHttpCacheMonitor monitor;
-
- /**
- * For LOCAL clients we get a handle to all the failovers, but we do not register a listener
- * with them. We create the RemoteCacheManager, but we do not get a cache.
- * <p>
- * The failover runner will get a cache from the manager. When the primary is restored it will
- * tell the manager for the failover to deregister the listener.
- * <p>
- * @param iaca
- * @param cacheMgr
- * @param cacheEventLogger
- * @param elementSerializer
- * @return AuxiliaryCache
- */
- @Override
- public <K, V> AuxiliaryCache<K, V> createCache( AuxiliaryCacheAttributes iaca, ICompositeCacheManager cacheMgr,
- ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
- {
- RemoteHttpCacheAttributes rca = (RemoteHttpCacheAttributes) iaca;
-
- // TODO, use the configured value.
- rca.setRemoteType( RemoteType.LOCAL );
-
- RemoteHttpClientListener<K, V> listener = new RemoteHttpClientListener<>( rca, cacheMgr, elementSerializer );
-
- IRemoteHttpCacheClient<K, V> remoteService = createRemoteHttpCacheClientForAttributes(rca);
-
- IRemoteCacheClient<K, V> remoteCacheClient =
- new RemoteHttpCache<>( rca, remoteService, listener, monitor );
- remoteCacheClient.setCacheEventLogger( cacheEventLogger );
- remoteCacheClient.setElementSerializer( elementSerializer );
-
- RemoteCacheNoWait<K, V> remoteCacheNoWait = new RemoteCacheNoWait<>( remoteCacheClient );
- remoteCacheNoWait.setCacheEventLogger( cacheEventLogger );
- remoteCacheNoWait.setElementSerializer( elementSerializer );
-
- return remoteCacheNoWait;
- }
-
- /**
- * This is an extension point. The manager and other classes will only create
- * RemoteHttpCacheClient through this method.
-
- * @param cattr the cache configuration
- * @return the client instance
- */
- protected <V, K> IRemoteHttpCacheClient<K, V> createRemoteHttpCacheClientForAttributes(RemoteHttpCacheAttributes cattr)
- {
- IRemoteHttpCacheClient<K, V> remoteService = OptionConverter.instantiateByClassName( cattr
- .getRemoteHttpClientClassName(), null );
-
- if ( remoteService == null )
- {
- log.info( "Creating the default client for {0}",
- () -> cattr.getCacheName());
- remoteService = new RemoteHttpCacheClient<>();
- }
-
- remoteService.initialize( cattr );
- return remoteService;
- }
-
- /**
- * @see org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory#initialize()
- */
- @Override
- public void initialize()
- {
- super.initialize();
- monitor = new RemoteHttpCacheMonitor(this);
- monitor.setDaemon(true);
- monitor.start();
- }
-
- /**
- * @see org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory#dispose()
- */
- @Override
- public void dispose()
- {
- if (monitor != null)
- {
- monitor.notifyShutdown();
- try
- {
- monitor.join(5000);
- }
- catch (InterruptedException e)
- {
- // swallow
- }
- monitor = null;
- }
-
- super.dispose();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheMonitor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheMonitor.java
deleted file mode 100644
index 6a5a2a7..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheMonitor.java
+++ /dev/null
@@ -1,136 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.client;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheMonitor;
-import org.apache.commons.jcs.auxiliary.remote.http.client.behavior.IRemoteHttpCacheClient;
-import org.apache.commons.jcs.engine.CacheStatus;
-
-/**
- * Upon the notification of a connection error, the monitor changes to operate in a time driven
- * mode. That is, it attempts to recover the connections on a periodic basis. When all failed
- * connections are restored, it changes back to the failure driven mode.
- */
-public class RemoteHttpCacheMonitor extends AbstractAuxiliaryCacheMonitor
-{
- /** Set of remote caches to monitor. This are added on error, if not before. */
- private final ConcurrentHashMap<RemoteHttpCache<?, ?>, RemoteHttpCache<?, ?>> remoteHttpCaches;
-
- /** Factory instance */
- private RemoteHttpCacheFactory factory = null;
-
- /**
- * Constructor for the RemoteCacheMonitor object
- *
- * @param factory the factory to set
- */
- public RemoteHttpCacheMonitor(RemoteHttpCacheFactory factory)
- {
- super("JCS-RemoteHttpCacheMonitor");
- this.factory = factory;
- this.remoteHttpCaches = new ConcurrentHashMap<>();
- setIdlePeriod(3000L);
- }
-
- /**
- * Notifies the cache monitor that an error occurred, and kicks off the error recovery process.
- * <p>
- * @param remoteCache
- */
- public void notifyError( RemoteHttpCache<?, ?> remoteCache )
- {
- if ( log.isInfoEnabled() )
- {
- log.info( "Notified of an error. " + remoteCache );
- }
-
- remoteHttpCaches.put( remoteCache, remoteCache );
- notifyError();
- }
-
- /**
- * Clean up all resources before shutdown
- */
- @Override
- protected void dispose()
- {
- this.remoteHttpCaches.clear();
- }
-
- // Avoid the use of any synchronization in the process of monitoring for
- // performance reasons.
- // If exception is thrown owing to synchronization,
- // just skip the monitoring until the next round.
- /** Main processing method for the RemoteHttpCacheMonitor object */
- @Override
- protected void doWork()
- {
- // If no factory has been set, skip
- if (factory == null)
- {
- return;
- }
-
- // If any cache is in error, it strongly suggests all caches
- // managed by the same RmicCacheManager instance are in error. So we fix
- // them once and for all.
- for (RemoteHttpCache<?, ?> remoteCache : this.remoteHttpCaches.values())
- {
- try
- {
- if ( remoteCache.getStatus() == CacheStatus.ERROR )
- {
- RemoteHttpCacheAttributes attributes = remoteCache.getRemoteHttpCacheAttributes();
-
- IRemoteHttpCacheClient<Serializable, Serializable> remoteService =
- factory.createRemoteHttpCacheClientForAttributes( attributes );
-
- if ( log.isInfoEnabled() )
- {
- log.info( "Performing Alive check on service " + remoteService );
- }
- // If we can't fix them, just skip and re-try in
- // the next round.
- if ( remoteService.isAlive() )
- {
- remoteCache.fixCache( remoteService );
- }
- else
- {
- allright.set(false);
- }
- break;
- }
- }
- catch ( IOException ex )
- {
- allright.set(false);
- // Problem encountered in fixing the caches managed by a
- // RemoteCacheManager instance.
- // Soldier on to the next RemoteHttpCache.
- log.error( ex );
- }
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpClientListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpClientListener.java
deleted file mode 100644
index 4129724..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpClientListener.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.client;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.remote.AbstractRemoteCacheListener;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-
-/** Does nothing */
-public class RemoteHttpClientListener<K, V>
- extends AbstractRemoteCacheListener<K, V>
-{
- /**
- * Only need one since it does work for all regions, just reference by multiple region names.
- * <p>
- * The constructor exports this object, making it available to receive incoming calls. The
- * callback port is anonymous unless a local port value was specified in the configuration.
- * <p>
- * @param irca cache configuration
- * @param cacheMgr the cache hub
- * @param elementSerializer a custom serializer
- */
- public RemoteHttpClientListener( IRemoteCacheAttributes irca, ICompositeCacheManager cacheMgr, IElementSerializer elementSerializer )
- {
- super( irca, cacheMgr, elementSerializer );
- }
-
- /** Nothing */
- @Override
- public void dispose()
- {
- // noop
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/behavior/IRemoteHttpCacheClient.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/behavior/IRemoteHttpCacheClient.java
deleted file mode 100644
index 9949b7e..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/client/behavior/IRemoteHttpCacheClient.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.client.behavior;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.remote.http.client.RemoteHttpCacheAttributes;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-
-import java.io.IOException;
-
-
-/**
- * It's not entirely clear that this interface is needed. I simply wanted the initialization method.
- * This could be added to the ICacheSerice method.
- */
-public interface IRemoteHttpCacheClient<K, V>
- extends ICacheServiceNonLocal<K, V>
-{
- /**
- * The provides an extension point. If you want to extend this and use a special dispatcher,
- * here is the place to do it.
- * <p>
- * @param attributes
- */
- void initialize( RemoteHttpCacheAttributes attributes );
-
- /**
- * Make and alive request.
- * <p>
- * @return true if we make a successful alive request.
- * @throws IOException
- */
- boolean isAlive()
- throws IOException;
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/server/AbstractRemoteCacheService.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/server/AbstractRemoteCacheService.java
deleted file mode 100644
index 8a425f4..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/server/AbstractRemoteCacheService.java
+++ /dev/null
@@ -1,601 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.server;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.logging.CacheEvent;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This class contains common methods for remote cache services. Eventually I hope to extract out
- * much of the RMI server to use this as well. I'm starting with the Http service.
- */
-public abstract class AbstractRemoteCacheService<K, V>
- implements ICacheServiceNonLocal<K, V>
-{
- /** An optional event logger */
- private transient ICacheEventLogger cacheEventLogger;
-
- /** The central hub */
- private ICompositeCacheManager cacheManager;
-
- /** Name of the event log source. */
- private String eventLogSourceName = "AbstractRemoteCacheService";
-
- /** Number of puts into the cache. */
- private int puts = 0;
-
- /** The interval at which we will log updates. */
- private final int logInterval = 100;
-
- /** log instance */
- private static final Log log = LogManager.getLog( AbstractRemoteCacheService.class );
-
- /**
- * Creates the super with the needed items.
- * <p>
- * @param cacheManager
- * @param cacheEventLogger
- */
- public AbstractRemoteCacheService( ICompositeCacheManager cacheManager, ICacheEventLogger cacheEventLogger )
- {
- this.cacheManager = cacheManager;
- this.cacheEventLogger = cacheEventLogger;
- }
-
- /**
- * @param item
- * @throws IOException
- */
- @Override
- public void update( ICacheElement<K, V> item )
- throws IOException
- {
- update( item, 0 );
- }
-
- /**
- * The internal processing is wrapped in event logging calls.
- * <p>
- * @param item
- * @param requesterId
- * @throws IOException
- */
- @Override
- public void update( ICacheElement<K, V> item, long requesterId )
- throws IOException
- {
- ICacheEvent<ICacheElement<K, V>> cacheEvent = createICacheEvent( item, requesterId, ICacheEventLogger.UPDATE_EVENT );
- try
- {
- logUpdateInfo( item );
-
- processUpdate( item, requesterId );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * The internal processing is wrapped in event logging calls.
- * <p>
- * @param item
- * @param requesterId
- * @throws IOException
- */
- abstract void processUpdate( ICacheElement<K, V> item, long requesterId )
- throws IOException;
-
- /**
- * Log some details.
- * <p>
- * @param item
- */
- private void logUpdateInfo( ICacheElement<K, V> item )
- {
- if ( log.isInfoEnabled() )
- {
- // not thread safe, but it doesn't have to be accurate
- puts++;
- if ( puts % logInterval == 0 )
- {
- log.info( "puts = {0}", puts );
- }
- }
-
- log.debug( "In update, put [{0}] in [{1}]", () -> item.getKey(),
- () -> item.getCacheName() );
- }
-
- /**
- * Returns a cache value from the specified remote cache; or null if the cache or key does not
- * exist.
- * <p>
- * @param cacheName
- * @param key
- * @return ICacheElement
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> get( String cacheName, K key )
- throws IOException
- {
- return this.get( cacheName, key, 0 );
- }
-
- /**
- * Returns a cache bean from the specified cache; or null if the key does not exist.
- * <p>
- * Adding the requestor id, allows the cache to determine the source of the get.
- * <p>
- * The internal processing is wrapped in event logging calls.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @return ICacheElement
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> get( String cacheName, K key, long requesterId )
- throws IOException
- {
- ICacheElement<K, V> element = null;
- ICacheEvent<K> cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.GET_EVENT );
- try
- {
- element = processGet( cacheName, key, requesterId );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- return element;
- }
-
- /**
- * Returns a cache bean from the specified cache; or null if the key does not exist.
- * <p>
- * Adding the requestor id, allows the cache to determine the source of the get.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @return ICacheElement
- * @throws IOException
- */
- abstract ICacheElement<K, V> processGet( String cacheName, K key, long requesterId )
- throws IOException;
-
- /**
- * Gets all matching items.
- * <p>
- * @param cacheName
- * @param pattern
- * @return Map of keys and wrapped objects
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern )
- throws IOException
- {
- return getMatching( cacheName, pattern, 0 );
- }
-
- /**
- * Retrieves all matching keys.
- * <p>
- * @param cacheName
- * @param pattern
- * @param requesterId
- * @return Map of keys and wrapped objects
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern, long requesterId )
- throws IOException
- {
- ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, pattern, requesterId,
- ICacheEventLogger.GETMATCHING_EVENT );
- try
- {
- return processGetMatching( cacheName, pattern, requesterId );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Retrieves all matching keys.
- * <p>
- * @param cacheName
- * @param pattern
- * @param requesterId
- * @return Map of keys and wrapped objects
- * @throws IOException
- */
- abstract Map<K, ICacheElement<K, V>> processGetMatching( String cacheName, String pattern, long requesterId )
- throws IOException;
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * @param cacheName
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys )
- throws IOException
- {
- return this.getMultiple( cacheName, keys, 0 );
- }
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * The internal processing is wrapped in event logging calls.
- * <p>
- * @param cacheName
- * @param keys
- * @param requesterId
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys, long requesterId )
- throws IOException
- {
- ICacheEvent<Serializable> cacheEvent = createICacheEvent( cacheName, (Serializable) keys, requesterId,
- ICacheEventLogger.GETMULTIPLE_EVENT );
- try
- {
- return processGetMultiple( cacheName, keys, requesterId );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * @param cacheName
- * @param keys
- * @param requesterId
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- * @throws IOException
- */
- abstract Map<K, ICacheElement<K, V>> processGetMultiple( String cacheName, Set<K> keys, long requesterId )
- throws IOException;
-
- /**
- * Return the keys in this cache.
- * <p>
- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet()
- */
- @Override
- public Set<K> getKeySet( String cacheName )
- {
- return processGetKeySet( cacheName );
- }
-
- /**
- * Gets the set of keys of objects currently in the cache.
- * <p>
- * @param cacheName
- * @return Set
- */
- public Set<K> processGetKeySet( String cacheName )
- {
- CompositeCache<K, V> cache = getCacheManager().getCache( cacheName );
-
- return cache.getKeySet();
- }
-
- /**
- * Removes the given key from the specified remote cache. Defaults the listener id to 0.
- * <p>
- * @param cacheName
- * @param key
- * @throws IOException
- */
- @Override
- public void remove( String cacheName, K key )
- throws IOException
- {
- remove( cacheName, key, 0 );
- }
-
- /**
- * Remove the key from the cache region and don't tell the source listener about it.
- * <p>
- * The internal processing is wrapped in event logging calls.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @throws IOException
- */
- @Override
- public void remove( String cacheName, K key, long requesterId )
- throws IOException
- {
- ICacheEvent<K> cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.REMOVE_EVENT );
- try
- {
- processRemove( cacheName, key, requesterId );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Remove the key from the cache region and don't tell the source listener about it.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @throws IOException
- */
- abstract void processRemove( String cacheName, K key, long requesterId )
- throws IOException;
-
- /**
- * Remove all keys from the specified remote cache.
- * <p>
- * @param cacheName
- * @throws IOException
- */
- @Override
- public void removeAll( String cacheName )
- throws IOException
- {
- removeAll( cacheName, 0 );
- }
-
- /**
- * Remove all keys from the specified remote cache.
- * <p>
- * The internal processing is wrapped in event logging calls.
- * <p>
- * @param cacheName
- * @param requesterId
- * @throws IOException
- */
- @Override
- public void removeAll( String cacheName, long requesterId )
- throws IOException
- {
- ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, "all", requesterId, ICacheEventLogger.REMOVEALL_EVENT );
- try
- {
- processRemoveAll( cacheName, requesterId );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Remove all keys from the specified remote cache.
- * <p>
- * @param cacheName
- * @param requesterId
- * @throws IOException
- */
- abstract void processRemoveAll( String cacheName, long requesterId )
- throws IOException;
-
- /**
- * Frees the specified remote cache.
- * <p>
- * @param cacheName
- * @throws IOException
- */
- @Override
- public void dispose( String cacheName )
- throws IOException
- {
- dispose( cacheName, 0 );
- }
-
- /**
- * Frees the specified remote cache.
- * <p>
- * @param cacheName
- * @param requesterId
- * @throws IOException
- */
- public void dispose( String cacheName, long requesterId )
- throws IOException
- {
- ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, "none", requesterId, ICacheEventLogger.DISPOSE_EVENT );
- try
- {
- processDispose( cacheName, requesterId );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * @param cacheName
- * @param requesterId
- * @throws IOException
- */
- abstract void processDispose( String cacheName, long requesterId )
- throws IOException;
-
- /**
- * Gets the stats attribute of the RemoteCacheServer object.
- * <p>
- * @return The stats value
- * @throws IOException
- */
- public String getStats()
- throws IOException
- {
- return cacheManager.getStats();
- }
-
- /**
- * Logs an event if an event logger is configured.
- * <p>
- * @param item
- * @param requesterId
- * @param eventName
- * @return ICacheEvent
- */
- protected ICacheEvent<ICacheElement<K, V>> createICacheEvent( ICacheElement<K, V> item, long requesterId, String eventName )
- {
- if ( cacheEventLogger == null )
- {
- return new CacheEvent<>();
- }
- String ipAddress = getExtraInfoForRequesterId( requesterId );
- return cacheEventLogger.createICacheEvent( getEventLogSourceName(), item.getCacheName(), eventName, ipAddress,
- item );
- }
-
- /**
- * Logs an event if an event logger is configured.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @param eventName
- * @return ICacheEvent
- */
- protected <T> ICacheEvent<T> createICacheEvent( String cacheName, T key, long requesterId, String eventName )
- {
- if ( cacheEventLogger == null )
- {
- return new CacheEvent<>();
- }
- String ipAddress = getExtraInfoForRequesterId( requesterId );
- return cacheEventLogger.createICacheEvent( getEventLogSourceName(), cacheName, eventName, ipAddress, key );
- }
-
- /**
- * Logs an event if an event logger is configured.
- * <p>
- * @param source
- * @param eventName
- * @param optionalDetails
- */
- protected void logApplicationEvent( String source, String eventName, String optionalDetails )
- {
- if ( cacheEventLogger != null )
- {
- cacheEventLogger.logApplicationEvent( source, eventName, optionalDetails );
- }
- }
-
- /**
- * Logs an event if an event logger is configured.
- * <p>
- * @param cacheEvent
- */
- protected <T> void logICacheEvent( ICacheEvent<T> cacheEvent )
- {
- if ( cacheEventLogger != null )
- {
- cacheEventLogger.logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Ip address for the client, if one is stored.
- * <p>
- * Protected for testing.
- * <p>
- * @param requesterId
- * @return String
- */
- protected abstract String getExtraInfoForRequesterId( long requesterId );
-
- /**
- * Allows it to be injected.
- * <p>
- * @param cacheEventLogger
- */
- public void setCacheEventLogger( ICacheEventLogger cacheEventLogger )
- {
- this.cacheEventLogger = cacheEventLogger;
- }
-
- /**
- * @param cacheManager the cacheManager to set
- */
- protected void setCacheManager( ICompositeCacheManager cacheManager )
- {
- this.cacheManager = cacheManager;
- }
-
- /**
- * @return the cacheManager
- */
- protected ICompositeCacheManager getCacheManager()
- {
- return cacheManager;
- }
-
- /**
- * @param eventLogSourceName the eventLogSourceName to set
- */
- protected void setEventLogSourceName( String eventLogSourceName )
- {
- this.eventLogSourceName = eventLogSourceName;
- }
-
- /**
- * @return the eventLogSourceName
- */
- protected String getEventLogSourceName()
- {
- return eventLogSourceName;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheServerAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheServerAttributes.java
deleted file mode 100644
index bbe0257..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheServerAttributes.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.server;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheAttributes;
-
-/**
- * Configuration for the RemoteHttpCacheServer. Most of these properties are used only by the
- * service.
- */
-public class RemoteHttpCacheServerAttributes
- extends AbstractAuxiliaryCacheAttributes
-{
- /** Don't change. */
- private static final long serialVersionUID = -3987239306108780496L;
-
- /** Can a cluster remote put to other remotes */
- private boolean localClusterConsistency = true;
-
- /** Can a cluster remote get from other remotes */
- private boolean allowClusterGet = true;
-
- /**
- * Should cluster updates be propagated to the locals
- * <p>
- * @return The localClusterConsistency value
- */
- public boolean isLocalClusterConsistency()
- {
- return localClusterConsistency;
- }
-
- /**
- * Should cluster updates be propagated to the locals
- * <p>
- * @param r The new localClusterConsistency value
- */
- public void setLocalClusterConsistency( boolean r )
- {
- this.localClusterConsistency = r;
- }
-
- /**
- * Should gets from non-cluster clients be allowed to get from other remote auxiliaries.
- * <p>
- * @return The localClusterConsistency value
- */
- public boolean isAllowClusterGet()
- {
- return allowClusterGet;
- }
-
- /**
- * Should we try to get from other cluster servers if we don't find the items locally.
- * <p>
- * @param r The new localClusterConsistency value
- */
- public void setAllowClusterGet( boolean r )
- {
- allowClusterGet = r;
- }
-
- /**
- * @return String details
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\nRemoteHttpCacheServiceAttributes" );
- buf.append( "\n cacheName = [" + this.getCacheName() + "]" );
- buf.append( "\n allowClusterGet = [" + this.isAllowClusterGet() + "]" );
- buf.append( "\n localClusterConsistency = [" + this.isLocalClusterConsistency() + "]" );
- buf.append( "\n eventQueueType = [" + this.getEventQueueType() + "]" );
- buf.append( "\n eventQueuePoolName = [" + this.getEventQueuePoolName() + "]" );
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheService.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheService.java
deleted file mode 100644
index f250e91..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheService.java
+++ /dev/null
@@ -1,269 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.server;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-
-/**
- * This does the work. It's called by the processor. The base class wraps the processing calls in
- * event logs, if an event logger is present.
- * <p>
- * For now we assume that all clients are non-cluster clients. And listener notification is not
- * supported.
- */
-public class RemoteHttpCacheService<K, V>
- extends AbstractRemoteCacheService<K, V>
-{
- /** The name used in the event logs. */
- private static final String EVENT_LOG_SOURCE_NAME = "RemoteHttpCacheServer";
-
- /** The configuration */
- private final RemoteHttpCacheServerAttributes remoteHttpCacheServerAttributes;
-
- /**
- * Create a process with a cache manager.
- * <p>
- * @param cacheManager
- * @param remoteHttpCacheServerAttributes
- * @param cacheEventLogger
- */
- public RemoteHttpCacheService( ICompositeCacheManager cacheManager,
- RemoteHttpCacheServerAttributes remoteHttpCacheServerAttributes,
- ICacheEventLogger cacheEventLogger )
- {
- super( cacheManager, cacheEventLogger );
- setEventLogSourceName( EVENT_LOG_SOURCE_NAME );
- this.remoteHttpCacheServerAttributes = remoteHttpCacheServerAttributes;
- }
-
- /**
- * Processes a get request.
- * <p>
- * If isAllowClusterGet is enabled we will treat this as a normal request or non-remote origins.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @return ICacheElement
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> processGet( String cacheName, K key, long requesterId )
- throws IOException
- {
- CompositeCache<K, V> cache = getCacheManager().getCache( cacheName );
-
- boolean keepLocal = !remoteHttpCacheServerAttributes.isAllowClusterGet();
- if ( keepLocal )
- {
- return cache.localGet( key );
- }
- else
- {
- return cache.get( key );
- }
- }
-
- /**
- * Processes a get request.
- * <p>
- * If isAllowClusterGet is enabled we will treat this as a normal request of non-remote
- * origination.
- * <p>
- * @param cacheName
- * @param keys
- * @param requesterId
- * @return Map
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> processGetMultiple( String cacheName, Set<K> keys, long requesterId )
- throws IOException
- {
- CompositeCache<K, V> cache = getCacheManager().getCache( cacheName );
-
- boolean keepLocal = !remoteHttpCacheServerAttributes.isAllowClusterGet();
- if ( keepLocal )
- {
- return cache.localGetMultiple( keys );
- }
- else
- {
- return cache.getMultiple( keys );
- }
- }
-
- /**
- * Processes a get request.
- * <p>
- * If isAllowClusterGet is enabled we will treat this as a normal request of non-remote
- * origination.
- * <p>
- * @param cacheName
- * @param pattern
- * @param requesterId
- * @return Map
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> processGetMatching( String cacheName, String pattern, long requesterId )
- throws IOException
- {
- CompositeCache<K, V> cache = getCacheManager().getCache( cacheName );
-
- boolean keepLocal = !remoteHttpCacheServerAttributes.isAllowClusterGet();
- if ( keepLocal )
- {
- return cache.localGetMatching( pattern );
- }
- else
- {
- return cache.getMatching( pattern );
- }
- }
-
- /**
- * Processes an update request.
- * <p>
- * If isLocalClusterConsistency is enabled we will treat this as a normal request of non-remote
- * origination.
- * <p>
- * @param item
- * @param requesterId
- * @throws IOException
- */
- @Override
- public void processUpdate( ICacheElement<K, V> item, long requesterId )
- throws IOException
- {
- CompositeCache<K, V> cache = getCacheManager().getCache( item.getCacheName() );
-
- boolean keepLocal = !remoteHttpCacheServerAttributes.isLocalClusterConsistency();
- if ( keepLocal )
- {
- cache.localUpdate( item );
- }
- else
- {
- cache.update( item );
- }
- }
-
- /**
- * Processes a remove request.
- * <p>
- * If isLocalClusterConsistency is enabled we will treat this as a normal request of non-remote
- * origination.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @throws IOException
- */
- @Override
- public void processRemove( String cacheName, K key, long requesterId )
- throws IOException
- {
- CompositeCache<K, V> cache = getCacheManager().getCache( cacheName );
-
- boolean keepLocal = !remoteHttpCacheServerAttributes.isLocalClusterConsistency();
- if ( keepLocal )
- {
- cache.localRemove( key );
- }
- else
- {
- cache.remove( key );
- }
- }
-
- /**
- * Processes a removeAll request.
- * <p>
- * If isLocalClusterConsistency is enabled we will treat this as a normal request of non-remote
- * origination.
- * <p>
- * @param cacheName
- * @param requesterId
- * @throws IOException
- */
- @Override
- public void processRemoveAll( String cacheName, long requesterId )
- throws IOException
- {
- CompositeCache<K, V> cache = getCacheManager().getCache( cacheName );
-
- boolean keepLocal = !remoteHttpCacheServerAttributes.isLocalClusterConsistency();
- if ( keepLocal )
- {
- cache.localRemoveAll();
- }
- else
- {
- cache.removeAll();
- }
- }
-
- /**
- * Processes a shutdown request.
- * <p>
- * @param cacheName
- * @param requesterId
- * @throws IOException
- */
- @Override
- public void processDispose( String cacheName, long requesterId )
- throws IOException
- {
- CompositeCache<K, V> cache = getCacheManager().getCache( cacheName );
- cache.dispose();
- }
-
- /**
- * This general method should be deprecated.
- * <p>
- * @throws IOException
- */
- @Override
- public void release()
- throws IOException
- {
- //nothing.
- }
-
- /**
- * This is called by the event log.
- * <p>
- * @param requesterId
- * @return requesterId + ""
- */
- @Override
- protected String getExtraInfoForRequesterId( long requesterId )
- {
- return requesterId + "";
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheServlet.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheServlet.java
deleted file mode 100644
index 50373f1..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheServlet.java
+++ /dev/null
@@ -1,380 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.server;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.ObjectInputStream;
-import java.io.OutputStream;
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheConfigurator;
-import org.apache.commons.jcs.auxiliary.remote.http.behavior.IRemoteHttpCacheConstants;
-import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheRequest;
-import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheResponse;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.io.ObjectInputStreamClassLoaderAware;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.config.PropertySetter;
-import org.apache.commons.jcs.utils.serialization.StandardSerializer;
-
-/**
- * This servlet simply reads and writes objects. The requests are packaged in a general wrapper. The
- * processor works on the wrapper object and returns a response wrapper.
- */
-public class RemoteHttpCacheServlet
- extends HttpServlet
-{
- /** Don't change. */
- private static final long serialVersionUID = 8752849397531933346L;
-
- /** The Logger. */
- private static final Log log = LogManager.getLog( RemoteHttpCacheServlet.class );
-
- /** The cache manager */
- private static CompositeCacheManager cacheMgr;
-
- /** The service that does the work. */
- private static ICacheServiceNonLocal<Serializable, Serializable> remoteCacheService;
-
- /** This needs to be standard, since the other side is standard */
- private final StandardSerializer serializer = new StandardSerializer();
-
- /** Number of service calls. */
- private int serviceCalls = 0;
-
- /** The interval at which we will log the count. */
- private final int logInterval = 100;
-
- /**
- * Initializes the cache.
- * <p>
- * This provides an easy extension point. Simply extend this servlet and override the init
- * method to change the way the properties are loaded.
- * @param config
- * @throws ServletException
- */
- @Override
- public void init( ServletConfig config )
- throws ServletException
- {
- try
- {
- cacheMgr = CompositeCacheManager.getInstance();
- }
- catch (CacheException e)
- {
- throw new ServletException(e);
- }
-
- remoteCacheService = createRemoteHttpCacheService( cacheMgr );
-
- super.init( config );
- }
-
- /**
- * Read the request, call the processor, write the response.
- * <p>
- * @param request
- * @param response
- * @throws ServletException
- * @throws IOException
- */
- @Override
- public void service( HttpServletRequest request, HttpServletResponse response )
- throws ServletException, IOException
- {
- incrementServiceCallCount();
- log.debug( "Servicing a request. {0}", request );
-
- RemoteCacheRequest<Serializable, Serializable> remoteRequest = readRequest( request );
- RemoteCacheResponse<Object> cacheResponse = processRequest( remoteRequest );
-
- writeResponse( response, cacheResponse );
- }
-
- /**
- * Read the request from the input stream.
- * <p>
- * @param request
- * @return RemoteHttpCacheRequest
- */
- protected RemoteCacheRequest<Serializable, Serializable> readRequest( HttpServletRequest request )
- {
- RemoteCacheRequest<Serializable, Serializable> remoteRequest = null;
- try
- {
- InputStream inputStream = request.getInputStream();
- log.debug( "After getting input stream and before reading it" );
-
- remoteRequest = readRequestFromStream( inputStream );
- }
- catch ( Exception e )
- {
- log.error( "Could not get a RemoteHttpCacheRequest object from the input stream.", e );
- }
- return remoteRequest;
- }
-
- /**
- * Reads the response from the stream and then closes it.
- * <p>
- * @param inputStream
- * @return RemoteHttpCacheRequest
- * @throws IOException
- * @throws ClassNotFoundException
- */
- protected RemoteCacheRequest<Serializable, Serializable> readRequestFromStream( InputStream inputStream )
- throws IOException, ClassNotFoundException
- {
- ObjectInputStream ois = new ObjectInputStreamClassLoaderAware( inputStream, null );
-
- @SuppressWarnings("unchecked") // Need to cast from Object
- RemoteCacheRequest<Serializable, Serializable> remoteRequest
- = (RemoteCacheRequest<Serializable, Serializable>) ois.readObject();
- ois.close();
- return remoteRequest;
- }
-
- /**
- * Write the response to the output stream.
- * <p>
- * @param response
- * @param cacheResponse
- */
- protected void writeResponse( HttpServletResponse response, RemoteCacheResponse<Object> cacheResponse )
- {
- try
- {
- response.setContentType( "application/octet-stream" );
-
- byte[] responseAsByteAray = serializer.serialize( cacheResponse );
- response.setContentLength( responseAsByteAray.length );
-
- OutputStream outputStream = response.getOutputStream();
- log.debug( "Opened output stream. Response size: {0}",
- () -> responseAsByteAray.length );
- // WRITE
- outputStream.write( responseAsByteAray );
- outputStream.flush();
- outputStream.close();
- }
- catch ( IOException e )
- {
- log.error( "Problem writing response. {0}", cacheResponse, e );
- }
- }
-
- /**
- * Processes the request. It will call the appropriate method on the service
- * <p>
- * @param request
- * @return RemoteHttpCacheResponse, never null
- */
- protected RemoteCacheResponse<Object> processRequest( RemoteCacheRequest<Serializable, Serializable> request )
- {
- RemoteCacheResponse<Object> response = new RemoteCacheResponse<>();
-
- if ( request == null )
- {
- String message = "The request is null. Cannot process";
- log.warn( message );
- response.setSuccess( false );
- response.setErrorMessage( message );
- }
- else
- {
- try
- {
- switch ( request.getRequestType() )
- {
- case GET:
- ICacheElement<Serializable, Serializable> element =
- remoteCacheService.get( request.getCacheName(), request.getKey(), request.getRequesterId() );
- response.setPayload(element);
- break;
- case GET_MULTIPLE:
- Map<Serializable, ICacheElement<Serializable, Serializable>> elementMap =
- remoteCacheService.getMultiple( request.getCacheName(), request.getKeySet(), request.getRequesterId() );
- if ( elementMap != null )
- {
- Map<Serializable, ICacheElement<Serializable, Serializable>> map = new HashMap<>();
- map.putAll(elementMap);
- response.setPayload(map);
- }
- break;
- case GET_MATCHING:
- Map<Serializable, ICacheElement<Serializable, Serializable>> elementMapMatching =
- remoteCacheService.getMatching( request.getCacheName(), request.getPattern(), request.getRequesterId() );
- if ( elementMapMatching != null )
- {
- Map<Serializable, ICacheElement<Serializable, Serializable>> map = new HashMap<>();
- map.putAll(elementMapMatching);
- response.setPayload(map);
- }
- break;
- case REMOVE:
- remoteCacheService.remove( request.getCacheName(), request.getKey(), request.getRequesterId() );
- break;
- case REMOVE_ALL:
- remoteCacheService.removeAll( request.getCacheName(), request.getRequesterId() );
- break;
- case UPDATE:
- remoteCacheService.update( request.getCacheElement(), request.getRequesterId() );
- break;
- case ALIVE_CHECK:
- case DISPOSE:
- response.setSuccess( true );
- // DO NOTHING
- break;
- case GET_KEYSET:
- Set<Serializable> keys = remoteCacheService.getKeySet( request.getCacheName() );
- response.setPayload( keys );
- break;
- default:
- String message = "Unknown event type. Cannot process " + request;
- log.warn( message );
- response.setSuccess( false );
- response.setErrorMessage( message );
- break;
- }
- }
- catch ( IOException e )
- {
- String message = "Problem processing request. " + request + " Error: " + e.getMessage();
- log.error( message, e );
- response.setSuccess( false );
- response.setErrorMessage( message );
- }
- }
-
- return response;
- }
-
- /**
- * Configures the attributes and the event logger and constructs a service.
- * <p>
- * @param cacheManager
- * @return RemoteHttpCacheService
- */
- protected <K, V> RemoteHttpCacheService<K, V> createRemoteHttpCacheService( ICompositeCacheManager cacheManager )
- {
- Properties props = cacheManager.getConfigurationProperties();
- ICacheEventLogger cacheEventLogger = configureCacheEventLogger( props );
- RemoteHttpCacheServerAttributes attributes = configureRemoteHttpCacheServerAttributes( props );
-
- RemoteHttpCacheService<K, V> service = new RemoteHttpCacheService<>( cacheManager, attributes, cacheEventLogger );
- log.info( "Created new RemoteHttpCacheService {0}", service );
- return service;
- }
-
- /**
- * Tries to get the event logger.
- * <p>
- * @param props
- * @return ICacheEventLogger
- */
- protected ICacheEventLogger configureCacheEventLogger( Properties props )
- {
- ICacheEventLogger cacheEventLogger = AuxiliaryCacheConfigurator
- .parseCacheEventLogger( props, IRemoteHttpCacheConstants.HTTP_CACHE_SERVER_PREFIX );
-
- return cacheEventLogger;
- }
-
- /**
- * Configure.
- * <p>
- * jcs.remotehttpcache.serverattributes.ATTRIBUTENAME=ATTRIBUTEVALUE
- * <p>
- * @param prop
- * @return RemoteCacheServerAttributesconfigureRemoteCacheServerAttributes
- */
- protected RemoteHttpCacheServerAttributes configureRemoteHttpCacheServerAttributes( Properties prop )
- {
- RemoteHttpCacheServerAttributes rcsa = new RemoteHttpCacheServerAttributes();
-
- // configure automatically
- PropertySetter.setProperties( rcsa, prop,
- IRemoteHttpCacheConstants.HTTP_CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + "." );
-
- return rcsa;
- }
-
- /**
- * @param rcs the remoteCacheService to set
- */
- protected void setRemoteCacheService(ICacheServiceNonLocal<Serializable, Serializable> rcs)
- {
- remoteCacheService = rcs;
- }
-
- /**
- * Log some details.
- */
- private void incrementServiceCallCount()
- {
- // not thread safe, but it doesn't have to be accurate
- serviceCalls++;
- if ( log.isInfoEnabled() )
- {
- if ( serviceCalls % logInterval == 0 )
- {
- log.info( "serviceCalls = {0}", serviceCalls );
- }
- }
- }
-
- /** Release the cache manager. */
- @Override
- public void destroy()
- {
- log.info( "Servlet Destroyed, shutting down JCS." );
-
- cacheMgr.shutDown();
- }
-
- /**
- * Get servlet information
- * <p>
- * @return basic info
- */
- @Override
- public String getServletInfo()
- {
- return "RemoteHttpCacheServlet";
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RegistryKeepAliveRunner.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RegistryKeepAliveRunner.java
deleted file mode 100644
index b09c3ab..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RegistryKeepAliveRunner.java
+++ /dev/null
@@ -1,196 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.server;
-
-/*
- * 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.
- */
-
-import java.rmi.Naming;
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-import java.rmi.registry.Registry;
-
-import org.apache.commons.jcs.auxiliary.remote.RemoteUtils;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This class tries to keep the registry alive. If if is able to create a registry, it will also
- * rebind the remote cache server.
- */
-public class RegistryKeepAliveRunner
- implements Runnable
-{
- /** The logger */
- private static final Log log = LogManager.getLog( RegistryKeepAliveRunner.class );
-
- /** The URL of the service to look for. */
- private String namingURL;
-
- /** The service name. */
- private String serviceName;
-
- /** the port on which to start the registry */
- private int registryPort;
-
- /** An optional event logger */
- private ICacheEventLogger cacheEventLogger;
-
- /** the registry */
- private Registry registry;
-
- /**
- * @param registryHost - Hostname of the registry
- * @param registryPort - the port on which to start the registry
- * @param serviceName
- */
- public RegistryKeepAliveRunner( String registryHost, int registryPort, String serviceName )
- {
- this.namingURL = RemoteUtils.getNamingURL(registryHost, registryPort, serviceName);
- this.serviceName = serviceName;
- this.registryPort = registryPort;
- }
-
- /**
- * Tries to lookup the server. If unsuccessful it will rebind the server using the factory
- * rebind method.
- * <p>
- */
- @Override
- public void run()
- {
- checkAndRestoreIfNeeded();
- }
-
- /**
- * Tries to lookup the server. If unsuccessful it will rebind the server using the factory
- * rebind method.
- */
- protected void checkAndRestoreIfNeeded()
- {
- log.debug( "looking up server {0}", namingURL );
-
- try
- {
- Object obj = Naming.lookup( namingURL );
-
- // Successful connection to the remote server.
- String message = "RMI registry looks fine. Found [" + obj + "] in registry [" + namingURL + "]";
- if ( cacheEventLogger != null )
- {
- cacheEventLogger.logApplicationEvent( "RegistryKeepAliveRunner", "Naming.lookup", message );
- }
- log.debug( message );
- }
- catch ( Exception ex )
- {
- // Failed to connect to the remote server.
- String message = "Problem finding server at [" + namingURL
- + "]. Will attempt to start registry and rebind.";
- log.error( message, ex );
- if ( cacheEventLogger != null )
- {
- cacheEventLogger.logError( "RegistryKeepAliveRunner", "Naming.lookup", message + ":" + ex.getMessage() );
- }
- createAndRegister( serviceName );
- }
- }
-
- /**
- * Creates the registry and registers the server.
- * <p>
- * @param serviceName the service name
- */
- protected void createAndRegister( String serviceName )
- {
- createReqistry( serviceName );
- registerServer( serviceName );
- }
-
- /**
- * Try to create the registry. Log errors
- * <p>
- * @param serviceName the service name
- */
- protected void createReqistry( String serviceName )
- {
- // TODO: Refactor method signature. This is ugly but required to keep the binary API compatibility
- this.registry = RemoteUtils.createRegistry(registryPort);
-
- if ( cacheEventLogger != null )
- {
- if (this.registry != null)
- {
- cacheEventLogger.logApplicationEvent( "RegistryKeepAliveRunner", "createRegistry",
- "Successfully created registry [" + serviceName + "]." );
- }
- else
- {
- cacheEventLogger.logError( "RegistryKeepAliveRunner", "createRegistry",
- "Could not start registry [" + serviceName + "]." );
- }
- }
- }
-
- /**
- * Try to rebind the server.
- * <p>
- * @param serviceName the service name
- */
- protected void registerServer( String serviceName )
- {
- try
- {
- // try to rebind anyway
- Remote server = RemoteCacheServerFactory.getRemoteCacheServer();
-
- if ( server == null )
- {
- throw new RemoteException( "Cannot register the server until it is created." );
- }
-
- this.registry.rebind( serviceName, server );
- String message = "Successfully rebound server to registry [" + serviceName + "].";
- if ( cacheEventLogger != null )
- {
- cacheEventLogger.logApplicationEvent( "RegistryKeepAliveRunner", "registerServer", message );
- }
- log.info( message );
- }
- catch ( RemoteException e )
- {
- String message = "Could not rebind server to registry [" + serviceName + "].";
- log.error( message, e );
- if ( cacheEventLogger != null )
- {
- cacheEventLogger.logError( "RegistryKeepAliveRunner", "registerServer", message + ":"
- + e.getMessage() );
- }
- }
- }
-
- /**
- * Allows it to be injected.
- * <p>
- * @param cacheEventLogger
- */
- public void setCacheEventLogger( ICacheEventLogger cacheEventLogger )
- {
- this.cacheEventLogger = cacheEventLogger;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServer.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServer.java
deleted file mode 100644
index 1d91bb6..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServer.java
+++ /dev/null
@@ -1,1528 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.server;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.rmi.RemoteException;
-import java.rmi.registry.Registry;
-import java.rmi.server.RMISocketFactory;
-import java.rmi.server.UnicastRemoteObject;
-import java.rmi.server.Unreferenced;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheListener;
-import org.apache.commons.jcs.auxiliary.remote.server.behavior.IRemoteCacheServer;
-import org.apache.commons.jcs.auxiliary.remote.server.behavior.IRemoteCacheServerAttributes;
-import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType;
-import org.apache.commons.jcs.engine.CacheEventQueueFactory;
-import org.apache.commons.jcs.engine.CacheListeners;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheEventQueue;
-import org.apache.commons.jcs.engine.behavior.ICacheListener;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-import org.apache.commons.jcs.engine.logging.CacheEvent;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.timing.ElapsedTimer;
-
-/**
- * This class provides remote cache services. The remote cache server propagates events from local
- * caches to other local caches. It can also store cached data, making it available to new clients.
- * <p>
- * Remote cache servers can be clustered. If the cache used by this remote cache is configured to
- * use a remote cache of type cluster, the two remote caches will communicate with each other.
- * Remote and put requests can be sent from one remote to another. If they are configured to
- * broadcast such event to their client, then remove an puts can be sent to all locals in the
- * cluster.
- * <p>
- * Get requests are made between clustered servers if AllowClusterGet is true. You can setup several
- * clients to use one remote server and several to use another. The get local will be distributed
- * between the two servers. Since caches are usually high get and low put, this should allow you to
- * scale.
- */
-public class RemoteCacheServer<K, V>
- extends UnicastRemoteObject
- implements IRemoteCacheServer<K, V>, Unreferenced
-{
- public static final String DFEAULT_REMOTE_CONFIGURATION_FILE = "/remote.cache.ccf";
-
- /** For serialization. Don't change. */
- private static final long serialVersionUID = -8072345435941473116L;
-
- /** log instance */
- private static final Log log = LogManager.getLog( RemoteCacheServer.class );
-
- /** Number of puts into the cache. */
- private int puts = 0;
-
- /** Maps cache name to CacheListeners object. association of listeners (regions). */
- private final transient ConcurrentMap<String, CacheListeners<K, V>> cacheListenersMap =
- new ConcurrentHashMap<>();
-
- /** maps cluster listeners to regions. */
- private final transient ConcurrentMap<String, CacheListeners<K, V>> clusterListenersMap =
- new ConcurrentHashMap<>();
-
- /** The central hub */
- private transient CompositeCacheManager cacheManager;
-
- /** relates listener id with a type */
- private final ConcurrentMap<Long, RemoteType> idTypeMap = new ConcurrentHashMap<>();
-
- /** relates listener id with an ip address */
- private final ConcurrentMap<Long, String> idIPMap = new ConcurrentHashMap<>();
-
- /** Used to get the next listener id. */
- private final int[] listenerId = new int[1];
-
- /** Configuration settings. */
- // package protected for access by unit test code
- final IRemoteCacheServerAttributes remoteCacheServerAttributes;
-
- /** The interval at which we will log updates. */
- private final int logInterval = 100;
-
- /** An optional event logger */
- private transient ICacheEventLogger cacheEventLogger;
-
- /**
- * Constructor for the RemoteCacheServer object. This initializes the server with the values
- * from the properties object.
- * <p>
- * @param rcsa
- * @param config cache hub configuration
- * @throws RemoteException
- */
- protected RemoteCacheServer( IRemoteCacheServerAttributes rcsa, Properties config )
- throws RemoteException
- {
- super( rcsa.getServicePort() );
- this.remoteCacheServerAttributes = rcsa;
- init( config );
- }
-
- /**
- * Constructor for the RemoteCacheServer object. This initializes the server with the values
- * from the properties object.
- * <p>
- * @param rcsa
- * @param config cache hub configuration
- * @param customRMISocketFactory
- * @throws RemoteException
- */
- protected RemoteCacheServer( IRemoteCacheServerAttributes rcsa, Properties config, RMISocketFactory customRMISocketFactory )
- throws RemoteException
- {
- super( rcsa.getServicePort(), customRMISocketFactory, customRMISocketFactory );
- this.remoteCacheServerAttributes = rcsa;
- init( config );
- }
-
- /**
- * Initialize the RMI Cache Server from a properties object.
- * <p>
- * @param prop the configuration properties
- * @throws RemoteException if the configuration of the cache manager instance fails
- */
- private void init( Properties prop ) throws RemoteException
- {
- try
- {
- cacheManager = createCacheManager( prop );
- }
- catch (CacheException e)
- {
- throw new RemoteException(e.getMessage(), e);
- }
-
- // cacheManager would have created a number of ICache objects.
- // Use these objects to set up the cacheListenersMap.
- cacheManager.getCacheNames().forEach(name -> {
- CompositeCache<K, V> cache = cacheManager.getCache( name );
- cacheListenersMap.put( name, new CacheListeners<>( cache ) );
- });
- }
-
- /**
- * Subclass can override this method to create the specific cache manager.
- * <p>
- * @param prop the configuration object.
- * @return The cache hub configured with this configuration.
- *
- * @throws CacheException if the configuration cannot be loaded
- */
- private CompositeCacheManager createCacheManager( Properties prop ) throws CacheException
- {
- CompositeCacheManager hub = CompositeCacheManager.getUnconfiguredInstance();
- hub.configure( prop );
- return hub;
- }
-
- /**
- * Puts a cache bean to the remote cache and notifies all listeners which <br>
- * <ol>
- * <li>have a different listener id than the originating host;</li>
- * <li>are currently subscribed to the related cache.</li>
- * </ol>
- * <p>
- * @param item
- * @throws IOException
- */
- public void put( ICacheElement<K, V> item )
- throws IOException
- {
- update( item );
- }
-
- /**
- * @param item
- * @throws IOException
- */
- @Override
- public void update( ICacheElement<K, V> item )
- throws IOException
- {
- update( item, 0 );
- }
-
- /**
- * The internal processing is wrapped in event logging calls.
- * <p>
- * @param item
- * @param requesterId
- * @throws IOException
- */
- @Override
- public void update( ICacheElement<K, V> item, long requesterId )
- throws IOException
- {
- ICacheEvent<ICacheElement<K, V>> cacheEvent = createICacheEvent( item, requesterId, ICacheEventLogger.UPDATE_EVENT );
- try
- {
- processUpdate( item, requesterId );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * An update can come from either a local cache's remote auxiliary, or it can come from a remote
- * server. A remote server is considered a a source of type cluster.
- * <p>
- * If the update came from a cluster, then we should tell the cache manager that this was a
- * remote put. This way, any lateral and remote auxiliaries configured for the region will not
- * be updated. This is basically how a remote listener works when plugged into a local cache.
- * <p>
- * If the cluster is configured to keep local cluster consistency, then all listeners will be
- * updated. This allows cluster server A to update cluster server B and then B to update its
- * clients if it is told to keep local cluster consistency. Otherwise, server A will update
- * server B and B will not tell its clients. If you cluster using lateral caches for instance,
- * this is how it will work. Updates to a cluster node, will never get to the leaves. The remote
- * cluster, with local cluster consistency, allows you to update leaves. This basically allows
- * you to have a failover remote server.
- * <p>
- * Since currently a cluster will not try to get from other cluster servers, you can scale a bit
- * with a cluster configuration. Puts and removes will be broadcasted to all clients, but the
- * get load on a remote server can be reduced.
- * <p>
- * @param item
- * @param requesterId
- */
- private void processUpdate( ICacheElement<K, V> item, long requesterId )
- {
- ElapsedTimer timer = new ElapsedTimer();
- logUpdateInfo( item );
-
- try
- {
- CacheListeners<K, V> cacheDesc = getCacheListeners( item.getCacheName() );
- /* Object val = */item.getVal();
-
- boolean fromCluster = isRequestFromCluster( requesterId );
-
- log.debug( "In update, requesterId = [{0}] fromCluster = {1}", requesterId, fromCluster );
-
- // ordered cache item update and notification.
- synchronized ( cacheDesc )
- {
- try
- {
- CompositeCache<K, V> c = (CompositeCache<K, V>) cacheDesc.cache;
-
- // If the source of this request was not from a cluster,
- // then consider it a local update. The cache manager will
- // try to
- // update all auxiliaries.
- //
- // This requires that two local caches not be connected to
- // two clustered remote caches. The failover runner will
- // have to make sure of this. ALos, the local cache needs
- // avoid updating this source. Will need to pass the source
- // id somehow. The remote cache should update all local
- // caches
- // but not update the cluster source. Cluster remote caches
- // should only be updated by the server and not the
- // RemoteCache.
- if ( fromCluster )
- {
- log.debug( "Put FROM cluster, NOT updating other auxiliaries for region. "
- + " requesterId [{0}]", requesterId );
- c.localUpdate( item );
- }
- else
- {
- log.debug( "Put NOT from cluster, updating other auxiliaries for region. "
- + " requesterId [{0}]", requesterId );
- c.update( item );
- }
- }
- catch ( IOException ce )
- {
- // swallow
- log.info( "Exception caught updating item. requesterId [{0}]: {1}",
- requesterId, ce.getMessage() );
- }
-
- // UPDATE LOCALS IF A REQUEST COMES FROM A CLUSTER
- // IF LOCAL CLUSTER CONSISTENCY IS CONFIGURED
- if ( !fromCluster || ( fromCluster && remoteCacheServerAttributes.isLocalClusterConsistency() ) )
- {
- ICacheEventQueue<K, V>[] qlist = getEventQList( cacheDesc, requesterId );
- log.debug( "qlist.length = {0}", qlist.length );
- for ( int i = 0; i < qlist.length; i++ )
- {
- qlist[i].addPutEvent( item );
- }
- }
- }
- }
- catch ( IOException e )
- {
- if ( cacheEventLogger != null )
- {
- cacheEventLogger.logError( "RemoteCacheServer", ICacheEventLogger.UPDATE_EVENT, e.getMessage()
- + " REGION: " + item.getCacheName() + " ITEM: " + item );
- }
-
- log.error( "Trouble in Update. requesterId [{0}]", requesterId, e );
- }
-
- // TODO use JAMON for timing
- log.debug( "put took {0} ms.", () -> timer.getElapsedTime());
- }
-
- /**
- * Log some details.
- * <p>
- * @param item
- */
- private void logUpdateInfo( ICacheElement<K, V> item )
- {
- // not thread safe, but it doesn't have to be 100% accurate
- puts++;
-
- if ( log.isInfoEnabled() )
- {
- if ( puts % logInterval == 0 )
- {
- log.info( "puts = {0}", puts );
- }
- }
-
- log.debug( "In update, put [{0}] in [{1}]",
- () -> item.getKey(), () -> item.getCacheName() );
- }
-
- /**
- * Returns a cache value from the specified remote cache; or null if the cache or key does not
- * exist.
- * <p>
- * @param cacheName
- * @param key
- * @return ICacheElement
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> get( String cacheName, K key )
- throws IOException
- {
- return this.get( cacheName, key, 0 );
- }
-
- /**
- * Returns a cache bean from the specified cache; or null if the key does not exist.
- * <p>
- * Adding the requestor id, allows the cache to determine the source of the get.
- * <p>
- * The internal processing is wrapped in event logging calls.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @return ICacheElement
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> get( String cacheName, K key, long requesterId )
- throws IOException
- {
- ICacheElement<K, V> element = null;
- ICacheEvent<K> cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.GET_EVENT );
- try
- {
- element = processGet( cacheName, key, requesterId );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- return element;
- }
-
- /**
- * Returns a cache bean from the specified cache; or null if the key does not exist.
- * <p>
- * Adding the requester id, allows the cache to determine the source of the get.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @return ICacheElement
- */
- private ICacheElement<K, V> processGet( String cacheName, K key, long requesterId )
- {
- boolean fromCluster = isRequestFromCluster( requesterId );
-
- log.debug( "get [{0}] from cache [{1}] requesterId = [{2}] fromCluster = {3}",
- key, cacheName, requesterId, fromCluster );
-
- CacheListeners<K, V> cacheDesc = getCacheListeners( cacheName );
-
- ICacheElement<K, V> element = getFromCacheListeners( key, fromCluster, cacheDesc, null );
- return element;
- }
-
- /**
- * Gets the item from the associated cache listeners.
- * <p>
- * @param key
- * @param fromCluster
- * @param cacheDesc
- * @param element
- * @return ICacheElement
- */
- private ICacheElement<K, V> getFromCacheListeners( K key, boolean fromCluster, CacheListeners<K, V> cacheDesc,
- ICacheElement<K, V> element )
- {
- ICacheElement<K, V> returnElement = element;
-
- if ( cacheDesc != null )
- {
- CompositeCache<K, V> c = (CompositeCache<K, V>) cacheDesc.cache;
-
- // If we have a get come in from a client and we don't have the item
- // locally, we will allow the cache to look in other non local sources,
- // such as a remote cache or a lateral.
- //
- // Since remote servers never get from clients and clients never go
- // remote from a remote call, this
- // will not result in any loops.
- //
- // This is the only instance I can think of where we allow a remote get
- // from a remote call. The purpose is to allow remote cache servers to
- // talk to each other. If one goes down, you want it to be able to get
- // data from those that were up when the failed server comes back o
- // line.
-
- if ( !fromCluster && this.remoteCacheServerAttributes.isAllowClusterGet() )
- {
- log.debug( "NonLocalGet. fromCluster [{0}] AllowClusterGet [{1}]",
- fromCluster, this.remoteCacheServerAttributes.isAllowClusterGet() );
- returnElement = c.get( key );
- }
- else
- {
- // Gets from cluster type remote will end up here.
- // Gets from all clients will end up here if allow cluster get is
- // false.
- log.debug( "LocalGet. fromCluster [{0}] AllowClusterGet [{1}]",
- fromCluster, this.remoteCacheServerAttributes.isAllowClusterGet() );
- returnElement = c.localGet( key );
- }
- }
-
- return returnElement;
- }
-
- /**
- * Gets all matching items.
- * <p>
- * @param cacheName
- * @param pattern
- * @return Map of keys and wrapped objects
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern )
- throws IOException
- {
- return getMatching( cacheName, pattern, 0 );
- }
-
- /**
- * Retrieves all matching keys.
- * <p>
- * @param cacheName
- * @param pattern
- * @param requesterId
- * @return Map of keys and wrapped objects
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern, long requesterId )
- throws IOException
- {
- ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, pattern, requesterId,
- ICacheEventLogger.GETMATCHING_EVENT );
- try
- {
- return processGetMatching( cacheName, pattern, requesterId );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Retrieves all matching keys.
- * <p>
- * @param cacheName
- * @param pattern
- * @param requesterId
- * @return Map of keys and wrapped objects
- */
- protected Map<K, ICacheElement<K, V>> processGetMatching( String cacheName, String pattern, long requesterId )
- {
- boolean fromCluster = isRequestFromCluster( requesterId );
-
- log.debug( "getMatching [{0}] from cache [{1}] requesterId = [{2}] fromCluster = {3}",
- pattern, cacheName, requesterId, fromCluster );
-
- CacheListeners<K, V> cacheDesc = null;
- try
- {
- cacheDesc = getCacheListeners( cacheName );
- }
- catch ( Exception e )
- {
- log.error( "Problem getting listeners.", e );
-
- if ( cacheEventLogger != null )
- {
- cacheEventLogger.logError( "RemoteCacheServer", ICacheEventLogger.GETMATCHING_EVENT, e.getMessage()
- + cacheName + " pattern: " + pattern );
- }
- }
-
- return getMatchingFromCacheListeners( pattern, fromCluster, cacheDesc );
- }
-
- /**
- * Gets the item from the associated cache listeners.
- * <p>
- * @param pattern
- * @param fromCluster
- * @param cacheDesc
- * @return Map of keys to results
- */
- private Map<K, ICacheElement<K, V>> getMatchingFromCacheListeners( String pattern, boolean fromCluster, CacheListeners<K, V> cacheDesc )
- {
- Map<K, ICacheElement<K, V>> elements = null;
- if ( cacheDesc != null )
- {
- CompositeCache<K, V> c = (CompositeCache<K, V>) cacheDesc.cache;
-
- // We always want to go remote and then merge the items. But this can lead to inconsistencies after
- // failover recovery. Removed items may show up. There is no good way to prevent this.
- // We should make it configurable.
-
- if ( !fromCluster && this.remoteCacheServerAttributes.isAllowClusterGet() )
- {
- log.debug( "NonLocalGetMatching. fromCluster [{0}] AllowClusterGet [{1}]",
- fromCluster, this.remoteCacheServerAttributes.isAllowClusterGet() );
- elements = c.getMatching( pattern );
- }
- else
- {
- // Gets from cluster type remote will end up here.
- // Gets from all clients will end up here if allow cluster get is
- // false.
-
- log.debug( "LocalGetMatching. fromCluster [{0}] AllowClusterGet [{1}]",
- fromCluster, this.remoteCacheServerAttributes.isAllowClusterGet() );
- elements = c.localGetMatching( pattern );
- }
- }
- return elements;
- }
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * @param cacheName
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys )
- throws IOException
- {
- return this.getMultiple( cacheName, keys, 0 );
- }
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * The internal processing is wrapped in event logging calls.
- * <p>
- * @param cacheName
- * @param keys
- * @param requesterId
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys, long requesterId )
- throws IOException
- {
- ICacheEvent<Serializable> cacheEvent = createICacheEvent( cacheName, (Serializable) keys, requesterId,
- ICacheEventLogger.GETMULTIPLE_EVENT );
- try
- {
- return processGetMultiple( cacheName, keys, requesterId );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * @param cacheName
- * @param keys
- * @param requesterId
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- */
- private Map<K, ICacheElement<K, V>> processGetMultiple( String cacheName, Set<K> keys, long requesterId )
- {
- boolean fromCluster = isRequestFromCluster( requesterId );
-
- log.debug( "getMultiple [{0}] from cache [{1}] requesterId = [{2}] fromCluster = {3}",
- keys, cacheName, requesterId, fromCluster );
-
- CacheListeners<K, V> cacheDesc = getCacheListeners( cacheName );
- Map<K, ICacheElement<K, V>> elements = getMultipleFromCacheListeners( keys, null, fromCluster, cacheDesc );
- return elements;
- }
-
- /**
- * Since a non-receiving remote cache client will not register a listener, it will not have a
- * listener id assigned from the server. As such the remote server cannot determine if it is a
- * cluster or a normal client. It will assume that it is a normal client.
- * <p>
- * @param requesterId
- * @return true is from a cluster.
- */
- private boolean isRequestFromCluster( long requesterId )
- {
- RemoteType remoteTypeL = idTypeMap.get( Long.valueOf( requesterId ) );
- return remoteTypeL == RemoteType.CLUSTER;
- }
-
- /**
- * Gets the items from the associated cache listeners.
- * <p>
- * @param keys
- * @param elements
- * @param fromCluster
- * @param cacheDesc
- * @return Map
- */
- private Map<K, ICacheElement<K, V>> getMultipleFromCacheListeners( Set<K> keys, Map<K, ICacheElement<K, V>> elements, boolean fromCluster, CacheListeners<K, V> cacheDesc )
- {
- Map<K, ICacheElement<K, V>> returnElements = elements;
-
- if ( cacheDesc != null )
- {
- CompositeCache<K, V> c = (CompositeCache<K, V>) cacheDesc.cache;
-
- // If we have a getMultiple come in from a client and we don't have the item
- // locally, we will allow the cache to look in other non local sources,
- // such as a remote cache or a lateral.
- //
- // Since remote servers never get from clients and clients never go
- // remote from a remote call, this
- // will not result in any loops.
- //
- // This is the only instance I can think of where we allow a remote get
- // from a remote call. The purpose is to allow remote cache servers to
- // talk to each other. If one goes down, you want it to be able to get
- // data from those that were up when the failed server comes back on
- // line.
-
- if ( !fromCluster && this.remoteCacheServerAttributes.isAllowClusterGet() )
- {
- log.debug( "NonLocalGetMultiple. fromCluster [{0}] AllowClusterGet [{1}]",
- fromCluster, this.remoteCacheServerAttributes.isAllowClusterGet() );
-
- returnElements = c.getMultiple( keys );
- }
- else
- {
- // Gets from cluster type remote will end up here.
- // Gets from all clients will end up here if allow cluster get is
- // false.
-
- log.debug( "LocalGetMultiple. fromCluster [{0}] AllowClusterGet [{1}]",
- fromCluster, this.remoteCacheServerAttributes.isAllowClusterGet() );
-
- returnElements = c.localGetMultiple( keys );
- }
- }
-
- return returnElements;
- }
-
- /**
- * Return the keys in the cache.
- * <p>
- * @param cacheName the name of the cache region
- * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet()
- */
- @Override
- public Set<K> getKeySet(String cacheName) throws IOException
- {
- return processGetKeySet( cacheName );
- }
-
- /**
- * Gets the set of keys of objects currently in the cache.
- * <p>
- * @param cacheName
- * @return Set
- */
- protected Set<K> processGetKeySet( String cacheName )
- {
- CacheListeners<K, V> cacheDesc = getCacheListeners( cacheName );
-
- if ( cacheDesc == null )
- {
- return Collections.emptySet();
- }
-
- CompositeCache<K, V> c = (CompositeCache<K, V>) cacheDesc.cache;
- return c.getKeySet();
- }
-
- /**
- * Removes the given key from the specified remote cache. Defaults the listener id to 0.
- * <p>
- * @param cacheName
- * @param key
- * @throws IOException
- */
- @Override
- public void remove( String cacheName, K key )
- throws IOException
- {
- remove( cacheName, key, 0 );
- }
-
- /**
- * Remove the key from the cache region and don't tell the source listener about it.
- * <p>
- * The internal processing is wrapped in event logging calls.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @throws IOException
- */
- @Override
- public void remove( String cacheName, K key, long requesterId )
- throws IOException
- {
- ICacheEvent<K> cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.REMOVE_EVENT );
- try
- {
- processRemove( cacheName, key, requesterId );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Remove the key from the cache region and don't tell the source listener about it.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @throws IOException
- */
- private void processRemove( String cacheName, K key, long requesterId )
- throws IOException
- {
- log.debug( "remove [{0}] from cache [{1}]", key, cacheName );
-
- CacheListeners<K, V> cacheDesc = cacheListenersMap.get( cacheName );
-
- boolean fromCluster = isRequestFromCluster( requesterId );
-
- if ( cacheDesc != null )
- {
- // best attempt to achieve ordered cache item removal and
- // notification.
- synchronized ( cacheDesc )
- {
- boolean removeSuccess = false;
-
- // No need to notify if it was not cached.
- CompositeCache<K, V> c = (CompositeCache<K, V>) cacheDesc.cache;
-
- if ( fromCluster )
- {
- log.debug( "Remove FROM cluster, NOT updating other auxiliaries for region" );
- removeSuccess = c.localRemove( key );
- }
- else
- {
- log.debug( "Remove NOT from cluster, updating other auxiliaries for region" );
- removeSuccess = c.remove( key );
- }
-
- log.debug( "remove [{0}] from cache [{1}] success (was it found) = {2}",
- key, cacheName, removeSuccess );
-
- // UPDATE LOCALS IF A REQUEST COMES FROM A CLUSTER
- // IF LOCAL CLUSTER CONSISTENCY IS CONFIGURED
- if ( !fromCluster || ( fromCluster && remoteCacheServerAttributes.isLocalClusterConsistency() ) )
- {
- ICacheEventQueue<K, V>[] qlist = getEventQList( cacheDesc, requesterId );
-
- for ( int i = 0; i < qlist.length; i++ )
- {
- qlist[i].addRemoveEvent( key );
- }
- }
- }
- }
- }
-
- /**
- * Remove all keys from the specified remote cache.
- * <p>
- * @param cacheName
- * @throws IOException
- */
- @Override
- public void removeAll( String cacheName )
- throws IOException
- {
- removeAll( cacheName, 0 );
- }
-
- /**
- * Remove all keys from the specified remote cache.
- * <p>
- * The internal processing is wrapped in event logging calls.
- * <p>
- * @param cacheName
- * @param requesterId
- * @throws IOException
- */
- @Override
- public void removeAll( String cacheName, long requesterId )
- throws IOException
- {
- ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, "all", requesterId, ICacheEventLogger.REMOVEALL_EVENT );
- try
- {
- processRemoveAll( cacheName, requesterId );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Remove all keys from the specified remote cache.
- * <p>
- * @param cacheName
- * @param requesterId
- * @throws IOException
- */
- private void processRemoveAll( String cacheName, long requesterId )
- throws IOException
- {
- CacheListeners<K, V> cacheDesc = cacheListenersMap.get( cacheName );
-
- boolean fromCluster = isRequestFromCluster( requesterId );
-
- if ( cacheDesc != null )
- {
- // best attempt to achieve ordered cache item removal and
- // notification.
- synchronized ( cacheDesc )
- {
- // No need to broadcast, or notify if it was not cached.
- CompositeCache<K, V> c = (CompositeCache<K, V>) cacheDesc.cache;
-
- if ( fromCluster )
- {
- log.debug( "RemoveALL FROM cluster, NOT updating other auxiliaries for region" );
- c.localRemoveAll();
- }
- else
- {
- log.debug( "RemoveALL NOT from cluster, updating other auxiliaries for region" );
- c.removeAll();
- }
-
- // update registered listeners
- if ( !fromCluster || ( fromCluster && remoteCacheServerAttributes.isLocalClusterConsistency() ) )
- {
- ICacheEventQueue<K, V>[] qlist = getEventQList( cacheDesc, requesterId );
-
- for ( int i = 0; i < qlist.length; i++ )
- {
- qlist[i].addRemoveAllEvent();
- }
- }
- }
- }
- }
-
- /**
- * How many put events have we received.
- * <p>
- * @return puts
- */
- // Currently only intended for use by unit tests
- int getPutCount()
- {
- return puts;
- }
-
- /**
- * Frees the specified remote cache.
- * <p>
- * @param cacheName
- * @throws IOException
- */
- @Override
- public void dispose( String cacheName )
- throws IOException
- {
- dispose( cacheName, 0 );
- }
-
- /**
- * Frees the specified remote cache.
- * <p>
- * @param cacheName
- * @param requesterId
- * @throws IOException
- */
- public void dispose( String cacheName, long requesterId )
- throws IOException
- {
- ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, "none", requesterId, ICacheEventLogger.DISPOSE_EVENT );
- try
- {
- processDispose( cacheName, requesterId );
- }
- finally
- {
- logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * @param cacheName
- * @param requesterId
- * @throws IOException
- */
- private void processDispose( String cacheName, long requesterId )
- throws IOException
- {
- log.info( "Dispose request received from listener [{0}]", requesterId );
-
- CacheListeners<K, V> cacheDesc = cacheListenersMap.get( cacheName );
-
- // this is dangerous
- if ( cacheDesc != null )
- {
- // best attempt to achieve ordered free-cache-op and notification.
- synchronized ( cacheDesc )
- {
- ICacheEventQueue<K, V>[] qlist = getEventQList( cacheDesc, requesterId );
-
- for ( int i = 0; i < qlist.length; i++ )
- {
- qlist[i].addDisposeEvent();
- }
- cacheManager.freeCache( cacheName );
- }
- }
- }
-
- /**
- * Frees all remote caches.
- * <p>
- * @throws IOException
- */
- @Override
- public void release()
- throws IOException
- {
- for (CacheListeners<K, V> cacheDesc : cacheListenersMap.values())
- {
- ICacheEventQueue<K, V>[] qlist = getEventQList( cacheDesc, 0 );
-
- for ( int i = 0; i < qlist.length; i++ )
- {
- qlist[i].addDisposeEvent();
- }
- }
- cacheManager.release();
- }
-
- /**
- * Returns the cache listener for the specified cache. Creates the cache and the cache
- * descriptor if they do not already exist.
- * <p>
- * @param cacheName
- * @return The cacheListeners value
- */
- protected CacheListeners<K, V> getCacheListeners( String cacheName )
- {
- CacheListeners<K, V> cacheListeners = cacheListenersMap.computeIfAbsent(cacheName, key -> {
- CompositeCache<K, V> cache = cacheManager.getCache(key);
- return new CacheListeners<>( cache );
- });
-
- return cacheListeners;
- }
-
- /**
- * Gets the clusterListeners attribute of the RemoteCacheServer object.
- * <p>
- * TODO may be able to remove this
- * @param cacheName
- * @return The clusterListeners value
- */
- protected CacheListeners<K, V> getClusterListeners( String cacheName )
- {
- CacheListeners<K, V> cacheListeners = clusterListenersMap.computeIfAbsent(cacheName, key -> {
- CompositeCache<K, V> cache = cacheManager.getCache( cacheName );
- return new CacheListeners<>( cache );
- });
-
- return cacheListeners;
- }
-
- /**
- * Gets the eventQList attribute of the RemoteCacheServer object. This returns the event queues
- * stored in the cacheListeners object for a particular region, if the queue is not for this
- * requester.
- * <p>
- * Basically, this makes sure that a request from a particular local cache, identified by its
- * listener id, does not result in a call to that same listener.
- * <p>
- * @param cacheListeners
- * @param requesterId
- * @return The eventQList value
- */
- @SuppressWarnings("unchecked") // No generic arrays in java
- private ICacheEventQueue<K, V>[] getEventQList( CacheListeners<K, V> cacheListeners, long requesterId )
- {
- ICacheEventQueue<K, V>[] list = cacheListeners.eventQMap.values().toArray( new ICacheEventQueue[0] );
- int count = 0;
- // Set those not qualified to null; Count those qualified.
- for ( int i = 0; i < list.length; i++ )
- {
- ICacheEventQueue<K, V> q = list[i];
- if ( q.isWorking() && q.getListenerId() != requesterId )
- {
- count++;
- }
- else
- {
- list[i] = null;
- }
- }
- if ( count == list.length )
- {
- // All qualified.
- return list;
- }
-
- // Returns only the qualified.
- ICacheEventQueue<K, V>[] qq = new ICacheEventQueue[count];
- count = 0;
- for ( int i = 0; i < list.length; i++ )
- {
- if ( list[i] != null )
- {
- qq[count++] = list[i];
- }
- }
- return qq;
- }
-
- /**
- * Removes dead event queues. Should clean out deregistered listeners.
- * <p>
- * @param eventQMap
- */
- private static <KK, VV> void cleanupEventQMap( Map<Long, ICacheEventQueue<KK, VV>> eventQMap )
- {
- // this does not care if the q is alive (i.e. if
- // there are active threads; it cares if the queue
- // is working -- if it has not encountered errors
- // above the failure threshold
- eventQMap.entrySet().removeIf(e -> !e.getValue().isWorking());
- }
-
- /**
- * Subscribes to the specified remote cache.
- * <p>
- * If the client id is 0, then the remote cache server will increment it's local count and
- * assign an id to the client.
- * <p>
- * @param cacheName the specified remote cache.
- * @param listener object to notify for cache changes. must be synchronized since there are
- * remote calls involved.
- * @throws IOException
- */
- @Override
- @SuppressWarnings("unchecked") // Need to cast to specific return type from getClusterListeners()
- public <KK, VV> void addCacheListener( String cacheName, ICacheListener<KK, VV> listener )
- throws IOException
- {
- if ( cacheName == null || listener == null )
- {
- throw new IllegalArgumentException( "cacheName and listener must not be null" );
- }
- CacheListeners<KK, VV> cacheListeners;
-
- IRemoteCacheListener<KK, VV> ircl = (IRemoteCacheListener<KK, VV>) listener;
-
- String listenerAddress = ircl.getLocalHostAddress();
-
- RemoteType remoteType = ircl.getRemoteType();
- if ( remoteType == RemoteType.CLUSTER )
- {
- log.debug( "adding cluster listener, listenerAddress [{0}]", listenerAddress );
- cacheListeners = (CacheListeners<KK, VV>)getClusterListeners( cacheName );
- }
- else
- {
- log.debug( "adding normal listener, listenerAddress [{0}]", listenerAddress );
- cacheListeners = (CacheListeners<KK, VV>)getCacheListeners( cacheName );
- }
- Map<Long, ICacheEventQueue<KK, VV>> eventQMap = cacheListeners.eventQMap;
- cleanupEventQMap( eventQMap );
-
- // synchronized ( listenerId )
- synchronized ( ICacheListener.class )
- {
- long id = 0;
- try
- {
- id = listener.getListenerId();
- // clients probably shouldn't do this.
- if ( id == 0 )
- {
- // must start at one so the next gets recognized
- long listenerIdB = nextListenerId();
- log.debug( "listener id={0} addded for cache [{1}], listenerAddress [{2}]",
- listenerIdB & 0xff, cacheName, listenerAddress );
- listener.setListenerId( listenerIdB );
- id = listenerIdB;
-
- // in case it needs synchronization
- String message = "Adding vm listener under new id = [" + listenerIdB + "], listenerAddress ["
- + listenerAddress + "]";
- logApplicationEvent( "RemoteCacheServer", "addCacheListener", message );
- log.info( message );
- }
- else
- {
- String message = "Adding listener under existing id = [" + id + "], listenerAddress ["
- + listenerAddress + "]";
- logApplicationEvent( "RemoteCacheServer", "addCacheListener", message );
- log.info( message );
- // should confirm the the host is the same as we have on
- // record, just in case a client has made a mistake.
- }
-
- // relate the type to an id
- this.idTypeMap.put( Long.valueOf( id ), remoteType);
- if ( listenerAddress != null )
- {
- this.idIPMap.put( Long.valueOf( id ), listenerAddress );
- }
- }
- catch ( IOException ioe )
- {
- String message = "Problem setting listener id, listenerAddress [" + listenerAddress + "]";
- log.error( message, ioe );
-
- if ( cacheEventLogger != null )
- {
- cacheEventLogger.logError( "RemoteCacheServer", "addCacheListener", message + " - "
- + ioe.getMessage() );
- }
- }
-
- CacheEventQueueFactory<KK, VV> fact = new CacheEventQueueFactory<>();
- ICacheEventQueue<KK, VV> q = fact.createCacheEventQueue( listener, id, cacheName, remoteCacheServerAttributes
- .getEventQueuePoolName(), remoteCacheServerAttributes.getEventQueueType() );
-
- eventQMap.put(Long.valueOf(listener.getListenerId()), q);
-
- log.info( cacheListeners );
- }
- }
-
- /**
- * Subscribes to all remote caches.
- * <p>
- * @param listener The feature to be added to the CacheListener attribute
- * @throws IOException
- */
- @Override
- public <KK, VV> void addCacheListener( ICacheListener<KK, VV> listener )
- throws IOException
- {
- for (String cacheName : cacheListenersMap.keySet())
- {
- addCacheListener( cacheName, listener );
-
- log.debug( "Adding listener for cache [{0}]", cacheName );
- }
- }
-
- /**
- * Unsubscribe this listener from this region. If the listener is registered, it will be removed
- * from the event queue map list.
- * <p>
- * @param cacheName
- * @param listener
- * @throws IOException
- */
- @Override
- public <KK, VV> void removeCacheListener( String cacheName, ICacheListener<KK, VV> listener )
- throws IOException
- {
- removeCacheListener( cacheName, listener.getListenerId() );
- }
-
- /**
- * Unsubscribe this listener from this region. If the listener is registered, it will be removed
- * from the event queue map list.
- * <p>
- * @param cacheName
- * @param listenerId
- */
- public void removeCacheListener( String cacheName, long listenerId )
- {
- String message = "Removing listener for cache region = [" + cacheName + "] and listenerId [" + listenerId + "]";
- logApplicationEvent( "RemoteCacheServer", "removeCacheListener", message );
- log.info( message );
-
- boolean isClusterListener = isRequestFromCluster( listenerId );
-
- CacheListeners<K, V> cacheDesc = null;
-
- if ( isClusterListener )
- {
- cacheDesc = getClusterListeners( cacheName );
- }
- else
- {
- cacheDesc = getCacheListeners( cacheName );
- }
- Map<Long, ICacheEventQueue<K, V>> eventQMap = cacheDesc.eventQMap;
- cleanupEventQMap( eventQMap );
- ICacheEventQueue<K, V> q = eventQMap.remove( Long.valueOf( listenerId ) );
-
- if ( q != null )
- {
- log.debug( "Found queue for cache region = [{0}] and listenerId [{1}]",
- cacheName, listenerId );
- q.destroy();
- cleanupEventQMap( eventQMap );
- }
- else
- {
- log.debug( "Did not find queue for cache region = [{0}] and listenerId [{1}]",
- cacheName, listenerId );
- }
-
- // cleanup
- idTypeMap.remove( Long.valueOf( listenerId ) );
- idIPMap.remove( Long.valueOf( listenerId ) );
-
- log.info( "After removing listener [{0}] cache region {1} listener size [{2}]",
- listenerId, cacheName, eventQMap.size() );
- }
-
- /**
- * Unsubscribes from all remote caches.
- * <p>
- * @param listener
- * @throws IOException
- */
- @Override
- public <KK, VV> void removeCacheListener( ICacheListener<KK, VV> listener )
- throws IOException
- {
- for (String cacheName : cacheListenersMap.keySet())
- {
- removeCacheListener( cacheName, listener );
-
- log.info( "Removing listener for cache [{0}]", cacheName );
- }
- }
-
- /**
- * Shuts down the remote server.
- * <p>
- * @throws IOException
- */
- @Override
- public void shutdown()
- throws IOException
- {
- shutdown("", Registry.REGISTRY_PORT);
- }
-
- /**
- * Shuts down a server at a particular host and port. Then it calls shutdown on the cache
- * itself.
- * <p>
- * @param host
- * @param port
- * @throws IOException
- */
- @Override
- public void shutdown( String host, int port )
- throws IOException
- {
- log.info( "Received shutdown request. Shutting down server." );
-
- synchronized (listenerId)
- {
- for (String cacheName : cacheListenersMap.keySet())
- {
- for (int i = 0; i <= listenerId[0]; i++)
- {
- removeCacheListener( cacheName, i );
- }
-
- log.info( "Removing listener for cache [{0}]", cacheName );
- }
-
- cacheListenersMap.clear();
- clusterListenersMap.clear();
- }
- RemoteCacheServerFactory.shutdownImpl( host, port );
- this.cacheManager.shutDown();
- }
-
- /**
- * Called by the RMI runtime sometime after the runtime determines that the reference list, the
- * list of clients referencing the remote object, becomes empty.
- */
- // TODO: test out the DGC.
- @Override
- public void unreferenced()
- {
- log.info( "*** Server now unreferenced and subject to GC. ***" );
- }
-
- /**
- * Returns the next generated listener id [0,255].
- * <p>
- * @return the listener id of a client. This should be unique for this server.
- */
- private long nextListenerId()
- {
- long id = 0;
- if ( listenerId[0] == Integer.MAX_VALUE )
- {
- synchronized ( listenerId )
- {
- id = listenerId[0];
- listenerId[0] = 0;
- // TODO: record & check if the generated id is currently being
- // used by a valid listener. Currently if the id wraps after
- // Long.MAX_VALUE,
- // we just assume it won't collide with an existing listener who
- // is live.
- }
- }
- else
- {
- synchronized ( listenerId )
- {
- id = ++listenerId[0];
- }
- }
- return id;
- }
-
- /**
- * Gets the stats attribute of the RemoteCacheServer object.
- * <p>
- * @return The stats value
- * @throws IOException
- */
- @Override
- public String getStats()
- throws IOException
- {
- return cacheManager.getStats();
- }
-
- /**
- * Logs an event if an event logger is configured.
- * <p>
- * @param item
- * @param requesterId
- * @param eventName
- * @return ICacheEvent
- */
- private ICacheEvent<ICacheElement<K, V>> createICacheEvent( ICacheElement<K, V> item, long requesterId, String eventName )
- {
- if ( cacheEventLogger == null )
- {
- return new CacheEvent<>();
- }
- String ipAddress = getExtraInfoForRequesterId( requesterId );
- return cacheEventLogger
- .createICacheEvent( "RemoteCacheServer", item.getCacheName(), eventName, ipAddress, item );
- }
-
- /**
- * Logs an event if an event logger is configured.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @param eventName
- * @return ICacheEvent
- */
- private <T> ICacheEvent<T> createICacheEvent( String cacheName, T key, long requesterId, String eventName )
- {
- if ( cacheEventLogger == null )
- {
- return new CacheEvent<>();
- }
- String ipAddress = getExtraInfoForRequesterId( requesterId );
- return cacheEventLogger.createICacheEvent( "RemoteCacheServer", cacheName, eventName, ipAddress, key );
- }
-
- /**
- * Logs an event if an event logger is configured.
- * <p>
- * @param source
- * @param eventName
- * @param optionalDetails
- */
- protected void logApplicationEvent( String source, String eventName, String optionalDetails )
- {
- if ( cacheEventLogger != null )
- {
- cacheEventLogger.logApplicationEvent( source, eventName, optionalDetails );
- }
- }
-
- /**
- * Logs an event if an event logger is configured.
- * <p>
- * @param cacheEvent
- */
- protected <T> void logICacheEvent( ICacheEvent<T> cacheEvent )
- {
- if ( cacheEventLogger != null )
- {
- cacheEventLogger.logICacheEvent( cacheEvent );
- }
- }
-
- /**
- * Ip address for the client, if one is stored.
- * <p>
- * Protected for testing.
- * <p>
- * @param requesterId
- * @return String
- */
- protected String getExtraInfoForRequesterId( long requesterId )
- {
- String ipAddress = idIPMap.get( Long.valueOf( requesterId ) );
- return ipAddress;
- }
-
- /**
- * Allows it to be injected.
- * <p>
- * @param cacheEventLogger
- */
- public void setCacheEventLogger( ICacheEventLogger cacheEventLogger )
- {
- this.cacheEventLogger = cacheEventLogger;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerAttributes.java
deleted file mode 100644
index 45a0a72..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerAttributes.java
+++ /dev/null
@@ -1,212 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.server;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.remote.CommonRemoteCacheAttributes;
-import org.apache.commons.jcs.auxiliary.remote.server.behavior.IRemoteCacheServerAttributes;
-
-/**
- * These attributes are used to configure the remote cache server.
- */
-public class RemoteCacheServerAttributes
- extends CommonRemoteCacheAttributes
- implements IRemoteCacheServerAttributes
-{
- /** Don't change */
- private static final long serialVersionUID = -2741662082869155365L;
-
- /** port the server will listen to */
- private int servicePort = 0;
-
- /** Can a cluster remote get from other remotes */
- private boolean allowClusterGet = true;
-
- /** The config file, the initialization is multistage. Remote cache then composite cache. */
- private String configFileName = "";
-
- /** Should we start the registry */
- private boolean DEFAULT_START_REGISTRY = true;
-
- /** Should we start the registry */
- private boolean startRegistry = DEFAULT_START_REGISTRY;
-
- /** Should we try to keep the registry alive */
- private boolean DEFAULT_USE_REGISTRY_KEEP_ALIVE = true;
-
- /** Should we try to keep the registry alive */
- private boolean useRegistryKeepAlive = DEFAULT_USE_REGISTRY_KEEP_ALIVE;
-
- /** The delay between runs */
- private long registryKeepAliveDelayMillis = 15 * 1000;
-
- /** Default constructor for the RemoteCacheAttributes object */
- public RemoteCacheServerAttributes()
- {
- super();
- }
-
- /**
- * Gets the localPort attribute of the RemoteCacheAttributes object
- * <p>
- * @return The localPort value
- */
- @Override
- public int getServicePort()
- {
- return this.servicePort;
- }
-
- /**
- * Sets the localPort attribute of the RemoteCacheAttributes object
- * <p>
- * @param p The new localPort value
- */
- @Override
- public void setServicePort( int p )
- {
- this.servicePort = p;
- }
-
- /**
- * Should gets from non-cluster clients be allowed to get from other remote auxiliaries.
- * <p>
- * @return The localClusterConsistency value
- */
- @Override
- public boolean isAllowClusterGet()
- {
- return allowClusterGet;
- }
-
- /**
- * Should we try to get from other cluster servers if we don't find the items locally.
- * <p>
- * @param r The new localClusterConsistency value
- */
- @Override
- public void setAllowClusterGet( boolean r )
- {
- allowClusterGet = r;
- }
-
- /**
- * Gets the ConfigFileName attribute of the IRemoteCacheAttributes object
- * <p>
- * @return The clusterServers value
- */
- @Override
- public String getConfigFileName()
- {
- return configFileName;
- }
-
- /**
- * Sets the ConfigFileName attribute of the IRemoteCacheAttributes object
- * <p>
- * @param s The new clusterServers value
- */
- @Override
- public void setConfigFileName( String s )
- {
- configFileName = s;
- }
-
- /**
- * Should we try to keep the registry alive
- * <p>
- * @param useRegistryKeepAlive the useRegistryKeepAlive to set
- */
- @Override
- public void setUseRegistryKeepAlive( boolean useRegistryKeepAlive )
- {
- this.useRegistryKeepAlive = useRegistryKeepAlive;
- }
-
- /**
- * Should we start the registry
- * <p>
- * @param startRegistry the startRegistry to set
- * @deprecated Always true, to be removed
- */
- @Override
- public void setStartRegistry( boolean startRegistry )
- {
- this.startRegistry = startRegistry;
- }
-
- /**
- * Should we start the registry
- * <p>
- * @return the startRegistry
- * @deprecated Always true, to be removed
- */
- @Override
- public boolean isStartRegistry()
- {
- return startRegistry;
- }
-
- /**
- * Should we try to keep the registry alive
- * <p>
- * @return the useRegistryKeepAlive
- */
- @Override
- public boolean isUseRegistryKeepAlive()
- {
- return useRegistryKeepAlive;
- }
-
- /**
- * @param registryKeepAliveDelayMillis the registryKeepAliveDelayMillis to set
- */
- @Override
- public void setRegistryKeepAliveDelayMillis( long registryKeepAliveDelayMillis )
- {
- this.registryKeepAliveDelayMillis = registryKeepAliveDelayMillis;
- }
-
- /**
- * @return the registryKeepAliveDelayMillis
- */
- @Override
- public long getRegistryKeepAliveDelayMillis()
- {
- return registryKeepAliveDelayMillis;
- }
-
- /**
- * @return String details
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder(super.toString());
- buf.append( "\n servicePort = [" + this.getServicePort() + "]" );
- buf.append( "\n allowClusterGet = [" + this.isAllowClusterGet() + "]" );
- buf.append( "\n configFileName = [" + this.getConfigFileName() + "]" );
- buf.append( "\n rmiSocketFactoryTimeoutMillis = [" + this.getRmiSocketFactoryTimeoutMillis() + "]" );
- buf.append( "\n useRegistryKeepAlive = [" + this.isUseRegistryKeepAlive() + "]" );
- buf.append( "\n registryKeepAliveDelayMillis = [" + this.getRegistryKeepAliveDelayMillis() + "]" );
- buf.append( "\n eventQueueType = [" + this.getEventQueueType() + "]" );
- buf.append( "\n eventQueuePoolName = [" + this.getEventQueuePoolName() + "]" );
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerFactory.java
deleted file mode 100644
index 1610ad5..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerFactory.java
+++ /dev/null
@@ -1,487 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.server;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.rmi.Naming;
-import java.rmi.NotBoundException;
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-import java.rmi.registry.Registry;
-import java.rmi.server.RMISocketFactory;
-import java.rmi.server.UnicastRemoteObject;
-import java.util.Properties;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheConfigurator;
-import org.apache.commons.jcs.auxiliary.remote.RemoteUtils;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheConstants;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceAdmin;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.config.OptionConverter;
-import org.apache.commons.jcs.utils.config.PropertySetter;
-import org.apache.commons.jcs.utils.threadpool.DaemonThreadFactory;
-
-/**
- * Provides remote cache services. This creates remote cache servers and can proxy command line
- * requests to a running server.
- */
-public class RemoteCacheServerFactory
- implements IRemoteCacheConstants
-{
- /** The logger */
- private static final Log log = LogManager.getLog( RemoteCacheServerFactory.class );
-
- /** The single instance of the RemoteCacheServer object. */
- private static RemoteCacheServer<?, ?> remoteCacheServer;
-
- /** The name of the service. */
- private static String serviceName = IRemoteCacheConstants.REMOTE_CACHE_SERVICE_VAL;
-
- /** Executes the registry keep alive. */
- private static ScheduledExecutorService keepAliveDaemon;
-
- /** A reference to the registry. */
- private static Registry registry = null;
-
- /** Constructor for the RemoteCacheServerFactory object. */
- private RemoteCacheServerFactory()
- {
- super();
- }
-
- /**
- * This will allow you to get stats from the server, etc. Perhaps we should provide methods on
- * the factory to do this instead.
- * <p>
- * A remote cache is either a local cache or a cluster cache.
- * </p>
- * @return Returns the remoteCacheServer.
- */
- @SuppressWarnings("unchecked") // Need cast to specific RemoteCacheServer
- public static <K, V> RemoteCacheServer<K, V> getRemoteCacheServer()
- {
- return (RemoteCacheServer<K, V>)remoteCacheServer;
- }
-
- // ///////////////////// Startup/shutdown methods. //////////////////
- /**
- * Starts up the remote cache server on this JVM, and binds it to the registry on the given host
- * and port.
- * <p>
- * A remote cache is either a local cache or a cluster cache.
- * <p>
- * @param host
- * @param port
- * @param props
- * @throws IOException
- */
- public static void startup( String host, int port, Properties props)
- throws IOException
- {
- if ( remoteCacheServer != null )
- {
- throw new IllegalArgumentException( "Server already started." );
- }
-
- synchronized ( RemoteCacheServer.class )
- {
- if ( remoteCacheServer != null )
- {
- return;
- }
- if ( host == null )
- {
- host = "";
- }
-
- RemoteCacheServerAttributes rcsa = configureRemoteCacheServerAttributes(props);
-
- // These should come from the file!
- rcsa.setRemoteLocation( host, port );
- log.info( "Creating server with these attributes: {0}", rcsa );
-
- setServiceName( rcsa.getRemoteServiceName() );
-
- RMISocketFactory customRMISocketFactory = configureObjectSpecificCustomFactory( props );
-
- RemoteUtils.configureGlobalCustomSocketFactory( rcsa.getRmiSocketFactoryTimeoutMillis() );
-
- // CONFIGURE THE EVENT LOGGER
- ICacheEventLogger cacheEventLogger = configureCacheEventLogger( props );
-
- // CREATE SERVER
- if ( customRMISocketFactory != null )
- {
- remoteCacheServer = new RemoteCacheServer<>( rcsa, props, customRMISocketFactory );
- }
- else
- {
- remoteCacheServer = new RemoteCacheServer<>( rcsa, props );
- }
-
- remoteCacheServer.setCacheEventLogger( cacheEventLogger );
-
- // START THE REGISTRY
- registry = RemoteUtils.createRegistry(port);
-
- // REGISTER THE SERVER
- registerServer( serviceName, remoteCacheServer );
-
- // KEEP THE REGISTRY ALIVE
- if ( rcsa.isUseRegistryKeepAlive() )
- {
- if ( keepAliveDaemon == null )
- {
- keepAliveDaemon = Executors.newScheduledThreadPool(1,
- new DaemonThreadFactory("JCS-RemoteCacheServerFactory-"));
- }
- RegistryKeepAliveRunner runner = new RegistryKeepAliveRunner( host, port, serviceName );
- runner.setCacheEventLogger( cacheEventLogger );
- keepAliveDaemon.scheduleAtFixedRate(runner, 0, rcsa.getRegistryKeepAliveDelayMillis(), TimeUnit.MILLISECONDS);
- }
- }
- }
-
- /**
- * Tries to get the event logger by new and old config styles.
- * <p>
- * @param props
- * @return ICacheEventLogger
- */
- protected static ICacheEventLogger configureCacheEventLogger( Properties props )
- {
- ICacheEventLogger cacheEventLogger = AuxiliaryCacheConfigurator
- .parseCacheEventLogger( props, IRemoteCacheConstants.CACHE_SERVER_PREFIX );
-
- // try the old way
- if ( cacheEventLogger == null )
- {
- cacheEventLogger = AuxiliaryCacheConfigurator.parseCacheEventLogger( props,
- IRemoteCacheConstants.PROPERTY_PREFIX );
- }
- return cacheEventLogger;
- }
-
- /**
- * This configures an object specific custom factory. This will be configured for just this
- * object in the registry. This can be null.
- * <p>
- * @param props
- * @return RMISocketFactory
- */
- protected static RMISocketFactory configureObjectSpecificCustomFactory( Properties props )
- {
- RMISocketFactory customRMISocketFactory =
- OptionConverter.instantiateByKey( props, CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX, null );
-
- if ( customRMISocketFactory != null )
- {
- PropertySetter.setProperties( customRMISocketFactory, props, CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX
- + "." );
- log.info( "Will use server specific custom socket factory. {0}",
- customRMISocketFactory );
- }
- else
- {
- log.info( "No server specific custom socket factory defined." );
- }
- return customRMISocketFactory;
- }
-
- /**
- * Registers the server with the registry. I broke this off because we might want to have code
- * that will restart a dead registry. It will need to rebind the server.
- * <p>
- * @param serviceName the name of the service
- * @param server the server object to bind
- * @throws RemoteException
- */
- protected static void registerServer(String serviceName, Remote server )
- throws RemoteException
- {
- if ( server == null )
- {
- throw new RemoteException( "Cannot register the server until it is created." );
- }
-
- if ( registry == null )
- {
- throw new RemoteException( "Cannot register the server: Registry is null." );
- }
-
- log.info( "Binding server to {0}", serviceName );
-
- registry.rebind( serviceName, server );
- }
-
- /**
- * Configure.
- * <p>
- * jcs.remotecache.serverattributes.ATTRIBUTENAME=ATTRIBUTEVALUE
- * <p>
- * @param prop
- * @return RemoteCacheServerAttributesconfigureRemoteCacheServerAttributes
- */
- protected static RemoteCacheServerAttributes configureRemoteCacheServerAttributes( Properties prop )
- {
- RemoteCacheServerAttributes rcsa = new RemoteCacheServerAttributes();
-
- // configure automatically
- PropertySetter.setProperties( rcsa, prop, CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + "." );
-
- configureManuallyIfValuesArePresent( prop, rcsa );
-
- return rcsa;
- }
-
- /**
- * This looks for the old config values.
- * <p>
- * @param prop
- * @param rcsa
- */
- private static void configureManuallyIfValuesArePresent( Properties prop, RemoteCacheServerAttributes rcsa )
- {
- // DEPRECATED CONFIG
- String servicePortStr = prop.getProperty( REMOTE_CACHE_SERVICE_PORT );
- if ( servicePortStr != null )
- {
- try
- {
- int servicePort = Integer.parseInt( servicePortStr );
- rcsa.setServicePort( servicePort );
- log.debug( "Remote cache service uses port number {0}", servicePort );
- }
- catch ( NumberFormatException ignore )
- {
- log.debug( "Remote cache service port property {0}" +
- " not specified. An anonymous port will be used.", REMOTE_CACHE_SERVICE_PORT );
- }
- }
-
- String socketTimeoutMillisStr = prop.getProperty( SOCKET_TIMEOUT_MILLIS );
- if ( socketTimeoutMillisStr != null )
- {
- try
- {
- int rmiSocketFactoryTimeoutMillis = Integer.parseInt( socketTimeoutMillisStr );
- rcsa.setRmiSocketFactoryTimeoutMillis( rmiSocketFactoryTimeoutMillis );
- log.debug( "Remote cache socket timeout {0} ms.", rmiSocketFactoryTimeoutMillis );
- }
- catch ( NumberFormatException ignore )
- {
- log.debug( "Remote cache socket timeout property {0}" +
- " not specified. The default will be used.", SOCKET_TIMEOUT_MILLIS );
- }
- }
-
- String lccStr = prop.getProperty( REMOTE_LOCAL_CLUSTER_CONSISTENCY );
- if ( lccStr != null )
- {
- boolean lcc = Boolean.parseBoolean( lccStr );
- rcsa.setLocalClusterConsistency( lcc );
- }
-
- String acgStr = prop.getProperty( REMOTE_ALLOW_CLUSTER_GET );
- if ( acgStr != null )
- {
- boolean acg = Boolean.parseBoolean( lccStr );
- rcsa.setAllowClusterGet( acg );
- }
-
- // Register the RemoteCacheServer remote object in the registry.
- rcsa.setRemoteServiceName(
- prop.getProperty( REMOTE_CACHE_SERVICE_NAME, REMOTE_CACHE_SERVICE_VAL ).trim() );
- }
-
- /**
- * Unbinds the remote server.
- * <p>
- * @param host
- * @param port
- * @throws IOException
- */
- static void shutdownImpl( String host, int port )
- throws IOException
- {
- synchronized ( RemoteCacheServer.class )
- {
- if ( remoteCacheServer == null )
- {
- return;
- }
- log.info( "Unbinding host={0}, port={1}, serviceName={2}",
- host, port, getServiceName() );
- try
- {
- Naming.unbind( RemoteUtils.getNamingURL(host, port, getServiceName()) );
- }
- catch ( MalformedURLException ex )
- {
- // impossible case.
- throw new IllegalArgumentException( ex.getMessage() + "; host=" + host + ", port=" + port
- + ", serviceName=" + getServiceName() );
- }
- catch ( NotBoundException ex )
- {
- // ignore.
- }
- remoteCacheServer.release();
- remoteCacheServer = null;
-
- // Shut down keepalive scheduler
- if ( keepAliveDaemon != null )
- {
- keepAliveDaemon.shutdownNow();
- keepAliveDaemon = null;
- }
-
- // Try to release registry
- if (registry != null)
- {
- UnicastRemoteObject.unexportObject(registry, true);
- registry = null;
- }
- }
- }
-
- /**
- * Creates an local RMI registry on the default port, starts up the remote cache server, and
- * binds it to the registry.
- * <p>
- * A remote cache is either a local cache or a cluster cache.
- * <p>
- * @param args The command line arguments
- * @throws Exception
- */
- public static void main( String[] args )
- throws Exception
- {
- Properties prop = args.length > 0 ? RemoteUtils.loadProps( args[args.length - 1] ) : new Properties();
-
- int port;
- try
- {
- port = Integer.parseInt( prop.getProperty( "registry.port" ) );
- }
- catch ( NumberFormatException ex )
- {
- port = Registry.REGISTRY_PORT;
- }
-
- // shutdown
- if ( args.length > 0 && args[0].toLowerCase().indexOf( "-shutdown" ) != -1 )
- {
- try
- {
- ICacheServiceAdmin admin = lookupCacheServiceAdmin(prop, port);
- admin.shutdown();
- }
- catch ( Exception ex )
- {
- log.error( "Problem calling shutdown.", ex );
- }
- log.debug( "done." );
- System.exit( 0 );
- }
-
- // STATS
- if ( args.length > 0 && args[0].toLowerCase().indexOf( "-stats" ) != -1 )
- {
- log.debug( "getting cache stats" );
-
- try
- {
- ICacheServiceAdmin admin = lookupCacheServiceAdmin(prop, port);
-
- try
- {
-// System.out.println( admin.getStats().toString() );
- log.debug( admin.getStats() );
- }
- catch ( IOException es )
- {
- log.error( es );
- }
- }
- catch ( Exception ex )
- {
- log.error( "Problem getting stats.", ex );
- }
- log.debug( "done." );
- System.exit( 0 );
- }
-
- // startup.
- String host = prop.getProperty( "registry.host" );
-
- if ( host == null || host.trim().equals( "" ) || host.trim().equals( "localhost" ) )
- {
- log.debug( "main> creating registry on the localhost" );
- RemoteUtils.createRegistry( port );
- }
- log.debug( "main> starting up RemoteCacheServer" );
- startup( host, port, prop);
- log.debug( "main> done" );
- }
-
- /**
- * Look up the remote cache service admin instance
- *
- * @param config the configuration properties
- * @param port the local port
- * @return the admin object instance
- *
- * @throws Exception if lookup fails
- */
- private static ICacheServiceAdmin lookupCacheServiceAdmin(Properties config, int port) throws Exception
- {
- String remoteServiceName = config.getProperty( REMOTE_CACHE_SERVICE_NAME, REMOTE_CACHE_SERVICE_VAL ).trim();
- String registry = RemoteUtils.getNamingURL("", port, remoteServiceName);
-
- log.debug( "looking up server {0}", registry );
- Object obj = Naming.lookup( registry );
- log.debug( "server found" );
-
- return (ICacheServiceAdmin) obj;
- }
-
- /**
- * @param serviceName the serviceName to set
- */
- protected static void setServiceName( String serviceName )
- {
- RemoteCacheServerFactory.serviceName = serviceName;
- }
-
- /**
- * @return the serviceName
- */
- protected static String getServiceName()
- {
- return serviceName;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheStartupServlet.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheStartupServlet.java
deleted file mode 100644
index 5bc7431..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheStartupServlet.java
+++ /dev/null
@@ -1,283 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.server;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.UnknownHostException;
-import java.nio.charset.StandardCharsets;
-import java.util.Properties;
-
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.auxiliary.remote.RemoteUtils;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.net.HostNameUtil;
-
-/**
- * This servlet can be used to startup the JCS remote cache. It is easy to
- * deploy the remote server in a tomcat base. This give you an easy way to
- * monitor its activity.
- * <p>
- * <code>
- * servlet>
- <servlet-name>JCSRemoteCacheStartupServlet</servlet-name>
- <servlet-class>
- org.apache.commons.jcs.auxiliary.remote.server.RemoteCacheStartupServlet
- </servlet-class>
- <load-on-startup>1</load-on-startup>
- </servlet>
-
-
- <servlet-mapping>
- <servlet-name>JCSRemoteCacheStartupServlet</servlet-name>
- <url-pattern>/jcs</url-pattern>
- </servlet-mapping>
- * </code>
- *
- * @author Aaron Smuts
- */
-public class RemoteCacheStartupServlet
- extends HttpServlet
-{
- /** Don't change */
- private static final long serialVersionUID = 1L;
-
- /** The logger */
- private static final Log log = LogManager.getLog(RemoteCacheStartupServlet.class);
-
- /** The default port to start the registry on. */
- private static final int DEFAULT_REGISTRY_PORT = 1101;
-
- /** properties file name */
- private static final String DEFAULT_PROPS_FILE_NAME = "/cache.ccf";
-
- /** properties file name, must set prior to calling get instance */
- private String propsFileName = DEFAULT_PROPS_FILE_NAME;
-
- /** Configuration properties */
- private int registryPort = DEFAULT_REGISTRY_PORT;
-
- /** Configuration properties */
- private String registryHost = null;
-
- /**
- * Starts the registry and then tries to bind to it.
- * <p>
- * Gets the port from a props file. Uses the local host name for the
- * registry host. Tries to start the registry, ignoring failure. Starts the
- * server.
- * <p>
- *
- * @throws ServletException
- */
- @Override
- public void init()
- throws ServletException
- {
- super.init();
-
- loadInitParams();
- Properties props = loadPropertiesFromFile();
-
- if (registryHost == null)
- {
- // we will always use the local machine for the registry
- try
- {
- registryHost = HostNameUtil.getLocalHostAddress();
- }
- catch (UnknownHostException e)
- {
- log.error("Could not get local address to use for the registry!", e);
- }
- }
-
- log.debug("registryHost = [{0}]", registryHost);
-
- if ("localhost".equals(registryHost) || "127.0.0.1".equals(registryHost))
- {
- log.warn("The local address [{0}] is INVALID. Other machines must "
- + "be able to use the address to reach this server.", registryHost);
- }
-
- try
- {
- if (props == null)
- {
- throw new ServletException("Could not load configuration from " + propsFileName);
- }
-
- RemoteCacheServerFactory.startup(registryHost, registryPort, props);
- log.info("Remote JCS Server started with properties from {0}", propsFileName);
- }
- catch (IOException e)
- {
- throw new ServletException("Problem starting remote cache server.", e);
- }
- }
-
- /**
- * It just dumps the stats.
- * <p>
- *
- * @param request
- * @param response
- * @throws ServletException
- * @throws IOException
- */
- @Override
- protected void service(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException
- {
- String stats = "";
-
- try
- {
- stats = CompositeCacheManager.getInstance().getStats();
- }
- catch (CacheException e)
- {
- throw new ServletException(e);
- }
-
- log.info(stats);
-
- try
- {
- String characterEncoding = response.getCharacterEncoding();
- if (characterEncoding == null)
- {
- characterEncoding = StandardCharsets.UTF_8.name();
- response.setCharacterEncoding(characterEncoding);
- }
- OutputStream os = response.getOutputStream();
- os.write(stats.getBytes(characterEncoding));
- os.close();
- }
- catch (IOException e)
- {
- log.error("Problem writing response.", e);
- }
- }
-
- /**
- * shuts the cache down.
- */
- @Override
- public void destroy()
- {
- super.destroy();
-
- log.info("Shutting down remote cache ");
-
- try
- {
- RemoteCacheServerFactory.shutdownImpl(registryHost, registryPort);
- }
- catch (IOException e)
- {
- log.error("Problem shutting down.", e);
- }
-
- try
- {
- CompositeCacheManager.getInstance().shutDown();
- }
- catch (CacheException e)
- {
- log.error("Could not retrieve cache manager instance", e);
- }
- }
-
- /**
- * Load configuration values from config file if possible
- */
- private Properties loadPropertiesFromFile()
- {
- Properties props = null;
-
- try
- {
- props = RemoteUtils.loadProps(propsFileName);
- if (props != null)
- {
- registryHost = props.getProperty("registry.host", registryHost);
- String portS = props.getProperty("registry.port", String.valueOf(registryPort));
- setRegistryPort(portS);
- }
- }
- catch (IOException e)
- {
- log.error("Problem loading props.", e);
- }
-
- return props;
- }
-
- /**
- * Load configuration values from init params if possible
- */
- private void loadInitParams()
- {
- ServletConfig config = getServletConfig();
- String _propsFileName = config.getInitParameter("propsFileName");
- if (null != _propsFileName)
- {
- this.propsFileName = _propsFileName;
- }
- String _registryHost = config.getInitParameter("registryHost");
- if (null != _registryHost)
- {
- this.registryHost = _registryHost;
- }
- String regPortString = config.getInitParameter("registryPort");
- if (null != regPortString)
- {
- setRegistryPort(regPortString);
- }
- }
-
- /**
- * Set registry port from string If the string cannot be parsed, the default
- * value is used
- *
- * @param portS
- */
- private void setRegistryPort(String portS)
- {
- try
- {
- this.registryPort = Integer.parseInt(portS);
- }
- catch (NumberFormatException e)
- {
- log.error("Problem converting port to an int.", e);
- this.registryPort = DEFAULT_REGISTRY_PORT;
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/TimeoutConfigurableRMISocketFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/TimeoutConfigurableRMISocketFactory.java
deleted file mode 100644
index 7d1f31a..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/TimeoutConfigurableRMISocketFactory.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.server;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.net.InetSocketAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.rmi.server.RMISocketFactory;
-
-/**
- * This can be injected into the the remote cache server as follows:
- *
- * <pre>
- * jcs.remotecache.customrmisocketfactory=org.apache.commons.jcs.auxiliary.remote.server.TimeoutConfigurableRMISocketFactory
- * jcs.remotecache.customrmisocketfactory.readTimeout=5000
- * jcs.remotecache.customrmisocketfactory.openTimeout=5000
- * </pre>
- */
-public class TimeoutConfigurableRMISocketFactory
- extends RMISocketFactory
- implements Serializable
-{
- /** Don't change. */
- private static final long serialVersionUID = 1489909775271203334L;
-
- /** The socket read timeout */
- private int readTimeout = 5000;
-
- /** The socket open timeout */
- private int openTimeout = 5000;
-
- /**
- * @param port
- * @return ServerSocket
- * @throws IOException
- */
- @Override
- public ServerSocket createServerSocket( int port )
- throws IOException
- {
- return new ServerSocket( port );
- }
-
- /**
- * @param host
- * @param port
- * @return Socket
- * @throws IOException
- */
- @Override
- public Socket createSocket( String host, int port )
- throws IOException
- {
- Socket socket = new Socket();
- socket.setSoTimeout( readTimeout );
- socket.setSoLinger( false, 0 );
- socket.connect( new InetSocketAddress( host, port ), openTimeout );
- return socket;
- }
-
- /**
- * @param readTimeout the readTimeout to set
- */
- public void setReadTimeout( int readTimeout )
- {
- this.readTimeout = readTimeout;
- }
-
- /**
- * @return the readTimeout
- */
- public int getReadTimeout()
- {
- return readTimeout;
- }
-
- /**
- * @param openTimeout the openTimeout to set
- */
- public void setOpenTimeout( int openTimeout )
- {
- this.openTimeout = openTimeout;
- }
-
- /**
- * @return the openTimeout
- */
- public int getOpenTimeout()
- {
- return openTimeout;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/behavior/IRemoteCacheServer.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/behavior/IRemoteCacheServer.java
deleted file mode 100644
index 8799b5a..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/behavior/IRemoteCacheServer.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.server.behavior;
-
-import java.rmi.Remote;
-import org.apache.commons.jcs.engine.behavior.ICacheObserver;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceAdmin;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-
-/*
- * 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.
- */
-
-/**
- * Interface for managing Remote objects
- *
- * @author Thomas Vandahl
- *
- */
-public interface IRemoteCacheServer<K, V>
- extends ICacheServiceNonLocal<K, V>, ICacheObserver, ICacheServiceAdmin, Remote
-{
- // empty
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/behavior/IRemoteCacheServerAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/behavior/IRemoteCacheServerAttributes.java
deleted file mode 100644
index 5817e2d..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/behavior/IRemoteCacheServerAttributes.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.server.behavior;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.remote.behavior.ICommonRemoteCacheAttributes;
-
-/**
- * This defines the minimal behavior for the objects that are used to configure
- * the remote cache server.
- */
-public interface IRemoteCacheServerAttributes
- extends ICommonRemoteCacheAttributes
-{
- /**
- * Gets the localPort attribute of the IRemoteCacheAttributes object.
- * <p>
- * @return The localPort value
- */
- int getServicePort();
-
- /**
- * Sets the localPort attribute of the IRemoteCacheAttributes object.
- * <p>
- * @param p
- * The new localPort value
- */
- void setServicePort( int p );
-
- /**
- * Should we try to get remotely when the request does not come in from a
- * cluster. If local L1 asks remote server R1 for element A and R1 doesn't
- * have it, should R1 look remotely? The difference is between a local and a
- * remote update. The local update stays local. Normal updates, removes,
- * etc, stay local when they come from a client. If this is set to true,
- * then they can go remote.
- * <p>
- * @return The localClusterConsistency value
- */
- boolean isAllowClusterGet();
-
- /**
- * Should cluster updates be propagated to the locals.
- * <p>
- * @param r
- * The new localClusterConsistency value
- */
- void setAllowClusterGet( boolean r );
-
- /**
- * Gets the ConfigFileName attribute of the IRemoteCacheAttributes object.
- * <p>
- * @return The configuration file name
- */
- String getConfigFileName();
-
- /**
- * Sets the ConfigFileName attribute of the IRemoteCacheAttributes object.
- * <p>
- * @param s
- * The new configuration file name
- */
- void setConfigFileName( String s );
-
- /**
- * Should we try to keep the registry alive
- * <p>
- * @param useRegistryKeepAlive the useRegistryKeepAlive to set
- */
- void setUseRegistryKeepAlive( boolean useRegistryKeepAlive );
-
- /**
- * Should we start the registry
- * <p>
- * @param startRegistry the startRegistry to set
- * @deprecated Always true, to be removed
- */
- void setStartRegistry( boolean startRegistry );
-
- /**
- * Should we start the registry
- * <p>
- * @return the startRegistry
- * @deprecated Always true, to be removed
- */
- boolean isStartRegistry();
-
- /**
- * Should we try to keep the registry alive
- * <p>
- * @return the useRegistryKeepAlive
- */
- boolean isUseRegistryKeepAlive();
-
- /**
- * @param registryKeepAliveDelayMillis the registryKeepAliveDelayMillis to set
- */
- void setRegistryKeepAliveDelayMillis( long registryKeepAliveDelayMillis );
-
- /**
- * @return the registryKeepAliveDelayMillis
- */
- long getRegistryKeepAliveDelayMillis();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/behavior/RemoteType.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/behavior/RemoteType.java
deleted file mode 100644
index 31c7cbf..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/server/behavior/RemoteType.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.server.behavior;
-
-/*
- * 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.
- */
-
-/**
- * Enum to describe the mode of the remote cache
- */
-public enum RemoteType
-{
- /** A remote cache is either a local cache or a cluster cache */
- LOCAL,
-
- /** A remote cache is either a local cache or a cluster cache */
- CLUSTER
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/util/RemoteCacheRequestFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/util/RemoteCacheRequestFactory.java
deleted file mode 100644
index b2c1bc8..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/util/RemoteCacheRequestFactory.java
+++ /dev/null
@@ -1,201 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.util;
-
-/*
- * 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.
- */
-
-import java.util.Set;
-
-import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheRequest;
-import org.apache.commons.jcs.auxiliary.remote.value.RemoteRequestType;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This creates request objects. You could write your own client and use the objects from this
- * factory.
- */
-public class RemoteCacheRequestFactory
-{
- /** The Logger. */
- private static final Log log = LogManager.getLog( RemoteCacheRequestFactory.class );
-
- /**
- * Create generic request
- * @param cacheName cache name
- * @param requestType type of request
- * @param requesterId id of requester
- * @return the request
- */
- private static <K, V> RemoteCacheRequest<K, V> createRequest(String cacheName, RemoteRequestType requestType, long requesterId)
- {
- RemoteCacheRequest<K, V> request = new RemoteCacheRequest<>();
- request.setCacheName( cacheName );
- request.setRequestType( requestType );
- request.setRequesterId( requesterId );
-
- log.debug( "Created: {0}", request );
-
- return request;
- }
-
- /**
- * Creates a get Request.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @return RemoteHttpCacheRequest
- */
- public static <K, V> RemoteCacheRequest<K, V> createGetRequest( String cacheName, K key, long requesterId )
- {
- RemoteCacheRequest<K, V> request = createRequest(cacheName, RemoteRequestType.GET, requesterId);
- request.setKey( key );
-
- return request;
- }
-
- /**
- * Creates a getMatching Request.
- * <p>
- * @param cacheName
- * @param pattern
- * @param requesterId
- * @return RemoteHttpCacheRequest
- */
- public static <K, V> RemoteCacheRequest<K, V> createGetMatchingRequest( String cacheName, String pattern, long requesterId )
- {
- RemoteCacheRequest<K, V> request = createRequest(cacheName, RemoteRequestType.GET_MATCHING, requesterId);
- request.setPattern( pattern );
-
- return request;
- }
-
- /**
- * Creates a getMultiple Request.
- * <p>
- * @param cacheName
- * @param keys
- * @param requesterId
- * @return RemoteHttpCacheRequest
- */
- public static <K, V> RemoteCacheRequest<K, V> createGetMultipleRequest( String cacheName, Set<K> keys, long requesterId )
- {
- RemoteCacheRequest<K, V> request = createRequest(cacheName, RemoteRequestType.GET_MULTIPLE, requesterId);
- request.setKeySet(keys);
-
- return request;
- }
-
- /**
- * Creates a remove Request.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @return RemoteHttpCacheRequest
- */
- public static <K, V> RemoteCacheRequest<K, V> createRemoveRequest( String cacheName, K key, long requesterId )
- {
- RemoteCacheRequest<K, V> request = createRequest(cacheName, RemoteRequestType.REMOVE, requesterId);
- request.setKey( key );
-
- return request;
- }
-
- /**
- * Creates a GetKeySet Request.
- * <p>
- * @param cacheName
- * @param requesterId
- * @return RemoteHttpCacheRequest
- */
- public static RemoteCacheRequest<String, String> createGetKeySetRequest( String cacheName, long requesterId )
- {
- RemoteCacheRequest<String, String> request = createRequest(cacheName, RemoteRequestType.GET_KEYSET, requesterId);
- request.setKey( cacheName );
-
- return request;
- }
-
- /**
- * Creates a removeAll Request.
- * <p>
- * @param cacheName
- * @param requesterId
- * @return RemoteHttpCacheRequest
- */
- public static <K, V> RemoteCacheRequest<K, V> createRemoveAllRequest( String cacheName, long requesterId )
- {
- RemoteCacheRequest<K, V> request = createRequest(cacheName, RemoteRequestType.REMOVE_ALL, requesterId);
-
- return request;
- }
-
- /**
- * Creates a dispose Request.
- * <p>
- * @param cacheName
- * @param requesterId
- * @return RemoteHttpCacheRequest
- */
- public static <K, V> RemoteCacheRequest<K, V> createDisposeRequest( String cacheName, long requesterId )
- {
- RemoteCacheRequest<K, V> request = createRequest(cacheName, RemoteRequestType.DISPOSE, requesterId);
-
- return request;
- }
-
- /**
- * Creates an Update Request.
- * <p>
- * @param cacheElement
- * @param requesterId
- * @return RemoteHttpCacheRequest
- */
- public static <K, V> RemoteCacheRequest<K, V> createUpdateRequest( ICacheElement<K, V> cacheElement, long requesterId )
- {
- RemoteCacheRequest<K, V> request = createRequest(null, RemoteRequestType.UPDATE, requesterId);
- if ( cacheElement != null )
- {
- request.setCacheName( cacheElement.getCacheName() );
- request.setCacheElement( cacheElement );
- request.setKey( cacheElement.getKey() );
- }
- else
- {
- log.error( "Can't create a proper update request for a null cache element." );
- }
-
- return request;
- }
-
- /**
- * Creates an alive check Request.
- * <p>
- * @param requesterId
- * @return RemoteHttpCacheRequest
- */
- public static <K, V> RemoteCacheRequest<K, V> createAliveCheckRequest( long requesterId )
- {
- RemoteCacheRequest<K, V> request = createRequest(null, RemoteRequestType.ALIVE_CHECK, requesterId);
-
- return request;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/value/RemoteCacheRequest.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/value/RemoteCacheRequest.java
deleted file mode 100644
index b99ef2d..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/value/RemoteCacheRequest.java
+++ /dev/null
@@ -1,187 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.value;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-import java.io.Serializable;
-import java.util.Set;
-
-/**
- * The basic request wrapper. The different types of requests are differentiated by their types.
- * <p>
- * Rather than creating sub object types, I created on object that has values for all types of
- * requests.
- */
-public class RemoteCacheRequest<K, V>
- implements Serializable
-{
- /** Don't change. */
- private static final long serialVersionUID = -8858447417390442569L;
-
- /** The request type specifies the type of request: get, put, remove, . . */
- private RemoteRequestType requestType = null;
-
- /** Used to identify the source. Same as listener id on the client side. */
- private long requesterId = 0;
-
- /** The name of the region */
- private String cacheName;
-
- /** The key, if this request has a key. */
- private K key;
-
- /** The keySet, if this request has a keySet. Only getMultiple requests. */
- private Set<K> keySet;
-
- /** The pattern, if this request uses a pattern. Only getMatching requests. */
- private String pattern;
-
- /** The ICacheEleemnt, if this request contains a value. Only update requests will have this. */
- private ICacheElement<K, V> cacheElement;
-
- /**
- * @param requestType the requestType to set
- */
- public void setRequestType( RemoteRequestType requestType )
- {
- this.requestType = requestType;
- }
-
- /**
- * @return the requestType
- */
- public RemoteRequestType getRequestType()
- {
- return requestType;
- }
-
- /**
- * @param cacheName the cacheName to set
- */
- public void setCacheName( String cacheName )
- {
- this.cacheName = cacheName;
- }
-
- /**
- * @return the cacheName
- */
- public String getCacheName()
- {
- return cacheName;
- }
-
- /**
- * @param key the key to set
- */
- public void setKey( K key )
- {
- this.key = key;
- }
-
- /**
- * @return the key
- */
- public K getKey()
- {
- return key;
- }
-
- /**
- * @param pattern the pattern to set
- */
- public void setPattern( String pattern )
- {
- this.pattern = pattern;
- }
-
- /**
- * @return the pattern
- */
- public String getPattern()
- {
- return pattern;
- }
-
- /**
- * @param cacheElement the cacheElement to set
- */
- public void setCacheElement( ICacheElement<K, V> cacheElement )
- {
- this.cacheElement = cacheElement;
- }
-
- /**
- * @return the cacheElement
- */
- public ICacheElement<K, V> getCacheElement()
- {
- return cacheElement;
- }
-
- /**
- * @param requesterId the requesterId to set
- */
- public void setRequesterId( long requesterId )
- {
- this.requesterId = requesterId;
- }
-
- /**
- * @return the requesterId
- */
- public long getRequesterId()
- {
- return requesterId;
- }
-
- /**
- * @param keySet the keySet to set
- */
- public void setKeySet( Set<K> keySet )
- {
- this.keySet = keySet;
- }
-
- /**
- * @return the keySet
- */
- public Set<K> getKeySet()
- {
- return keySet;
- }
-
- /** @return string */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\nRemoteHttpCacheRequest" );
- buf.append( "\n requesterId [" + getRequesterId() + "]" );
- buf.append( "\n requestType [" + getRequestType() + "]" );
- buf.append( "\n cacheName [" + getCacheName() + "]" );
- buf.append( "\n key [" + getKey() + "]" );
- buf.append( "\n keySet [" + getKeySet() + "]" );
- buf.append( "\n pattern [" + getPattern() + "]" );
- buf.append( "\n cacheElement [" + getCacheElement() + "]" );
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/value/RemoteCacheResponse.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/value/RemoteCacheResponse.java
deleted file mode 100644
index 8292a6a..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/value/RemoteCacheResponse.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.value;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-
-/**
- * This is the response wrapper. The servlet wraps all different type of responses in one of these
- * objects.
- */
-public class RemoteCacheResponse<T>
- implements Serializable
-{
- /** Don't change. */
- private static final long serialVersionUID = -8858447417390442568L;
-
- /** Was the event processed without error */
- private boolean success = true;
-
- /** Simple error messaging */
- private String errorMessage;
-
- /**
- * The payload. Typically a key / ICacheElement<K, V> map. A normal get will return a map with one
- * record.
- */
- private T payload;
-
- /**
- * @param success the success to set
- */
- public void setSuccess( boolean success )
- {
- this.success = success;
- }
-
- /**
- * @return the success
- */
- public boolean isSuccess()
- {
- return success;
- }
-
- /**
- * @param errorMessage the errorMessage to set
- */
- public void setErrorMessage( String errorMessage )
- {
- this.errorMessage = errorMessage;
- }
-
- /**
- * @return the errorMessage
- */
- public String getErrorMessage()
- {
- return errorMessage;
- }
-
- /**
- * @param payload the payload to set
- */
- public void setPayload( T payload )
- {
- this.payload = payload;
- }
-
- /**
- * @return the payload
- */
- public T getPayload()
- {
- return payload;
- }
-
- /** @return string */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\nRemoteHttpCacheResponse" );
- buf.append( "\n success [" + isSuccess() + "]" );
- buf.append( "\n payload [" + getPayload() + "]" );
- buf.append( "\n errorMessage [" + getErrorMessage() + "]" );
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/value/RemoteRequestType.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/value/RemoteRequestType.java
deleted file mode 100644
index ea6d4e1..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/value/RemoteRequestType.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.value;
-
-/*
- * 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.
- */
-
-/**
- * The different types of requests
- */
-public enum RemoteRequestType
-{
- /** Alive check request type. */
- ALIVE_CHECK,
-
- /** Get request type. */
- GET,
-
- /** Get Multiple request type. */
- GET_MULTIPLE,
-
- /** Get Matching request type. */
- GET_MATCHING,
-
- /** Update request type. */
- UPDATE,
-
- /** Remove request type. */
- REMOVE,
-
- /** Remove All request type. */
- REMOVE_ALL,
-
- /** Get keys request type. */
- GET_KEYSET,
-
- /** Dispose request type. */
- DISPOSE,
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/AbstractCacheEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/AbstractCacheEventQueue.java
deleted file mode 100644
index 18588a5..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/AbstractCacheEventQueue.java
+++ /dev/null
@@ -1,437 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-import java.io.IOException;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheEventQueue;
-import org.apache.commons.jcs.engine.behavior.ICacheListener;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * An abstract base class to the different implementations
- */
-public abstract class AbstractCacheEventQueue<K, V>
- implements ICacheEventQueue<K, V>
-{
- /** The logger. */
- private static final Log log = LogManager.getLog( AbstractCacheEventQueue.class );
-
- /** default */
- protected static final int DEFAULT_WAIT_TO_DIE_MILLIS = 10000;
-
- /**
- * time to wait for an event before snuffing the background thread if the queue is empty. make
- * configurable later
- */
- private int waitToDieMillis = DEFAULT_WAIT_TO_DIE_MILLIS;
-
- /**
- * When the events are pulled off the queue, then tell the listener to handle the specific event
- * type. The work is done by the listener.
- */
- private ICacheListener<K, V> listener;
-
- /** Id of the listener registered with this queue */
- private long listenerId;
-
- /** The cache region name, if applicable. */
- private String cacheName;
-
- /** Maximum number of failures before we buy the farm. */
- private int maxFailure;
-
- /** in milliseconds */
- private int waitBeforeRetry;
-
- /**
- * This means that the queue is functional. If we reached the max number of failures, the queue
- * is marked as non functional and will never work again.
- */
- private final AtomicBoolean working = new AtomicBoolean(true);
-
- /**
- * Returns the time to wait for events before killing the background thread.
- * <p>
- * @return int
- */
- public int getWaitToDieMillis()
- {
- return waitToDieMillis;
- }
-
- /**
- * Sets the time to wait for events before killing the background thread.
- * <p>
- * @param wtdm the ms for the q to sit idle.
- */
- public void setWaitToDieMillis( int wtdm )
- {
- waitToDieMillis = wtdm;
- }
-
- /**
- * Creates a brief string identifying the listener and the region.
- * <p>
- * @return String debugging info.
- */
- @Override
- public String toString()
- {
- return "CacheEventQueue [listenerId=" + listenerId + ", cacheName=" + cacheName + "]";
- }
-
- /**
- * @return The listenerId value
- */
- @Override
- public long getListenerId()
- {
- return listenerId;
- }
-
- /**
- * @return the cacheName
- */
- protected String getCacheName()
- {
- return cacheName;
- }
-
- /**
- * Initializes the queue.
- * <p>
- * @param listener
- * @param listenerId
- * @param cacheName
- * @param maxFailure
- * @param waitBeforeRetry
- */
- protected void initialize( ICacheListener<K, V> listener, long listenerId, String cacheName, int maxFailure,
- int waitBeforeRetry)
- {
- if ( listener == null )
- {
- throw new IllegalArgumentException( "listener must not be null" );
- }
-
- this.listener = listener;
- this.listenerId = listenerId;
- this.cacheName = cacheName;
- this.maxFailure = maxFailure <= 0 ? 3 : maxFailure;
- this.waitBeforeRetry = waitBeforeRetry <= 0 ? 500 : waitBeforeRetry;
-
- log.debug( "Constructed: {0}", this );
- }
-
- /**
- * This adds a put event to the queue. When it is processed, the element will be put to the
- * listener.
- * <p>
- * @param ce The feature to be added to the PutEvent attribute
- * @throws IOException
- */
- @Override
- public void addPutEvent( ICacheElement<K, V> ce )
- {
- put( new PutEvent( ce ) );
- }
-
- /**
- * This adds a remove event to the queue. When processed the listener's remove method will be
- * called for the key.
- * <p>
- * @param key The feature to be added to the RemoveEvent attribute
- * @throws IOException
- */
- @Override
- public void addRemoveEvent( K key )
- {
- put( new RemoveEvent( key ) );
- }
-
- /**
- * This adds a remove all event to the queue. When it is processed, all elements will be removed
- * from the cache.
- */
- @Override
- public void addRemoveAllEvent()
- {
- put( new RemoveAllEvent() );
- }
-
- /**
- * This adds a dispose event to the queue. When it is processed, the cache is shut down
- */
- @Override
- public void addDisposeEvent()
- {
- put( new DisposeEvent() );
- }
-
- /**
- * Adds an event to the queue.
- * <p>
- * @param event
- */
- protected abstract void put( AbstractCacheEvent event );
-
-
- // /////////////////////////// Inner classes /////////////////////////////
- /**
- * Retries before declaring failure.
- * <p>
- * @author asmuts
- */
- protected abstract class AbstractCacheEvent implements Runnable
- {
- /** Number of failures encountered processing this event. */
- int failures = 0;
-
- /**
- * Main processing method for the AbstractCacheEvent object
- */
- @Override
- @SuppressWarnings("synthetic-access")
- public void run()
- {
- try
- {
- doRun();
- }
- catch ( IOException e )
- {
- log.warn( e );
- if ( ++failures >= maxFailure )
- {
- log.warn( "Error while running event from Queue: {0}. "
- + "Dropping Event and marking Event Queue as "
- + "non-functional.", this );
- destroy();
- return;
- }
- log.info( "Error while running event from Queue: {0}. "
- + "Retrying...", this );
- try
- {
- Thread.sleep( waitBeforeRetry );
- run();
- }
- catch ( InterruptedException ie )
- {
- log.warn( "Interrupted while sleeping for retry on event "
- + "{0}.", this );
- destroy();
- }
- }
- }
-
- /**
- * @throws IOException
- */
- protected abstract void doRun()
- throws IOException;
- }
-
- /**
- * An element should be put in the cache.
- * <p>
- * @author asmuts
- */
- protected class PutEvent
- extends AbstractCacheEvent
- {
- /** The element to put to the listener */
- private final ICacheElement<K, V> ice;
-
- /**
- * Constructor for the PutEvent object.
- * <p>
- * @param ice
- */
- PutEvent( ICacheElement<K, V> ice )
- {
- this.ice = ice;
- }
-
- /**
- * Call put on the listener.
- * <p>
- * @throws IOException
- */
- @Override
- protected void doRun()
- throws IOException
- {
- listener.handlePut( ice );
- }
-
- /**
- * For debugging.
- * <p>
- * @return Info on the key and value.
- */
- @Override
- public String toString()
- {
- return new StringBuilder( "PutEvent for key: " )
- .append( ice.getKey() )
- .append( " value: " )
- .append( ice.getVal() )
- .toString();
- }
-
- }
-
- /**
- * An element should be removed from the cache.
- * <p>
- * @author asmuts
- */
- protected class RemoveEvent
- extends AbstractCacheEvent
- {
- /** The key to remove from the listener */
- private final K key;
-
- /**
- * Constructor for the RemoveEvent object
- * <p>
- * @param key
- */
- RemoveEvent( K key )
- {
- this.key = key;
- }
-
- /**
- * Call remove on the listener.
- * <p>
- * @throws IOException
- */
- @Override
- protected void doRun()
- throws IOException
- {
- listener.handleRemove( cacheName, key );
- }
-
- /**
- * For debugging.
- * <p>
- * @return Info on the key to remove.
- */
- @Override
- public String toString()
- {
- return new StringBuilder( "RemoveEvent for " )
- .append( key )
- .toString();
- }
-
- }
-
- /**
- * All elements should be removed from the cache when this event is processed.
- * <p>
- * @author asmuts
- */
- protected class RemoveAllEvent
- extends AbstractCacheEvent
- {
- /**
- * Call removeAll on the listener.
- * <p>
- * @throws IOException
- */
- @Override
- protected void doRun()
- throws IOException
- {
- listener.handleRemoveAll( cacheName );
- }
-
- /**
- * For debugging.
- * <p>
- * @return The name of the event.
- */
- @Override
- public String toString()
- {
- return "RemoveAllEvent";
- }
- }
-
- /**
- * The cache should be disposed when this event is processed.
- * <p>
- * @author asmuts
- */
- protected class DisposeEvent
- extends AbstractCacheEvent
- {
- /**
- * Called when gets to the end of the queue
- * <p>
- * @throws IOException
- */
- @Override
- protected void doRun()
- throws IOException
- {
- listener.handleDispose( cacheName );
- }
-
- /**
- * For debugging.
- * <p>
- * @return The name of the event.
- */
- @Override
- public String toString()
- {
- return "DisposeEvent";
- }
- }
-
- /**
- * @return whether the queue is functional.
- */
- @Override
- public boolean isWorking()
- {
- return working.get();
- }
-
- /**
- * This means that the queue is functional. If we reached the max number of failures, the queue
- * is marked as non functional and will never work again.
- * <p>
- * @param b
- */
- public void setWorking( boolean b )
- {
- working.set(b);
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheAdaptor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheAdaptor.java
deleted file mode 100644
index 28ea819..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheAdaptor.java
+++ /dev/null
@@ -1,137 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-import java.io.IOException;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICache;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheListener;
-
-/**
- * Used for Cache-to-Cache messaging purposes. These are used in the balking
- * facades in the lateral and remote caches.
- */
-public class CacheAdaptor<K, V>
- implements ICacheListener<K, V>
-{
- /** The cache we are adapting. */
- private final ICache<K, V> cache;
-
- /** The unique id of this listener. */
- private long listenerId = 0;
-
- /**
- * Sets the listenerId attribute of the CacheAdaptor object
- * <p>
- * @param id
- * The new listenerId value
- * @throws IOException
- */
- @Override
- public void setListenerId( long id )
- throws IOException
- {
- this.listenerId = id;
- }
-
- /**
- * Gets the listenerId attribute of the CacheAdaptor object
- * <p>
- * @return The listenerId value
- * @throws IOException
- */
- @Override
- public long getListenerId()
- throws IOException
- {
- return this.listenerId;
- }
-
- /**
- * Constructor for the CacheAdaptor object
- * <p>
- * @param cache
- */
- public CacheAdaptor( ICache<K, V> cache )
- {
- this.cache = cache;
- }
-
- /**
- * Puts an item into the cache.
- * <p>
- * @param item
- * @throws IOException
- */
- @Override
- public void handlePut( ICacheElement<K, V> item )
- throws IOException
- {
- try
- {
- cache.update( item );
- }
- catch ( IOException e )
- {
- // swallow
- }
- }
-
- /**
- * Removes an item.
- * <p>
- * @param cacheName
- * @param key
- * @throws IOException
- */
- @Override
- public void handleRemove( String cacheName, K key )
- throws IOException
- {
- cache.remove( key );
- }
-
- /**
- * Clears the region.
- * <p>
- * @param cacheName
- * @throws IOException
- */
- @Override
- public void handleRemoveAll( String cacheName )
- throws IOException
- {
- cache.removeAll();
- }
-
- /**
- * Shutdown call.
- * <p>
- * @param cacheName
- * @throws IOException
- */
- @Override
- public void handleDispose( String cacheName )
- throws IOException
- {
- cache.dispose();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheElement.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheElement.java
deleted file mode 100644
index 224b34d..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheElement.java
+++ /dev/null
@@ -1,160 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-
-/**
- * Generic element wrapper. Often stuffed inside another.
- */
-public class CacheElement<K, V>
- implements ICacheElement<K, V>
-{
- /** Don't change */
- private static final long serialVersionUID = -6062305728297627263L;
-
- /** The name of the cache region. This is a namespace. */
- private final String cacheName;
-
- /** This is the cache key by which the value can be referenced. */
- private final K key;
-
- /** This is the cached value, reference by the key. */
- private final V val;
-
- /**
- * These attributes hold information about the element and what it is
- * allowed to do.
- */
- private IElementAttributes attr;
-
- /**
- * Constructor for the CacheElement object
- * <p>
- * @param cacheName
- * @param key
- * @param val
- */
- public CacheElement( String cacheName, K key, V val )
- {
- this.cacheName = cacheName;
- this.key = key;
- this.val = val;
- }
-
- /**
- * Constructor for the CacheElement object
- * <p>
- * @param cacheName
- * @param key
- * @param val
- * @param attrArg
- */
- public CacheElement( String cacheName, K key, V val, IElementAttributes attrArg )
- {
- this(cacheName, key, val);
- this.attr = attrArg;
- }
-
- /**
- * Gets the cacheName attribute of the CacheElement object
- * <p>
- * @return The cacheName value
- */
- @Override
- public String getCacheName()
- {
- return this.cacheName;
- }
-
- /**
- * Gets the key attribute of the CacheElement object
- * <p>
- * @return The key value
- */
- @Override
- public K getKey()
- {
- return this.key;
- }
-
- /**
- * Gets the val attribute of the CacheElement object
- * <p>
- * @return The val value
- */
- @Override
- public V getVal()
- {
- return this.val;
- }
-
- /**
- * Sets the attributes attribute of the CacheElement object
- * <p>
- * @param attr
- * The new IElementAttributes value
- */
- @Override
- public void setElementAttributes( IElementAttributes attr )
- {
- this.attr = attr;
- }
-
- /**
- * Gets the IElementAttributes attribute of the CacheElement object
- * <p>
- * @return The IElementAttributes value, never null
- */
- @Override
- public IElementAttributes getElementAttributes()
- {
- // create default attributes if they are null
- // this shouldn't happen, but could if a corrupt
- // object was sent over the wire.
- if ( this.attr == null )
- {
- this.attr = new ElementAttributes();
- }
- return this.attr;
- }
-
- /**
- * @return a hash of the key only
- */
- @Override
- public int hashCode()
- {
- return key.hashCode();
- }
-
- /**
- * For debugging only.
- * <p>
- * @return String representation
- */
- @Override
- public String toString()
- {
- return "[CacheElement: cacheName [" + cacheName + "], key [" + key + "], val [" + val + "], attr [" + attr
- + "]";
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheElementSerialized.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheElementSerialized.java
deleted file mode 100644
index 8a3d253..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheElementSerialized.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICacheElementSerialized;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-
-import java.util.Arrays;
-
-/** Either serialized value or the value should be null; */
-public class CacheElementSerialized<K, V>
- extends CacheElement<K, V>
- implements ICacheElementSerialized<K, V>
-{
- /** Don't change. */
- private static final long serialVersionUID = -7265084818647601874L;
-
- /** The serialized value. */
- private final byte[] serializedValue;
-
- /**
- * Constructs a usable wrapper.
- * <p>
- * @param cacheNameArg
- * @param keyArg
- * @param serializedValueArg
- * @param elementAttributesArg
- */
- public CacheElementSerialized( String cacheNameArg, K keyArg, byte[] serializedValueArg,
- IElementAttributes elementAttributesArg )
- {
- super(cacheNameArg, keyArg, null, elementAttributesArg);
- this.serializedValue = serializedValueArg;
- }
-
- /** @return byte[] */
- @Override
- public byte[] getSerializedValue()
- {
- return this.serializedValue;
- }
-
- /**
- * For debugging only.
- * <p>
- * @return debugging string.
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\n CacheElementSerialized: " );
- buf.append( "\n CacheName = [" + getCacheName() + "]" );
- buf.append( "\n Key = [" + getKey() + "]" );
- buf.append( "\n SerializedValue = " + Arrays.toString(getSerializedValue()) );
- buf.append( "\n ElementAttributes = " + getElementAttributes() );
- return buf.toString();
- }
-
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheEventQueue.java
deleted file mode 100644
index bf2758f..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheEventQueue.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICacheListener;
-import org.apache.commons.jcs.utils.threadpool.PoolConfiguration;
-import org.apache.commons.jcs.utils.threadpool.PoolConfiguration.WhenBlockedPolicy;
-import org.apache.commons.jcs.utils.threadpool.ThreadPoolManager;
-
-/**
- * An event queue is used to propagate ordered cache events to one and only one target listener.
- */
-public class CacheEventQueue<K, V>
- extends PooledCacheEventQueue<K, V>
-{
- /** The type of queue -- there are pooled and single */
- private static final QueueType queueType = QueueType.SINGLE;
-
- /**
- * Constructs with the specified listener and the cache name.
- * <p>
- * @param listener
- * @param listenerId
- * @param cacheName
- */
- public CacheEventQueue( ICacheListener<K, V> listener, long listenerId, String cacheName )
- {
- this( listener, listenerId, cacheName, 10, 500 );
- }
-
- /**
- * Constructor for the CacheEventQueue object
- * <p>
- * @param listener
- * @param listenerId
- * @param cacheName
- * @param maxFailure
- * @param waitBeforeRetry
- */
- public CacheEventQueue( ICacheListener<K, V> listener, long listenerId, String cacheName, int maxFailure,
- int waitBeforeRetry )
- {
- super( listener, listenerId, cacheName, maxFailure, waitBeforeRetry, null );
- }
-
- /**
- * Initializes the queue.
- * <p>
- * @param listener
- * @param listenerId
- * @param cacheName
- * @param maxFailure
- * @param waitBeforeRetry
- * @param threadPoolName
- */
- @Override
- protected void initialize( ICacheListener<K, V> listener, long listenerId, String cacheName, int maxFailure,
- int waitBeforeRetry, String threadPoolName )
- {
- super.initialize(listener, listenerId, cacheName, maxFailure, waitBeforeRetry);
-
- // create a default pool with one worker thread to mimic the SINGLE queue behavior
- pool = ThreadPoolManager.getInstance().createPool(
- new PoolConfiguration(false, 0, 1, 0, getWaitToDieMillis(), WhenBlockedPolicy.RUN, 0),
- "CacheEventQueue.QProcessor-" + getCacheName());
- }
-
- /**
- * What type of queue is this.
- * <p>
- * @return queueType
- */
- @Override
- public QueueType getQueueType()
- {
- return queueType;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheEventQueueFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheEventQueueFactory.java
deleted file mode 100644
index afeb798..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheEventQueueFactory.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICacheEventQueue;
-import org.apache.commons.jcs.engine.behavior.ICacheListener;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This class hands out event Queues. This allows us to change the implementation more easily. You
- * can confugure the cache to use a custom type.
- * <p>
- * @author aaronsm
- */
-public class CacheEventQueueFactory<K, V>
-{
- /** The logger. */
- private static final Log log = LogManager.getLog( CacheEventQueueFactory.class );
-
- /**
- * The most commonly used factory method.
- * <p>
- * @param listener
- * @param listenerId
- * @param cacheName
- * @param threadPoolName
- * @param poolType - SINGLE, POOLED
- * @return ICacheEventQueue
- */
- public ICacheEventQueue<K, V> createCacheEventQueue( ICacheListener<K, V> listener, long listenerId, String cacheName,
- String threadPoolName, ICacheEventQueue.QueueType poolType )
- {
- return createCacheEventQueue( listener, listenerId, cacheName, 10, 500, threadPoolName, poolType );
- }
-
- /**
- * Fully configured event queue.
- * <p>
- * @param listener
- * @param listenerId
- * @param cacheName
- * @param maxFailure
- * @param waitBeforeRetry
- * @param threadPoolName null is OK, if not a pooled event queue this is ignored
- * @param poolType single or pooled
- * @return ICacheEventQueue
- */
- public ICacheEventQueue<K, V> createCacheEventQueue( ICacheListener<K, V> listener, long listenerId, String cacheName,
- int maxFailure, int waitBeforeRetry, String threadPoolName,
- ICacheEventQueue.QueueType poolType )
- {
- log.debug( "threadPoolName = [{0}] poolType = {1}", threadPoolName, poolType );
-
- ICacheEventQueue<K, V> eventQueue = null;
- if ( poolType == null || ICacheEventQueue.QueueType.SINGLE == poolType )
- {
- eventQueue = new CacheEventQueue<>( listener, listenerId, cacheName, maxFailure, waitBeforeRetry );
- }
- else if ( ICacheEventQueue.QueueType.POOLED == poolType )
- {
- eventQueue = new PooledCacheEventQueue<>( listener, listenerId, cacheName, maxFailure, waitBeforeRetry,
- threadPoolName );
- }
-
- return eventQueue;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheGroup.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheGroup.java
deleted file mode 100644
index 0da5a6d..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheGroup.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-
-/**
- * Holder for attributes specific to a group. The grouping functionality is on
- * the way out.
- */
-public class CacheGroup
-{
- /** Element configuration. */
- private IElementAttributes attr;
-
- /** Constructor for the CacheGroup object */
- public CacheGroup()
- {
- super();
- }
-
- /**
- * Sets the attributes attribute of the CacheGroup object
- * <p>
- * @param attr
- * The new attributes value
- */
- public void setElementAttributes( IElementAttributes attr )
- {
- this.attr = attr;
- }
-
- /**
- * Gets the attrributes attribute of the CacheGroup object
- * <p>
- * @return The attrributes value
- */
- public IElementAttributes getElementAttrributes()
- {
- return attr;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheInfo.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheInfo.java
deleted file mode 100644
index 6256d0e..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheInfo.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-/*
- * 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.
- */
-
-import java.rmi.dgc.VMID;
-
-/**
- * This is a static variable holder for the distribution auxiliaries that need something like a vmid.
- */
-public final class CacheInfo
-{
- /** shouldn't be instantiated */
- private CacheInfo()
- {
- super();
- }
-
- /**
- * Used to identify a client, so we can run multiple clients off one host.
- * Need since there is no way to identify a client other than by host in
- * rmi.
- * <p>
- * TODO: may have some trouble in failover mode if the cache keeps its old
- * id. We may need to reset this when moving into failover.
- */
- private static final VMID vmid = new VMID();
-
- /** By default this is the hashcode of the VMID */
- public static final long listenerId = vmid.hashCode();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheListeners.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheListeners.java
deleted file mode 100644
index 1359c4b..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheListeners.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-/*
- * 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.
- */
-
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import org.apache.commons.jcs.engine.behavior.ICache;
-import org.apache.commons.jcs.engine.behavior.ICacheEventQueue;
-
-/**
- * Used to associates a set of [cache listener to cache event queue] for a
- * cache.
- */
-public class CacheListeners<K, V>
-{
- /** The cache using the queue. */
- public final ICache<K, V> cache;
-
- /** Map ICacheListener to ICacheEventQueue */
- public final ConcurrentMap<Long, ICacheEventQueue<K, V>> eventQMap =
- new ConcurrentHashMap<>();
-
- /**
- * Constructs with the given cache.
- * <p>
- * @param cache
- */
- public CacheListeners( ICache<K, V> cache )
- {
- if ( cache == null )
- {
- throw new IllegalArgumentException( "cache must not be null" );
- }
- this.cache = cache;
- }
-
- /** @return info on the listeners */
- @Override
- public String toString()
- {
- StringBuilder buffer = new StringBuilder();
- buffer.append( "\n CacheListeners" );
- if ( cache != null )
- {
- buffer.append( "\n Region = " + cache.getCacheName() );
- }
- if ( eventQMap != null )
- {
- buffer.append( "\n Event Queue Map " );
- buffer.append( "\n size = " + eventQMap.size() );
- eventQMap.forEach((key, value)
- -> buffer.append( "\n Entry: key: ").append(key)
- .append(", value: ").append(value));
- }
- else
- {
- buffer.append( "\n No Listeners. " );
- }
- return buffer.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheStatus.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheStatus.java
deleted file mode 100644
index 6d09baf..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheStatus.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-/*
- * 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.
- */
-
-/**
- * Cache statuses
- * <p>
- * @version $Id: CacheStatus.java 536904 2007-05-10 16:03:42Z tv $
- */
-public enum CacheStatus
-{
- /** Cache alive status. */
- ALIVE,
-
- /** Cache disposed status. */
- DISPOSED,
-
- /** Cache in error. */
- ERROR
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheWatchRepairable.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheWatchRepairable.java
deleted file mode 100644
index 97b5a2b..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheWatchRepairable.java
+++ /dev/null
@@ -1,170 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.CopyOnWriteArraySet;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICacheListener;
-import org.apache.commons.jcs.engine.behavior.ICacheObserver;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * Intercepts the requests to the underlying ICacheObserver object so that the listeners can be
- * recorded locally for remote connection recovery purposes. (Durable subscription like those in JMS
- * is not implemented at this stage for it can be too expensive.)
- */
-public class CacheWatchRepairable
- implements ICacheObserver
-{
- /** The logger */
- private static final Log log = LogManager.getLog( CacheWatchRepairable.class );
-
- /** the underlying ICacheObserver. */
- private ICacheObserver cacheWatch;
-
- /** Map of cache regions. */
- private final ConcurrentMap<String, Set<ICacheListener<?, ?>>> cacheMap =
- new ConcurrentHashMap<>();
-
- /**
- * Replaces the underlying cache watch service and re-attaches all existing listeners to the new
- * cache watch.
- * <p>
- * @param cacheWatch The new cacheWatch value
- */
- public void setCacheWatch( ICacheObserver cacheWatch )
- {
- this.cacheWatch = cacheWatch;
- for (Map.Entry<String, Set<ICacheListener<?, ?>>> entry : cacheMap.entrySet())
- {
- String cacheName = entry.getKey();
- for (ICacheListener<?, ?> listener : entry.getValue())
- {
- try
- {
- log.info( "Adding listener to cache watch. ICacheListener = "
- + "{0} | ICacheObserver = {1}", listener, cacheWatch );
- cacheWatch.addCacheListener( cacheName, listener );
- }
- catch ( IOException ex )
- {
- log.error( "Problem adding listener. ICacheListener = {0} | "
- + "ICacheObserver = {1}", listener, cacheWatch, ex );
- }
- }
- }
- }
-
- /**
- * Adds a feature to the CacheListener attribute of the CacheWatchRepairable object
- * <p>
- * @param cacheName The feature to be added to the CacheListener attribute
- * @param obj The feature to be added to the CacheListener attribute
- * @throws IOException
- */
- @Override
- public <K, V> void addCacheListener( String cacheName, ICacheListener<K, V> obj )
- throws IOException
- {
- // Record the added cache listener locally, regardless of whether the
- // remote add-listener operation succeeds or fails.
- Set<ICacheListener<?, ?>> listenerSet = cacheMap.computeIfAbsent(cacheName, key -> {
- return new CopyOnWriteArraySet<>();
- });
-
- listenerSet.add( obj );
-
- log.info( "Adding listener to cache watch. ICacheListener = {0} | "
- + "ICacheObserver = {1} | cacheName = {2}", obj, cacheWatch,
- cacheName );
- cacheWatch.addCacheListener( cacheName, obj );
- }
-
- /**
- * Adds a feature to the CacheListener attribute of the CacheWatchRepairable object
- * <p>
- * @param obj The feature to be added to the CacheListener attribute
- * @throws IOException
- */
- @Override
- public <K, V> void addCacheListener( ICacheListener<K, V> obj )
- throws IOException
- {
- // Record the added cache listener locally, regardless of whether the
- // remote add-listener operation succeeds or fails.
- for (Set<ICacheListener<?, ?>> listenerSet : cacheMap.values())
- {
- listenerSet.add( obj );
- }
-
- log.info( "Adding listener to cache watch. ICacheListener = {0} | "
- + "ICacheObserver = {1}", obj, cacheWatch );
- cacheWatch.addCacheListener( obj );
- }
-
- /**
- * Tell the server to release us.
- * <p>
- * @param cacheName
- * @param obj
- * @throws IOException
- */
- @Override
- public <K, V> void removeCacheListener( String cacheName, ICacheListener<K, V> obj )
- throws IOException
- {
- log.info( "removeCacheListener, cacheName [{0}]", cacheName );
- // Record the removal locally, regardless of whether the remote
- // remove-listener operation succeeds or fails.
- Set<ICacheListener<?, ?>> listenerSet = cacheMap.get( cacheName );
- if ( listenerSet != null )
- {
- listenerSet.remove( obj );
- }
- cacheWatch.removeCacheListener( cacheName, obj );
- }
-
- /**
- * @param obj
- * @throws IOException
- */
- @Override
- public <K, V> void removeCacheListener( ICacheListener<K, V> obj )
- throws IOException
- {
- log.info( "removeCacheListener, ICacheListener [{0}]", obj );
-
- // Record the removal locally, regardless of whether the remote
- // remove-listener operation succeeds or fails.
- for (Set<ICacheListener<?, ?>> listenerSet : cacheMap.values())
- {
- log.debug( "Before removing [{0}] the listenerSet = {1}", obj,
- listenerSet );
- listenerSet.remove( obj );
- }
- cacheWatch.removeCacheListener( obj );
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CompositeCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CompositeCacheAttributes.java
deleted file mode 100644
index 31da4be..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CompositeCacheAttributes.java
+++ /dev/null
@@ -1,443 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
-
-/**
- * The CompositeCacheAttributes defines the general cache region settings. If a region is not
- * explicitly defined in the cache.ccf then it inherits the cache default settings.
- * <p>
- * If all the default attributes are not defined in the default region definition in the cache.ccf,
- * the hard coded defaults will be used.
- */
-public class CompositeCacheAttributes
- implements ICompositeCacheAttributes
-{
- /** Don't change */
- private static final long serialVersionUID = 6754049978134196787L;
-
- /** default lateral switch */
- private static final boolean DEFAULT_USE_LATERAL = true;
-
- /** default remote switch */
- private static final boolean DEFAULT_USE_REMOTE = true;
-
- /** default disk switch */
- private static final boolean DEFAULT_USE_DISK = true;
-
- /** default shrinker setting */
- private static final boolean DEFAULT_USE_SHRINKER = false;
-
- /** default max objects value */
- private static final int DEFAULT_MAX_OBJECTS = 100;
-
- /** default */
- private static final int DEFAULT_MAX_MEMORY_IDLE_TIME_SECONDS = 60 * 120;
-
- /** default interval to run the shrinker */
- private static final int DEFAULT_SHRINKER_INTERVAL_SECONDS = 30;
-
- /** default */
- private static final int DEFAULT_MAX_SPOOL_PER_RUN = -1;
-
- /** default */
- private static final String DEFAULT_MEMORY_CACHE_NAME = "org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache";
-
- /** Default number to send to disk at a time when memory fills. */
- private static final int DEFAULT_CHUNK_SIZE = 2;
-
- /** allow lateral caches */
- private boolean useLateral = DEFAULT_USE_LATERAL;
-
- /** allow remote caches */
- private boolean useRemote = DEFAULT_USE_REMOTE;
-
- /** Whether we should use a disk cache if it is configured. */
- private boolean useDisk = DEFAULT_USE_DISK;
-
- /** Whether or not we should run the memory shrinker thread. */
- private boolean useMemoryShrinker = DEFAULT_USE_SHRINKER;
-
- /** The maximum objects that the memory cache will be allowed to hold. */
- private int maxObjs = DEFAULT_MAX_OBJECTS;
-
- /** maxMemoryIdleTimeSeconds */
- private long maxMemoryIdleTimeSeconds = DEFAULT_MAX_MEMORY_IDLE_TIME_SECONDS;
-
- /** shrinkerIntervalSeconds */
- private long shrinkerIntervalSeconds = DEFAULT_SHRINKER_INTERVAL_SECONDS;
-
- /** The maximum number the shrinker will spool to disk per run. */
- private int maxSpoolPerRun = DEFAULT_MAX_SPOOL_PER_RUN;
-
- /** The name of this cache region. */
- private String cacheName;
-
- /** The name of the memory cache implementation class. */
- private String memoryCacheName;
-
- /** Set via DISK_USAGE_PATTERN_NAME */
- private DiskUsagePattern diskUsagePattern = DiskUsagePattern.SWAP;
-
- /** How many to spool to disk at a time. */
- private int spoolChunkSize = DEFAULT_CHUNK_SIZE;
-
- /**
- * Constructor for the CompositeCacheAttributes object
- */
- public CompositeCacheAttributes()
- {
- super();
- // set this as the default so the configuration is a bit simpler
- memoryCacheName = DEFAULT_MEMORY_CACHE_NAME;
- }
-
- /**
- * Sets the maxObjects attribute of the CompositeCacheAttributes object
- * <p>
- * @param maxObjs The new maxObjects value
- */
- @Override
- public void setMaxObjects( int maxObjs )
- {
- this.maxObjs = maxObjs;
- }
-
- /**
- * Gets the maxObjects attribute of the CompositeCacheAttributes object
- * <p>
- * @return The maxObjects value
- */
- @Override
- public int getMaxObjects()
- {
- return this.maxObjs;
- }
-
- /**
- * Sets the useDisk attribute of the CompositeCacheAttributes object
- * <p>
- * @param useDisk The new useDisk value
- */
- @Override
- public void setUseDisk( boolean useDisk )
- {
- this.useDisk = useDisk;
- }
-
- /**
- * Gets the useDisk attribute of the CompositeCacheAttributes object
- * <p>
- * @return The useDisk value
- */
- @Override
- public boolean isUseDisk()
- {
- return useDisk;
- }
-
- /**
- * Sets the useLateral attribute of the CompositeCacheAttributes object
- * <p>
- * @param b The new useLateral value
- */
- @Override
- public void setUseLateral( boolean b )
- {
- this.useLateral = b;
- }
-
- /**
- * Gets the useLateral attribute of the CompositeCacheAttributes object
- * <p>
- * @return The useLateral value
- */
- @Override
- public boolean isUseLateral()
- {
- return this.useLateral;
- }
-
- /**
- * Sets the useRemote attribute of the CompositeCacheAttributes object
- * <p>
- * @param useRemote The new useRemote value
- */
- @Override
- public void setUseRemote( boolean useRemote )
- {
- this.useRemote = useRemote;
- }
-
- /**
- * Gets the useRemote attribute of the CompositeCacheAttributes object
- * <p>
- * @return The useRemote value
- */
- @Override
- public boolean isUseRemote()
- {
- return this.useRemote;
- }
-
- /**
- * Sets the cacheName attribute of the CompositeCacheAttributes object
- * <p>
- * @param s The new cacheName value
- */
- @Override
- public void setCacheName( String s )
- {
- this.cacheName = s;
- }
-
- /**
- * Gets the cacheName attribute of the CompositeCacheAttributes object
- * <p>
- * @return The cacheName value
- */
- @Override
- public String getCacheName()
- {
- return this.cacheName;
- }
-
- /**
- * Sets the memoryCacheName attribute of the CompositeCacheAttributes object
- * <p>
- * @param s The new memoryCacheName value
- */
- @Override
- public void setMemoryCacheName( String s )
- {
- this.memoryCacheName = s;
- }
-
- /**
- * Gets the memoryCacheName attribute of the CompositeCacheAttributes object
- * <p>
- * @return The memoryCacheName value
- */
- @Override
- public String getMemoryCacheName()
- {
- return this.memoryCacheName;
- }
-
- /**
- * Whether the memory cache should perform background memory shrinkage.
- * <p>
- * @param useShrinker The new UseMemoryShrinker value
- */
- @Override
- public void setUseMemoryShrinker( boolean useShrinker )
- {
- this.useMemoryShrinker = useShrinker;
- }
-
- /**
- * Whether the memory cache should perform background memory shrinkage.
- * <p>
- * @return The UseMemoryShrinker value
- */
- @Override
- public boolean isUseMemoryShrinker()
- {
- return this.useMemoryShrinker;
- }
-
- /**
- * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space.
- * <p>
- * @param seconds The new MaxMemoryIdleTimeSeconds value
- */
- @Override
- public void setMaxMemoryIdleTimeSeconds( long seconds )
- {
- this.maxMemoryIdleTimeSeconds = seconds;
- }
-
- /**
- * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space.
- * <p>
- * @return The MaxMemoryIdleTimeSeconds value
- */
- @Override
- public long getMaxMemoryIdleTimeSeconds()
- {
- return this.maxMemoryIdleTimeSeconds;
- }
-
- /**
- * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space.
- * This sets the shrinker interval.
- * <p>
- * @param seconds The new ShrinkerIntervalSeconds value
- */
- @Override
- public void setShrinkerIntervalSeconds( long seconds )
- {
- this.shrinkerIntervalSeconds = seconds;
- }
-
- /**
- * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space.
- * This gets the shrinker interval.
- * <p>
- * @return The ShrinkerIntervalSeconds value
- */
- @Override
- public long getShrinkerIntervalSeconds()
- {
- return this.shrinkerIntervalSeconds;
- }
-
- /**
- * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space.
- * This sets the maximum number of items to spool per run.
- * <p>
- * If the value is -1, then there is no limit to the number of items to be spooled.
- * <p>
- * @param maxSpoolPerRun The new maxSpoolPerRun value
- */
- @Override
- public void setMaxSpoolPerRun( int maxSpoolPerRun )
- {
- this.maxSpoolPerRun = maxSpoolPerRun;
- }
-
- /**
- * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space.
- * This gets the maximum number of items to spool per run.
- * <p>
- * @return The maxSpoolPerRun value
- */
- @Override
- public int getMaxSpoolPerRun()
- {
- return this.maxSpoolPerRun;
- }
-
- /**
- * By default this is SWAP_ONLY.
- * <p>
- * @param diskUsagePattern The diskUsagePattern to set.
- */
- @Override
- public void setDiskUsagePattern( DiskUsagePattern diskUsagePattern )
- {
- this.diskUsagePattern = diskUsagePattern;
- }
-
- /**
- * Translates the name to the disk usage pattern short value.
- * <p>
- * The allowed values are SWAP and UPDATE.
- * <p>
- * @param diskUsagePatternName The diskUsagePattern to set.
- */
- @Override
- public void setDiskUsagePatternName( String diskUsagePatternName )
- {
- if ( diskUsagePatternName != null )
- {
- String name = diskUsagePatternName.toUpperCase().trim();
- if ( name.startsWith( "SWAP" ) )
- {
- this.setDiskUsagePattern( DiskUsagePattern.SWAP );
- }
- else if ( name.startsWith( "UPDATE" ) )
- {
- this.setDiskUsagePattern( DiskUsagePattern.UPDATE );
- }
- }
- }
-
- /**
- * Number to send to disk at at time when memory is full.
- * <p>
- * @return int
- */
- @Override
- public int getSpoolChunkSize()
- {
- return spoolChunkSize;
- }
-
- /**
- * Number to send to disk at a time.
- * <p>
- * @param spoolChunkSize
- */
- @Override
- public void setSpoolChunkSize( int spoolChunkSize )
- {
- this.spoolChunkSize = spoolChunkSize;
- }
-
- /**
- * @return Returns the diskUsagePattern.
- */
- @Override
- public DiskUsagePattern getDiskUsagePattern()
- {
- return diskUsagePattern;
- }
-
- /**
- * Dumps the core attributes.
- * <p>
- * @return For debugging.
- */
- @Override
- public String toString()
- {
- StringBuilder dump = new StringBuilder();
-
- dump.append( "[ " );
- dump.append( "useLateral = " ).append( useLateral );
- dump.append( ", useRemote = " ).append( useRemote );
- dump.append( ", useDisk = " ).append( useDisk );
- dump.append( ", maxObjs = " ).append( maxObjs );
- dump.append( ", maxSpoolPerRun = " ).append( maxSpoolPerRun );
- dump.append( ", diskUsagePattern = " ).append( diskUsagePattern );
- dump.append( ", spoolChunkSize = " ).append( spoolChunkSize );
- dump.append( " ]" );
-
- return dump.toString();
- }
-
- /**
- * @see java.lang.Object#clone()
- */
- @Override
- public ICompositeCacheAttributes clone()
- {
- try
- {
- return (ICompositeCacheAttributes)super.clone();
- }
- catch (CloneNotSupportedException e)
- {
- throw new RuntimeException("Clone not supported. This should never happen.", e);
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/ElementAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/ElementAttributes.java
deleted file mode 100644
index 053fefc..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/ElementAttributes.java
+++ /dev/null
@@ -1,459 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-/*
- * 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.
- */
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.control.event.behavior.IElementEventHandler;
-
-/**
- * This it the element attribute descriptor class. Each element in the cache has an ElementAttribute
- * object associated with it. An ElementAttributes object can be associated with an element in 3
- * ways:
- * <ol>
- * <li>When the item is put into the cache, you can associate an element attributes object.</li>
- * <li>If not attributes object is include when the element is put into the cache, then the default
- * attributes for the region will be used.</li>
- * <li>The element attributes can be reset. This effectively results in a retrieval followed by a
- * put. Hence, this is the same as 1.</li>
- * </ol>
- */
-public class ElementAttributes
- implements IElementAttributes
-{
- /** Don't change. */
- private static final long serialVersionUID = 7814990748035017441L;
-
- /** Can this item be flushed to disk */
- private boolean IS_SPOOL = true;
-
- /** Is this item laterally distributable */
- private boolean IS_LATERAL = true;
-
- /** Can this item be sent to the remote cache */
- private boolean IS_REMOTE = true;
-
- /**
- * You can turn off expiration by setting this to true. This causes the cache to bypass both max
- * life and idle time expiration.
- */
- private boolean IS_ETERNAL = true;
-
- /** Max life seconds */
- private long maxLife = -1;
-
- /**
- * The maximum time an entry can be idle. Setting this to -1 causes the idle time check to be
- * ignored.
- */
- private long maxIdleTime = -1;
-
- /** The byte size of the field. Must be manually set. */
- private int size = 0;
-
- /** The creation time. This is used to enforce the max life. */
- private long createTime = 0;
-
- /** The last access time. This is used to enforce the max idel time. */
- private long lastAccessTime = 0;
-
- /**
- * The list of Event handlers to use. This is transient, since the event handlers cannot usually
- * be serialized. This means that you cannot attach a post serialization event to an item.
- * <p>
- * TODO we need to check that when an item is passed to a non-local cache that if the local
- * cache had a copy with event handlers, that those handlers are used.
- */
- private transient ArrayList<IElementEventHandler> eventHandlers;
-
- private long timeFactor = 1000;
-
- /**
- * Constructor for the IElementAttributes object
- */
- public ElementAttributes()
- {
- this.createTime = System.currentTimeMillis();
- this.lastAccessTime = this.createTime;
- }
-
- /**
- * Constructor for the IElementAttributes object
- * <p>
- * @param attr
- */
- protected ElementAttributes( ElementAttributes attr )
- {
- IS_ETERNAL = attr.IS_ETERNAL;
-
- // waterfall onto disk, for pure disk set memory to 0
- IS_SPOOL = attr.IS_SPOOL;
-
- // lateral
- IS_LATERAL = attr.IS_LATERAL;
-
- // central rmi store
- IS_REMOTE = attr.IS_REMOTE;
-
- maxLife = attr.maxLife;
- // time-to-live
- maxIdleTime = attr.maxIdleTime;
- size = attr.size;
- }
-
- /**
- * Sets the maxLife attribute of the IAttributes object.
- * <p>
- * @param mls The new MaxLifeSeconds value
- */
- @Override
- public void setMaxLife(long mls)
- {
- this.maxLife = mls;
- }
-
- /**
- * Sets the maxLife attribute of the IAttributes object. How many seconds it can live after
- * creation.
- * <p>
- * If this is exceeded the element will not be returned, instead it will be removed. It will be
- * removed on retrieval, or removed actively if the memory shrinker is turned on.
- * @return The MaxLifeSeconds value
- */
- @Override
- public long getMaxLife()
- {
- return this.maxLife;
- }
-
- /**
- * Sets the idleTime attribute of the IAttributes object. This is the maximum time the item can
- * be idle in the cache, that is not accessed.
- * <p>
- * If this is exceeded the element will not be returned, instead it will be removed. It will be
- * removed on retrieval, or removed actively if the memory shrinker is turned on.
- * @param idle The new idleTime value
- */
- @Override
- public void setIdleTime( long idle )
- {
- this.maxIdleTime = idle;
- }
-
- /**
- * Size in bytes. This is not used except in the admin pages. It will be 0 by default
- * and is only updated when the element is serialized.
- * <p>
- * @param size The new size value
- */
- @Override
- public void setSize( int size )
- {
- this.size = size;
- }
-
- /**
- * Gets the size attribute of the IAttributes object
- * <p>
- * @return The size value
- */
- @Override
- public int getSize()
- {
- return size;
- }
-
- /**
- * Gets the createTime attribute of the IAttributes object.
- * <p>
- * This should be the current time in milliseconds returned by the sysutem call when the element
- * is put in the cache.
- * <p>
- * Putting an item in the cache overrides any existing items.
- * @return The createTime value
- */
- @Override
- public long getCreateTime()
- {
- return createTime;
- }
-
- /**
- * Sets the createTime attribute of the IElementAttributes object
- */
- public void setCreateTime()
- {
- createTime = System.currentTimeMillis();
- }
-
- /**
- * Gets the idleTime attribute of the IAttributes object.
- * <p>
- * @return The idleTime value
- */
- @Override
- public long getIdleTime()
- {
- return this.maxIdleTime;
- }
-
- /**
- * Gets the time left to live of the IAttributes object.
- * <p>
- * This is the (max life + create time) - current time.
- * @return The TimeToLiveSeconds value
- */
- @Override
- public long getTimeToLiveSeconds()
- {
- final long now = System.currentTimeMillis();
- final long timeFactorForMilliseconds = getTimeFactorForMilliseconds();
- return ( this.getCreateTime() + this.getMaxLife() * timeFactorForMilliseconds - now ) / 1000;
- }
-
- /**
- * Gets the LastAccess attribute of the IAttributes object.
- * <p>
- * @return The LastAccess value.
- */
- @Override
- public long getLastAccessTime()
- {
- return this.lastAccessTime;
- }
-
- /**
- * Sets the LastAccessTime as now of the IElementAttributes object
- */
- @Override
- public void setLastAccessTimeNow()
- {
- this.lastAccessTime = System.currentTimeMillis();
- }
-
- /**
- * only for use from test code
- */
- public void setLastAccessTime(long time)
- {
- this.lastAccessTime = time;
- }
-
- /**
- * Can this item be spooled to disk
- * <p>
- * By default this is true.
- * @return The spoolable value
- */
- @Override
- public boolean getIsSpool()
- {
- return this.IS_SPOOL;
- }
-
- /**
- * Sets the isSpool attribute of the IElementAttributes object
- * <p>
- * By default this is true.
- * @param val The new isSpool value
- */
- @Override
- public void setIsSpool( boolean val )
- {
- this.IS_SPOOL = val;
- }
-
- /**
- * Is this item laterally distributable. Can it be sent to auxiliaries of type lateral.
- * <p>
- * By default this is true.
- * @return The isLateral value
- */
- @Override
- public boolean getIsLateral()
- {
- return this.IS_LATERAL;
- }
-
- /**
- * Sets the isLateral attribute of the IElementAttributes object
- * <p>
- * By default this is true.
- * @param val The new isLateral value
- */
- @Override
- public void setIsLateral( boolean val )
- {
- this.IS_LATERAL = val;
- }
-
- /**
- * Can this item be sent to the remote cache
- * @return true if the item can be sent to a remote auxiliary
- */
- @Override
- public boolean getIsRemote()
- {
- return this.IS_REMOTE;
- }
-
- /**
- * Sets the isRemote attribute of the ElementAttributes object
- * @param val The new isRemote value
- */
- @Override
- public void setIsRemote( boolean val )
- {
- this.IS_REMOTE = val;
- }
-
- /**
- * You can turn off expiration by setting this to true. The max life value will be ignored.
- * <p>
- * @return true if the item cannot expire.
- */
- @Override
- public boolean getIsEternal()
- {
- return this.IS_ETERNAL;
- }
-
- /**
- * Sets the isEternal attribute of the ElementAttributes object. True means that the item should
- * never expire. If can still be removed if it is the least recently used, and you are using the
- * LRUMemory cache. it just will not be filtered for expiration by the cache hub.
- * <p>
- * @param val The new isEternal value
- */
- @Override
- public void setIsEternal( boolean val )
- {
- this.IS_ETERNAL = val;
- }
-
- /**
- * Adds a ElementEventHandler. Handler's can be registered for multiple events. A registered
- * handler will be called at every recognized event.
- * <p>
- * The alternative would be to register handlers for each event. Or maybe The handler interface
- * should have a method to return whether it cares about certain events.
- * <p>
- * @param eventHandler The ElementEventHandler to be added to the list.
- */
- @Override
- public void addElementEventHandler( IElementEventHandler eventHandler )
- {
- // lazy here, no concurrency problems expected
- if ( this.eventHandlers == null )
- {
- this.eventHandlers = new ArrayList<>();
- }
- this.eventHandlers.add( eventHandler );
- }
-
- /**
- * Sets the eventHandlers of the IElementAttributes object.
- * <p>
- * This add the references to the local list. Subsequent changes in the caller's list will not
- * be reflected.
- * <p>
- * @param eventHandlers List of IElementEventHandler objects
- */
- @Override
- public void addElementEventHandlers( List<IElementEventHandler> eventHandlers )
- {
- if ( eventHandlers == null )
- {
- return;
- }
-
- for (IElementEventHandler handler : eventHandlers)
- {
- addElementEventHandler(handler);
- }
- }
-
- @Override
- public long getTimeFactorForMilliseconds()
- {
- return timeFactor;
- }
-
- @Override
- public void setTimeFactorForMilliseconds(long factor)
- {
- this.timeFactor = factor;
- }
-
- /**
- * Gets the elementEventHandlers. Returns null if none exist. Makes checking easy.
- * <p>
- * @return The elementEventHandlers List of IElementEventHandler objects
- */
- @Override
- public ArrayList<IElementEventHandler> getElementEventHandlers()
- {
- return this.eventHandlers;
- }
-
- /**
- * For logging and debugging the element IElementAttributes.
- * <p>
- * @return String info about the values.
- */
- @Override
- public String toString()
- {
- StringBuilder dump = new StringBuilder();
-
- dump.append( "[ IS_LATERAL = " ).append( IS_LATERAL );
- dump.append( ", IS_SPOOL = " ).append( IS_SPOOL );
- dump.append( ", IS_REMOTE = " ).append( IS_REMOTE );
- dump.append( ", IS_ETERNAL = " ).append( IS_ETERNAL );
- dump.append( ", MaxLifeSeconds = " ).append( this.getMaxLife() );
- dump.append( ", IdleTime = " ).append( this.getIdleTime() );
- dump.append( ", CreateTime = " ).append( this.getCreateTime() );
- dump.append( ", LastAccessTime = " ).append( this.getLastAccessTime() );
- dump.append( ", getTimeToLiveSeconds() = " ).append( String.valueOf( getTimeToLiveSeconds() ) );
- dump.append( ", createTime = " ).append( String.valueOf( createTime ) ).append( " ]" );
-
- return dump.toString();
- }
-
- /**
- * @see java.lang.Object#clone()
- */
- @Override
- public IElementAttributes clone()
- {
- try
- {
- ElementAttributes c = (ElementAttributes) super.clone();
- c.setCreateTime();
- return c;
- }
- catch (CloneNotSupportedException e)
- {
- throw new RuntimeException("Clone not supported. This should never happen.", e);
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/PooledCacheEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/PooledCacheEventQueue.java
deleted file mode 100644
index cd94f7d..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/PooledCacheEventQueue.java
+++ /dev/null
@@ -1,191 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-import java.util.ArrayList;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.ThreadPoolExecutor;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICacheListener;
-import org.apache.commons.jcs.engine.stats.StatElement;
-import org.apache.commons.jcs.engine.stats.Stats;
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.threadpool.ThreadPoolManager;
-
-/**
- * An event queue is used to propagate ordered cache events to one and only one target listener.
- * <p>
- * This is a modified version of the experimental version. It uses a PooledExecutor and a
- * BoundedBuffer to queue up events and execute them as threads become available.
- * <p>
- * The PooledExecutor is static, because presumably these processes will be IO bound, so throwing
- * more than a few threads at them will serve no purpose other than to saturate the IO interface. In
- * light of this, having one thread per region seems unnecessary. This may prove to be false.
- */
-public class PooledCacheEventQueue<K, V>
- extends AbstractCacheEventQueue<K, V>
-{
- /** The logger. */
- private static final Log log = LogManager.getLog( PooledCacheEventQueue.class );
-
- /** The type of event queue */
- private static final QueueType queueType = QueueType.POOLED;
-
- /** The Thread Pool to execute events with. */
- protected ExecutorService pool = null;
-
- /** The Thread Pool queue */
- protected BlockingQueue<Runnable> queue = null;
-
- /**
- * Constructor for the CacheEventQueue object
- * <p>
- * @param listener
- * @param listenerId
- * @param cacheName
- * @param maxFailure
- * @param waitBeforeRetry
- * @param threadPoolName
- */
- public PooledCacheEventQueue( ICacheListener<K, V> listener, long listenerId, String cacheName, int maxFailure,
- int waitBeforeRetry, String threadPoolName )
- {
- initialize( listener, listenerId, cacheName, maxFailure, waitBeforeRetry, threadPoolName );
- }
-
- /**
- * Initializes the queue.
- * <p>
- * @param listener
- * @param listenerId
- * @param cacheName
- * @param maxFailure
- * @param waitBeforeRetry
- * @param threadPoolName
- */
- protected void initialize( ICacheListener<K, V> listener, long listenerId, String cacheName, int maxFailure,
- int waitBeforeRetry, String threadPoolName )
- {
- super.initialize(listener, listenerId, cacheName, maxFailure, waitBeforeRetry);
-
- // this will share the same pool with other event queues by default.
- pool = ThreadPoolManager.getInstance().getExecutorService(
- (threadPoolName == null) ? "cache_event_queue" : threadPoolName );
-
- if (pool instanceof ThreadPoolExecutor)
- {
- queue = ((ThreadPoolExecutor) pool).getQueue();
- }
- }
-
- /**
- * @return the queue type
- */
- @Override
- public QueueType getQueueType()
- {
- return queueType;
- }
-
- /**
- * Destroy the queue. Interrupt all threads.
- */
- @Override
- public synchronized void destroy()
- {
- if ( isWorking() )
- {
- setWorking(false);
- pool.shutdownNow();
- log.info( "Cache event queue destroyed: {0}", this );
- }
- }
-
- /**
- * Adds an event to the queue.
- * <p>
- * @param event
- */
- @Override
- protected void put( AbstractCacheEvent event )
- {
- pool.execute( event );
- }
-
- /**
- * @return IStats
- */
- @Override
- public IStats getStatistics()
- {
- IStats stats = new Stats();
- stats.setTypeName( "Pooled Cache Event Queue" );
-
- ArrayList<IStatElement<?>> elems = new ArrayList<>();
-
- elems.add(new StatElement<>( "Working", Boolean.valueOf(isWorking()) ) );
- elems.add(new StatElement<>( "Empty", Boolean.valueOf(this.isEmpty()) ) );
-
- if ( queue != null )
- {
- elems.add(new StatElement<>( "Queue Size", Integer.valueOf(queue.size()) ) );
- elems.add(new StatElement<>( "Queue Capacity", Integer.valueOf(queue.remainingCapacity()) ) );
- }
-
- stats.setStatElements( elems );
-
- return stats;
- }
-
- /**
- * If the Queue is using a bounded channel we can determine the size. If it is zero or we can't
- * determine the size, we return true.
- * <p>
- * @return whether or not there are items in the queue
- */
- @Override
- public boolean isEmpty()
- {
- return size() == 0;
- }
-
- /**
- * Returns the number of elements in the queue. If the queue cannot determine the size
- * accurately it will return 0.
- * <p>
- * @return number of items in the queue.
- */
- @Override
- public int size()
- {
- if ( queue == null )
- {
- return 0;
- }
- else
- {
- return queue.size();
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/ZombieCacheService.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/ZombieCacheService.java
deleted file mode 100644
index 061da02..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/ZombieCacheService.java
+++ /dev/null
@@ -1,151 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheService;
-import org.apache.commons.jcs.engine.behavior.IZombie;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * Zombie adapter for any cache service. Balks at every call.
- */
-public class ZombieCacheService<K, V>
- implements ICacheService<K, V>, IZombie
-{
- /** The logger. */
- private static final Log log = LogManager.getLog( ZombieCacheService.class );
-
- /**
- * @param item
- */
- public void put( ICacheElement<K, V> item )
- {
- log.debug( "Zombie put for item {0}", item );
- // zombies have no inner life
- }
-
- /**
- * Does nothing.
- * <p>
- * @param item
- */
- @Override
- public void update( ICacheElement<K, V> item )
- {
- // zombies have no inner life
- }
-
- /**
- * @param cacheName
- * @param key
- * @return null. zombies have no internal data
- */
- @Override
- public ICacheElement<K, V> get( String cacheName, K key )
- {
- return null;
- }
-
- /**
- * Returns an empty map. Zombies have no internal data.
- * <p>
- * @param cacheName
- * @param keys
- * @return Collections.EMPTY_MAP
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys )
- {
- return Collections.emptyMap();
- }
-
- /**
- * Returns an empty map. Zombies have no internal data.
- * <p>
- * @param cacheName
- * @param pattern
- * @return Collections.EMPTY_MAP
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern )
- {
- return Collections.emptyMap();
- }
-
- /**
- * Logs the get to debug, but always balks.
- * <p>
- * @param cacheName
- * @param key
- * @param container
- * @return null always
- */
- public Serializable get( String cacheName, K key, boolean container )
- {
- log.debug( "Zombie get for key [{0}] cacheName [{1}] container [{2}]",
- key, cacheName, container);
- // zombies have no inner life
- return null;
- }
-
- /**
- * @param cacheName
- * @param key
- */
- @Override
- public void remove( String cacheName, K key )
- {
- // zombies have no inner life
- }
-
- /**
- * @param cacheName
- */
- @Override
- public void removeAll( String cacheName )
- {
- // zombies have no inner life
- }
-
- /**
- * @param cacheName
- */
- @Override
- public void dispose( String cacheName )
- {
- // zombies have no inner life
- }
-
- /**
- * Frees all caches.
- */
- @Override
- public void release()
- {
- // zombies have no inner life
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/ZombieCacheServiceNonLocal.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/ZombieCacheServiceNonLocal.java
deleted file mode 100644
index 8aa5630..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/ZombieCacheServiceNonLocal.java
+++ /dev/null
@@ -1,316 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.timing.ElapsedTimer;
-
-/**
- * Zombie adapter for the non local cache services. It just balks if there is no queue configured.
- * <p>
- * If a queue is configured, then events will be added to the queue. The idea is that when proper
- * operation is restored, the non local cache will walk the queue. The queue must be bounded so it
- * does not eat memory.
- * <p>
- * This originated in the remote cache.
- */
-public class ZombieCacheServiceNonLocal<K, V>
- extends ZombieCacheService<K, V>
- implements ICacheServiceNonLocal<K, V>
-{
- /** The logger */
- private static final Log log = LogManager.getLog( ZombieCacheServiceNonLocal.class );
-
- /** How big can the queue grow. */
- private int maxQueueSize = 0;
-
- /** The queue */
- private final ConcurrentLinkedQueue<ZombieEvent> queue;
-
- /**
- * Default.
- */
- public ZombieCacheServiceNonLocal()
- {
- queue = new ConcurrentLinkedQueue<>();
- }
-
- /**
- * Sets the maximum number of items that will be allowed on the queue.
- * <p>
- * @param maxQueueSize
- */
- public ZombieCacheServiceNonLocal( int maxQueueSize )
- {
- this.maxQueueSize = maxQueueSize;
- queue = new ConcurrentLinkedQueue<>();
- }
-
- /**
- * Gets the number of items on the queue.
- * <p>
- * @return size of the queue.
- */
- public int getQueueSize()
- {
- return queue.size();
- }
-
- private void addQueue(ZombieEvent event)
- {
- queue.add(event);
- if (queue.size() > maxQueueSize)
- {
- queue.poll(); // drop oldest entry
- }
- }
-
- /**
- * Adds an update event to the queue if the maxSize is greater than 0;
- * <p>
- * @param item ICacheElement
- * @param listenerId - identifies the caller.
- */
- @Override
- public void update( ICacheElement<K, V> item, long listenerId )
- {
- if ( maxQueueSize > 0 )
- {
- PutEvent<K, V> event = new PutEvent<>( item, listenerId );
- addQueue( event );
- }
- // Zombies have no inner life
- }
-
- /**
- * Adds a removeAll event to the queue if the maxSize is greater than 0;
- * <p>
- * @param cacheName - region name
- * @param key - item key
- * @param listenerId - identifies the caller.
- */
- @Override
- public void remove( String cacheName, K key, long listenerId )
- {
- if ( maxQueueSize > 0 )
- {
- RemoveEvent<K> event = new RemoveEvent<>( cacheName, key, listenerId );
- addQueue( event );
- }
- // Zombies have no inner life
- }
-
- /**
- * Adds a removeAll event to the queue if the maxSize is greater than 0;
- * <p>
- * @param cacheName - name of the region
- * @param listenerId - identifies the caller.
- */
- @Override
- public void removeAll( String cacheName, long listenerId )
- {
- if ( maxQueueSize > 0 )
- {
- RemoveAllEvent event = new RemoveAllEvent( cacheName, listenerId );
- addQueue( event );
- }
- // Zombies have no inner life
- }
-
- /**
- * Does nothing. Gets are synchronous and cannot be added to a queue.
- * <p>
- * @param cacheName - region name
- * @param key - item key
- * @param requesterId - identifies the caller.
- * @return null
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> get( String cacheName, K key, long requesterId )
- throws IOException
- {
- // Zombies have no inner life
- return null;
- }
-
- /**
- * Does nothing.
- * <p>
- * @param cacheName
- * @param pattern
- * @param requesterId
- * @return empty map
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern, long requesterId )
- throws IOException
- {
- return Collections.emptyMap();
- }
-
- /**
- * @param cacheName - region name
- * @param keys - item key
- * @param requesterId - identity of the caller
- * @return an empty map. zombies have no internal data
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys, long requesterId )
- {
- return new HashMap<>();
- }
-
- /**
- * Does nothing.
- * <p>
- * @param cacheName - region name
- * @return empty set
- */
- @Override
- public Set<K> getKeySet( String cacheName )
- {
- return Collections.emptySet();
- }
-
- /**
- * Walk the queue, calling the service for each queue operation.
- * <p>
- * @param service
- * @throws Exception
- */
- public synchronized void propagateEvents( ICacheServiceNonLocal<K, V> service )
- throws Exception
- {
- int cnt = 0;
- log.info( "Propagating events to the new ICacheServiceNonLocal." );
- ElapsedTimer timer = new ElapsedTimer();
- while ( !queue.isEmpty() )
- {
- cnt++;
-
- // for each item, call the appropriate service method
- ZombieEvent event = queue.poll();
-
- if ( event instanceof PutEvent )
- {
- @SuppressWarnings("unchecked") // Type checked by instanceof
- PutEvent<K, V> putEvent = (PutEvent<K, V>) event;
- service.update( putEvent.element, event.requesterId );
- }
- else if ( event instanceof RemoveEvent )
- {
- @SuppressWarnings("unchecked") // Type checked by instanceof
- RemoveEvent<K> removeEvent = (RemoveEvent<K>) event;
- service.remove( event.cacheName, removeEvent.key, event.requesterId );
- }
- else if ( event instanceof RemoveAllEvent )
- {
- service.removeAll( event.cacheName, event.requesterId );
- }
- }
- log.info( "Propagated {0} events to the new ICacheServiceNonLocal in {1}",
- cnt, timer.getElapsedTimeString() );
- }
-
- /**
- * Base of the other events.
- */
- protected static abstract class ZombieEvent
- {
- /** The name of the region. */
- String cacheName;
-
- /** The id of the requester */
- long requesterId;
- }
-
- /**
- * A basic put event.
- */
- private static class PutEvent<K, V>
- extends ZombieEvent
- {
- /** The element to put */
- ICacheElement<K, V> element;
-
- /**
- * Set the element
- * @param element
- * @param requesterId
- */
- public PutEvent( ICacheElement<K, V> element, long requesterId )
- {
- this.requesterId = requesterId;
- this.element = element;
- }
- }
-
- /**
- * A basic Remove event.
- */
- private static class RemoveEvent<K>
- extends ZombieEvent
- {
- /** The key to remove */
- K key;
-
- /**
- * Set the element
- * @param cacheName
- * @param key
- * @param requesterId
- */
- public RemoveEvent( String cacheName, K key, long requesterId )
- {
- this.cacheName = cacheName;
- this.requesterId = requesterId;
- this.key = key;
- }
- }
-
- /**
- * A basic RemoveAll event.
- */
- private static class RemoveAllEvent
- extends ZombieEvent
- {
- /**
- * @param cacheName
- * @param requesterId
- */
- public RemoveAllEvent( String cacheName, long requesterId )
- {
- this.cacheName = cacheName;
- this.requesterId = requesterId;
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/ZombieCacheWatch.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/ZombieCacheWatch.java
deleted file mode 100644
index 8a17e57..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/ZombieCacheWatch.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICacheListener;
-import org.apache.commons.jcs.engine.behavior.ICacheObserver;
-import org.apache.commons.jcs.engine.behavior.IZombie;
-
-/**
- * Zombie Observer.
- */
-public class ZombieCacheWatch
- implements ICacheObserver, IZombie
-{
- /**
- * Adds a feature to the CacheListener attribute of the ZombieCacheWatch object
- * <p>
- * @param cacheName The feature to be added to the CacheListener attribute
- * @param obj The feature to be added to the CacheListener attribute
- */
- @Override
- public <K, V> void addCacheListener( String cacheName, ICacheListener<K, V> obj )
- {
- // empty
- }
-
- /**
- * Adds a feature to the CacheListener attribute of the ZombieCacheWatch object
- * <p>
- * @param obj The feature to be added to the CacheListener attribute
- */
- @Override
- public <K, V> void addCacheListener( ICacheListener<K, V> obj )
- {
- // empty
- }
-
- /**
- * @param cacheName
- * @param obj
- */
- @Override
- public <K, V> void removeCacheListener( String cacheName, ICacheListener<K, V> obj )
- {
- // empty
- }
-
- /**
- * @param obj
- */
- @Override
- public <K, V> void removeCacheListener( ICacheListener<K, V> obj )
- {
- // empty
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICache.java
deleted file mode 100644
index 1dd0b7f..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICache.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.Set;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.match.behavior.IKeyMatcher;
-
-/**
- * This is the top level interface for all cache like structures. It defines the methods used
- * internally by JCS to access, modify, and instrument such structures.
- *
- * This allows for a suite of reusable components for accessing such structures, for example
- * asynchronous access via an event queue.
- */
-public interface ICache<K, V>
- extends ICacheType
-{
- /** Delimiter of a cache name component. This is used for hierarchical deletion */
- String NAME_COMPONENT_DELIMITER = ":";
-
- /**
- * Puts an item to the cache.
- *
- * @param element
- * @throws IOException
- */
- void update( ICacheElement<K, V> element )
- throws IOException;
-
- /**
- * Gets an item from the cache.
- *
- * @param key
- * @return a cache element, or null if there is no data in cache for this key
- * @throws IOException
- */
- ICacheElement<K, V> get( K key )
- throws IOException;
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- *
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no data in cache for any of these keys
- * @throws IOException
- */
- Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
- throws IOException;
-
- /**
- * Gets items from the cache matching the given pattern. Items from memory will replace those from remote sources.
- *
- * This only works with string keys. It's too expensive to do a toString on every key.
- *
- * Auxiliaries will do their best to handle simple expressions. For instance, the JDBC disk cache will convert * to % and . to _
- *
- * @param pattern
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no data matching the pattern.
- * @throws IOException
- */
- Map<K, ICacheElement<K, V>> getMatching(String pattern)
- throws IOException;
-
- /**
- * Removes an item from the cache.
- *
- * @param key
- * @return false if there was an error in removal
- * @throws IOException
- */
- boolean remove( K key )
- throws IOException;
-
- /**
- * Removes all cached items from the cache.
- *
- * @throws IOException
- */
- void removeAll()
- throws IOException;
-
- /**
- * Prepares for shutdown.
- * @throws IOException
- */
- void dispose()
- throws IOException;
-
- /**
- * Returns the current cache size in number of elements.
- *
- * @return number of elements
- */
- int getSize();
-
- /**
- * Returns the cache status.
- *
- * @return Alive or Error
- */
- CacheStatus getStatus();
-
- /**
- * Returns the cache stats.
- *
- * @return String of important historical information.
- */
- String getStats();
-
- /**
- * Returns the cache name.
- *
- * @return usually the region name.
- */
- String getCacheName();
-
- /**
- * Sets the key matcher used by get matching.
- *
- * @param keyMatcher
- */
- void setKeyMatcher( IKeyMatcher<K> keyMatcher );
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheElement.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheElement.java
deleted file mode 100644
index acb82ea..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheElement.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-
-/**
- * Every item is the cache is wrapped in an ICacheElement. This contains
- * information about the element: the region name, the key, the value, and the
- * element attributes.
- * <p>
- * The element attributes have lots of useful information about each element,
- * such as when they were created, how long they have to live, and if they are
- * allowed to be spooled, etc.
- *
- */
-public interface ICacheElement<K, V>
- extends Serializable
-{
-
- /**
- * Gets the cacheName attribute of the ICacheElement<K, V> object. The cacheName
- * is also known as the region name.
- *
- * @return The cacheName value
- */
- String getCacheName();
-
- /**
- * Gets the key attribute of the ICacheElement<K, V> object
- *
- * @return The key value
- */
- K getKey();
-
- /**
- * Gets the val attribute of the ICacheElement<K, V> object
- *
- * @return The val value
- */
- V getVal();
-
- /**
- * Gets the attributes attribute of the ICacheElement<K, V> object
- *
- * @return The attributes value
- */
- IElementAttributes getElementAttributes();
-
- /**
- * Sets the attributes attribute of the ICacheElement<K, V> object
- *
- * @param attr
- * The new attributes value
- */
- void setElementAttributes( IElementAttributes attr );
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheElementSerialized.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheElementSerialized.java
deleted file mode 100644
index 1d80da6..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheElementSerialized.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-/*
- * 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.
- */
-
-/**
- * This interface defines the behavior of the serialized element wrapper.
- * <p>
- * The value is stored as a byte array. This should allow for a variety of serialization mechanisms.
- * <p>
- * This currently extends ICacheElement<K, V> for backward compatibility.
- *<p>
- * @author Aaron Smuts
- */
-public interface ICacheElementSerialized<K, V>
- extends ICacheElement<K, V>
-{
- /**
- * Gets the value attribute of the ICacheElementSerialized object. This is the value the client
- * cached serialized by some mechanism.
- *<p>
- * @return The serialized value
- */
- byte[] getSerializedValue();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheEventQueue.java
deleted file mode 100644
index 3676385..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheEventQueue.java
+++ /dev/null
@@ -1,125 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-import java.io.IOException;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-
-/**
- * Interface for a cache event queue. An event queue is used to propagate
- * ordered cache events to one and only one target listener.
- */
-public interface ICacheEventQueue<K, V>
-{
- enum QueueType
- {
- /** Does not use a thread pool. */
- SINGLE,
-
- /** Uses a thread pool. */
- POOLED
- }
-
- /**
- * Return the type of event queue we are using, either single or pooled.
- * <p>
- * @return the queue type: single or pooled
- */
- QueueType getQueueType();
-
- /**
- * Adds a feature to the PutEvent attribute of the ICacheEventQueue object
- * <p>
- * @param ce
- * The feature to be added to the PutEvent attribute
- * @throws IOException
- */
- void addPutEvent( ICacheElement<K, V> ce )
- throws IOException;
-
- /**
- * Adds a feature to the RemoveEvent attribute of the ICacheEventQueue
- * object
- * <p>
- * @param key
- * The feature to be added to the RemoveEvent attribute
- * @throws IOException
- */
- void addRemoveEvent( K key )
- throws IOException;
-
- /**
- * Adds a feature to the RemoveAllEvent attribute of the ICacheEventQueue
- * object
- * <p>
- * @throws IOException
- */
- void addRemoveAllEvent()
- throws IOException;
-
- /**
- * Adds a feature to the DisposeEvent attribute of the ICacheEventQueue
- * object
- * <p>
- * @throws IOException
- */
- void addDisposeEvent()
- throws IOException;
-
- /**
- * Gets the listenerId attribute of the ICacheEventQueue object
- *
- * @return The listenerId value
- */
- long getListenerId();
-
- /** Description of the Method */
- void destroy();
-
- /**
- * A Queue is working unless it has reached its max failure count.
- * <p>
- * @return boolean
- */
- boolean isWorking();
-
- /**
- * Returns the number of elements in the queue. If the queue cannot
- * determine the size accurately it will return 1.
- * <p>
- * @return number of items in the queue.
- */
- int size();
-
- /**
- * Are there elements in the queue.
- * <p>
- * @return true if there are stil elements.
- */
- boolean isEmpty();
-
- /**
- * Returns the historical and statistical data for an event queue cache.
- * <p>
- * @return IStats
- */
- IStats getStatistics();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheListener.java
deleted file mode 100644
index 5e15913..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheListener.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-
-/**
- * Used to receive a cache event notification.
- * <p>
- * Note: objects which implement this interface are local listeners to cache changes, whereas
- * objects which implement IRmiCacheListener are remote listeners to cache changes.
- */
-public interface ICacheListener<K, V>
-{
- /**
- * Notifies the subscribers for a cache entry update.
- * <p>
- * @param item
- * @throws IOException
- */
- void handlePut( ICacheElement<K, V> item )
- throws IOException;
-
- /**
- * Notifies the subscribers for a cache entry removal.
- * <p>
- * @param cacheName
- * @param key
- * @throws IOException
- */
- void handleRemove( String cacheName, K key )
- throws IOException;
-
- /**
- * Notifies the subscribers for a cache remove-all.
- * <p>
- * @param cacheName
- * @throws IOException
- */
- void handleRemoveAll( String cacheName )
- throws IOException;
-
- /**
- * Notifies the subscribers for freeing up the named cache.
- * <p>
- * @param cacheName
- * @throws IOException
- */
- void handleDispose( String cacheName )
- throws IOException;
-
- /**
- * sets unique identifier of listener home
- * <p>
- * @param id The new listenerId value
- * @throws IOException
- */
- void setListenerId( long id )
- throws IOException;
-
- /**
- * Gets the listenerId attribute of the ICacheListener object
- * <p>
- * @return The listenerId value
- * @throws IOException
- */
- long getListenerId()
- throws IOException;
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheObserver.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheObserver.java
deleted file mode 100644
index 11c9a05..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheObserver.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-
-/**
- * Used to register interest in receiving cache changes. <br>
- * <br>
- * Note: server which implements this interface provides a local cache event
- * notification service, whereas server which implements IRmiCacheWatch provides
- * a remote cache event notification service.
- *
- */
-public interface ICacheObserver
-{
- /**
- * Subscribes to the specified cache.
- *
- * @param cacheName
- * the specified cache.
- * @param obj
- * object to notify for cache changes.
- * @throws IOException
- */
- <K, V> void addCacheListener( String cacheName, ICacheListener<K, V> obj )
- throws IOException;
-
- //, CacheNotFoundException;
-
- /**
- * Subscribes to all caches.
- *
- * @param obj
- * object to notify for all cache changes.
- * @throws IOException
- */
- <K, V> void addCacheListener( ICacheListener<K, V> obj )
- throws IOException;
-
- /**
- * Unsubscribes from the specified cache.
- * @param cacheName
- *
- * @param obj
- * existing subscriber.
- * @throws IOException
- */
- <K, V> void removeCacheListener( String cacheName, ICacheListener<K, V> obj )
- throws IOException;
-
- /**
- * Unsubscribes from all caches.
- *
- * @param obj
- * existing subscriber.
- * @throws IOException
- */
- <K, V> void removeCacheListener( ICacheListener<K, V> obj )
- throws IOException;
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheService.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheService.java
deleted file mode 100644
index 9f4aca5..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheService.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.access.exception.ObjectExistsException;
-import org.apache.commons.jcs.access.exception.ObjectNotFoundException;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Used to retrieve and update the cache.
- * <p>
- * Note: server which implements this interface provides a local cache service, whereas server which
- * implements IRmiCacheService provides a remote cache service.
- */
-public interface ICacheService<K, V>
-{
- /**
- * Puts a cache item to the cache.
- * <p>
- * @param item
- * @throws ObjectExistsException
- * @throws IOException
- */
- void update( ICacheElement<K, V> item )
- throws ObjectExistsException, IOException;
-
- /**
- * Returns a cache bean from the specified cache; or null if the key does not exist.
- * <p>
- * @param cacheName
- * @param key
- * @return the ICacheElement<K, V> or null if not found
- * @throws ObjectNotFoundException
- * @throws IOException
- */
- ICacheElement<K, V> get( String cacheName, K key )
- throws ObjectNotFoundException, IOException;
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * @param cacheName
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- * @throws ObjectNotFoundException
- * @throws IOException
- */
- Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys )
- throws ObjectNotFoundException, IOException;
-
- /**
- * Gets multiple items from the cache matching the pattern.
- * <p>
- * @param cacheName
- * @param pattern
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache matching the pattern.
- * @throws IOException
- */
- Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern )
- throws IOException;
-
- /**
- * Removes the given key from the specified cache.
- * <p>
- * @param cacheName
- * @param key
- * @throws IOException
- */
- void remove( String cacheName, K key )
- throws IOException;
-
- /**
- * Remove all keys from the specified cache.
- * @param cacheName
- * @throws IOException
- */
- void removeAll( String cacheName )
- throws IOException;
-
- /**
- * Frees the specified cache.
- * <p>
- * @param cacheName
- * @throws IOException
- */
- void dispose( String cacheName )
- throws IOException;
-
- /**
- * Frees all caches.
- * @throws IOException
- */
- void release()
- throws IOException;
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheServiceAdmin.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheServiceAdmin.java
deleted file mode 100644
index 856ff51..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheServiceAdmin.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-
-/**
- * Description of the Interface
- *
- */
-public interface ICacheServiceAdmin
-{
-
- /**
- * Gets the stats attribute of the ICacheServiceAdmin object
- *
- * @return The stats value
- * @throws IOException
- */
- String getStats()
- throws IOException;
-
- /** Description of the Method
- * @throws IOException*/
- void shutdown()
- throws IOException;
-
- /** Description of the Method
- * @param host
- * @param port
- * @throws IOException*/
- void shutdown( String host, int port )
- throws IOException;
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheServiceNonLocal.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheServiceNonLocal.java
deleted file mode 100644
index 4fbf29f..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheServiceNonLocal.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.rmi.Remote;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Used to retrieve and update non local caches, such as the remote and lateral caches. Unlike
- * ICacheService, the methods here have a requester id. This allows us to avoid propagating events
- * to ourself.
- * <p>
- * TODO consider not extending ICacheService
- */
-public interface ICacheServiceNonLocal<K, V>
- extends Remote, ICacheService<K, V>
-{
- /**
- * Puts a cache item to the cache.
- * <p>
- * @param item
- * @param requesterId
- * @throws IOException
- */
- void update( ICacheElement<K, V> item, long requesterId )
- throws IOException;
-
- /**
- * Removes the given key from the specified cache.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @throws IOException
- */
- void remove( String cacheName, K key, long requesterId )
- throws IOException;
-
- /**
- * Remove all keys from the specified cache.
- * <p>
- * @param cacheName
- * @param requesterId
- * @throws IOException
- */
- void removeAll( String cacheName, long requesterId )
- throws IOException;
-
- /**
- * Returns a cache bean from the specified cache; or null if the key does not exist.
- * <p>
- * Adding the requester id, allows the cache to determine the source of the get.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- * @return ICacheElement
- * @throws IOException
- */
- ICacheElement<K, V> get( String cacheName, K key, long requesterId )
- throws IOException;
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * @param cacheName
- * @param keys
- * @param requesterId
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- * @throws IOException
- */
- Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys, long requesterId )
- throws IOException;
-
- /**
- * Gets multiple items from the cache matching the pattern.
- * <p>
- * @param cacheName
- * @param pattern
- * @param requesterId
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache matching the pattern.
- * @throws IOException
- */
- Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern, long requesterId )
- throws IOException;
-
- /**
- * Get a set of the keys for all elements in the cache.
- * <p>
- * @param cacheName the name of the cache
- * @return a set of the key type
- * TODO This should probably be done in chunks with a range passed in. This
- * will be a problem if someone puts a 1,000,000 or so items in a
- * region.
- */
- Set<K> getKeySet( String cacheName ) throws IOException;
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheType.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheType.java
deleted file mode 100644
index 3828f3a..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICacheType.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-/*
- * 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.
- */
-
-/**
- * Interface implemented by a specific cache.
- *
- */
-public interface ICacheType
-{
- enum CacheType {
- /** Composite/ memory cache type, central hub. */
- CACHE_HUB,
-
- /** Disk cache type. */
- DISK_CACHE,
-
- /** Lateral cache type. */
- LATERAL_CACHE,
-
- /** Remote cache type. */
- REMOTE_CACHE
- }
-
- /**
- * Returns the cache type.
- * <p>
- * @return The cacheType value
- */
- CacheType getCacheType();
-
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICompositeCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICompositeCacheAttributes.java
deleted file mode 100644
index 7d22e4e..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICompositeCacheAttributes.java
+++ /dev/null
@@ -1,244 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-
-/**
- * This defines the minimal behavior for the Cache Configuration settings.
- */
-public interface ICompositeCacheAttributes
- extends Serializable, Cloneable
-{
- enum DiskUsagePattern
- {
- /** Items will only go to disk when the memory limit is reached. This is the default. */
- SWAP,
-
- /**
- * Items will go to disk on a normal put. If The disk usage pattern is UPDATE, the swap will be
- * disabled.
- */
- UPDATE
- }
-
- /**
- * SetMaxObjects is used to set the attribute to determine the maximum
- * number of objects allowed in the memory cache. If the max number of
- * objects or the cache size is set, the default for the one not set is
- * ignored. If both are set, both are used to determine the capacity of the
- * cache, i.e., object will be removed from the cache if either limit is
- * reached. TODO: move to MemoryCache config file.
- * <p>
- * @param size
- * The new maxObjects value
- */
- void setMaxObjects( int size );
-
- /**
- * Gets the maxObjects attribute of the ICompositeCacheAttributes object
- * <p>
- * @return The maxObjects value
- */
- int getMaxObjects();
-
- /**
- * Sets the useDisk attribute of the ICompositeCacheAttributes object
- * <p>
- * @param useDisk
- * The new useDisk value
- */
- void setUseDisk( boolean useDisk );
-
- /**
- * Gets the useDisk attribute of the ICompositeCacheAttributes object
- * <p>
- * @return The useDisk value
- */
- boolean isUseDisk();
-
- /**
- * set whether the cache should use a lateral cache
- * <p>
- * @param d
- * The new useLateral value
- */
- void setUseLateral( boolean d );
-
- /**
- * Gets the useLateral attribute of the ICompositeCacheAttributes object
- * <p>
- * @return The useLateral value
- */
- boolean isUseLateral();
-
- /**
- * Sets whether the cache is remote enabled
- * <p>
- * @param isRemote
- * The new useRemote value
- */
- void setUseRemote( boolean isRemote );
-
- /**
- * returns whether the cache is remote enabled
- * <p>
- * @return The useRemote value
- */
- boolean isUseRemote();
-
- /**
- * Sets the name of the cache, referenced by the appropriate manager.
- * <p>
- * @param s
- * The new cacheName value
- */
- void setCacheName( String s );
-
- /**
- * Gets the cacheName attribute of the ICompositeCacheAttributes object
- * <p>
- * @return The cacheName value
- */
- String getCacheName();
-
- /**
- * Sets the name of the MemoryCache, referenced by the appropriate manager.
- * TODO: create a separate memory cache attribute class.
- * <p>
- * @param s
- * The new memoryCacheName value
- */
- void setMemoryCacheName( String s );
-
- /**
- * Gets the memoryCacheName attribute of the ICompositeCacheAttributes
- * object
- * <p>
- * @return The memoryCacheName value
- */
- String getMemoryCacheName();
-
- /**
- * Whether the memory cache should perform background memory shrinkage.
- * <p>
- * @param useShrinker
- * The new UseMemoryShrinker value
- */
- void setUseMemoryShrinker( boolean useShrinker );
-
- /**
- * Whether the memory cache should perform background memory shrinkage.
- * <p>
- * @return The UseMemoryShrinker value
- */
- boolean isUseMemoryShrinker();
-
- /**
- * If UseMemoryShrinker is true the memory cache should auto-expire elements
- * to reclaim space.
- * <p>
- * @param seconds
- * The new MaxMemoryIdleTimeSeconds value
- */
- void setMaxMemoryIdleTimeSeconds( long seconds );
-
- /**
- * If UseMemoryShrinker is true the memory cache should auto-expire elements
- * to reclaim space.
- * <p>
- * @return The MaxMemoryIdleTimeSeconds value
- */
- long getMaxMemoryIdleTimeSeconds();
-
- /**
- * If UseMemoryShrinker is true the memory cache should auto-expire elements
- * to reclaim space. This sets the shrinker interval.
- * <p>
- * @param seconds
- * The new ShrinkerIntervalSeconds value
- */
- void setShrinkerIntervalSeconds( long seconds );
-
- /**
- * If UseMemoryShrinker is true the memory cache should auto-expire elements
- * to reclaim space. This gets the shrinker interval.
- * <p>
- * @return The ShrinkerIntervalSeconds value
- */
- long getShrinkerIntervalSeconds();
-
- /**
- * If UseMemoryShrinker is true the memory cache should auto-expire elements
- * to reclaim space. This sets the maximum number of items to spool per run.
- * <p>
- * @param maxSpoolPerRun
- * The new maxSpoolPerRun value
- */
- void setMaxSpoolPerRun( int maxSpoolPerRun );
-
- /**
- * If UseMemoryShrinker is true the memory cache should auto-expire elements
- * to reclaim space. This gets the maximum number of items to spool per run.
- * <p>
- * @return The maxSpoolPerRun value
- */
- int getMaxSpoolPerRun();
-
- /**
- * By default this is SWAP_ONLY.
- * <p>
- * @param diskUsagePattern The diskUsagePattern to set.
- */
- void setDiskUsagePattern( DiskUsagePattern diskUsagePattern );
-
- /**
- * Translates the name to the disk usage pattern short value.
- * <p>
- * The allowed values are SWAP and UPDATE.
- * <p>
- * @param diskUsagePatternName The diskUsagePattern to set.
- */
- void setDiskUsagePatternName( String diskUsagePatternName );
-
- /**
- * @return Returns the diskUsagePattern.
- */
- DiskUsagePattern getDiskUsagePattern();
-
- /**
- * Number to send to disk at at time when memory is full.
- * <p>
- * @return int
- */
- int getSpoolChunkSize();
-
- /**
- * Number to send to disk at a time.
- * <p>
- * @param spoolChunkSize
- */
- void setSpoolChunkSize( int spoolChunkSize );
-
- /**
- * Clone object
- */
- ICompositeCacheAttributes clone();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICompositeCacheManager.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICompositeCacheManager.java
deleted file mode 100644
index caf499c..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/ICompositeCacheManager.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-
-import java.util.Properties;
-
-/**
- * I need the interface so I can plug in mock managers for testing.
- *
- * @author Aaron Smuts
- */
-public interface ICompositeCacheManager extends IShutdownObservable
-{
- /**
- * Gets the cache attribute of the CacheHub object
- *
- * @param cacheName
- * @return CompositeCache
- */
- <K, V> CompositeCache<K, V> getCache( String cacheName );
-
- /**
- * Gets the auxiliary cache attribute of the CacheHub object
- *
- * @param auxName
- * @param cacheName
- * @return AuxiliaryCache
- */
- <K, V> AuxiliaryCache<K, V> getAuxiliaryCache( String auxName, String cacheName );
-
- /**
- * This is exposed so other manager can get access to the props.
- * <p>
- * @return the configurationProperties
- */
- Properties getConfigurationProperties();
-
- /**
- * Gets stats for debugging.
- * <p>
- * @return String
- */
- String getStats();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IElementAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IElementAttributes.java
deleted file mode 100644
index 116d187..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IElementAttributes.java
+++ /dev/null
@@ -1,204 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.jcs.engine.control.event.behavior.IElementEventHandler;
-
-/**
- * Interface for cache element attributes classes. Every item is the cache is associated with an
- * element attributes object. It is used to track the life of the object as well as to restrict its
- * behavior. By default, elements get a clone of the region's attributes.
- */
-public interface IElementAttributes extends Serializable, Cloneable
-{
- /**
- * Sets the maxLife attribute of the IAttributes object.
- * <p>
- * @param mls The new MaxLifeSeconds value
- */
- void setMaxLife(long mls);
-
- /**
- * Sets the maxLife attribute of the IAttributes object. How many seconds it can live after
- * creation.
- * <p>
- * If this is exceeded the element will not be returned, instead it will be removed. It will be
- * removed on retrieval, or removed actively if the memory shrinker is turned on.
- * @return The MaxLifeSeconds value
- */
- long getMaxLife();
-
- /**
- * Sets the idleTime attribute of the IAttributes object. This is the maximum time the item can
- * be idle in the cache, that is not accessed.
- * <p>
- * If this is exceeded the element will not be returned, instead it will be removed. It will be
- * removed on retrieval, or removed actively if the memory shrinker is turned on.
- * @param idle The new idleTime value
- */
- void setIdleTime( long idle );
-
- /**
- * Size in bytes. This is not used except in the admin pages. It will be 0 by default
- * and is only updated when the element is serialized.
- * <p>
- * @param size The new size value
- */
- void setSize( int size );
-
- /**
- * Gets the size attribute of the IAttributes object
- * <p>
- * @return The size value
- */
- int getSize();
-
- /**
- * Gets the createTime attribute of the IAttributes object.
- * <p>
- * This should be the current time in milliseconds returned by the sysutem call when the element
- * is put in the cache.
- * <p>
- * Putting an item in the cache overrides any existing items.
- * @return The createTime value
- */
- long getCreateTime();
-
- /**
- * Gets the LastAccess attribute of the IAttributes object.
- * <p>
- * @return The LastAccess value.
- */
- long getLastAccessTime();
-
- /**
- * Sets the LastAccessTime as now of the IElementAttributes object
- */
- void setLastAccessTimeNow();
-
- /**
- * Gets the idleTime attribute of the IAttributes object
- * @return The idleTime value
- */
- long getIdleTime();
-
- /**
- * Gets the time left to live of the IAttributes object.
- * <p>
- * This is the (max life + create time) - current time.
- * @return The TimeToLiveSeconds value
- */
- long getTimeToLiveSeconds();
-
- /**
- * Can this item be spooled to disk
- * <p>
- * By default this is true.
- * @return The spoolable value
- */
- boolean getIsSpool();
-
- /**
- * Sets the isSpool attribute of the IElementAttributes object
- * <p>
- * By default this is true.
- * @param val The new isSpool value
- */
- void setIsSpool( boolean val );
-
- /**
- * Is this item laterally distributable. Can it be sent to auxiliaries of type lateral.
- * <p>
- * By default this is true.
- * @return The isLateral value
- */
- boolean getIsLateral();
-
- /**
- * Sets the isLateral attribute of the IElementAttributes object
- * <p>
- * By default this is true.
- * @param val The new isLateral value
- */
- void setIsLateral( boolean val );
-
- /**
- * Can this item be sent to the remote cache.
- * <p>
- * By default this is true.
- * @return The isRemote value
- */
- boolean getIsRemote();
-
- /**
- * Sets the isRemote attribute of the IElementAttributes object.
- * <p>
- * By default this is true.
- * @param val The new isRemote value
- */
- void setIsRemote( boolean val );
-
- /**
- * This turns off expiration if it is true.
- * @return The IsEternal value
- */
- boolean getIsEternal();
-
- /**
- * Sets the isEternal attribute of the IElementAttributes object
- * @param val The new isEternal value
- */
- void setIsEternal( boolean val );
-
- /**
- * Adds a ElementEventHandler. Handler's can be registered for multiple events. A registered
- * handler will be called at every recognized event.
- * @param eventHandler The feature to be added to the ElementEventHandler
- */
- void addElementEventHandler( IElementEventHandler eventHandler );
-
- /**
- * Gets the elementEventHandlers.
- * <p>
- * Event handlers are transient. The only events defined are in memory events. All handlers are
- * lost if the item goes to disk.
- * @return The elementEventHandlers value, null if there are none
- */
- ArrayList<IElementEventHandler> getElementEventHandlers();
-
- /**
- * Sets the eventHandlers of the IElementAttributes object
- * @param eventHandlers value
- */
- void addElementEventHandlers( List<IElementEventHandler> eventHandlers );
-
- long getTimeFactorForMilliseconds();
-
- void setTimeFactorForMilliseconds(long factor);
-
- /**
- * Clone object
- */
- IElementAttributes clone();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IElementSerializer.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IElementSerializer.java
deleted file mode 100644
index 2a74713..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IElementSerializer.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-
-/**
- * Defines the behavior for cache element serializers. This layer of abstraction allows us to plug
- * in different serialization mechanisms, such as a compressing standard serializer.
- * <p>
- * @author Aaron Smuts
- */
-public interface IElementSerializer
-{
- /**
- * Turns an object into a byte array.
- * @param obj
- * @return byte[]
- * @throws IOException
- */
- <T> byte[] serialize( T obj )
- throws IOException;
-
- /**
- * Turns a byte array into an object.
- * @param bytes data bytes
- * @param loader class loader to use
- * @return Object
- * @throws IOException
- * @throws ClassNotFoundException thrown if we don't know the object.
- */
- <T> T deSerialize( byte[] bytes, ClassLoader loader )
- throws IOException, ClassNotFoundException;
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IProvideScheduler.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IProvideScheduler.java
deleted file mode 100644
index 29ad9d2..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IProvideScheduler.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-/*
- * 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.
- */
-
-import java.util.concurrent.ScheduledExecutorService;
-
-
-/**
- * Marker interface for providers of the central ScheduledExecutorService
- * <p>
- * @author Thomas Vandahl
- *
- */
-public interface IProvideScheduler
-{
- /**
- * Get an instance of a central ScheduledExecutorService
- * @return the central scheduler
- */
- ScheduledExecutorService getScheduledExecutorService();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IRequireScheduler.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IRequireScheduler.java
deleted file mode 100644
index 09ea8a7..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IRequireScheduler.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-/*
- * 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.
- */
-
-import java.util.concurrent.ScheduledExecutorService;
-
-
-/**
- * Marker interface to allow the injection of a central ScheduledExecutorService
- * for all modules requiring scheduled background operations.
- * <p>
- * @author Thomas Vandahl
- *
- */
-public interface IRequireScheduler
-{
- /**
- * Inject an instance of a central ScheduledExecutorService
- * @param scheduledExecutor
- */
- void setScheduledExecutorService( ScheduledExecutorService scheduledExecutor );
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IShutdownObservable.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IShutdownObservable.java
deleted file mode 100644
index c428037..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IShutdownObservable.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-/*
- * 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.
- */
-
-/**
- * ShutdownObservers can observe ShutdownObservable objects.
- * The CacheManager is the primary observable that this is intended for.
- * <p>
- * Most shutdown operations will occur outside this framework for now. The initial
- * goal is to allow background threads that are not reachable through any reference
- * that the cache manager maintains to be killed on shutdown.
- * <p>
- * Perhaps the composite cache itself should be the observable object.
- * It doesn't make much of a difference. There are some problems with
- * region by region shutdown. Some auxiliaries are local. They will
- * need to track when every region has shutdown before doing things like
- * closing the socket with a lateral.
- * <p>
- * @author Aaron Smuts
- *
- */
-public interface IShutdownObservable
-{
-
- /**
- * Registers an observer with the observable object.
- * @param observer
- */
- void registerShutdownObserver( IShutdownObserver observer );
-
- /**
- * Deregisters the observer with the observable.
- *
- * @param observer
- */
- void deregisterShutdownObserver( IShutdownObserver observer );
-
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IShutdownObserver.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IShutdownObserver.java
deleted file mode 100644
index 22b4052..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IShutdownObserver.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-/*
- * 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.
- */
-
-/**
- * This interface is required of all shutdown observers. These observers
- * can observer ShutdownObservable objects. The CacheManager is the primary
- * observable that this is intended for.
- * <p>
- * Most shutdown operations will occur outside this framework for now. The initial
- * goal is to allow background threads that are not reachable through any reference
- * that the cache manager maintains to be killed on shutdown.
- *
- * @author Aaron Smuts
- *
- */
-public interface IShutdownObserver
-{
- /**
- * Tells the observer that the observable has received a shutdown command.
- *
- */
- void shutdown();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IZombie.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IZombie.java
deleted file mode 100644
index 2c726c6..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/IZombie.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.apache.commons.jcs.engine.behavior;
-
-/*
- * 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.
- */
-
-/**
- * Interface to mark an object as zombie for error recovery purposes.
- *
- */
-public interface IZombie
-{
- // Zombies have no inner life.
- // No qaulia found.
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/CompositeCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/CompositeCache.java
deleted file mode 100644
index 7601996..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/CompositeCache.java
+++ /dev/null
@@ -1,1693 +0,0 @@
-package org.apache.commons.jcs.engine.control;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.access.exception.ObjectNotFoundException;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.behavior.ICache;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes.DiskUsagePattern;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.behavior.IRequireScheduler;
-import org.apache.commons.jcs.engine.control.event.ElementEvent;
-import org.apache.commons.jcs.engine.control.event.behavior.ElementEventType;
-import org.apache.commons.jcs.engine.control.event.behavior.IElementEvent;
-import org.apache.commons.jcs.engine.control.event.behavior.IElementEventHandler;
-import org.apache.commons.jcs.engine.control.event.behavior.IElementEventQueue;
-import org.apache.commons.jcs.engine.control.group.GroupId;
-import org.apache.commons.jcs.engine.match.KeyMatcherPatternImpl;
-import org.apache.commons.jcs.engine.match.behavior.IKeyMatcher;
-import org.apache.commons.jcs.engine.memory.behavior.IMemoryCache;
-import org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache;
-import org.apache.commons.jcs.engine.memory.shrinking.ShrinkerThread;
-import org.apache.commons.jcs.engine.stats.CacheStats;
-import org.apache.commons.jcs.engine.stats.StatElement;
-import org.apache.commons.jcs.engine.stats.behavior.ICacheStats;
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This is the primary hub for a single cache/region. It controls the flow of items through the
- * cache. The auxiliary and memory caches are plugged in here.
- * <p>
- * This is the core of a JCS region. Hence, this simple class is the core of JCS.
- */
-public class CompositeCache<K, V>
- implements ICache<K, V>, IRequireScheduler
-{
- /** log instance */
- private static final Log log = LogManager.getLog(CompositeCache.class);
-
- /**
- * EventQueue for handling element events. Lazy initialized. One for each region. To be more efficient, the manager
- * should pass a shared queue in.
- */
- private IElementEventQueue elementEventQ;
-
- /** Auxiliary caches. */
- @SuppressWarnings("unchecked") // OK because this is an empty array
- private AuxiliaryCache<K, V>[] auxCaches = new AuxiliaryCache[0];
-
- /** is this alive? */
- private AtomicBoolean alive;
-
- /** Region Elemental Attributes, default. */
- private IElementAttributes attr;
-
- /** Cache Attributes, for hub and memory auxiliary. */
- private ICompositeCacheAttributes cacheAttr;
-
- /** How many times update was called. */
- private AtomicLong updateCount;
-
- /** How many times remove was called. */
- private AtomicLong removeCount;
-
- /** Memory cache hit count */
- private AtomicLong hitCountRam;
-
- /** Auxiliary cache hit count (number of times found in ANY auxiliary) */
- private AtomicLong hitCountAux;
-
- /** Count of misses where element was not found. */
- private AtomicLong missCountNotFound;
-
- /** Count of misses where element was expired. */
- private AtomicLong missCountExpired;
-
- /** Cache manager. */
- private CompositeCacheManager cacheManager = null;
-
- /**
- * The cache hub can only have one memory cache. This could be made more flexible in the future,
- * but they are tied closely together. More than one doesn't make much sense.
- */
- private IMemoryCache<K, V> memCache;
-
- /** Key matcher used by the getMatching API */
- private IKeyMatcher<K> keyMatcher = new KeyMatcherPatternImpl<>();
-
- private ScheduledFuture<?> future;
-
- /**
- * Constructor for the Cache object
- * <p>
- * @param cattr The cache attribute
- * @param attr The default element attributes
- */
- public CompositeCache(ICompositeCacheAttributes cattr, IElementAttributes attr)
- {
- this.attr = attr;
- this.cacheAttr = cattr;
- this.alive = new AtomicBoolean(true);
- this.updateCount = new AtomicLong(0);
- this.removeCount = new AtomicLong(0);
- this.hitCountRam = new AtomicLong(0);
- this.hitCountAux = new AtomicLong(0);
- this.missCountNotFound = new AtomicLong(0);
- this.missCountExpired = new AtomicLong(0);
-
- createMemoryCache(cattr);
-
- log.info("Constructed cache with name [{0}] and cache attributes {1}",
- cacheAttr.getCacheName(), cattr);
- }
-
- /**
- * Injector for Element event queue
- *
- * @param queue
- */
- public void setElementEventQueue(IElementEventQueue queue)
- {
- this.elementEventQ = queue;
- }
-
- /**
- * Injector for cache manager
- *
- * @param manager
- */
- public void setCompositeCacheManager(CompositeCacheManager manager)
- {
- this.cacheManager = manager;
- }
-
- /**
- * @see org.apache.commons.jcs.engine.behavior.IRequireScheduler#setScheduledExecutorService(java.util.concurrent.ScheduledExecutorService)
- */
- @Override
- public void setScheduledExecutorService(ScheduledExecutorService scheduledExecutor)
- {
- if (cacheAttr.isUseMemoryShrinker())
- {
- future = scheduledExecutor.scheduleAtFixedRate(
- new ShrinkerThread<>(this), 0, cacheAttr.getShrinkerIntervalSeconds(),
- TimeUnit.SECONDS);
- }
- }
-
- /**
- * This sets the list of auxiliary caches for this region.
- * <p>
- * @param auxCaches
- */
- public void setAuxCaches(AuxiliaryCache<K, V>[] auxCaches)
- {
- this.auxCaches = auxCaches;
- }
-
- /**
- * Get the list of auxiliary caches for this region.
- * <p>
- * @return an array of auxiliary caches, may be empty, never null
- */
- public AuxiliaryCache<K, V>[] getAuxCaches()
- {
- return this.auxCaches;
- }
-
- /**
- * Standard update method.
- * <p>
- * @param ce
- * @throws IOException
- */
- @Override
- public void update(ICacheElement<K, V> ce)
- throws IOException
- {
- update(ce, false);
- }
-
- /**
- * Standard update method.
- * <p>
- * @param ce
- * @throws IOException
- */
- public void localUpdate(ICacheElement<K, V> ce)
- throws IOException
- {
- update(ce, true);
- }
-
- /**
- * Put an item into the cache. If it is localOnly, then do no notify remote or lateral
- * auxiliaries.
- * <p>
- * @param cacheElement the ICacheElement<K, V>
- * @param localOnly Whether the operation should be restricted to local auxiliaries.
- * @throws IOException
- */
- protected void update(ICacheElement<K, V> cacheElement, boolean localOnly)
- throws IOException
- {
-
- if (cacheElement.getKey() instanceof String
- && cacheElement.getKey().toString().endsWith(NAME_COMPONENT_DELIMITER))
- {
- throw new IllegalArgumentException("key must not end with " + NAME_COMPONENT_DELIMITER
- + " for a put operation");
- }
- else if (cacheElement.getKey() instanceof GroupId)
- {
- throw new IllegalArgumentException("key cannot be a GroupId " + " for a put operation");
- }
-
- log.debug("Updating memory cache {0}", () -> cacheElement.getKey());
-
- updateCount.incrementAndGet();
- memCache.update(cacheElement);
- updateAuxiliaries(cacheElement, localOnly);
-
- cacheElement.getElementAttributes().setLastAccessTimeNow();
- }
-
- /**
- * This method is responsible for updating the auxiliaries if they are present. If it is local
- * only, any lateral and remote auxiliaries will not be updated.
- * <p>
- * Before updating an auxiliary it checks to see if the element attributes permit the operation.
- * <p>
- * Disk auxiliaries are only updated if the disk cache is not merely used as a swap. If the disk
- * cache is merely a swap, then items will only go to disk when they overflow from memory.
- * <p>
- * This is called by update(cacheElement, localOnly) after it updates the memory cache.
- * <p>
- * This is protected to make it testable.
- * <p>
- * @param cacheElement
- * @param localOnly
- * @throws IOException
- */
- protected void updateAuxiliaries(ICacheElement<K, V> cacheElement, boolean localOnly)
- throws IOException
- {
- // UPDATE AUXILLIARY CACHES
- // There are 3 types of auxiliary caches: remote, lateral, and disk
- // more can be added if future auxiliary caches don't fit the model
- // You could run a database cache as either a remote or a local disk.
- // The types would describe the purpose.
- if (auxCaches.length > 0)
- {
- log.debug("Updating auxiliary caches");
- }
- else
- {
- log.debug("No auxiliary cache to update");
- }
-
- for (ICache<K, V> aux : auxCaches)
- {
- if (aux == null)
- {
- continue;
- }
-
- log.debug("Auxiliary cache type: {0}", aux.getCacheType());
-
- switch (aux.getCacheType())
- {
- // SEND TO REMOTE STORE
- case REMOTE_CACHE:
- log.debug("ce.getElementAttributes().getIsRemote() = {0}",
- () -> cacheElement.getElementAttributes().getIsRemote());
-
- if (cacheElement.getElementAttributes().getIsRemote() && !localOnly)
- {
- try
- {
- // need to make sure the group cache understands that
- // the key is a group attribute on update
- aux.update(cacheElement);
- log.debug("Updated remote store for {0} {1}",
- cacheElement.getKey(), cacheElement);
- }
- catch (IOException ex)
- {
- log.error("Failure in updateExclude", ex);
- }
- }
- break;
-
- // SEND LATERALLY
- case LATERAL_CACHE:
- // lateral can't do the checking since it is dependent on the
- // cache region restrictions
- log.debug("lateralcache in aux list: cattr {0}", () -> cacheAttr.isUseLateral());
- if (cacheAttr.isUseLateral() && cacheElement.getElementAttributes().getIsLateral() && !localOnly)
- {
- // DISTRIBUTE LATERALLY
- // Currently always multicast even if the value is
- // unchanged, to cause the cache item to move to the front.
- aux.update(cacheElement);
- log.debug("updated lateral cache for {0}", () -> cacheElement.getKey());
- }
- break;
-
- // update disk if the usage pattern permits
- case DISK_CACHE:
- log.debug("diskcache in aux list: cattr {0}", () -> cacheAttr.isUseDisk());
- if (cacheAttr.isUseDisk()
- && cacheAttr.getDiskUsagePattern() == DiskUsagePattern.UPDATE
- && cacheElement.getElementAttributes().getIsSpool())
- {
- aux.update(cacheElement);
- log.debug("updated disk cache for {0}", () -> cacheElement.getKey());
- }
- break;
-
- default: // CACHE_HUB
- break;
- }
- }
- }
-
- /**
- * Writes the specified element to any disk auxiliaries. Might want to rename this "overflow" in
- * case the hub wants to do something else.
- * <p>
- * If JCS is not configured to use the disk as a swap, that is if the the
- * CompositeCacheAttribute diskUsagePattern is not SWAP_ONLY, then the item will not be spooled.
- * <p>
- * @param ce The CacheElement
- */
- public void spoolToDisk(ICacheElement<K, V> ce)
- {
- // if the item is not spoolable, return
- if (!ce.getElementAttributes().getIsSpool())
- {
- // there is an event defined for this.
- handleElementEvent(ce, ElementEventType.SPOOLED_NOT_ALLOWED);
- return;
- }
-
- boolean diskAvailable = false;
-
- // SPOOL TO DISK.
- for (ICache<K, V> aux : auxCaches)
- {
- if (aux != null && aux.getCacheType() == CacheType.DISK_CACHE)
- {
- diskAvailable = true;
-
- if (cacheAttr.getDiskUsagePattern() == DiskUsagePattern.SWAP)
- {
- // write the last items to disk.2
- try
- {
- handleElementEvent(ce, ElementEventType.SPOOLED_DISK_AVAILABLE);
- aux.update(ce);
- }
- catch (IOException ex)
- {
- // impossible case.
- log.error("Problem spooling item to disk cache.", ex);
- throw new IllegalStateException(ex.getMessage());
- }
-
- log.debug("spoolToDisk done for: {0} on disk cache[{1}]",
- () -> ce.getKey(), () -> aux.getCacheName());
- }
- else
- {
- log.debug("DiskCache available, but JCS is not configured "
- + "to use the DiskCache as a swap.");
- }
- }
- }
-
- if (!diskAvailable)
- {
- handleElementEvent(ce, ElementEventType.SPOOLED_DISK_NOT_AVAILABLE);
- }
- }
-
- /**
- * Gets an item from the cache.
- * <p>
- * @param key
- * @return element from the cache, or null if not present
- * @see org.apache.commons.jcs.engine.behavior.ICache#get(Object)
- */
- @Override
- public ICacheElement<K, V> get(K key)
- {
- return get(key, false);
- }
-
- /**
- * Do not try to go remote or laterally for this get.
- * <p>
- * @param key
- * @return ICacheElement
- */
- public ICacheElement<K, V> localGet(K key)
- {
- return get(key, true);
- }
-
- /**
- * Look in memory, then disk, remote, or laterally for this item. The order is dependent on the
- * order in the cache.ccf file.
- * <p>
- * Do not try to go remote or laterally for this get if it is localOnly. Otherwise try to go
- * remote or lateral if such an auxiliary is configured for this region.
- * <p>
- * @param key
- * @param localOnly
- * @return ICacheElement
- */
- protected ICacheElement<K, V> get(K key, boolean localOnly)
- {
- ICacheElement<K, V> element = null;
-
- boolean found = false;
-
- log.debug("get: key = {0}, localOnly = {1}", key, localOnly);
-
- try
- {
- // First look in memory cache
- element = memCache.get(key);
-
- if (element != null)
- {
- // Found in memory cache
- if (isExpired(element))
- {
- log.debug("{0} - Memory cache hit, but element expired",
- () -> cacheAttr.getCacheName());
-
- doExpires(element);
- element = null;
- }
- else
- {
- log.debug("{0} - Memory cache hit", () -> cacheAttr.getCacheName());
-
- // Update counters
- hitCountRam.incrementAndGet();
- }
-
- found = true;
- }
- else
- {
- // Item not found in memory. If local invocation look in aux
- // caches, even if not local look in disk auxiliaries
- for (AuxiliaryCache<K, V> aux : auxCaches)
- {
- if (aux != null)
- {
- CacheType cacheType = aux.getCacheType();
-
- if (!localOnly || cacheType == CacheType.DISK_CACHE)
- {
- log.debug("Attempting to get from aux [{0}] which is of type: {1}",
- () -> aux.getCacheName(), () -> cacheType);
-
- try
- {
- element = aux.get(key);
- }
- catch (IOException e)
- {
- log.error("Error getting from aux", e);
- }
- }
-
- log.debug("Got CacheElement: {0}", element);
-
- // Item found in one of the auxiliary caches.
- if (element != null)
- {
- if (isExpired(element))
- {
- log.debug("{0} - Aux cache[{1}] hit, but element expired.",
- () -> cacheAttr.getCacheName(), () -> aux.getCacheName());
-
- // This will tell the remotes to remove the item
- // based on the element's expiration policy. The elements attributes
- // associated with the item when it created govern its behavior
- // everywhere.
- doExpires(element);
- element = null;
- }
- else
- {
- log.debug("{0} - Aux cache[{1}] hit.",
- () -> cacheAttr.getCacheName(), () -> aux.getCacheName());
-
- // Update counters
- hitCountAux.incrementAndGet();
- copyAuxiliaryRetrievedItemToMemory(element);
- }
-
- found = true;
-
- break;
- }
- }
- }
- }
- }
- catch (IOException e)
- {
- log.error("Problem encountered getting element.", e);
- }
-
- if (!found)
- {
- missCountNotFound.incrementAndGet();
-
- log.debug("{0} - Miss", () -> cacheAttr.getCacheName());
- }
-
- if (element != null)
- {
- element.getElementAttributes().setLastAccessTimeNow();
- }
-
- return element;
- }
-
- protected void doExpires(ICacheElement<K, V> element)
- {
- missCountExpired.incrementAndGet();
- remove(element.getKey());
- }
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
- {
- return getMultiple(keys, false);
- }
-
- /**
- * Gets multiple items from the cache based on the given set of keys. Do not try to go remote or
- * laterally for this data.
- * <p>
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- */
- public Map<K, ICacheElement<K, V>> localGetMultiple(Set<K> keys)
- {
- return getMultiple(keys, true);
- }
-
- /**
- * Look in memory, then disk, remote, or laterally for these items. The order is dependent on
- * the order in the cache.ccf file. Keep looking in each cache location until either the element
- * is found, or the method runs out of places to look.
- * <p>
- * Do not try to go remote or laterally for this get if it is localOnly. Otherwise try to go
- * remote or lateral if such an auxiliary is configured for this region.
- * <p>
- * @param keys
- * @param localOnly
- * @return ICacheElement
- */
- protected Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys, boolean localOnly)
- {
- Map<K, ICacheElement<K, V>> elements = new HashMap<>();
-
- log.debug("get: key = {0}, localOnly = {1}", keys, localOnly);
-
- try
- {
- // First look in memory cache
- elements.putAll(getMultipleFromMemory(keys));
-
- // If fewer than all items were found in memory, then keep looking.
- if (elements.size() != keys.size())
- {
- Set<K> remainingKeys = pruneKeysFound(keys, elements);
- elements.putAll(getMultipleFromAuxiliaryCaches(remainingKeys, localOnly));
- }
- }
- catch (IOException e)
- {
- log.error("Problem encountered getting elements.", e);
- }
-
- // if we didn't find all the elements, increment the miss count by the number of elements not found
- if (elements.size() != keys.size())
- {
- missCountNotFound.addAndGet(keys.size() - elements.size());
-
- log.debug("{0} - {1} Misses", () -> cacheAttr.getCacheName(),
- () -> keys.size() - elements.size());
- }
-
- return elements;
- }
-
- /**
- * Gets items for the keys in the set. Returns a map: key -> result.
- * <p>
- * @param keys
- * @return the elements found in the memory cache
- * @throws IOException
- */
- private Map<K, ICacheElement<K, V>> getMultipleFromMemory(Set<K> keys)
- throws IOException
- {
- Map<K, ICacheElement<K, V>> elementsFromMemory = memCache.getMultiple(keys);
- elementsFromMemory.entrySet().removeIf(entry -> {
- ICacheElement<K, V> element = entry.getValue();
- if (isExpired(element))
- {
- log.debug("{0} - Memory cache hit, but element expired",
- () -> cacheAttr.getCacheName());
-
- doExpires(element);
- return true;
- }
- else
- {
- log.debug("{0} - Memory cache hit", () -> cacheAttr.getCacheName());
-
- // Update counters
- hitCountRam.incrementAndGet();
- return false;
- }
- });
-
- return elementsFromMemory;
- }
-
- /**
- * If local invocation look in aux caches, even if not local look in disk auxiliaries.
- * <p>
- * @param keys
- * @param localOnly
- * @return the elements found in the auxiliary caches
- * @throws IOException
- */
- private Map<K, ICacheElement<K, V>> getMultipleFromAuxiliaryCaches(Set<K> keys, boolean localOnly)
- throws IOException
- {
- Map<K, ICacheElement<K, V>> elements = new HashMap<>();
- Set<K> remainingKeys = new HashSet<>(keys);
-
- for (AuxiliaryCache<K, V> aux : auxCaches)
- {
- if (aux != null)
- {
- Map<K, ICacheElement<K, V>> elementsFromAuxiliary =
- new HashMap<>();
-
- CacheType cacheType = aux.getCacheType();
-
- if (!localOnly || cacheType == CacheType.DISK_CACHE)
- {
- log.debug("Attempting to get from aux [{0}] which is of type: {1}",
- () -> aux.getCacheName(), () -> cacheType);
-
- try
- {
- elementsFromAuxiliary.putAll(aux.getMultiple(remainingKeys));
- }
- catch (IOException e)
- {
- log.error("Error getting from aux", e);
- }
- }
-
- log.debug("Got CacheElements: {0}", elementsFromAuxiliary);
-
- processRetrievedElements(aux, elementsFromAuxiliary);
- elements.putAll(elementsFromAuxiliary);
-
- if (elements.size() == keys.size())
- {
- break;
- }
- else
- {
- remainingKeys = pruneKeysFound(keys, elements);
- }
- }
- }
-
- return elements;
- }
-
- /**
- * Build a map of all the matching elements in all of the auxiliaries and memory.
- * <p>
- * @param pattern
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any matching keys
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching(String pattern)
- {
- return getMatching(pattern, false);
- }
-
- /**
- * Build a map of all the matching elements in all of the auxiliaries and memory. Do not try to
- * go remote or laterally for this data.
- * <p>
- * @param pattern
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any matching keys
- */
- public Map<K, ICacheElement<K, V>> localGetMatching(String pattern)
- {
- return getMatching(pattern, true);
- }
-
- /**
- * Build a map of all the matching elements in all of the auxiliaries and memory. Items in
- * memory will replace from the auxiliaries in the returned map. The auxiliaries are accessed in
- * opposite order. It's assumed that those closer to home are better.
- * <p>
- * Do not try to go remote or laterally for this get if it is localOnly. Otherwise try to go
- * remote or lateral if such an auxiliary is configured for this region.
- * <p>
- * @param pattern
- * @param localOnly
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any matching keys
- */
- protected Map<K, ICacheElement<K, V>> getMatching(String pattern, boolean localOnly)
- {
- log.debug("get: pattern [{0}], localOnly = {1}", pattern, localOnly);
-
- try
- {
- return Stream.concat(
- getMatchingFromMemory(pattern).entrySet().stream(),
- getMatchingFromAuxiliaryCaches(pattern, localOnly).entrySet().stream())
- .collect(Collectors.toMap(
- entry -> entry.getKey(),
- entry -> entry.getValue(),
- // Prefer memory entries
- (mem, aux) -> mem));
- }
- catch (IOException e)
- {
- log.error("Problem encountered getting elements.", e);
- }
-
- return new HashMap<>();
- }
-
- /**
- * Gets the key array from the memcache. Builds a set of matches. Calls getMultiple with the
- * set. Returns a map: key -> result.
- * <p>
- * @param pattern
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any matching keys
- * @throws IOException
- */
- protected Map<K, ICacheElement<K, V>> getMatchingFromMemory(String pattern)
- throws IOException
- {
- // find matches in key array
- // this avoids locking the memory cache, but it uses more memory
- Set<K> keyArray = memCache.getKeySet();
- Set<K> matchingKeys = getKeyMatcher().getMatchingKeysFromArray(pattern, keyArray);
-
- // call get multiple
- return getMultipleFromMemory(matchingKeys);
- }
-
- /**
- * If local invocation look in aux caches, even if not local look in disk auxiliaries.
- * <p>
- * Moves in reverse order of definition. This will allow you to override those that are from the
- * remote with those on disk.
- * <p>
- * @param pattern
- * @param localOnly
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any matching keys
- * @throws IOException
- */
- private Map<K, ICacheElement<K, V>> getMatchingFromAuxiliaryCaches(String pattern, boolean localOnly)
- throws IOException
- {
- Map<K, ICacheElement<K, V>> elements = new HashMap<>();
-
- for (int i = auxCaches.length - 1; i >= 0; i--)
- {
- AuxiliaryCache<K, V> aux = auxCaches[i];
-
- if (aux != null)
- {
- Map<K, ICacheElement<K, V>> elementsFromAuxiliary =
- new HashMap<>();
-
- CacheType cacheType = aux.getCacheType();
-
- if (!localOnly || cacheType == CacheType.DISK_CACHE)
- {
- log.debug("Attempting to get from aux [{0}] which is of type: {1}",
- () -> aux.getCacheName(), () -> cacheType);
-
- try
- {
- elementsFromAuxiliary.putAll(aux.getMatching(pattern));
- }
- catch (IOException e)
- {
- log.error("Error getting from aux", e);
- }
-
- log.debug("Got CacheElements: {0}", elementsFromAuxiliary);
-
- processRetrievedElements(aux, elementsFromAuxiliary);
- elements.putAll(elementsFromAuxiliary);
- }
- }
- }
-
- return elements;
- }
-
- /**
- * Remove expired elements retrieved from an auxiliary. Update memory with good items.
- * <p>
- * @param aux the auxiliary cache instance
- * @param elementsFromAuxiliary
- * @throws IOException
- */
- private void processRetrievedElements(AuxiliaryCache<K, V> aux, Map<K, ICacheElement<K, V>> elementsFromAuxiliary)
- throws IOException
- {
- elementsFromAuxiliary.entrySet().removeIf(entry -> {
- ICacheElement<K, V> element = entry.getValue();
-
- // Item found in one of the auxiliary caches.
- if (element != null)
- {
- if (isExpired(element))
- {
- log.debug("{0} - Aux cache[{1}] hit, but element expired.",
- () -> cacheAttr.getCacheName(), () -> aux.getCacheName());
-
- // This will tell the remote caches to remove the item
- // based on the element's expiration policy. The elements attributes
- // associated with the item when it created govern its behavior
- // everywhere.
- doExpires(element);
- return true;
- }
- else
- {
- log.debug("{0} - Aux cache[{1}] hit.",
- () -> cacheAttr.getCacheName(), () -> aux.getCacheName());
-
- // Update counters
- hitCountAux.incrementAndGet();
- try
- {
- copyAuxiliaryRetrievedItemToMemory(element);
- }
- catch (IOException e)
- {
- log.error("{0} failed to copy element to memory {1}",
- cacheAttr.getCacheName(), element, e);
- }
- }
- }
-
- return false;
- });
- }
-
- /**
- * Copies the item to memory if the memory size is greater than 0. Only spool if the memory
- * cache size is greater than 0, else the item will immediately get put into purgatory.
- * <p>
- * @param element
- * @throws IOException
- */
- private void copyAuxiliaryRetrievedItemToMemory(ICacheElement<K, V> element)
- throws IOException
- {
- if (memCache.getCacheAttributes().getMaxObjects() > 0)
- {
- memCache.update(element);
- }
- else
- {
- log.debug("Skipping memory update since no items are allowed in memory");
- }
- }
-
- /**
- * Returns a set of keys that were not found.
- * <p>
- * @param keys
- * @param foundElements
- * @return the original set of cache keys, minus any cache keys present in the map keys of the
- * foundElements map
- */
- private Set<K> pruneKeysFound(Set<K> keys, Map<K, ICacheElement<K, V>> foundElements)
- {
- Set<K> remainingKeys = new HashSet<>(keys);
- remainingKeys.removeAll(foundElements.keySet());
-
- return remainingKeys;
- }
-
- /**
- * Get a set of the keys for all elements in the cache
- * <p>
- * @return A set of the key type
- */
- public Set<K> getKeySet()
- {
- return getKeySet(false);
- }
-
- /**
- * Get a set of the keys for all elements in the cache
- * <p>
- * @param localOnly true if only memory keys are requested
- *
- * @return A set of the key type
- */
- public Set<K> getKeySet(boolean localOnly)
- {
- HashSet<K> allKeys = new HashSet<>();
-
- allKeys.addAll(memCache.getKeySet());
- for (AuxiliaryCache<K, V> aux : auxCaches)
- {
- if (aux != null)
- {
- if(!localOnly || aux.getCacheType() == CacheType.DISK_CACHE)
- {
- try
- {
- allKeys.addAll(aux.getKeySet());
- }
- catch (IOException e)
- {
- // ignore
- }
- }
- }
- }
- return allKeys;
- }
-
- /**
- * Removes an item from the cache.
- * <p>
- * @param key
- * @return true is it was removed
- * @see org.apache.commons.jcs.engine.behavior.ICache#remove(Object)
- */
- @Override
- public boolean remove(K key)
- {
- return remove(key, false);
- }
-
- /**
- * Do not propagate removeall laterally or remotely.
- * <p>
- * @param key
- * @return true if the item was already in the cache.
- */
- public boolean localRemove(K key)
- {
- return remove(key, true);
- }
-
- /**
- * fromRemote: If a remove call was made on a cache with both, then the remote should have been
- * called. If it wasn't then the remote is down. we'll assume it is down for all. If it did come
- * from the remote then the cache is remotely configured and lateral removal is unnecessary. If
- * it came laterally then lateral removal is unnecessary. Does this assume that there is only
- * one lateral and remote for the cache? Not really, the initial removal should take care of the
- * problem if the source cache was similarly configured. Otherwise the remote cache, if it had
- * no laterals, would remove all the elements from remotely configured caches, but if those
- * caches had some other weird laterals that were not remotely configured, only laterally
- * propagated then they would go out of synch. The same could happen for multiple remotes. If
- * this looks necessary we will need to build in an identifier to specify the source of a
- * removal.
- * <p>
- * @param key
- * @param localOnly
- * @return true if the item was in the cache, else false
- */
- protected boolean remove(K key, boolean localOnly)
- {
- removeCount.incrementAndGet();
-
- boolean removed = false;
-
- try
- {
- removed = memCache.remove(key);
- }
- catch (IOException e)
- {
- log.error(e);
- }
-
- // Removes from all auxiliary caches.
- for (ICache<K, V> aux : auxCaches)
- {
- if (aux == null)
- {
- continue;
- }
-
- CacheType cacheType = aux.getCacheType();
-
- // for now let laterals call remote remove but not vice versa
- if (localOnly && (cacheType == CacheType.REMOTE_CACHE || cacheType == CacheType.LATERAL_CACHE))
- {
- continue;
- }
- try
- {
- log.debug("Removing {0} from cacheType {1}", key, cacheType);
-
- boolean b = aux.remove(key);
-
- // Don't take the remote removal into account.
- if (!removed && cacheType != CacheType.REMOTE_CACHE)
- {
- removed = b;
- }
- }
- catch (IOException ex)
- {
- log.error("Failure removing from aux", ex);
- }
- }
-
- return removed;
- }
-
- /**
- * Clears the region. This command will be sent to all auxiliaries. Some auxiliaries, such as
- * the JDBC disk cache, can be configured to not honor removeAll requests.
- * <p>
- * @see org.apache.commons.jcs.engine.behavior.ICache#removeAll()
- */
- @Override
- public void removeAll()
- throws IOException
- {
- removeAll(false);
- }
-
- /**
- * Will not pass the remove message remotely.
- * <p>
- * @throws IOException
- */
- public void localRemoveAll()
- throws IOException
- {
- removeAll(true);
- }
-
- /**
- * Removes all cached items.
- * <p>
- * @param localOnly must pass in false to get remote and lateral aux's updated. This prevents
- * looping.
- * @throws IOException
- */
- protected void removeAll(boolean localOnly)
- throws IOException
- {
- try
- {
- memCache.removeAll();
-
- log.debug("Removed All keys from the memory cache.");
- }
- catch (IOException ex)
- {
- log.error("Trouble updating memory cache.", ex);
- }
-
- // Removes from all auxiliary disk caches.
- for (ICache<K, V> aux : auxCaches)
- {
- if (aux != null && (aux.getCacheType() == CacheType.DISK_CACHE || !localOnly))
- {
- try
- {
- log.debug("Removing All keys from cacheType {0}",
- () -> aux.getCacheType());
-
- aux.removeAll();
- }
- catch (IOException ex)
- {
- log.error("Failure removing all from aux", ex);
- }
- }
- }
- }
-
- /**
- * Flushes all cache items from memory to auxiliary caches and close the auxiliary caches.
- */
- @Override
- public void dispose()
- {
- dispose(false);
- }
-
- /**
- * Invoked only by CacheManager. This method disposes of the auxiliaries one by one. For the
- * disk cache, the items in memory are freed, meaning that they will be sent through the
- * overflow channel to disk. After the auxiliaries are disposed, the memory cache is disposed.
- * <p>
- * @param fromRemote
- */
- public void dispose(boolean fromRemote)
- {
- // If already disposed, return immediately
- if (alive.compareAndSet(true, false) == false)
- {
- return;
- }
-
- log.info("In DISPOSE, [{0}] fromRemote [{1}]",
- () -> this.cacheAttr.getCacheName(), () -> fromRemote);
-
- // Remove us from the cache managers list
- // This will call us back but exit immediately
- if (cacheManager != null)
- {
- cacheManager.freeCache(getCacheName(), fromRemote);
- }
-
- // Try to stop shrinker thread
- if (future != null)
- {
- future.cancel(true);
- }
-
- // Now, shut down the event queue
- if (elementEventQ != null)
- {
- elementEventQ.dispose();
- elementEventQ = null;
- }
-
- // Dispose of each auxiliary cache, Remote auxiliaries will be
- // skipped if 'fromRemote' is true.
- for (ICache<K, V> aux : auxCaches)
- {
- try
- {
- // Skip this auxiliary if:
- // - The auxiliary is null
- // - The auxiliary is not alive
- // - The auxiliary is remote and the invocation was remote
- if (aux == null || aux.getStatus() != CacheStatus.ALIVE
- || (fromRemote && aux.getCacheType() == CacheType.REMOTE_CACHE))
- {
- log.info("In DISPOSE, [{0}] SKIPPING auxiliary [{1}] fromRemote [{2}]",
- () -> this.cacheAttr.getCacheName(), () -> aux.getCacheName(),
- () -> fromRemote);
- continue;
- }
-
- log.info("In DISPOSE, [{0}] auxiliary [{1}]",
- () -> this.cacheAttr.getCacheName(), () -> aux.getCacheName());
-
- // IT USED TO BE THE CASE THAT (If the auxiliary is not a lateral, or the cache
- // attributes
- // have 'getUseLateral' set, all the elements currently in
- // memory are written to the lateral before disposing)
- // I changed this. It was excessive. Only the disk cache needs the items, since only
- // the disk cache is in a situation to not get items on a put.
- if (aux.getCacheType() == CacheType.DISK_CACHE)
- {
- int numToFree = memCache.getSize();
- memCache.freeElements(numToFree);
-
- log.info("In DISPOSE, [{0}] put {1} into auxiliary [{2}]",
- () -> this.cacheAttr.getCacheName(), () -> numToFree,
- () -> aux.getCacheName());
- }
-
- // Dispose of the auxiliary
- aux.dispose();
- }
- catch (IOException ex)
- {
- log.error("Failure disposing of aux.", ex);
- }
- }
-
- log.info("In DISPOSE, [{0}] disposing of memory cache.",
- () -> this.cacheAttr.getCacheName());
- try
- {
- memCache.dispose();
- }
- catch (IOException ex)
- {
- log.error("Failure disposing of memCache", ex);
- }
- }
-
- /**
- * Calling save cause the entire contents of the memory cache to be flushed to all auxiliaries.
- * Though this put is extremely fast, this could bog the cache and should be avoided. The
- * dispose method should call a version of this. Good for testing.
- */
- public void save()
- {
- if (alive.compareAndSet(true, false) == false)
- {
- return;
- }
-
- for (ICache<K, V> aux : auxCaches)
- {
- try
- {
- if (aux.getStatus() == CacheStatus.ALIVE)
- {
- for (K key : memCache.getKeySet())
- {
- ICacheElement<K, V> ce = memCache.get(key);
-
- if (ce != null)
- {
- aux.update(ce);
- }
- }
- }
- }
- catch (IOException ex)
- {
- log.error("Failure saving aux caches.", ex);
- }
- }
-
- log.debug("Called save for [{0}]", () -> cacheAttr.getCacheName());
- }
-
- /**
- * Gets the size attribute of the Cache object. This return the number of elements, not the byte
- * size.
- * <p>
- * @return The size value
- */
- @Override
- public int getSize()
- {
- return memCache.getSize();
- }
-
- /**
- * Gets the cacheType attribute of the Cache object.
- * <p>
- * @return The cacheType value
- */
- @Override
- public CacheType getCacheType()
- {
- return CacheType.CACHE_HUB;
- }
-
- /**
- * Gets the status attribute of the Cache object.
- * <p>
- * @return The status value
- */
- @Override
- public CacheStatus getStatus()
- {
- return alive.get() ? CacheStatus.ALIVE : CacheStatus.DISPOSED;
- }
-
- /**
- * Gets stats for debugging.
- * <p>
- * @return String
- */
- @Override
- public String getStats()
- {
- return getStatistics().toString();
- }
-
- /**
- * This returns data gathered for this region and all the auxiliaries it currently uses.
- * <p>
- * @return Statistics and Info on the Region.
- */
- public ICacheStats getStatistics()
- {
- ICacheStats stats = new CacheStats();
- stats.setRegionName(this.getCacheName());
-
- // store the composite cache stats first
- ArrayList<IStatElement<?>> elems = new ArrayList<>();
-
- elems.add(new StatElement<>("HitCountRam", Long.valueOf(getHitCountRam())));
- elems.add(new StatElement<>("HitCountAux", Long.valueOf(getHitCountAux())));
-
- stats.setStatElements(elems);
-
- // memory + aux, memory is not considered an auxiliary internally
- int total = auxCaches.length + 1;
- ArrayList<IStats> auxStats = new ArrayList<>(total);
-
- auxStats.add(getMemoryCache().getStatistics());
-
- for (AuxiliaryCache<K, V> aux : auxCaches)
- {
- auxStats.add(aux.getStatistics());
- }
-
- // store the auxiliary stats
- stats.setAuxiliaryCacheStats(auxStats);
-
- return stats;
- }
-
- /**
- * Gets the cacheName attribute of the Cache object. This is also known as the region name.
- * <p>
- * @return The cacheName value
- */
- @Override
- public String getCacheName()
- {
- return cacheAttr.getCacheName();
- }
-
- /**
- * Gets the default element attribute of the Cache object This returns a copy. It does not
- * return a reference to the attributes.
- * <p>
- * @return The attributes value
- */
- public IElementAttributes getElementAttributes()
- {
- if (attr != null)
- {
- return attr.clone();
- }
- return null;
- }
-
- /**
- * Sets the default element attribute of the Cache object.
- * <p>
- * @param attr
- */
- public void setElementAttributes(IElementAttributes attr)
- {
- this.attr = attr;
- }
-
- /**
- * Gets the ICompositeCacheAttributes attribute of the Cache object.
- * <p>
- * @return The ICompositeCacheAttributes value
- */
- public ICompositeCacheAttributes getCacheAttributes()
- {
- return this.cacheAttr;
- }
-
- /**
- * Sets the ICompositeCacheAttributes attribute of the Cache object.
- * <p>
- * @param cattr The new ICompositeCacheAttributes value
- */
- public void setCacheAttributes(ICompositeCacheAttributes cattr)
- {
- this.cacheAttr = cattr;
- // need a better way to do this, what if it is in error
- this.memCache.initialize(this);
- }
-
- /**
- * Gets the elementAttributes attribute of the Cache object.
- * <p>
- * @param key
- * @return The elementAttributes value
- * @throws CacheException
- * @throws IOException
- */
- public IElementAttributes getElementAttributes(K key)
- throws CacheException, IOException
- {
- ICacheElement<K, V> ce = get(key);
- if (ce == null)
- {
- throw new ObjectNotFoundException("key " + key + " is not found");
- }
- return ce.getElementAttributes();
- }
-
- /**
- * Determine if the element is expired based on the values of the element attributes
- *
- * @param element the element
- *
- * @return true if the element is expired
- */
- public boolean isExpired(ICacheElement<K, V> element)
- {
- return isExpired(element, System.currentTimeMillis(),
- ElementEventType.EXCEEDED_MAXLIFE_ONREQUEST,
- ElementEventType.EXCEEDED_IDLETIME_ONREQUEST);
- }
-
- /**
- * Check if the element is expired based on the values of the element attributes
- *
- * @param element the element
- * @param timestamp the timestamp to compare to
- * @param eventMaxlife the event to fire in case the max life time is exceeded
- * @param eventIdle the event to fire in case the idle time is exceeded
- *
- * @return true if the element is expired
- */
- public boolean isExpired(ICacheElement<K, V> element, long timestamp,
- ElementEventType eventMaxlife, ElementEventType eventIdle)
- {
- try
- {
- IElementAttributes attributes = element.getElementAttributes();
-
- if (!attributes.getIsEternal())
- {
- // Remove if maxLifeSeconds exceeded
- long maxLifeSeconds = attributes.getMaxLife();
- long createTime = attributes.getCreateTime();
-
- final long timeFactorForMilliseconds = attributes.getTimeFactorForMilliseconds();
-
- if (maxLifeSeconds != -1 && (timestamp - createTime) > (maxLifeSeconds * timeFactorForMilliseconds))
- {
- log.debug("Exceeded maxLife: {0}", () -> element.getKey());
-
- handleElementEvent(element, eventMaxlife);
- return true;
- }
- long idleTime = attributes.getIdleTime();
- long lastAccessTime = attributes.getLastAccessTime();
-
- // Remove if maxIdleTime exceeded
- // If you have a 0 size memory cache, then the last access will
- // not get updated.
- // you will need to set the idle time to -1.
- if ((idleTime != -1) && (timestamp - lastAccessTime) > idleTime * timeFactorForMilliseconds)
- {
- log.debug("Exceeded maxIdle: {0}", () -> element.getKey());
-
- handleElementEvent(element, eventIdle);
- return true;
- }
- }
- }
- catch (Exception e)
- {
- log.error("Error determining expiration period, expiring", e);
- return true;
- }
-
- return false;
- }
-
- /**
- * If there are event handlers for the item, then create an event and queue it up.
- * <p>
- * This does not call handle directly; instead the handler and the event are put into a queue.
- * This prevents the event handling from blocking normal cache operations.
- * <p>
- * @param element the item
- * @param eventType the event type
- */
- public void handleElementEvent(ICacheElement<K, V> element, ElementEventType eventType)
- {
- ArrayList<IElementEventHandler> eventHandlers = element.getElementAttributes().getElementEventHandlers();
- if (eventHandlers != null)
- {
- log.debug("Element Handlers are registered. Create event type {0}", eventType);
- if (elementEventQ == null)
- {
- log.warn("No element event queue available for cache {0}", getCacheName());
- return;
- }
- IElementEvent<ICacheElement<K, V>> event = new ElementEvent<>(element, eventType);
- for (IElementEventHandler hand : eventHandlers)
- {
- try
- {
- elementEventQ.addElementEvent(hand, event);
- }
- catch (IOException e)
- {
- log.error("Trouble adding element event to queue", e);
- }
- }
- }
- }
-
- /**
- * Create the MemoryCache based on the config parameters.
- * TODO: consider making this an auxiliary, despite its close tie to the CacheHub.
- * TODO: might want to create a memory cache config file separate from that of the hub -- ICompositeCacheAttributes
- * <p>
- * @param cattr
- */
- private void createMemoryCache(ICompositeCacheAttributes cattr)
- {
- if (memCache == null)
- {
- try
- {
- Class<?> c = Class.forName(cattr.getMemoryCacheName());
- @SuppressWarnings("unchecked") // Need cast
- IMemoryCache<K, V> newInstance = (IMemoryCache<K, V>) c.newInstance();
- memCache = newInstance;
- memCache.initialize(this);
- }
- catch (Exception e)
- {
- log.warn("Failed to init mem cache, using: LRUMemoryCache", e);
-
- this.memCache = new LRUMemoryCache<>();
- this.memCache.initialize(this);
- }
- }
- else
- {
- log.warn("Refusing to create memory cache -- already exists.");
- }
- }
-
- /**
- * Access to the memory cache for instrumentation.
- * <p>
- * @return the MemoryCache implementation
- */
- public IMemoryCache<K, V> getMemoryCache()
- {
- return memCache;
- }
-
- /**
- * Number of times a requested item was found in the memory cache.
- * <p>
- * @return number of hits in memory
- */
- public long getHitCountRam()
- {
- return hitCountRam.get();
- }
-
- /**
- * Number of times a requested item was found in and auxiliary cache.
- * @return number of auxiliary hits.
- */
- public long getHitCountAux()
- {
- return hitCountAux.get();
- }
-
- /**
- * Number of times a requested element was not found.
- * @return number of misses.
- */
- public long getMissCountNotFound()
- {
- return missCountNotFound.get();
- }
-
- /**
- * Number of times a requested element was found but was expired.
- * @return number of found but expired gets.
- */
- public long getMissCountExpired()
- {
- return missCountExpired.get();
- }
-
- /**
- * @return Returns the updateCount.
- */
- public long getUpdateCount()
- {
- return updateCount.get();
- }
-
- /**
- * Sets the key matcher used by get matching.
- * <p>
- * @param keyMatcher
- */
- @Override
- public void setKeyMatcher(IKeyMatcher<K> keyMatcher)
- {
- if (keyMatcher != null)
- {
- this.keyMatcher = keyMatcher;
- }
- }
-
- /**
- * Returns the key matcher used by get matching.
- * <p>
- * @return keyMatcher
- */
- public IKeyMatcher<K> getKeyMatcher()
- {
- return this.keyMatcher;
- }
-
- /**
- * This returns the stats.
- * <p>
- * @return getStats()
- */
- @Override
- public String toString()
- {
- return getStats();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/CompositeCacheConfigurator.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/CompositeCacheConfigurator.java
deleted file mode 100644
index c132376..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/CompositeCacheConfigurator.java
+++ /dev/null
@@ -1,535 +0,0 @@
-package org.apache.commons.jcs.engine.control;
-
-/*
- * 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.
- */
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Properties;
-import java.util.StringTokenizer;
-
-import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheConfigurator;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheFactory;
-import org.apache.commons.jcs.engine.behavior.ICache;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.behavior.IRequireScheduler;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.engine.match.KeyMatcherPatternImpl;
-import org.apache.commons.jcs.engine.match.behavior.IKeyMatcher;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.config.OptionConverter;
-import org.apache.commons.jcs.utils.config.PropertySetter;
-
-/**
- * This class configures JCS based on a properties object.
- * <p>
- * This class is based on the log4j class org.apache.log4j.PropertyConfigurator which was made by:
- * "Luke Blanshard" <Luke@quiq.com>"Mark DONSZELMANN" <Mark.Donszelmann@cern.ch>"Anders Kristensen"
- * <akristensen@dynamicsoft.com>
- */
-public class CompositeCacheConfigurator
-{
- /** The logger */
- private static final Log log = LogManager.getLog( CompositeCacheConfigurator.class );
-
- /** The prefix of relevant system properties */
- protected static final String SYSTEM_PROPERTY_KEY_PREFIX = "jcs";
-
- /** normal region prefix */
- protected static final String REGION_PREFIX = "jcs.region.";
-
- /** system region prefix. might not be used */
- protected static final String SYSTEM_REGION_PREFIX = "jcs.system.";
-
- /** auxiliary prefix */
- protected static final String AUXILIARY_PREFIX = "jcs.auxiliary.";
-
- /** .attributes */
- protected static final String ATTRIBUTE_PREFIX = ".attributes";
-
- /** .cacheattributes */
- protected static final String CACHE_ATTRIBUTE_PREFIX = ".cacheattributes";
-
- /** .elementattributes */
- protected static final String ELEMENT_ATTRIBUTE_PREFIX = ".elementattributes";
-
- /**
- * jcs.auxiliary.NAME.keymatcher=CLASSNAME
- * <p>
- * jcs.auxiliary.NAME.keymatcher.attributes.CUSTOMPROPERTY=VALUE
- */
- public static final String KEY_MATCHER_PREFIX = ".keymatcher";
-
- /**
- * Constructor for the CompositeCacheConfigurator object
- */
- public CompositeCacheConfigurator()
- {
- // empty
- }
-
- /**
- * Create caches used internally. System status gives them creation priority.
- *<p>
- * @param props Configuration properties
- * @param ccm Cache hub
- */
- protected void parseSystemRegions( Properties props, CompositeCacheManager ccm )
- {
- for (String key : props.stringPropertyNames() )
- {
- if ( key.startsWith( SYSTEM_REGION_PREFIX ) && key.indexOf( "attributes" ) == -1 )
- {
- String regionName = key.substring( SYSTEM_REGION_PREFIX.length() );
- String auxiliaries = OptionConverter.findAndSubst( key, props );
- ICache<?, ?> cache;
- synchronized ( regionName )
- {
- cache = parseRegion( props, ccm, regionName, auxiliaries, null, SYSTEM_REGION_PREFIX );
- }
- ccm.addCache( regionName, cache );
- }
- }
- }
-
- /**
- * Parse region elements.
- *<p>
- * @param props Configuration properties
- * @param ccm Cache hub
- */
- protected void parseRegions( Properties props, CompositeCacheManager ccm )
- {
- List<String> regionNames = new ArrayList<>();
-
- for (String key : props.stringPropertyNames() )
- {
- if ( key.startsWith( REGION_PREFIX ) && key.indexOf( "attributes" ) == -1 )
- {
- String regionName = key.substring( REGION_PREFIX.length() );
- regionNames.add( regionName );
- String auxiliaries = OptionConverter.findAndSubst( key, props );
- ICache<?, ?> cache;
- synchronized ( regionName )
- {
- cache = parseRegion( props, ccm, regionName, auxiliaries );
- }
- ccm.addCache( regionName, cache );
- }
- }
-
- log.info( "Parsed regions {0}", regionNames );
- }
-
- /**
- * Create cache region.
- *<p>
- * @param props Configuration properties
- * @param ccm Cache hub
- * @param regName Name of the cache region
- * @param auxiliaries Comma separated list of auxiliaries
- *
- * @return CompositeCache
- */
- protected <K, V> CompositeCache<K, V> parseRegion(
- Properties props, CompositeCacheManager ccm, String regName, String auxiliaries )
- {
- return parseRegion( props, ccm, regName, auxiliaries, null, REGION_PREFIX );
- }
-
- /**
- * Get all the properties for a region and configure its cache.
- * <p>
- * This method tells the other parse method the name of the region prefix.
- *<p>
- * @param props Configuration properties
- * @param ccm Cache hub
- * @param regName Name of the cache region
- * @param auxiliaries Comma separated list of auxiliaries
- * @param cca Cache configuration
- *
- * @return CompositeCache
- */
- protected <K, V> CompositeCache<K, V> parseRegion(
- Properties props, CompositeCacheManager ccm, String regName, String auxiliaries,
- ICompositeCacheAttributes cca )
- {
- return parseRegion( props, ccm, regName, auxiliaries, cca, REGION_PREFIX );
- }
-
- /**
- * Get all the properties for a region and configure its cache.
- *<p>
- * @param props Configuration properties
- * @param ccm Cache hub
- * @param regName Name of the cache region
- * @param auxiliaries Comma separated list of auxiliaries
- * @param cca Cache configuration
- * @param regionPrefix Prefix for the region
- *
- * @return CompositeCache
- */
- protected <K, V> CompositeCache<K, V> parseRegion(
- Properties props, CompositeCacheManager ccm, String regName, String auxiliaries,
- ICompositeCacheAttributes cca, String regionPrefix )
- {
- // First, create or get the cache and element attributes, and create
- // the cache.
- IElementAttributes ea = parseElementAttributes( props, regName,
- ccm.getDefaultElementAttributes(), regionPrefix );
-
- ICompositeCacheAttributes instantiationCca = cca == null
- ? parseCompositeCacheAttributes(props, regName, ccm.getDefaultCacheAttributes(), regionPrefix)
- : cca;
- CompositeCache<K, V> cache = newCache(instantiationCca, ea);
-
- // Inject cache manager
- cache.setCompositeCacheManager(ccm);
-
- // Inject scheduler service
- cache.setScheduledExecutorService(ccm.getScheduledExecutorService());
-
- // Inject element event queue
- cache.setElementEventQueue(ccm.getElementEventQueue());
-
- if (cache.getMemoryCache() instanceof IRequireScheduler)
- {
- ((IRequireScheduler)cache.getMemoryCache()).setScheduledExecutorService(
- ccm.getScheduledExecutorService());
- }
-
- if (auxiliaries != null)
- {
- // Next, create the auxiliaries for the new cache
- List<AuxiliaryCache<K, V>> auxList = new ArrayList<>();
-
- log.debug( "Parsing region name \"{0}\", value \"{1}\"", regName, auxiliaries );
-
- // We must skip over ',' but not white space
- StringTokenizer st = new StringTokenizer( auxiliaries, "," );
-
- // If value is not in the form ", appender.." or "", then we should set
- // the priority of the category.
-
- if ( !( auxiliaries.startsWith( "," ) || auxiliaries.equals( "" ) ) )
- {
- // just to be on the safe side...
- if ( !st.hasMoreTokens() )
- {
- return null;
- }
- }
-
- AuxiliaryCache<K, V> auxCache;
- String auxName;
- while ( st.hasMoreTokens() )
- {
- auxName = st.nextToken().trim();
- if ( auxName == null || auxName.equals( "," ) )
- {
- continue;
- }
- log.debug( "Parsing auxiliary named \"{0}\".", auxName );
-
- auxCache = parseAuxiliary( props, ccm, auxName, regName );
-
- if ( auxCache != null )
- {
- if (auxCache instanceof IRequireScheduler)
- {
- ((IRequireScheduler) auxCache).setScheduledExecutorService(
- ccm.getScheduledExecutorService());
- }
-
- auxList.add( auxCache );
- }
- }
-
- // Associate the auxiliaries with the cache
- @SuppressWarnings("unchecked") // No generic arrays in java
- AuxiliaryCache<K, V>[] auxArray = auxList.toArray( new AuxiliaryCache[0] );
- cache.setAuxCaches( auxArray );
- }
-
- // Return the new cache
- return cache;
- }
-
- protected <K, V> CompositeCache<K, V> newCache(
- ICompositeCacheAttributes cca, IElementAttributes ea)
- {
- return new CompositeCache<>( cca, ea );
- }
-
- /**
- * Get an ICompositeCacheAttributes for the listed region.
- *<p>
- * @param props Configuration properties
- * @param regName the region name
- * @param defaultCCAttr the default cache attributes
- *
- * @return ICompositeCacheAttributes
- */
- protected ICompositeCacheAttributes parseCompositeCacheAttributes( Properties props,
- String regName, ICompositeCacheAttributes defaultCCAttr )
- {
- return parseCompositeCacheAttributes( props, regName, defaultCCAttr, REGION_PREFIX );
- }
-
- /**
- * Get the main attributes for a region.
- *<p>
- * @param props Configuration properties
- * @param regName the region name
- * @param defaultCCAttr the default cache attributes
- * @param regionPrefix the region prefix
- *
- * @return ICompositeCacheAttributes
- */
- protected ICompositeCacheAttributes parseCompositeCacheAttributes( Properties props,
- String regName, ICompositeCacheAttributes defaultCCAttr, String regionPrefix )
- {
- ICompositeCacheAttributes ccAttr;
-
- String attrName = regionPrefix + regName + CACHE_ATTRIBUTE_PREFIX;
-
- // auxFactory was not previously initialized.
- // String prefix = regionPrefix + regName + ATTRIBUTE_PREFIX;
- ccAttr = OptionConverter.instantiateByKey( props, attrName, null );
-
- if ( ccAttr == null )
- {
- log.info( "No special CompositeCacheAttributes class defined for "
- + "key [{0}], using default class.", attrName );
-
- ccAttr = defaultCCAttr;
- }
-
- log.debug( "Parsing options for \"{0}\"", attrName );
-
- PropertySetter.setProperties( ccAttr, props, attrName + "." );
- ccAttr.setCacheName( regName );
-
- log.debug( "End of parsing for \"{0}\"", attrName );
-
- // GET CACHE FROM FACTORY WITH ATTRIBUTES
- ccAttr.setCacheName( regName );
- return ccAttr;
- }
-
- /**
- * Create the element attributes from the properties object for a cache region.
- *<p>
- * @param props Configuration properties
- * @param regName the region name
- * @param defaultEAttr the default element attributes
- * @param regionPrefix the region prefix
- *
- * @return IElementAttributes
- */
- protected IElementAttributes parseElementAttributes( Properties props, String regName,
- IElementAttributes defaultEAttr, String regionPrefix )
- {
- IElementAttributes eAttr;
-
- String attrName = regionPrefix + regName + CompositeCacheConfigurator.ELEMENT_ATTRIBUTE_PREFIX;
-
- // auxFactory was not previously initialized.
- // String prefix = regionPrefix + regName + ATTRIBUTE_PREFIX;
- eAttr = OptionConverter.instantiateByKey( props, attrName, null );
- if ( eAttr == null )
- {
- log.info( "No special ElementAttribute class defined for key [{0}], "
- + "using default class.", attrName );
-
- eAttr = defaultEAttr;
- }
-
- log.debug( "Parsing options for \"{0}\"", attrName );
-
- PropertySetter.setProperties( eAttr, props, attrName + "." );
- // eAttr.setCacheName( regName );
-
- log.debug( "End of parsing for \"{0}\"", attrName );
-
- // GET CACHE FROM FACTORY WITH ATTRIBUTES
- // eAttr.setCacheName( regName );
- return eAttr;
- }
-
- /**
- * Get an aux cache for the listed aux for a region.
- *<p>
- * @param props the configuration properties
- * @param ccm Cache hub
- * @param auxName the name of the auxiliary cache
- * @param regName the name of the region.
- * @return AuxiliaryCache
- */
- protected <K, V> AuxiliaryCache<K, V> parseAuxiliary( Properties props, CompositeCacheManager ccm,
- String auxName, String regName )
- {
- log.debug( "parseAuxiliary {0}", auxName );
-
- // GET CACHE
- @SuppressWarnings("unchecked") // Common map for all caches
- AuxiliaryCache<K, V> auxCache = (AuxiliaryCache<K, V>) ccm.getAuxiliaryCache(auxName, regName);
-
- if (auxCache == null)
- {
- // GET FACTORY
- AuxiliaryCacheFactory auxFac = ccm.registryFacGet( auxName );
- if ( auxFac == null )
- {
- // auxFactory was not previously initialized.
- String prefix = AUXILIARY_PREFIX + auxName;
- auxFac = OptionConverter.instantiateByKey( props, prefix, null );
- if ( auxFac == null )
- {
- log.error( "Could not instantiate auxFactory named \"{0}\"", auxName );
- return null;
- }
-
- auxFac.setName( auxName );
-
- if ( auxFac instanceof IRequireScheduler)
- {
- ((IRequireScheduler)auxFac).setScheduledExecutorService(ccm.getScheduledExecutorService());
- }
-
- auxFac.initialize();
- ccm.registryFacPut( auxFac );
- }
-
- // GET ATTRIBUTES
- AuxiliaryCacheAttributes auxAttr = ccm.registryAttrGet( auxName );
- String attrName = AUXILIARY_PREFIX + auxName + ATTRIBUTE_PREFIX;
- if ( auxAttr == null )
- {
- // auxFactory was not previously initialized.
- String prefix = AUXILIARY_PREFIX + auxName + ATTRIBUTE_PREFIX;
- auxAttr = OptionConverter.instantiateByKey( props, prefix, null );
- if ( auxAttr == null )
- {
- log.error( "Could not instantiate auxAttr named \"{0}\"", attrName );
- return null;
- }
- auxAttr.setName( auxName );
- ccm.registryAttrPut( auxAttr );
- }
-
- auxAttr = auxAttr.clone();
-
- log.debug( "Parsing options for \"{0}\"", attrName );
-
- PropertySetter.setProperties( auxAttr, props, attrName + "." );
- auxAttr.setCacheName( regName );
-
- log.debug( "End of parsing for \"{0}\"", attrName );
-
- // GET CACHE FROM FACTORY WITH ATTRIBUTES
- auxAttr.setCacheName( regName );
-
- String auxPrefix = AUXILIARY_PREFIX + auxName;
-
- // CONFIGURE THE EVENT LOGGER
- ICacheEventLogger cacheEventLogger =
- AuxiliaryCacheConfigurator.parseCacheEventLogger( props, auxPrefix );
-
- // CONFIGURE THE ELEMENT SERIALIZER
- IElementSerializer elementSerializer =
- AuxiliaryCacheConfigurator.parseElementSerializer( props, auxPrefix );
-
- // CONFIGURE THE KEYMATCHER
- //IKeyMatcher keyMatcher = parseKeyMatcher( props, auxPrefix );
- // TODO add to factory interface
-
- // Consider putting the compositeCache back in the factory interface
- // since the manager may not know about it at this point.
- // need to make sure the manager already has the cache
- // before the auxiliary is created.
- try
- {
- auxCache = auxFac.createCache( auxAttr, ccm, cacheEventLogger, elementSerializer );
- }
- catch (Exception e)
- {
- log.error( "Could not instantiate auxiliary cache named \"{0}\"", regName, e );
- return null;
- }
-
- ccm.addAuxiliaryCache(auxName, regName, auxCache);
- }
-
- return auxCache;
- }
-
- /**
- * Any property values will be replaced with system property values that match the key.
- * <p>
- * @param props
- */
- protected static void overrideWithSystemProperties( Properties props )
- {
- // override any setting with values from the system properties.
- Properties sysProps = System.getProperties();
- for (String key : sysProps.stringPropertyNames())
- {
- if ( key.startsWith( SYSTEM_PROPERTY_KEY_PREFIX ) )
- {
- log.info( "Using system property [[{0}] [{1}]]", () -> key,
- () -> sysProps.getProperty( key ) );
- props.setProperty( key, sysProps.getProperty( key ) );
- }
- }
- }
-
- /**
- * Creates a custom key matcher if one is defined. Else, it uses the default.
- * <p>
- * @param props
- * @param auxPrefix - ex. AUXILIARY_PREFIX + auxName
- * @return IKeyMatcher
- */
- protected <K> IKeyMatcher<K> parseKeyMatcher( Properties props, String auxPrefix )
- {
-
- // auxFactory was not previously initialized.
- String keyMatcherClassName = auxPrefix + KEY_MATCHER_PREFIX;
- IKeyMatcher<K> keyMatcher = OptionConverter.instantiateByKey( props, keyMatcherClassName, null );
- if ( keyMatcher != null )
- {
- String attributePrefix = auxPrefix + KEY_MATCHER_PREFIX + ATTRIBUTE_PREFIX;
- PropertySetter.setProperties( keyMatcher, props, attributePrefix + "." );
- log.info( "Using custom key matcher [{0}] for auxiliary [{1}]", keyMatcher, auxPrefix );
- }
- else
- {
- // use the default standard serializer
- keyMatcher = new KeyMatcherPatternImpl<>();
- log.info( "Using standard key matcher [{0}] for auxiliary [{1}]", keyMatcher, auxPrefix );
- }
- return keyMatcher;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/CompositeCacheManager.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/CompositeCacheManager.java
deleted file mode 100644
index b13b66d..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/CompositeCacheManager.java
+++ /dev/null
@@ -1,927 +0,0 @@
-package org.apache.commons.jcs.engine.control;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.management.ManagementFactory;
-import java.security.AccessControlException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Executors;
-import java.util.concurrent.LinkedBlockingDeque;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.Collectors;
-
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.admin.JCSAdminBean;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheFactory;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheConstants;
-import org.apache.commons.jcs.engine.CompositeCacheAttributes;
-import org.apache.commons.jcs.engine.ElementAttributes;
-import org.apache.commons.jcs.engine.behavior.ICache;
-import org.apache.commons.jcs.engine.behavior.ICacheType.CacheType;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.behavior.IProvideScheduler;
-import org.apache.commons.jcs.engine.behavior.IShutdownObserver;
-import org.apache.commons.jcs.engine.control.event.ElementEventQueue;
-import org.apache.commons.jcs.engine.control.event.behavior.IElementEventQueue;
-import org.apache.commons.jcs.engine.stats.CacheStats;
-import org.apache.commons.jcs.engine.stats.behavior.ICacheStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.config.OptionConverter;
-import org.apache.commons.jcs.utils.threadpool.DaemonThreadFactory;
-import org.apache.commons.jcs.utils.threadpool.ThreadPoolManager;
-import org.apache.commons.jcs.utils.timing.ElapsedTimer;
-
-/**
- * Manages a composite cache. This provides access to caches and is the primary way to shutdown the
- * caching system as a whole.
- * <p>
- * The composite cache manager is responsible for creating / configuring cache regions. It serves as
- * a factory for the ComositeCache class. The CompositeCache is the core of JCS, the hub for various
- * auxiliaries.
- */
-public class CompositeCacheManager
- implements IRemoteCacheConstants, ICompositeCacheManager, IProvideScheduler
-{
- /** The logger */
- private static final Log log = LogManager.getLog( CompositeCacheManager.class );
-
- /** JMX object name */
- public static final String JMX_OBJECT_NAME = "org.apache.commons.jcs:type=JCSAdminBean";
-
- /** This is the name of the config file that we will look for by default. */
- private static final String DEFAULT_CONFIG = "/cache.ccf";
-
- /** default region prefix */
- private static final String DEFAULT_REGION = "jcs.default";
-
- /** Should we use system property substitutions. */
- private static final boolean DEFAULT_USE_SYSTEM_PROPERTIES = true;
-
- /** Once configured, you can force a reconfiguration of sorts. */
- private static final boolean DEFAULT_FORCE_RECONFIGURATION = false;
-
- /** Caches managed by this cache manager */
- private final ConcurrentMap<String, ICache<?, ?>> caches = new ConcurrentHashMap<>();
-
- /** Number of clients accessing this cache manager */
- private final AtomicInteger clients = new AtomicInteger(0);
-
- /** Default cache attributes for this cache manager */
- private ICompositeCacheAttributes defaultCacheAttr = new CompositeCacheAttributes();
-
- /** Default element attributes for this cache manager */
- private IElementAttributes defaultElementAttr = new ElementAttributes();
-
- /** Used to keep track of configured auxiliaries */
- private final ConcurrentMap<String, AuxiliaryCacheFactory> auxiliaryFactoryRegistry =
- new ConcurrentHashMap<>( );
-
- /** Used to keep track of attributes for auxiliaries. */
- private final ConcurrentMap<String, AuxiliaryCacheAttributes> auxiliaryAttributeRegistry =
- new ConcurrentHashMap<>( );
-
- /** Used to keep track of configured auxiliaries */
- private final ConcurrentMap<String, AuxiliaryCache<?, ?>> auxiliaryCaches =
- new ConcurrentHashMap<>( );
-
- /** Properties with which this manager was configured. This is exposed for other managers. */
- private Properties configurationProperties;
-
- /** The default auxiliary caches to be used if not preconfigured */
- private String defaultAuxValues;
-
- /** The Singleton Instance */
- private static CompositeCacheManager instance;
-
- /** Stack for those waiting for notification of a shutdown. */
- private final LinkedBlockingDeque<IShutdownObserver> shutdownObservers = new LinkedBlockingDeque<>();
-
- /** The central background scheduler. */
- private ScheduledExecutorService scheduledExecutor;
-
- /** The central event queue. */
- private IElementEventQueue elementEventQueue;
-
- /** Shutdown hook thread instance */
- private Thread shutdownHook;
-
- /** Indicates whether the instance has been initialized. */
- private boolean isInitialized = false;
-
- /** Indicates whether configure has been called. */
- private boolean isConfigured = false;
-
- /** Indicates whether JMX bean has been registered. */
- private boolean isJMXRegistered = false;
-
- private String jmxName = JMX_OBJECT_NAME;
-
- /**
- * Gets the CacheHub instance. For backward compatibility, if this creates the instance it will
- * attempt to configure it with the default configuration. If you want to configure from your
- * own source, use {@link #getUnconfiguredInstance}and then call {@link #configure}
- * <p>
- * @return CompositeCacheManager
- * @throws CacheException if the configuration cannot be loaded
- */
- public static synchronized CompositeCacheManager getInstance() throws CacheException
- {
- return getInstance( DEFAULT_CONFIG );
- }
-
- /**
- * Initializes the cache manager using the props file for the given name.
- * <p>
- * @param propsFilename
- * @return CompositeCacheManager configured from the give propsFileName
- * @throws CacheException if the configuration cannot be loaded
- */
- public static synchronized CompositeCacheManager getInstance( String propsFilename ) throws CacheException
- {
- if ( instance == null )
- {
- log.info( "Instance is null, creating with config [{0}]", propsFilename );
- instance = createInstance();
- }
-
- if (!instance.isInitialized())
- {
- instance.initialize();
- }
-
- if (!instance.isConfigured())
- {
- instance.configure( propsFilename );
- }
-
- instance.clients.incrementAndGet();
-
- return instance;
- }
-
- /**
- * Get a CacheHub instance which is not configured. If an instance already exists, it will be
- * returned.
- *<p>
- * @return CompositeCacheManager
- */
- public static synchronized CompositeCacheManager getUnconfiguredInstance()
- {
- if ( instance == null )
- {
- log.info( "Instance is null, returning unconfigured instance" );
- instance = createInstance();
- }
-
- if (!instance.isInitialized())
- {
- instance.initialize();
- }
-
- instance.clients.incrementAndGet();
-
- return instance;
- }
-
- /**
- * Simple factory method, must override in subclasses so getInstance creates / returns the
- * correct object.
- * <p>
- * @return CompositeCacheManager
- */
- protected static CompositeCacheManager createInstance()
- {
- return new CompositeCacheManager();
- }
-
- /**
- * Default constructor
- */
- protected CompositeCacheManager()
- {
- // empty
- }
-
- /** Creates a shutdown hook and starts the scheduler service */
- protected void initialize()
- {
- if (!isInitialized)
- {
- this.shutdownHook = new Thread(() -> {
- if ( isInitialized() )
- {
- log.info("Shutdown hook activated. Shutdown was not called. Shutting down JCS.");
- shutDown();
- }
- });
- try
- {
- Runtime.getRuntime().addShutdownHook( shutdownHook );
- }
- catch ( AccessControlException e )
- {
- log.error( "Could not register shutdown hook.", e );
- }
-
- this.scheduledExecutor = Executors.newScheduledThreadPool(4,
- new DaemonThreadFactory("JCS-Scheduler-", Thread.MIN_PRIORITY));
-
- // Register JMX bean
- if (!isJMXRegistered && jmxName != null)
- {
- MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- JCSAdminBean adminBean = new JCSAdminBean(this);
- try
- {
- ObjectName jmxObjectName = new ObjectName(jmxName);
- mbs.registerMBean(adminBean, jmxObjectName);
- isJMXRegistered = true;
- }
- catch (Exception e)
- {
- log.warn( "Could not register JMX bean.", e );
- }
- }
-
- isInitialized = true;
- }
- }
-
- /**
- * Get the element event queue
- *
- * @return the elementEventQueue
- */
- public IElementEventQueue getElementEventQueue()
- {
- return elementEventQueue;
- }
-
- /**
- * Get the scheduler service
- *
- * @return the scheduledExecutor
- */
- @Override
- public ScheduledExecutorService getScheduledExecutorService()
- {
- return scheduledExecutor;
- }
-
- /**
- * Configure with default properties file
- * @throws CacheException if the configuration cannot be loaded
- */
- public void configure() throws CacheException
- {
- configure( DEFAULT_CONFIG );
- }
-
- /**
- * Configure from specific properties file.
- * <p>
- * @param propFile Path <u>within classpath </u> to load configuration from
- * @throws CacheException if the configuration cannot be loaded
- */
- public void configure( String propFile ) throws CacheException
- {
- log.info( "Creating cache manager from config file: {0}", propFile );
-
- Properties props = new Properties();
-
- try (InputStream is = getClass().getResourceAsStream( propFile ))
- {
- props.load( is );
- log.debug( "File [{0}] contained {1} properties", () -> propFile, () -> props.size());
- }
- catch ( IOException ex )
- {
- throw new CacheException("Failed to load properties for name [" + propFile + "]", ex);
- }
-
- configure( props );
- }
-
- /**
- * Configure from properties object.
- * <p>
- * This method will call configure, instructing it to use system properties as a default.
- * @param props
- */
- public void configure( Properties props )
- {
- configure( props, DEFAULT_USE_SYSTEM_PROPERTIES );
- }
-
- /**
- * Configure from properties object, overriding with values from the system properties if
- * instructed.
- * <p>
- * You can override a specific value by passing in a system property:
- * <p>
- * For example, you could override this value in the cache.ccf file by starting up your program
- * with the argument: -Djcs.auxiliary.LTCP.attributes.TcpListenerPort=1111
- * <p>
- * @param props
- * @param useSystemProperties -- if true, values starting with jcs will be put into the props
- * file prior to configuring the cache.
- */
- public void configure( Properties props, boolean useSystemProperties )
- {
- configure( props, useSystemProperties, DEFAULT_FORCE_RECONFIGURATION );
- }
-
- /**
- * Configure from properties object, overriding with values from the system properties if
- * instructed.
- * <p>
- * You can override a specific value by passing in a system property:
- * <p>
- * For example, you could override this value in the cache.ccf file by starting up your program
- * with the argument: -Djcs.auxiliary.LTCP.attributes.TcpListenerPort=1111
- * <p>
- * @param props
- * @param useSystemProperties -- if true, values starting with jcs will be put into the props
- * file prior to configuring the cache.
- * @param forceReconfiguration - if the manager is already configured, we will try again. This
- * may not work properly.
- */
- public synchronized void configure( Properties props, boolean useSystemProperties, boolean forceReconfiguration )
- {
- if ( props == null )
- {
- log.error( "No properties found. Please configure the cache correctly." );
- return;
- }
-
- if ( isConfigured )
- {
- if ( !forceReconfiguration )
- {
- log.debug( "Configure called after the manager has been configured. "
- + "Force reconfiguration is false. Doing nothing" );
- return;
- }
- else
- {
- log.info( "Configure called after the manager has been configured. "
- + "Force reconfiguration is true. Reconfiguring as best we can." );
- }
- }
- if ( useSystemProperties )
- {
- CompositeCacheConfigurator.overrideWithSystemProperties( props );
- }
- doConfigure( props );
- }
-
- /**
- * Configure the cache using the supplied properties.
- * <p>
- * @param properties assumed not null
- */
- private void doConfigure( Properties properties )
- {
- // We will expose this for managers that need raw properties.
- this.configurationProperties = properties;
-
- // set the props value and then configure the ThreadPoolManager
- ThreadPoolManager.setProps( properties );
- ThreadPoolManager poolMgr = ThreadPoolManager.getInstance();
- log.debug( "ThreadPoolManager = {0}", poolMgr);
-
- // Create event queue
- this.elementEventQueue = new ElementEventQueue();
-
- // configure the cache
- CompositeCacheConfigurator configurator = newConfigurator();
-
- ElapsedTimer timer = new ElapsedTimer();
-
- // set default value list
- this.defaultAuxValues = OptionConverter.findAndSubst( CompositeCacheManager.DEFAULT_REGION,
- properties );
-
- log.info( "Setting default auxiliaries to \"{0}\"", this.defaultAuxValues );
-
- // set default cache attr
- this.defaultCacheAttr = configurator.parseCompositeCacheAttributes( properties, "",
- new CompositeCacheAttributes(), DEFAULT_REGION );
-
- log.info( "setting defaultCompositeCacheAttributes to {0}", this.defaultCacheAttr );
-
- // set default element attr
- this.defaultElementAttr = configurator.parseElementAttributes( properties, "",
- new ElementAttributes(), DEFAULT_REGION );
-
- log.info( "setting defaultElementAttributes to {0}", this.defaultElementAttr );
-
- // set up system caches to be used by non system caches
- // need to make sure there is no circularity of reference
- configurator.parseSystemRegions( properties, this );
-
- // setup preconfigured caches
- configurator.parseRegions( properties, this );
-
- log.info( "Finished configuration in {0} ms.", () -> timer.getElapsedTime());
-
- isConfigured = true;
- }
-
- /**
- * Gets the defaultCacheAttributes attribute of the CacheHub object
- * <p>
- * @return The defaultCacheAttributes value
- */
- public ICompositeCacheAttributes getDefaultCacheAttributes()
- {
- return this.defaultCacheAttr.clone();
- }
-
- /**
- * Gets the defaultElementAttributes attribute of the CacheHub object
- * <p>
- * @return The defaultElementAttributes value
- */
- public IElementAttributes getDefaultElementAttributes()
- {
- return this.defaultElementAttr.clone();
- }
-
- /**
- * Gets the cache attribute of the CacheHub object
- * <p>
- * @param cacheName
- * @return CompositeCache -- the cache region controller
- */
- @Override
- public <K, V> CompositeCache<K, V> getCache( String cacheName )
- {
- return getCache( cacheName, getDefaultCacheAttributes() );
- }
-
- /**
- * Gets the cache attribute of the CacheHub object
- * <p>
- * @param cacheName
- * @param cattr
- * @return CompositeCache
- */
- public <K, V> CompositeCache<K, V> getCache( String cacheName, ICompositeCacheAttributes cattr )
- {
- cattr.setCacheName( cacheName );
- return getCache( cattr, getDefaultElementAttributes() );
- }
-
- /**
- * Gets the cache attribute of the CacheHub object
- * <p>
- * @param cacheName
- * @param cattr
- * @param attr
- * @return CompositeCache
- */
- public <K, V> CompositeCache<K, V> getCache( String cacheName, ICompositeCacheAttributes cattr, IElementAttributes attr )
- {
- cattr.setCacheName( cacheName );
- return getCache( cattr, attr );
- }
-
- /**
- * Gets the cache attribute of the CacheHub object
- * <p>
- * @param cattr
- * @return CompositeCache
- */
- public <K, V> CompositeCache<K, V> getCache( ICompositeCacheAttributes cattr )
- {
- return getCache( cattr, getDefaultElementAttributes() );
- }
-
- /**
- * If the cache has already been created, then the CacheAttributes and the element Attributes
- * will be ignored. Currently there is no overriding the CacheAttributes once it is set up. You
- * can change the default ElementAttributes for a region later.
- * <p>
- * Overriding the default elemental attributes will require changing the way the attributes are
- * assigned to elements. Get cache creates a cache with defaults if none are specified. We might
- * want to create separate method for creating/getting. . .
- * <p>
- * @param cattr
- * @param attr
- * @return CompositeCache
- */
- @SuppressWarnings("unchecked") // Need to cast because of common map for all caches
- public <K, V> CompositeCache<K, V> getCache( ICompositeCacheAttributes cattr, IElementAttributes attr )
- {
- log.debug( "attr = {0}", attr );
-
- CompositeCache<K, V> cache = (CompositeCache<K, V>) caches.computeIfAbsent(cattr.getCacheName(),
- cacheName -> {
- CompositeCacheConfigurator configurator = newConfigurator();
- return configurator.parseRegion( this.getConfigurationProperties(), this, cacheName,
- this.defaultAuxValues, cattr );
- });
-
- return cache;
- }
-
- protected CompositeCacheConfigurator newConfigurator() {
- return new CompositeCacheConfigurator();
- }
-
- /**
- * @param name
- */
- public void freeCache( String name )
- {
- freeCache( name, false );
- }
-
- /**
- * @param name
- * @param fromRemote
- */
- public void freeCache( String name, boolean fromRemote )
- {
- CompositeCache<?, ?> cache = (CompositeCache<?, ?>) caches.remove( name );
-
- if ( cache != null )
- {
- cache.dispose( fromRemote );
- }
- }
-
- /**
- * Calls freeCache on all regions
- */
- public void shutDown()
- {
- synchronized (CompositeCacheManager.class)
- {
- // shutdown element event queue
- if (this.elementEventQueue != null)
- {
- this.elementEventQueue.dispose();
- }
-
- // shutdown all scheduled jobs
- this.scheduledExecutor.shutdownNow();
-
- // shutdown all thread pools
- ThreadPoolManager.dispose();
-
- // notify any observers
- IShutdownObserver observer = null;
- while ((observer = shutdownObservers.poll()) != null)
- {
- observer.shutdown();
- }
-
- // Unregister JMX bean
- if (isJMXRegistered)
- {
- MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- try
- {
- ObjectName jmxObjectName = new ObjectName(jmxName);
- mbs.unregisterMBean(jmxObjectName);
- }
- catch (Exception e)
- {
- log.warn( "Could not unregister JMX bean.", e );
- }
-
- isJMXRegistered = false;
- }
-
- // do the traditional shutdown of the regions.
- getCacheNames().forEach(this::freeCache);
-
- // shut down auxiliaries
- for (String key : auxiliaryCaches.keySet())
- {
- try
- {
- freeAuxiliaryCache(key);
- }
- catch (IOException e)
- {
- log.warn("Auxiliary cache {0} failed to shut down", key, e);
- }
- }
-
- // shut down factories
- auxiliaryFactoryRegistry.values().forEach(AuxiliaryCacheFactory::dispose);
-
- auxiliaryAttributeRegistry.clear();
- auxiliaryFactoryRegistry.clear();
-
- if (shutdownHook != null)
- {
- try
- {
- Runtime.getRuntime().removeShutdownHook(shutdownHook);
- }
- catch (IllegalStateException e)
- {
- // May fail if the JVM is already shutting down
- }
-
- this.shutdownHook = null;
- }
-
- isConfigured = false;
- isInitialized = false;
- }
- }
-
- /** */
- public void release()
- {
- release( false );
- }
-
- /**
- * @param fromRemote
- */
- private void release( boolean fromRemote )
- {
- synchronized ( CompositeCacheManager.class )
- {
- // Wait until called by the last client
- if ( clients.decrementAndGet() > 0 )
- {
- log.debug( "Release called, but {0} remain", clients);
- return;
- }
-
- log.debug( "Last client called release. There are {0} caches which will be disposed",
- () -> caches.size());
-
- caches.values().stream()
- .filter(cache -> cache != null)
- .forEach(cache -> {
- ((CompositeCache<?, ?>)cache).dispose( fromRemote );
- });
- }
- }
-
- /**
- * Returns a list of the current cache names.
- * @return Set<String>
- */
- public Set<String> getCacheNames()
- {
- return caches.keySet();
- }
-
- /**
- * @return ICacheType.CACHE_HUB
- */
- public CacheType getCacheType()
- {
- return CacheType.CACHE_HUB;
- }
-
- /**
- * @param auxFac
- */
- public void registryFacPut( AuxiliaryCacheFactory auxFac )
- {
- auxiliaryFactoryRegistry.put( auxFac.getName(), auxFac );
- }
-
- /**
- * @param name
- * @return AuxiliaryCacheFactory
- */
- public AuxiliaryCacheFactory registryFacGet( String name )
- {
- return auxiliaryFactoryRegistry.get( name );
- }
-
- /**
- * @param auxAttr
- */
- public void registryAttrPut( AuxiliaryCacheAttributes auxAttr )
- {
- auxiliaryAttributeRegistry.put( auxAttr.getName(), auxAttr );
- }
-
- /**
- * @param name
- * @return AuxiliaryCacheAttributes
- */
- public AuxiliaryCacheAttributes registryAttrGet( String name )
- {
- return auxiliaryAttributeRegistry.get( name );
- }
-
- /**
- * Add a cache to the map of registered caches
- *
- * @param cacheName the region name
- * @param cache the cache instance
- */
- public void addCache(String cacheName, ICache<?, ?> cache)
- {
- caches.put(cacheName, cache);
- }
-
- /**
- * Add a cache to the map of registered auxiliary caches
- *
- * @param auxName the auxiliary name
- * @param cacheName the region name
- * @param cache the cache instance
- */
- public void addAuxiliaryCache(String auxName, String cacheName, AuxiliaryCache<?, ?> cache)
- {
- String key = String.format("aux.%s.region.%s", auxName, cacheName);
- auxiliaryCaches.put(key, cache);
- }
-
- /**
- * Get a cache from the map of registered auxiliary caches
- *
- * @param auxName the auxiliary name
- * @param cacheName the region name
- *
- * @return the cache instance
- */
- @Override
- @SuppressWarnings("unchecked") // because of common map for all auxiliary caches
- public <K, V> AuxiliaryCache<K, V> getAuxiliaryCache(String auxName, String cacheName)
- {
- String key = String.format("aux.%s.region.%s", auxName, cacheName);
- return (AuxiliaryCache<K, V>) auxiliaryCaches.get(key);
- }
-
- /**
- * Dispose a cache and remove it from the map of registered auxiliary caches
- *
- * @param auxName the auxiliary name
- * @param cacheName the region name
- * @throws IOException if disposing of the cache fails
- */
- public void freeAuxiliaryCache(String auxName, String cacheName) throws IOException
- {
- String key = String.format("aux.%s.region.%s", auxName, cacheName);
- freeAuxiliaryCache(key);
- }
-
- /**
- * Dispose a cache and remove it from the map of registered auxiliary caches
- *
- * @param key the key into the map of auxiliaries
- * @throws IOException if disposing of the cache fails
- */
- public void freeAuxiliaryCache(String key) throws IOException
- {
- AuxiliaryCache<?, ?> aux = auxiliaryCaches.remove( key );
-
- if ( aux != null )
- {
- aux.dispose();
- }
- }
-
- /**
- * Gets stats for debugging. This calls gets statistics and then puts all the results in a
- * string. This returns data for all regions.
- * <p>
- * @return String
- */
- @Override
- public String getStats()
- {
- ICacheStats[] stats = getStatistics();
- if ( stats == null )
- {
- return "NONE";
- }
-
- // force the array elements into a string.
- StringBuilder buf = new StringBuilder();
- Arrays.stream(stats).forEach(stat -> {
- buf.append( "\n---------------------------\n" );
- buf.append( stat );
- });
- return buf.toString();
- }
-
- /**
- * This returns data gathered for all regions and all the auxiliaries they currently uses.
- * <p>
- * @return ICacheStats[]
- */
- public ICacheStats[] getStatistics()
- {
- List<ICacheStats> cacheStats = caches.values().stream()
- .filter(cache -> cache != null)
- .map(cache -> ((CompositeCache<?, ?>)cache).getStatistics() )
- .collect(Collectors.toList());
-
- return cacheStats.toArray( new CacheStats[0] );
- }
-
- /**
- * Perhaps the composite cache itself should be the observable object. It doesn't make much of a
- * difference. There are some problems with region by region shutdown. Some auxiliaries are
- * global. They will need to track when every region has shutdown before doing things like
- * closing the socket with a lateral.
- * <p>
- * @param observer
- */
- @Override
- public void registerShutdownObserver( IShutdownObserver observer )
- {
- if (!shutdownObservers.contains(observer))
- {
- shutdownObservers.push( observer );
- }
- else
- {
- log.warn("Shutdown observer added twice {0}", observer);
- }
- }
-
- /**
- * @param observer
- */
- @Override
- public void deregisterShutdownObserver( IShutdownObserver observer )
- {
- shutdownObservers.remove( observer );
- }
-
- /**
- * This is exposed so other manager can get access to the props.
- * <p>
- * @return the configurationProperties
- */
- @Override
- public Properties getConfigurationProperties()
- {
- return configurationProperties;
- }
-
- /**
- * @return the isInitialized
- */
- public boolean isInitialized()
- {
- return isInitialized;
- }
-
- /**
- * @return the isConfigured
- */
- public boolean isConfigured()
- {
- return isConfigured;
- }
-
- public void setJmxName(final String name)
- {
- if (isJMXRegistered)
- {
- throw new IllegalStateException("Too late, MBean registration is done");
- }
- jmxName = name;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/ElementEvent.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/ElementEvent.java
deleted file mode 100644
index e25a603..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/ElementEvent.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package org.apache.commons.jcs.engine.control.event;
-
-/*
- * 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.
- */
-
-import java.util.EventObject;
-
-import org.apache.commons.jcs.engine.control.event.behavior.ElementEventType;
-import org.apache.commons.jcs.engine.control.event.behavior.IElementEvent;
-
-/**
- * Element events will trigger the creation of Element Event objects. This is a wrapper around the
- * cache element that indicates the event triggered.
- */
-public class ElementEvent<T>
- extends EventObject
- implements IElementEvent<T>
-{
- /** Don't change */
- private static final long serialVersionUID = -5364117411457467056L;
-
- /** default event code */
- private ElementEventType elementEvent = ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND;
-
- /**
- * Constructor for the ElementEvent object
- * <p>
- * @param source The Cache Element
- * @param elementEvent The event id defined in the enum class.
- */
- public ElementEvent( T source, ElementEventType elementEvent )
- {
- super( source );
- this.elementEvent = elementEvent;
- }
-
- /**
- * Gets the elementEvent attribute of the ElementEvent object
- * <p>
- * @return The elementEvent value. The List of values is defined in ElementEventType.
- */
- @Override
- public ElementEventType getElementEvent()
- {
- return elementEvent;
- }
-
- /**
- * @return the source of the event.
- */
- @SuppressWarnings("unchecked") // Generified
- @Override
- public T getSource()
- {
- return (T) super.getSource();
-
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/ElementEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/ElementEventQueue.java
deleted file mode 100644
index d86843f..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/ElementEventQueue.java
+++ /dev/null
@@ -1,184 +0,0 @@
-package org.apache.commons.jcs.engine.control.event;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.concurrent.ExecutorService;
-
-import org.apache.commons.jcs.engine.control.event.behavior.IElementEvent;
-import org.apache.commons.jcs.engine.control.event.behavior.IElementEventHandler;
-import org.apache.commons.jcs.engine.control.event.behavior.IElementEventQueue;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.threadpool.PoolConfiguration;
-import org.apache.commons.jcs.utils.threadpool.PoolConfiguration.WhenBlockedPolicy;
-import org.apache.commons.jcs.utils.threadpool.ThreadPoolManager;
-
-/**
- * An event queue is used to propagate ordered cache events to one and only one target listener.
- */
-public class ElementEventQueue
- implements IElementEventQueue
-{
- private static final String THREAD_PREFIX = "JCS-ElementEventQueue-";
-
- /** The logger */
- private static final Log log = LogManager.getLog( ElementEventQueue.class );
-
- /** shutdown or not */
- private boolean destroyed = false;
-
- /** The worker thread pool. */
- private ExecutorService queueProcessor;
-
- /**
- * Constructor for the ElementEventQueue object
- */
- public ElementEventQueue()
- {
- queueProcessor = ThreadPoolManager.getInstance().createPool(
- new PoolConfiguration(false, 0, 1, 1, 0, WhenBlockedPolicy.RUN, 1), THREAD_PREFIX);
-
- log.debug( "Constructed: {0}", this );
- }
-
- /**
- * Dispose queue
- */
- @Override
- public void dispose()
- {
- if ( !destroyed )
- {
- destroyed = true;
-
- // synchronize on queue so the thread will not wait forever,
- // and then interrupt the QueueProcessor
- queueProcessor.shutdownNow();
- queueProcessor = null;
-
- log.info( "Element event queue destroyed: {0}", this );
- }
- }
-
- /**
- * Adds an ElementEvent to be handled
- * @param hand The IElementEventHandler
- * @param event The IElementEventHandler IElementEvent event
- * @throws IOException
- */
- @Override
- public <T> void addElementEvent( IElementEventHandler hand, IElementEvent<T> event )
- throws IOException
- {
-
- log.debug( "Adding Event Handler to QUEUE, !destroyed = {0}", !destroyed );
-
- if (destroyed)
- {
- log.warn("Event submitted to disposed element event queue {0}", event);
- }
- else
- {
- ElementEventRunner runner = new ElementEventRunner( hand, event );
-
- log.debug( "runner = {0}", runner );
-
- queueProcessor.execute(runner);
- }
- }
-
- // /////////////////////////// Inner classes /////////////////////////////
-
- /**
- * Retries before declaring failure.
- */
- protected abstract class AbstractElementEventRunner
- implements Runnable
- {
- /**
- * Main processing method for the AbstractElementEvent object
- */
- @SuppressWarnings("synthetic-access")
- @Override
- public void run()
- {
- try
- {
- doRun();
- // happy and done.
- }
- catch ( IOException e )
- {
- // Too bad. The handler has problems.
- log.warn( "Giving up element event handling {0}", ElementEventQueue.this, e );
- }
- }
-
- /**
- * This will do the work or trigger the work to be done.
- * <p>
- * @throws IOException
- */
- protected abstract void doRun()
- throws IOException;
- }
-
- /**
- * ElementEventRunner.
- */
- private class ElementEventRunner
- extends AbstractElementEventRunner
- {
- /** the handler */
- private final IElementEventHandler hand;
-
- /** event */
- private final IElementEvent<?> event;
-
- /**
- * Constructor for the PutEvent object.
- * <p>
- * @param hand
- * @param event
- * @throws IOException
- */
- @SuppressWarnings("synthetic-access")
- ElementEventRunner( IElementEventHandler hand, IElementEvent<?> event )
- throws IOException
- {
- log.debug( "Constructing {0}", this );
- this.hand = hand;
- this.event = event;
- }
-
- /**
- * Tells the handler to handle the event.
- * <p>
- * @throws IOException
- */
- @Override
- protected void doRun()
- throws IOException
- {
- hand.handleElementEvent( event );
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/behavior/ElementEventType.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/behavior/ElementEventType.java
deleted file mode 100644
index 52b0fe8..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/behavior/ElementEventType.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package org.apache.commons.jcs.engine.control.event.behavior;
-
-/*
- * 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.
- */
-
-/**
- * This describes the events that an item can encounter.
- */
-public enum ElementEventType
-{
- /** Background expiration */
- EXCEEDED_MAXLIFE_BACKGROUND,
-
- /*** Expiration discovered on request */
- EXCEEDED_MAXLIFE_ONREQUEST,
-
- /** Background expiration */
- EXCEEDED_IDLETIME_BACKGROUND,
-
- /** Expiration discovered on request */
- EXCEEDED_IDLETIME_ONREQUEST,
-
- /** Moving from memory to disk (what if no disk?) */
- SPOOLED_DISK_AVAILABLE,
-
- /** Moving from memory to disk (what if no disk?) */
- SPOOLED_DISK_NOT_AVAILABLE,
-
- /** Moving from memory to disk, but item is not spoolable */
- SPOOLED_NOT_ALLOWED //,
-
- /** Removed actively by a remove command. (Could distinguish between local and remote) */
- //REMOVED,
- /**
- * Element was requested from cache. Not sure we ever want to implement this.
- */
- //GET
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/behavior/IElementEvent.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/behavior/IElementEvent.java
deleted file mode 100644
index 74b9c7f..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/behavior/IElementEvent.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.apache.commons.jcs.engine.control.event.behavior;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-
-/**
- * Defines how an element event object should behave.
- */
-public interface IElementEvent<T>
- extends Serializable
-{
- /**
- * Gets the elementEvent attribute of the IElementEvent object. This code is Contained in the
- * IElememtEventConstants class.
- *<p>
- * @return The elementEvent value
- */
- ElementEventType getElementEvent();
-
- /**
- * @return the source of the event.
- */
- T getSource();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/behavior/IElementEventHandler.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/behavior/IElementEventHandler.java
deleted file mode 100644
index 3aed8b7..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/behavior/IElementEventHandler.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.apache.commons.jcs.engine.control.event.behavior;
-
-/*
- * 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.
- */
-
-/**
- * This interface defines the behavior for event handler. Event handlers are
- * transient. They are not replicated and are not written to disk.
- * <p>
- * If you want an event handler by default for all elements in a region, then
- * you can add it to the default element attributes. This way it will get created
- * whenever an item gets put into the cache.
- *
- */
-public interface IElementEventHandler
-{
- /**
- * Handle events for this element. The events are typed.
- *
- * @param event
- * The event created by the cache.
- */
- <T> void handleElementEvent( IElementEvent<T> event );
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/behavior/IElementEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/behavior/IElementEventQueue.java
deleted file mode 100644
index fc5f84e..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/behavior/IElementEventQueue.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package org.apache.commons.jcs.engine.control.event.behavior;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-
-/**
- * Interface for an element event queue. An event queue is used to propagate
- * ordered element events in one region.
- *
- */
-public interface IElementEventQueue
-{
- /**
- * Adds an ElementEvent to be handled
- *
- * @param hand
- * The IElementEventHandler
- * @param event
- * The IElementEventHandler IElementEvent event
- * @throws IOException
- */
- <T> void addElementEvent( IElementEventHandler hand, IElementEvent<T> event )
- throws IOException;
-
- /**
- * Destroy the event queue
- *
- */
- void dispose();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/group/GroupAttrName.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/group/GroupAttrName.java
deleted file mode 100644
index 8da08eb..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/group/GroupAttrName.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package org.apache.commons.jcs.engine.control.group;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-
-/**
- * Description of the Class
- */
-public class GroupAttrName<T>
- implements Serializable
-{
- /** Don't change */
- private static final long serialVersionUID = 1586079686300744198L;
-
- /** Description of the Field */
- public final GroupId groupId;
-
- /** the name of the attribute */
- public final T attrName;
-
- /** Cached toString value */
- private String toString;
-
- /**
- * Constructor for the GroupAttrName object
- * @param groupId
- * @param attrName
- */
- public GroupAttrName( GroupId groupId, T attrName )
- {
- this.groupId = groupId;
- this.attrName = attrName;
-
- if ( groupId == null )
- {
- throw new IllegalArgumentException( "groupId must not be null." );
- }
- }
-
- /**
- * Tests object equality.
- * @param obj The <code>GroupAttrName</code> instance to test.
- * @return Whether equal.
- */
- @Override
- public boolean equals( Object obj )
- {
- if ( obj == null || !( obj instanceof GroupAttrName ) )
- {
- return false;
- }
- GroupAttrName<?> to = (GroupAttrName<?>) obj;
-
- if (groupId.equals( to.groupId ))
- {
- if (attrName == null && to.attrName == null)
- {
- return true;
- }
- else if (attrName == null || to.attrName == null)
- {
- return false;
- }
-
- return attrName.equals( to.attrName );
- }
-
- return false;
- }
-
- /**
- * @return A hash code based on the hash code of @ #groupid} and {@link #attrName}.
- */
- @Override
- public int hashCode()
- {
- if (attrName == null)
- {
- return groupId.hashCode();
- }
-
- return groupId.hashCode() ^ attrName.hashCode();
- }
-
- /**
- * @return the cached value.
- */
- @Override
- public String toString()
- {
- if ( toString == null )
- {
- toString = "[GAN: groupId=" + groupId + ", attrName=" + attrName + "]";
- }
-
- return toString;
- }
-
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/group/GroupId.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/group/GroupId.java
deleted file mode 100644
index 5bdd83a..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/group/GroupId.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package org.apache.commons.jcs.engine.control.group;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-
-/**
- * Used to avoid name conflict when group cache items are mixed with non-group cache items in the
- * same cache.
- */
-public class GroupId
- implements Serializable
-{
- /** Don't change. */
- private static final long serialVersionUID = 4626368486444860133L;
-
- /** Description of the Field */
- public final String groupName;
-
- /** the name of the region. */
- public final String cacheName;
-
- /** Cached toString value. */
- private String toString;
-
- /**
- * Constructor for the GroupId object
- * <p>
- * @param cacheName
- * @param groupName
- */
- public GroupId( String cacheName, String groupName )
- {
- this.cacheName = cacheName;
- this.groupName = groupName;
-
- if ( cacheName == null )
- {
- throw new IllegalArgumentException( "cacheName must not be null." );
- }
- if ( groupName == null )
- {
- throw new IllegalArgumentException( "groupName must not be null." );
- }
- }
-
- /**
- * @param obj
- * @return cacheName.equals( g.cacheName ) &&groupName.equals( g.groupName );
- */
- @Override
- public boolean equals( Object obj )
- {
- if ( obj == null || !( obj instanceof GroupId ) )
- {
- return false;
- }
- GroupId g = (GroupId) obj;
- return cacheName.equals( g.cacheName ) && groupName.equals( g.groupName );
- }
-
- /**
- * @return cacheName.hashCode() + groupName.hashCode();
- */
- @Override
- public int hashCode()
- {
- return cacheName.hashCode() + groupName.hashCode();
- }
-
- /**
- * Caches the value.
- * <p>
- * @return debugging string.
- */
- @Override
- public String toString()
- {
- if ( toString == null )
- {
- toString = "[groupId=" + cacheName + ", " + groupName + ']';
- }
-
- return toString;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/logging/CacheEvent.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/logging/CacheEvent.java
deleted file mode 100644
index c07ecac..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/logging/CacheEvent.java
+++ /dev/null
@@ -1,177 +0,0 @@
-package org.apache.commons.jcs.engine.logging;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent;
-
-import java.util.Date;
-
-/** It's returned from create and passed into log. */
-public class CacheEvent<K>
- implements ICacheEvent<K>
-{
- /** Don't change. */
- private static final long serialVersionUID = -5913139566421714330L;
-
- /** The time at which this object was created. */
- private final long createTime = System.currentTimeMillis();
-
- /** The auxiliary or other source of the event. */
- private String source;
-
- /** The cache region */
- private String region;
-
- /** The event name: update, get, remove, etc. */
- private String eventName;
-
- /** disk location, ip, etc. */
- private String optionalDetails;
-
- /** The key that was put or retrieved. */
- private K key;
-
- /**
- * @param source the source to set
- */
- @Override
- public void setSource( String source )
- {
- this.source = source;
- }
-
- /**
- * @return the source
- */
- @Override
- public String getSource()
- {
- return source;
- }
-
- /**
- * @param region the region to set
- */
- @Override
- public void setRegion( String region )
- {
- this.region = region;
- }
-
- /**
- * @return the region
- */
- @Override
- public String getRegion()
- {
- return region;
- }
-
- /**
- * @param eventName the eventName to set
- */
- @Override
- public void setEventName( String eventName )
- {
- this.eventName = eventName;
- }
-
- /**
- * @return the eventName
- */
- @Override
- public String getEventName()
- {
- return eventName;
- }
-
- /**
- * @param optionalDetails the optionalDetails to set
- */
- @Override
- public void setOptionalDetails( String optionalDetails )
- {
- this.optionalDetails = optionalDetails;
- }
-
- /**
- * @return the optionalDetails
- */
- @Override
- public String getOptionalDetails()
- {
- return optionalDetails;
- }
-
- /**
- * @param key the key to set
- */
- @Override
- public void setKey( K key )
- {
- this.key = key;
- }
-
- /**
- * @return the key
- */
- @Override
- public K getKey()
- {
- return key;
- }
-
- /**
- * The time at which this object was created.
- * <p>
- * @return the createTime
- */
- public long getCreateTime()
- {
- return createTime;
- }
-
- /**
- * @return reflection toString
- */
- @Override
- public String toString()
- {
- StringBuilder sb = new StringBuilder();
- sb.append("CacheEvent: ").append(eventName).append(" Created: ").append(new Date(createTime));
- if (source != null)
- {
- sb.append(" Source: ").append(source);
- }
- if (region != null)
- {
- sb.append(" Region: ").append(region);
- }
- if (key != null)
- {
- sb.append(" Key: ").append(key);
- }
- if (optionalDetails != null)
- {
- sb.append(" Details: ").append(optionalDetails);
- }
- return sb.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/logging/CacheEventLoggerDebugLogger.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/logging/CacheEventLoggerDebugLogger.java
deleted file mode 100644
index 4a2d56b..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/logging/CacheEventLoggerDebugLogger.java
+++ /dev/null
@@ -1,104 +0,0 @@
-package org.apache.commons.jcs.engine.logging;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This implementation simple logs to a logger at debug level, for all events. It's mainly
- * for testing. It isn't very useful otherwise.
- */
-public class CacheEventLoggerDebugLogger
- implements ICacheEventLogger
-{
- /** This is the name of the category. */
- private String logCategoryName = CacheEventLoggerDebugLogger.class.getName();
-
- /** The logger. This is recreated on set logCategoryName */
- private Log log = LogManager.getLog( logCategoryName );
-
- /**
- * @param source
- * @param region
- * @param eventName
- * @param optionalDetails
- * @param key
- * @return ICacheEvent
- */
- @Override
- public <T> ICacheEvent<T> createICacheEvent( String source, String region, String eventName,
- String optionalDetails, T key )
- {
- ICacheEvent<T> event = new CacheEvent<>();
- event.setSource( source );
- event.setRegion( region );
- event.setEventName( eventName );
- event.setOptionalDetails( optionalDetails );
- event.setKey( key );
-
- return event;
- }
-
- /**
- * @param source
- * @param eventName
- * @param optionalDetails
- */
- @Override
- public void logApplicationEvent( String source, String eventName, String optionalDetails )
- {
- log.debug( "{0} | {1} | {2}", source, eventName, optionalDetails );
- }
-
- /**
- * @param source
- * @param eventName
- * @param errorMessage
- */
- @Override
- public void logError( String source, String eventName, String errorMessage )
- {
- log.debug( "{0} | {1} | {2}", source, eventName, errorMessage );
- }
-
- /**
- * @param event
- */
- @Override
- public <T> void logICacheEvent( ICacheEvent<T> event )
- {
- log.debug( event );
- }
-
- /**
- * @param logCategoryName
- */
- public synchronized void setLogCategoryName( String logCategoryName )
- {
- if ( logCategoryName != null && !logCategoryName.equals( this.logCategoryName ) )
- {
- this.logCategoryName = logCategoryName;
- log = LogManager.getLog( logCategoryName );
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/logging/behavior/ICacheEvent.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/logging/behavior/ICacheEvent.java
deleted file mode 100644
index 82238f2..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/logging/behavior/ICacheEvent.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package org.apache.commons.jcs.engine.logging.behavior;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-
-/** Defines the common fields required by a cache event. */
-public interface ICacheEvent<K>
- extends Serializable
-{
- /**
- * @param source the source to set
- */
- void setSource( String source );
-
- /**
- * @return the source
- */
- String getSource();
-
- /**
- * @param region the region to set
- */
- void setRegion( String region );
-
- /**
- * @return the region
- */
- String getRegion();
-
- /**
- * @param eventName the eventName to set
- */
- void setEventName( String eventName );
-
- /**
- * @return the eventName
- */
- String getEventName();
-
- /**
- * @param optionalDetails the optionalDetails to set
- */
- void setOptionalDetails( String optionalDetails );
-
- /**
- * @return the optionalDetails
- */
- String getOptionalDetails();
-
- /**
- * @param key the key to set
- */
- void setKey( K key );
-
- /**
- * @return the key
- */
- K getKey();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/logging/behavior/ICacheEventLogger.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/logging/behavior/ICacheEventLogger.java
deleted file mode 100644
index 7b08c67..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/logging/behavior/ICacheEventLogger.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package org.apache.commons.jcs.engine.logging.behavior;
-
-/*
- * 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.
- */
-
-/**
- * This defines the behavior for event logging. Auxiliaries will send events to injected event
- * loggers.
- * <p>
- * In general all ICache interface methods should call the logger if one is configured. This will be
- * done on an ad hoc basis for now. Various auxiliaries may have additional events.
- */
-public interface ICacheEventLogger
-{
- // TODO: Use enum
- /** ICache update */
- String UPDATE_EVENT = "update";
-
- /** ICache get */
- String GET_EVENT = "get";
-
- /** ICache getMultiple */
- String GETMULTIPLE_EVENT = "getMultiple";
-
- /** ICache getMatching */
- String GETMATCHING_EVENT = "getMatching";
-
- /** ICache remove */
- String REMOVE_EVENT = "remove";
-
- /** ICache removeAll */
- String REMOVEALL_EVENT = "removeAll";
-
- /** ICache dispose */
- String DISPOSE_EVENT = "dispose";
-
- /** ICache enqueue. The time in the queue. */
- //String ENQUEUE_EVENT = "enqueue";
- /**
- * Creates an event.
- * <p>
- * @param source - e.g. RemoteCacheServer
- * @param region - the name of the region
- * @param eventName - e.g. update, get, put, remove
- * @param optionalDetails - any extra message
- * @param key - the cache key
- * @return ICacheEvent
- */
- <T> ICacheEvent<T> createICacheEvent( String source, String region,
- String eventName, String optionalDetails, T key );
-
- /**
- * Logs an event.
- * <p>
- * @param event - the event created in createICacheEvent
- */
- <T> void logICacheEvent( ICacheEvent<T> event );
-
- /**
- * Logs an event. These are internal application events that do not correspond to ICache calls.
- * <p>
- * @param source - e.g. RemoteCacheServer
- * @param eventName - e.g. update, get, put, remove
- * @param optionalDetails - any extra message
- */
- void logApplicationEvent( String source, String eventName, String optionalDetails );
-
- /**
- * Logs an error.
- * <p>
- * @param source - e.g. RemoteCacheServer
- * @param eventName - e.g. update, get, put, remove
- * @param errorMessage - any error message
- */
- void logError( String source, String eventName, String errorMessage );
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/match/KeyMatcherPatternImpl.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/match/KeyMatcherPatternImpl.java
deleted file mode 100644
index 5b935d7..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/match/KeyMatcherPatternImpl.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.apache.commons.jcs.engine.match;
-
-import java.util.Set;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.match.behavior.IKeyMatcher;
-
-/** This implementation of the KeyMatcher uses standard Java Pattern matching. */
-public class KeyMatcherPatternImpl<K>
- implements IKeyMatcher<K>
-{
- /** Serial version */
- private static final long serialVersionUID = 6667352064144381264L;
-
- /**
- * Creates a pattern and find matches on the array.
- * <p>
- * @param pattern
- * @param keyArray
- * @return Set of the matching keys
- */
- @Override
- public Set<K> getMatchingKeysFromArray( String pattern, Set<K> keyArray )
- {
- Pattern compiledPattern = Pattern.compile( pattern );
-
- return keyArray.stream()
- .filter(key -> compiledPattern.matcher(key.toString()).matches())
- .collect(Collectors.toSet());
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/match/behavior/IKeyMatcher.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/match/behavior/IKeyMatcher.java
deleted file mode 100644
index 74e9d01..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/match/behavior/IKeyMatcher.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.apache.commons.jcs.engine.match.behavior;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-import java.util.Set;
-
-/** Key matchers need to implement this interface. */
-public interface IKeyMatcher<K> extends Serializable
-{
- /**
- * Creates a pattern and find matches on the array.
- * <p>
- * @param pattern
- * @param keyArray
- * @return Set of the matching keys
- */
- Set<K> getMatchingKeysFromArray( String pattern, Set<K> keyArray );
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractDoubleLinkedListMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractDoubleLinkedListMemoryCache.java
deleted file mode 100644
index c28103b..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractDoubleLinkedListMemoryCache.java
+++ /dev/null
@@ -1,526 +0,0 @@
-package org.apache.commons.jcs.engine.memory;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.control.group.GroupAttrName;
-import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor;
-import org.apache.commons.jcs.engine.stats.StatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.struct.DoubleLinkedList;
-
-/**
- * This class contains methods that are common to memory caches using the double linked list, such
- * as the LRU, MRU, FIFO, and LIFO caches.
- * <p>
- * Children can control the expiration algorithm by controlling the update and get. The last item in the list will be the one
- * removed when the list fills. For instance LRU should more items to the front as they are used. FIFO should simply add new items
- * to the front of the list.
- */
-public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends AbstractMemoryCache<K, V>
-{
- /** The logger. */
- private static final Log log = LogManager.getLog(AbstractDoubleLinkedListMemoryCache.class);
-
- /** thread-safe double linked list for lru */
- protected DoubleLinkedList<MemoryElementDescriptor<K, V>> list; // TODO privatise
-
- /**
- * For post reflection creation initialization.
- * <p>
- *
- * @param hub
- */
- @Override
- public void initialize(CompositeCache<K, V> hub)
- {
- super.initialize(hub);
- list = new DoubleLinkedList<>();
- log.info("initialized MemoryCache for {0}", () -> getCacheName());
- }
-
- /**
- * This is called by super initialize.
- *
- * NOTE: should return a thread safe map
- *
- * <p>
- *
- * @return new ConcurrentHashMap()
- */
- @Override
- public ConcurrentMap<K, MemoryElementDescriptor<K, V>> createMap()
- {
- return new ConcurrentHashMap<>();
- }
-
- /**
- * Calls the abstract method updateList.
- * <p>
- * If the max size is reached, an element will be put to disk.
- * <p>
- *
- * @param ce
- * The cache element, or entry wrapper
- * @throws IOException
- */
- @Override
- public final void update(ICacheElement<K, V> ce) throws IOException
- {
- putCnt.incrementAndGet();
-
- lock.lock();
- try
- {
- MemoryElementDescriptor<K, V> newNode = adjustListForUpdate(ce);
-
- // this should be synchronized if we were not using a ConcurrentHashMap
- final K key = newNode.getCacheElement().getKey();
- MemoryElementDescriptor<K, V> oldNode = map.put(key, newNode);
-
- // If the node was the same as an existing node, remove it.
- if (oldNode != null && key.equals(oldNode.getCacheElement().getKey()))
- {
- list.remove(oldNode);
- }
- }
- finally
- {
- lock.unlock();
- }
-
- // If we are over the max spool some
- spoolIfNeeded();
- }
-
- /**
- * Children implement this to control the cache expiration algorithm
- * <p>
- *
- * @param ce
- * @return MemoryElementDescriptor the new node
- * @throws IOException
- */
- protected abstract MemoryElementDescriptor<K, V> adjustListForUpdate(ICacheElement<K, V> ce) throws IOException;
-
- /**
- * If the max size has been reached, spool.
- * <p>
- *
- * @throws Error
- */
- private void spoolIfNeeded() throws Error
- {
- int size = map.size();
- // If the element limit is reached, we need to spool
-
- if (size <= this.getCacheAttributes().getMaxObjects())
- {
- return;
- }
-
- log.debug("In memory limit reached, spooling");
-
- // Write the last 'chunkSize' items to disk.
- int chunkSizeCorrected = Math.min(size, chunkSize);
-
- log.debug("About to spool to disk cache, map size: {0}, max objects: {1}, "
- + "maximum items to spool: {2}", () -> size,
- () -> this.getCacheAttributes().getMaxObjects(),
- () -> chunkSizeCorrected);
-
- // The spool will put them in a disk event queue, so there is no
- // need to pre-queue the queuing. This would be a bit wasteful
- // and wouldn't save much time in this synchronous call.
- lock.lock();
-
- try
- {
- for (int i = 0; i < chunkSizeCorrected; i++)
- {
- ICacheElement<K, V> lastElement = spoolLastElement();
- if (lastElement == null)
- {
- break;
- }
- }
-
- // If this is out of the sync block it can detect a mismatch
- // where there is none.
- if (log.isDebugEnabled() && map.size() != list.size())
- {
- log.debug("update: After spool, size mismatch: map.size() = {0}, "
- + "linked list size = {1}", map.size(), list.size());
- }
- }
- finally
- {
- lock.unlock();
- }
-
- log.debug("update: After spool map size: {0} linked list size = {1}",
- () -> map.size(), () -> list.size());
- }
-
- /**
- * This instructs the memory cache to remove the <i>numberToFree</i> according to its eviction
- * policy. For example, the LRUMemoryCache will remove the <i>numberToFree</i> least recently
- * used items. These will be spooled to disk if a disk auxiliary is available.
- * <p>
- *
- * @param numberToFree
- * @return the number that were removed. if you ask to free 5, but there are only 3, you will
- * get 3.
- * @throws IOException
- */
- @Override
- public int freeElements(int numberToFree) throws IOException
- {
- int freed = 0;
-
- lock.lock();
-
- try
- {
- for (; freed < numberToFree; freed++)
- {
- ICacheElement<K, V> element = spoolLastElement();
- if (element == null)
- {
- break;
- }
- }
- }
- finally
- {
- lock.unlock();
- }
-
- return freed;
- }
-
- /**
- * This spools the last element in the LRU, if one exists.
- * <p>
- *
- * @return ICacheElement<K, V> if there was a last element, else null.
- * @throws Error
- */
- private ICacheElement<K, V> spoolLastElement() throws Error
- {
- ICacheElement<K, V> toSpool = null;
-
- final MemoryElementDescriptor<K, V> last = list.getLast();
- if (last != null)
- {
- toSpool = last.getCacheElement();
- if (toSpool != null)
- {
- getCompositeCache().spoolToDisk(toSpool);
- if (map.remove(toSpool.getKey()) == null)
- {
- log.warn("update: remove failed for key: {0}", toSpool.getKey());
-
- if (log.isTraceEnabled())
- {
- verifyCache();
- }
- }
- }
- else
- {
- throw new Error("update: last.ce is null!");
- }
-
- list.remove(last);
- }
-
- return toSpool;
- }
-
- /**
- * @see org.apache.commons.jcs.engine.memory.AbstractMemoryCache#get(java.lang.Object)
- */
- @Override
- public ICacheElement<K, V> get(K key) throws IOException
- {
- ICacheElement<K, V> ce = super.get(key);
-
- if (log.isTraceEnabled())
- {
- verifyCache();
- }
-
- return ce;
- }
-
- /**
- * Adjust the list as needed for a get. This allows children to control the algorithm
- * <p>
- *
- * @param me
- */
- protected abstract void adjustListForGet(MemoryElementDescriptor<K, V> me);
-
- /**
- * Update control structures after get
- * (guarded by the lock)
- *
- * @param me the memory element descriptor
- */
- @Override
- protected void lockedGetElement(MemoryElementDescriptor<K, V> me)
- {
- adjustListForGet(me);
- }
-
- /**
- * Remove element from control structure
- * (guarded by the lock)
- *
- * @param me the memory element descriptor
- */
- @Override
- protected void lockedRemoveElement(MemoryElementDescriptor<K, V> me)
- {
- list.remove(me);
- }
-
- /**
- * Removes all cached items from the cache control structures.
- * (guarded by the lock)
- */
- @Override
- protected void lockedRemoveAll()
- {
- list.removeAll();
- }
-
- // --------------------------- internal methods (linked list implementation)
- /**
- * Adds a new node to the start of the link list.
- * <p>
- *
- * @param ce
- * The feature to be added to the First
- * @return MemoryElementDescriptor
- */
- protected MemoryElementDescriptor<K, V> addFirst(ICacheElement<K, V> ce)
- {
- lock.lock();
- try
- {
- MemoryElementDescriptor<K, V> me = new MemoryElementDescriptor<>(ce);
- list.addFirst(me);
- if ( log.isTraceEnabled() )
- {
- verifyCache(ce.getKey());
- }
- return me;
- }
- finally
- {
- lock.unlock();
- }
- }
-
- /**
- * Adds a new node to the end of the link list.
- * <p>
- *
- * @param ce
- * The feature to be added to the First
- * @return MemoryElementDescriptor
- */
- protected MemoryElementDescriptor<K, V> addLast(ICacheElement<K, V> ce)
- {
- lock.lock();
- try
- {
- MemoryElementDescriptor<K, V> me = new MemoryElementDescriptor<>(ce);
- list.addLast(me);
- if ( log.isTraceEnabled() )
- {
- verifyCache(ce.getKey());
- }
- return me;
- }
- finally
- {
- lock.unlock();
- }
- }
-
- // ---------------------------------------------------------- debug methods
-
- /**
- * Dump the cache entries from first to list for debugging.
- */
- @SuppressWarnings("unchecked")
- // No generics for public fields
- private void dumpCacheEntries()
- {
- log.trace("dumpingCacheEntries");
- for (MemoryElementDescriptor<K, V> me = list.getFirst(); me != null; me = (MemoryElementDescriptor<K, V>) me.next)
- {
- log.trace("dumpCacheEntries> key={0}, val={1}",
- me.getCacheElement().getKey(), me.getCacheElement().getVal());
- }
- }
-
- /**
- * Checks to see if all the items that should be in the cache are. Checks consistency between
- * List and map.
- */
- @SuppressWarnings("unchecked")
- // No generics for public fields
- private void verifyCache()
- {
- boolean found = false;
- log.trace("verifycache[{0}]: map contains {1} elements, linked list "
- + "contains {2} elements", getCacheName(), map.size(),
- list.size());
- log.trace("verifycache: checking linked list by key ");
- for (MemoryElementDescriptor<K, V> li = list.getFirst(); li != null; li = (MemoryElementDescriptor<K, V>) li.next)
- {
- K key = li.getCacheElement().getKey();
- if (!map.containsKey(key))
- {
- log.error("verifycache[{0}]: map does not contain key : {1}",
- getCacheName(), key);
- log.error("key class={0}", key.getClass());
- log.error("key hashcode={0}", key.hashCode());
- log.error("key toString={0}", key.toString());
- if (key instanceof GroupAttrName)
- {
- GroupAttrName<?> name = (GroupAttrName<?>) key;
- log.error("GroupID hashcode={0}", name.groupId.hashCode());
- log.error("GroupID.class={0}", name.groupId.getClass());
- log.error("AttrName hashcode={0}", name.attrName.hashCode());
- log.error("AttrName.class={0}", name.attrName.getClass());
- }
- dumpMap();
- }
- else if (map.get(key) == null)
- {
- log.error("verifycache[{0}]: linked list retrieval returned "
- + "null for key: {1}", getCacheName(), key);
- }
- }
-
- log.trace("verifycache: checking linked list by value ");
- for (MemoryElementDescriptor<K, V> li = list.getFirst(); li != null; li = (MemoryElementDescriptor<K, V>) li.next)
- {
- if (!map.containsValue(li))
- {
- log.error("verifycache[{0}]: map does not contain value: {1}",
- getCacheName(), li);
- dumpMap();
- }
- }
-
- log.trace("verifycache: checking via keysets!");
- for (Object val : map.keySet())
- {
- found = false;
-
- for (MemoryElementDescriptor<K, V> li = list.getFirst(); li != null; li = (MemoryElementDescriptor<K, V>) li.next)
- {
- if (val.equals(li.getCacheElement().getKey()))
- {
- found = true;
- break;
- }
- }
- if (!found)
- {
- log.error("verifycache[{0}]: key not found in list : {1}",
- getCacheName(), val);
- dumpCacheEntries();
- if (map.containsKey(val))
- {
- log.error("verifycache: map contains key");
- }
- else
- {
- log.error("verifycache: map does NOT contain key, what the HECK!");
- }
- }
- }
- }
-
- /**
- * Logs an error if an element that should be in the cache is not.
- * <p>
- *
- * @param key
- */
- @SuppressWarnings("unchecked")
- // No generics for public fields
- private void verifyCache(K key)
- {
- boolean found = false;
-
- // go through the linked list looking for the key
- for (MemoryElementDescriptor<K, V> li = list.getFirst(); li != null; li = (MemoryElementDescriptor<K, V>) li.next)
- {
- if (li.getCacheElement().getKey() == key)
- {
- found = true;
- log.trace("verifycache(key) key match: {0}", key);
- break;
- }
- }
- if (!found)
- {
- log.error("verifycache(key)[{0}], couldn't find key! : {1}",
- getCacheName(), key);
- }
- }
-
- /**
- * This returns semi-structured information on the memory cache, such as the size, put count,
- * hit count, and miss count.
- * <p>
- *
- * @see org.apache.commons.jcs.engine.memory.behavior.IMemoryCache#getStatistics()
- */
- @Override
- public IStats getStatistics()
- {
- IStats stats = super.getStatistics();
- stats.setTypeName( /* add algorithm name */"Memory Cache");
-
- List<IStatElement<?>> elems = stats.getStatElements();
-
- elems.add(new StatElement<>("List Size", Integer.valueOf(list.size())));
-
- return stats;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractMemoryCache.java
deleted file mode 100644
index e0b1bdb..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractMemoryCache.java
+++ /dev/null
@@ -1,513 +0,0 @@
-package org.apache.commons.jcs.engine.memory;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.stream.Collectors;
-
-import org.apache.commons.jcs.engine.behavior.ICache;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.control.group.GroupAttrName;
-import org.apache.commons.jcs.engine.control.group.GroupId;
-import org.apache.commons.jcs.engine.memory.behavior.IMemoryCache;
-import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor;
-import org.apache.commons.jcs.engine.stats.StatElement;
-import org.apache.commons.jcs.engine.stats.Stats;
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This base includes some common code for memory caches.
- */
-public abstract class AbstractMemoryCache<K, V>
- implements IMemoryCache<K, V>
-{
- /** Log instance */
- private static final Log log = LogManager.getLog( AbstractMemoryCache.class );
-
- /** Cache Attributes. Regions settings. */
- private ICompositeCacheAttributes cacheAttributes;
-
- /** The cache region this store is associated with */
- private CompositeCache<K, V> cache;
-
- /** How many to spool at a time. */
- protected int chunkSize;
-
- protected final Lock lock = new ReentrantLock();
-
- /** Map where items are stored by key. This is created by the concrete child class. */
- protected Map<K, MemoryElementDescriptor<K, V>> map;// TODO privatise
-
- /** number of hits */
- protected AtomicLong hitCnt;
-
- /** number of misses */
- protected AtomicLong missCnt;
-
- /** number of puts */
- protected AtomicLong putCnt;
-
- /**
- * For post reflection creation initialization
- * <p>
- * @param hub
- */
- @Override
- public void initialize( CompositeCache<K, V> hub )
- {
- hitCnt = new AtomicLong(0);
- missCnt = new AtomicLong(0);
- putCnt = new AtomicLong(0);
-
- this.cacheAttributes = hub.getCacheAttributes();
- this.chunkSize = cacheAttributes.getSpoolChunkSize();
- this.cache = hub;
-
- this.map = createMap();
- }
-
- /**
- * Children must implement this method. A FIFO implementation may use a tree map. An LRU might
- * use a hashtable. The map returned should be threadsafe.
- * <p>
- * @return a threadsafe Map
- */
- public abstract Map<K, MemoryElementDescriptor<K, V>> createMap();
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
- throws IOException
- {
- if (keys != null)
- {
- return keys.stream()
- .map(key -> {
- try
- {
- return get(key);
- }
- catch (IOException e)
- {
- return null;
- }
- })
- .filter(element -> element != null)
- .collect(Collectors.toMap(
- element -> element.getKey(),
- element -> element));
- }
-
- return new HashMap<>();
- }
-
- /**
- * Get an item from the cache without affecting its last access time or position. Not all memory
- * cache implementations can get quietly.
- * <p>
- * @param key Identifies item to find
- * @return Element matching key if found, or null
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> getQuiet( K key )
- throws IOException
- {
- ICacheElement<K, V> ce = null;
-
- MemoryElementDescriptor<K, V> me = map.get( key );
- if ( me != null )
- {
- log.debug( "{0}: MemoryCache quiet hit for {1}",
- () -> getCacheName(), () -> key );
-
- ce = me.getCacheElement();
- }
- else
- {
- log.debug( "{0}: MemoryCache quiet miss for {1}",
- () -> getCacheName(), () -> key );
- }
-
- return ce;
- }
-
- /**
- * Puts an item to the cache.
- * <p>
- * @param ce Description of the Parameter
- * @throws IOException Description of the Exception
- */
- @Override
- public abstract void update( ICacheElement<K, V> ce )
- throws IOException;
-
- /**
- * Removes all cached items from the cache.
- * <p>
- * @throws IOException
- */
- @Override
- public void removeAll() throws IOException
- {
- lock.lock();
- try
- {
- lockedRemoveAll();
- map.clear();
- }
- finally
- {
- lock.unlock();
- }
- }
-
- /**
- * Removes all cached items from the cache control structures.
- * (guarded by the lock)
- */
- protected abstract void lockedRemoveAll();
-
- /**
- * Prepares for shutdown. Reset statistics
- * <p>
- * @throws IOException
- */
- @Override
- public void dispose()
- throws IOException
- {
- removeAll();
- hitCnt.set(0);
- missCnt.set(0);
- putCnt.set(0);
- log.info( "Memory Cache dispose called." );
- }
-
- /**
- * @return statistics about the cache
- */
- @Override
- public IStats getStatistics()
- {
- IStats stats = new Stats();
- stats.setTypeName( "Abstract Memory Cache" );
-
- ArrayList<IStatElement<?>> elems = new ArrayList<>();
- stats.setStatElements(elems);
-
- elems.add(new StatElement<>("Put Count", putCnt));
- elems.add(new StatElement<>("Hit Count", hitCnt));
- elems.add(new StatElement<>("Miss Count", missCnt));
- elems.add(new StatElement<>( "Map Size", Integer.valueOf(getSize()) ) );
-
- return stats;
- }
-
- /**
- * Returns the current cache size.
- * <p>
- * @return The size value
- */
- @Override
- public int getSize()
- {
- return this.map.size();
- }
-
- /**
- * Returns the cache (aka "region") name.
- * <p>
- * @return The cacheName value
- */
- public String getCacheName()
- {
- String attributeCacheName = this.cacheAttributes.getCacheName();
- if(attributeCacheName != null)
- {
- return attributeCacheName;
- }
- return cache.getCacheName();
- }
-
- /**
- * Puts an item to the cache.
- * <p>
- * @param ce the item
- */
- @Override
- public void waterfal( ICacheElement<K, V> ce )
- {
- this.cache.spoolToDisk( ce );
- }
-
- // ---------------------------------------------------------- debug method
- /**
- * Dump the cache map for debugging.
- */
- public void dumpMap()
- {
- if (log.isTraceEnabled())
- {
- log.trace("dumpingMap");
- map.entrySet().forEach(e ->
- log.trace("dumpMap> key={0}, val={1}", e.getKey(),
- e.getValue().getCacheElement().getVal()));
- }
- }
-
- /**
- * Returns the CacheAttributes.
- * <p>
- * @return The CacheAttributes value
- */
- @Override
- public ICompositeCacheAttributes getCacheAttributes()
- {
- return this.cacheAttributes;
- }
-
- /**
- * Sets the CacheAttributes.
- * <p>
- * @param cattr The new CacheAttributes value
- */
- @Override
- public void setCacheAttributes( ICompositeCacheAttributes cattr )
- {
- this.cacheAttributes = cattr;
- }
-
- /**
- * Gets the cache hub / region that the MemoryCache is used by
- * <p>
- * @return The cache value
- */
- @Override
- public CompositeCache<K, V> getCompositeCache()
- {
- return this.cache;
- }
-
- /**
- * Remove all keys of the same group hierarchy.
- * @param key the key
- * @return true if something has been removed
- */
- protected boolean removeByGroup(K key)
- {
- GroupId groupId = ((GroupAttrName<?>) key).groupId;
-
- // remove all keys of the same group hierarchy.
- return map.entrySet().removeIf(entry -> {
- K k = entry.getKey();
-
- if (k instanceof GroupAttrName && ((GroupAttrName<?>) k).groupId.equals(groupId))
- {
- lock.lock();
- try
- {
- lockedRemoveElement(entry.getValue());
- return true;
- }
- finally
- {
- lock.unlock();
- }
- }
-
- return false;
- });
- }
-
- /**
- * Remove all keys of the same name hierarchy.
- *
- * @param key the key
- * @return true if something has been removed
- */
- protected boolean removeByHierarchy(K key)
- {
- String keyString = key.toString();
-
- // remove all keys of the same name hierarchy.
- return map.entrySet().removeIf(entry -> {
- K k = entry.getKey();
-
- if (k instanceof String && ((String) k).startsWith(keyString))
- {
- lock.lock();
- try
- {
- lockedRemoveElement(entry.getValue());
- return true;
- }
- finally
- {
- lock.unlock();
- }
- }
-
- return false;
- });
- }
-
- /**
- * Remove element from control structure
- * (guarded by the lock)
- *
- * @param me the memory element descriptor
- */
- protected abstract void lockedRemoveElement(MemoryElementDescriptor<K, V> me);
-
- /**
- * Removes an item from the cache. This method handles hierarchical removal. If the key is a
- * String and ends with the CacheConstants.NAME_COMPONENT_DELIMITER, then all items with keys
- * starting with the argument String will be removed.
- * <p>
- *
- * @param key
- * @return true if the removal was successful
- * @throws IOException
- */
- @Override
- public boolean remove(K key) throws IOException
- {
- log.debug("removing item for key: {0}", key);
-
- boolean removed = false;
-
- // handle partial removal
- if (key instanceof String && ((String) key).endsWith(ICache.NAME_COMPONENT_DELIMITER))
- {
- removed = removeByHierarchy(key);
- }
- else if (key instanceof GroupAttrName && ((GroupAttrName<?>) key).attrName == null)
- {
- removed = removeByGroup(key);
- }
- else
- {
- // remove single item.
- lock.lock();
- try
- {
- MemoryElementDescriptor<K, V> me = map.remove(key);
- if (me != null)
- {
- lockedRemoveElement(me);
- removed = true;
- }
- }
- finally
- {
- lock.unlock();
- }
- }
-
- return removed;
- }
-
- /**
- * Get an Array of the keys for all elements in the memory cache
- *
- * @return An Object[]
- */
- @Override
- public Set<K> getKeySet()
- {
- return new LinkedHashSet<>(map.keySet());
- }
-
- /**
- * Get an item from the cache.
- * <p>
- *
- * @param key Identifies item to find
- * @return ICacheElement<K, V> if found, else null
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> get(K key) throws IOException
- {
- ICacheElement<K, V> ce = null;
-
- log.debug("{0}: getting item for key {1}", () -> getCacheName(),
- () -> key);
-
- MemoryElementDescriptor<K, V> me = map.get(key);
-
- if (me != null)
- {
- hitCnt.incrementAndGet();
- ce = me.getCacheElement();
-
- lock.lock();
- try
- {
- lockedGetElement(me);
- }
- finally
- {
- lock.unlock();
- }
-
- log.debug("{0}: MemoryCache hit for {1}", () -> getCacheName(),
- () -> key);
- }
- else
- {
- missCnt.incrementAndGet();
-
- log.debug("{0}: MemoryCache miss for {1}", () -> getCacheName(),
- () -> key);
- }
-
- return ce;
- }
-
- /**
- * Update control structures after get
- * (guarded by the lock)
- *
- * @param me the memory element descriptor
- */
- protected abstract void lockedGetElement(MemoryElementDescriptor<K, V> me);
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/behavior/IMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/behavior/IMemoryCache.java
deleted file mode 100644
index 3ac2f4b..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/behavior/IMemoryCache.java
+++ /dev/null
@@ -1,187 +0,0 @@
-package org.apache.commons.jcs.engine.memory.behavior;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.Set;
-
-/** For the framework. Insures methods a MemoryCache needs to access. */
-public interface IMemoryCache<K, V>
-{
- /**
- * Initialize the memory cache
- * <p>
- * @param cache The cache (region) this memory store is attached to.
- */
- void initialize( CompositeCache<K, V> cache );
-
- /**
- * Destroy the memory cache
- * <p>
- * @throws IOException
- */
- void dispose()
- throws IOException;
-
- /**
- * Get the number of elements contained in the memory store
- * <p>
- * @return Element count
- */
- int getSize();
-
- /**
- * Returns the historical and statistical data for a region's memory cache.
- * <p>
- * @return Statistics and Info for the Memory Cache.
- */
- IStats getStatistics();
-
- /**
- * Get a set of the keys for all elements in the memory cache.
- * <p>
- * @return a set of the key type
- * TODO This should probably be done in chunks with a range passed in. This
- * will be a problem if someone puts a 1,000,000 or so items in a
- * region.
- */
- Set<K> getKeySet();
-
- /**
- * Removes an item from the cache
- * <p>
- * @param key
- * Identifies item to be removed
- * @return Description of the Return Value
- * @throws IOException
- * Description of the Exception
- */
- boolean remove( K key )
- throws IOException;
-
- /**
- * Removes all cached items from the cache.
- * <p>
- * @throws IOException
- * Description of the Exception
- */
- void removeAll()
- throws IOException;
-
- /**
- * This instructs the memory cache to remove the <i>numberToFree</i>
- * according to its eviction policy. For example, the LRUMemoryCache will
- * remove the <i>numberToFree</i> least recently used items. These will be
- * spooled to disk if a disk auxiliary is available.
- * <p>
- * @param numberToFree
- * @return the number that were removed. if you ask to free 5, but there are
- * only 3, you will get 3.
- * @throws IOException
- */
- int freeElements( int numberToFree )
- throws IOException;
-
- /**
- * Get an item from the cache
- * <p>
- * @param key
- * Description of the Parameter
- * @return Description of the Return Value
- * @throws IOException
- * Description of the Exception
- */
- ICacheElement<K, V> get( K key )
- throws IOException;
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map
- * if there is no data in cache for any of these keys
- * @throws IOException
- */
- Map<K, ICacheElement<K, V>> getMultiple( Set<K> keys )
- throws IOException;
-
- /**
- * Get an item from the cache without effecting its order or last access
- * time
- * <p>
- * @param key
- * Description of the Parameter
- * @return The quiet value
- * @throws IOException
- * Description of the Exception
- */
- ICacheElement<K, V> getQuiet( K key )
- throws IOException;
-
- /**
- * Spools the item contained in the provided element to disk
- * <p>
- * @param ce
- * Description of the Parameter
- * @throws IOException
- * Description of the Exception
- */
- void waterfal( ICacheElement<K, V> ce )
- throws IOException;
-
- /**
- * Puts an item to the cache.
- * <p>
- * @param ce
- * Description of the Parameter
- * @throws IOException
- * Description of the Exception
- */
- void update( ICacheElement<K, V> ce )
- throws IOException;
-
- /**
- * Returns the CacheAttributes for the region.
- * <p>
- * @return The cacheAttributes value
- */
- ICompositeCacheAttributes getCacheAttributes();
-
- /**
- * Sets the CacheAttributes of the region.
- * <p>
- * @param cattr
- * The new cacheAttributes value
- */
- void setCacheAttributes( ICompositeCacheAttributes cattr );
-
- /**
- * Gets the cache hub / region that uses the MemoryCache.
- * <p>
- * @return The cache value
- */
- CompositeCache<K, V> getCompositeCache();
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/fifo/FIFOMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/fifo/FIFOMemoryCache.java
deleted file mode 100644
index 00f48f9..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/fifo/FIFOMemoryCache.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package org.apache.commons.jcs.engine.memory.fifo;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.memory.AbstractDoubleLinkedListMemoryCache;
-import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor;
-
-/**
- * The items are spooled in the order they are added. No adjustments to the list are made on get.
- */
-public class FIFOMemoryCache<K, V>
- extends AbstractDoubleLinkedListMemoryCache<K, V>
-{
- /**
- * Puts an item to the cache. Removes any pre-existing entries of the same key from the linked
- * list and adds this one first.
- * <p>
- * @param ce The cache element, or entry wrapper
- * @return MemoryElementDescriptor the new node
- * @throws IOException
- */
- @Override
- protected MemoryElementDescriptor<K, V> adjustListForUpdate( ICacheElement<K, V> ce )
- throws IOException
- {
- return addFirst( ce );
- }
-
- /**
- * Does nothing.
- * <p>
- * @param me
- */
- @Override
- protected void adjustListForGet( MemoryElementDescriptor<K, V> me )
- {
- // DO NOTHING
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCache.java
deleted file mode 100644
index 51f8df5..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCache.java
+++ /dev/null
@@ -1,202 +0,0 @@
-package org.apache.commons.jcs.engine.memory.lru;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Map;
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.memory.AbstractMemoryCache;
-import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This is a test memory manager using the jdk1.4 LinkedHashMap.
- */
-public class LHMLRUMemoryCache<K, V>
- extends AbstractMemoryCache<K, V>
-{
- /** The Logger. */
- private static final Log log = LogManager.getLog( LRUMemoryCache.class );
-
- /**
- * For post reflection creation initialization
- * <p>
- * @param hub
- */
- @Override
- public void initialize( CompositeCache<K, V> hub )
- {
- super.initialize( hub );
- log.info( "initialized LHMLRUMemoryCache for {0}", () -> getCacheName() );
- }
-
- /**
- * Returns a synchronized LHMSpooler
- * <p>
- * @return Collections.synchronizedMap( new LHMSpooler() )
- */
- @Override
- public Map<K, MemoryElementDescriptor<K, V>> createMap()
- {
- return Collections.synchronizedMap( new LHMSpooler() );
- }
-
- /**
- * Puts an item to the cache.
- * <p>
- * @param ce Description of the Parameter
- * @throws IOException
- */
- @Override
- public void update( ICacheElement<K, V> ce )
- throws IOException
- {
- putCnt.incrementAndGet();
- map.put( ce.getKey(), new MemoryElementDescriptor<>(ce) );
- }
-
- /**
- * Update control structures after get
- * (guarded by the lock)
- *
- * @param me the memory element descriptor
- */
- @Override
- protected void lockedGetElement(MemoryElementDescriptor<K, V> me)
- {
- // empty
- }
-
- /**
- * Remove element from control structure
- * (guarded by the lock)
- *
- * @param me the memory element descriptor
- */
- @Override
- protected void lockedRemoveElement(MemoryElementDescriptor<K, V> me)
- {
- // empty
- }
-
- /**
- * Removes all cached items from the cache control structures.
- * (guarded by the lock)
- */
- @Override
- protected void lockedRemoveAll()
- {
- // empty
- }
-
- /**
- * This returns semi-structured information on the memory cache, such as the size, put count,
- * hit count, and miss count.
- * <p>
- * @return IStats
- */
- @Override
- public IStats getStatistics()
- {
- IStats stats = super.getStatistics();
- stats.setTypeName( "LHMLRU Memory Cache" );
-
- return stats;
- }
-
- // ---------------------------------------------------------- debug methods
-
- /**
- * Dump the cache entries from first to last for debugging.
- */
- public void dumpCacheEntries()
- {
- dumpMap();
- }
-
- /**
- * This can't be implemented.
- * <p>
- * @param numberToFree
- * @return 0
- * @throws IOException
- */
- @Override
- public int freeElements( int numberToFree )
- throws IOException
- {
- // can't be implemented using the LHM
- return 0;
- }
-
- // ---------------------------------------------------------- extended map
-
- /**
- * Implementation of removeEldestEntry in LinkedHashMap
- */
- protected class LHMSpooler
- extends java.util.LinkedHashMap<K, MemoryElementDescriptor<K, V>>
- {
- /** Don't change. */
- private static final long serialVersionUID = -1255907868906762484L;
-
- /**
- * Initialize to a small size--for now, 1/2 of max 3rd variable "true" indicates that it
- * should be access and not time governed. This could be configurable.
- */
- public LHMSpooler()
- {
- super( (int) ( getCacheAttributes().getMaxObjects() * .5 ), .75F, true );
- }
-
- /**
- * Remove eldest. Automatically called by LinkedHashMap.
- * <p>
- * @param eldest
- * @return true if removed
- */
- @SuppressWarnings("synthetic-access")
- @Override
- protected boolean removeEldestEntry( Map.Entry<K, MemoryElementDescriptor<K, V>> eldest )
- {
- ICacheElement<K, V> element = eldest.getValue().getCacheElement();
-
- if ( size() <= getCacheAttributes().getMaxObjects() )
- {
- return false;
- }
- else
- {
- log.debug( "LHMLRU max size: {0}. Spooling element, key: {1}",
- () -> getCacheAttributes().getMaxObjects(), () -> element.getKey() );
-
- waterfal( element );
-
- log.debug( "LHMLRU size: {0}", () -> map.size() );
- }
- return true;
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/lru/LRUMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/lru/LRUMemoryCache.java
deleted file mode 100644
index a9eb4de..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/lru/LRUMemoryCache.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package org.apache.commons.jcs.engine.memory.lru;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.memory.AbstractDoubleLinkedListMemoryCache;
-import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor;
-
-/**
- * A fast reference management system. The least recently used items move to the end of the list and
- * get spooled to disk if the cache hub is configured to use a disk cache. Most of the cache
- * bottlenecks are in IO. There are no io bottlenecks here, it's all about processing power.
- * <p>
- * Even though there are only a few adjustments necessary to maintain the double linked list, we
- * might want to find a more efficient memory manager for large cache regions.
- * <p>
- * The LRUMemoryCache is most efficient when the first element is selected. The smaller the region,
- * the better the chance that this will be the case. < .04 ms per put, p3 866, 1/10 of that per get
- */
-public class LRUMemoryCache<K, V>
- extends AbstractDoubleLinkedListMemoryCache<K, V>
-{
- /**
- * Puts an item to the cache. Removes any pre-existing entries of the same key from the linked
- * list and adds this one first.
- * <p>
- * @param ce The cache element, or entry wrapper
- * @return MemoryElementDescriptor the new node
- * @throws IOException
- */
- @Override
- protected MemoryElementDescriptor<K, V> adjustListForUpdate( ICacheElement<K, V> ce )
- throws IOException
- {
- return addFirst( ce );
- }
-
- /**
- * Makes the item the first in the list.
- * <p>
- * @param me
- */
- @Override
- protected void adjustListForGet( MemoryElementDescriptor<K, V> me )
- {
- list.makeFirst( me );
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/mru/MRUMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/mru/MRUMemoryCache.java
deleted file mode 100644
index 3638fd9..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/mru/MRUMemoryCache.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.apache.commons.jcs.engine.memory.mru;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.memory.AbstractDoubleLinkedListMemoryCache;
-import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor;
-
-/**
- * The most recently used items move to the front of the list and get spooled to disk if the cache
- * hub is configured to use a disk cache.
- */
-public class MRUMemoryCache<K, V>
- extends AbstractDoubleLinkedListMemoryCache<K, V>
-{
- /**
- * Adds the item to the front of the list. A put doesn't count as a usage.
- * <p>
- * It's not clear if the put operation should be different. Perhaps this should remove the oldest
- * if full, and then put.
- * <p>
- * @param ce
- * @return MemoryElementDescriptor the new node
- * @throws IOException
- */
- @Override
- protected MemoryElementDescriptor<K, V> adjustListForUpdate( ICacheElement<K, V> ce )
- throws IOException
- {
- return addFirst( ce );
- }
-
- /**
- * Makes the item the last in the list.
- * <p>
- * @param me
- */
- @Override
- protected void adjustListForGet( MemoryElementDescriptor<K, V> me )
- {
- list.makeLast( me );
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/shrinking/ShrinkerThread.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/shrinking/ShrinkerThread.java
deleted file mode 100644
index 0cbe492..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/shrinking/ShrinkerThread.java
+++ /dev/null
@@ -1,202 +0,0 @@
-package org.apache.commons.jcs.engine.memory.shrinking;
-
-/*
- * 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.
- */
-
-import java.util.Set;
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.control.event.behavior.ElementEventType;
-import org.apache.commons.jcs.engine.memory.behavior.IMemoryCache;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * A background memory shrinker. Memory problems and concurrent modification exception caused by
- * acting directly on an iterator of the underlying memory cache should have been solved.
- * @version $Id$
- */
-public class ShrinkerThread<K, V>
- implements Runnable
-{
- /** The logger */
- private static final Log log = LogManager.getLog( ShrinkerThread.class );
-
- /** The CompositeCache instance which this shrinker is watching */
- private final CompositeCache<K, V> cache;
-
- /** Maximum memory idle time for the whole cache */
- private final long maxMemoryIdleTime;
-
- /** Maximum number of items to spool per run. Default is -1, or no limit. */
- private final int maxSpoolPerRun;
-
- /** Should we limit the number spooled per run. If so, the maxSpoolPerRun will be used. */
- private boolean spoolLimit = false;
-
- /**
- * Constructor for the ShrinkerThread object.
- * <p>
- * @param cache The MemoryCache which the new shrinker should watch.
- */
- public ShrinkerThread( CompositeCache<K, V> cache )
- {
- super();
-
- this.cache = cache;
-
- long maxMemoryIdleTimeSeconds = cache.getCacheAttributes().getMaxMemoryIdleTimeSeconds();
-
- if ( maxMemoryIdleTimeSeconds < 0 )
- {
- this.maxMemoryIdleTime = -1;
- }
- else
- {
- this.maxMemoryIdleTime = maxMemoryIdleTimeSeconds * 1000;
- }
-
- this.maxSpoolPerRun = cache.getCacheAttributes().getMaxSpoolPerRun();
- if ( this.maxSpoolPerRun != -1 )
- {
- this.spoolLimit = true;
- }
-
- }
-
- /**
- * Main processing method for the ShrinkerThread object
- */
- @Override
- public void run()
- {
- shrink();
- }
-
- /**
- * This method is called when the thread wakes up. First the method obtains an array of keys for
- * the cache region. It iterates through the keys and tries to get the item from the cache
- * without affecting the last access or position of the item. The item is checked for
- * expiration, the expiration check has 3 parts:
- * <ol>
- * <li>Has the cacheattributes.MaxMemoryIdleTimeSeconds defined for the region been exceeded? If
- * so, the item should be move to disk.</li> <li>Has the item exceeded MaxLifeSeconds defined in
- * the element attributes? If so, remove it.</li> <li>Has the item exceeded IdleTime defined in
- * the element attributes? If so, remove it. If there are event listeners registered for the
- * cache element, they will be called.</li>
- * </ol>
- * TODO Change element event handling to use the queue, then move the queue to the region and
- * access via the Cache.
- */
- protected void shrink()
- {
- log.debug( "Shrinking memory cache for: {0}", () -> this.cache.getCacheName() );
-
- IMemoryCache<K, V> memCache = cache.getMemoryCache();
-
- try
- {
- Set<K> keys = memCache.getKeySet();
- int size = keys.size();
- log.debug( "Keys size: {0}", size );
-
- int spoolCount = 0;
-
- for (K key : keys)
- {
- final ICacheElement<K, V> cacheElement = memCache.getQuiet( key );
-
- if ( cacheElement == null )
- {
- continue;
- }
-
- IElementAttributes attributes = cacheElement.getElementAttributes();
-
- boolean remove = false;
-
- long now = System.currentTimeMillis();
-
- // If the element is not eternal, check if it should be
- // removed and remove it if so.
- if ( !attributes.getIsEternal() )
- {
- remove = cache.isExpired( cacheElement, now,
- ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND,
- ElementEventType.EXCEEDED_IDLETIME_BACKGROUND );
-
- if ( remove )
- {
- memCache.remove( key );
- }
- }
-
- // If the item is not removed, check is it has been idle
- // long enough to be spooled.
-
- if ( !remove && maxMemoryIdleTime != -1 )
- {
- if ( !spoolLimit || spoolCount < this.maxSpoolPerRun )
- {
- final long lastAccessTime = attributes.getLastAccessTime();
-
- if ( lastAccessTime + maxMemoryIdleTime < now )
- {
- log.debug( "Exceeded memory idle time: {0}", key );
-
- // Shouldn't we ensure that the element is
- // spooled before removing it from memory?
- // No the disk caches have a purgatory. If it fails
- // to spool that does not affect the
- // responsibilities of the memory cache.
-
- spoolCount++;
-
- memCache.remove( key );
- memCache.waterfal( cacheElement );
- }
- }
- else
- {
- log.debug( "spoolCount = \"{0}\"; maxSpoolPerRun = \"{1}\"",
- spoolCount, maxSpoolPerRun );
-
- // stop processing if limit has been reached.
- if ( spoolLimit && spoolCount >= this.maxSpoolPerRun )
- {
- return;
- }
- }
- }
- }
- }
- catch ( Throwable t )
- {
- log.info( "Unexpected trouble in shrink cycle", t );
-
- // concurrent modifications should no longer be a problem
- // It is up to the IMemoryCache to return an array of keys
-
- // stop for now
- return;
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/soft/SoftReferenceMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/soft/SoftReferenceMemoryCache.java
deleted file mode 100644
index 6dbb0b3..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/soft/SoftReferenceMemoryCache.java
+++ /dev/null
@@ -1,240 +0,0 @@
-package org.apache.commons.jcs.engine.memory.soft;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.lang.ref.SoftReference;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.LinkedBlockingQueue;
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.memory.AbstractMemoryCache;
-import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor;
-import org.apache.commons.jcs.engine.memory.util.SoftReferenceElementDescriptor;
-import org.apache.commons.jcs.engine.stats.StatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * A JCS IMemoryCache that has {@link SoftReference} to all its values.
- * This cache does not respect {@link ICompositeCacheAttributes#getMaxObjects()}
- * as overflowing is handled by Java GC.
- * <p>
- * The cache also has strong references to a maximum number of objects given by
- * the maxObjects parameter
- *
- * @author halset
- */
-public class SoftReferenceMemoryCache<K, V> extends AbstractMemoryCache<K, V>
-{
- /** The logger. */
- private static final Log log = LogManager.getLog(SoftReferenceMemoryCache.class);
-
- /**
- * Strong references to the maxObjects number of newest objects.
- * <p>
- * Trimming is done by {@link #trimStrongReferences()} instead of by
- * overriding removeEldestEntry to be able to control waterfalling as easy
- * as possible
- */
- private LinkedBlockingQueue<ICacheElement<K, V>> strongReferences;
-
- /**
- * For post reflection creation initialization
- * <p>
- * @param hub
- */
- @Override
- public synchronized void initialize( CompositeCache<K, V> hub )
- {
- super.initialize( hub );
- strongReferences = new LinkedBlockingQueue<>();
- log.info( "initialized Soft Reference Memory Cache for {0}",
- () -> getCacheName() );
- }
-
- /**
- * @see org.apache.commons.jcs.engine.memory.AbstractMemoryCache#createMap()
- */
- @Override
- public ConcurrentMap<K, MemoryElementDescriptor<K, V>> createMap()
- {
- return new ConcurrentHashMap<>();
- }
-
- /**
- * @see org.apache.commons.jcs.engine.memory.behavior.IMemoryCache#getKeySet()
- */
- @Override
- public Set<K> getKeySet()
- {
- Set<K> keys = new HashSet<>();
- for (Map.Entry<K, MemoryElementDescriptor<K, V>> e : map.entrySet())
- {
- SoftReferenceElementDescriptor<K, V> sred = (SoftReferenceElementDescriptor<K, V>) e.getValue();
- if (sred.getCacheElement() != null)
- {
- keys.add(e.getKey());
- }
- }
-
- return keys;
- }
-
- /**
- * Returns the current cache size.
- * <p>
- * @return The size value
- */
- @Override
- public int getSize()
- {
- int size = 0;
- for (MemoryElementDescriptor<K, V> me : map.values())
- {
- SoftReferenceElementDescriptor<K, V> sred = (SoftReferenceElementDescriptor<K, V>) me;
- if (sred.getCacheElement() != null)
- {
- size++;
- }
- }
- return size;
- }
-
- /**
- * @return statistics about the cache
- */
- @Override
- public IStats getStatistics()
- {
- IStats stats = super.getStatistics();
- stats.setTypeName("Soft Reference Memory Cache");
-
- List<IStatElement<?>> elems = stats.getStatElements();
- int emptyrefs = map.size() - getSize();
- elems.add(new StatElement<>("Empty References", Integer.valueOf(emptyrefs)));
- elems.add(new StatElement<>("Strong References", Integer.valueOf(strongReferences.size())));
-
- return stats;
- }
-
- /**
- * Update control structures after get
- * (guarded by the lock)
- *
- * @param me the memory element descriptor
- */
- @Override
- protected void lockedGetElement(MemoryElementDescriptor<K, V> me)
- {
- ICacheElement<K, V> val = me.getCacheElement();
- val.getElementAttributes().setLastAccessTimeNow();
-
- // update the ordering of the strong references
- strongReferences.add(val);
- trimStrongReferences();
- }
-
- /**
- * Remove element from control structure
- * (guarded by the lock)
- *
- * @param me the memory element descriptor
- */
- @Override
- protected void lockedRemoveElement(MemoryElementDescriptor<K, V> me)
- {
- strongReferences.remove(me.getCacheElement());
- }
-
- /**
- * Removes all cached items from the cache control structures.
- * (guarded by the lock)
- */
- @Override
- protected void lockedRemoveAll()
- {
- strongReferences.clear();
- }
-
- /**
- * Puts an item to the cache.
- * <p>
- * @param ce Description of the Parameter
- * @throws IOException Description of the Exception
- */
- @Override
- public void update(ICacheElement<K, V> ce) throws IOException
- {
- putCnt.incrementAndGet();
- ce.getElementAttributes().setLastAccessTimeNow();
-
- lock.lock();
-
- try
- {
- map.put(ce.getKey(), new SoftReferenceElementDescriptor<>(ce));
- strongReferences.add(ce);
- trimStrongReferences();
- }
- finally
- {
- lock.unlock();
- }
- }
-
- /**
- * Trim the number of strong references to equal or below the number given
- * by the maxObjects parameter.
- */
- private void trimStrongReferences()
- {
- int max = getCacheAttributes().getMaxObjects();
- int startsize = strongReferences.size();
-
- for (int cursize = startsize; cursize > max; cursize--)
- {
- ICacheElement<K, V> ce = strongReferences.poll();
- waterfal(ce);
- }
- }
-
- /**
- * This can't be implemented.
- * <p>
- * @param numberToFree
- * @return 0
- * @throws IOException
- */
- @Override
- public int freeElements(int numberToFree) throws IOException
- {
- return 0;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/util/MemoryElementDescriptor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/util/MemoryElementDescriptor.java
deleted file mode 100644
index 613f2b5..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/util/MemoryElementDescriptor.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.apache.commons.jcs.engine.memory.util;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.utils.struct.DoubleLinkedListNode;
-
-/**
- * This wrapper is needed for double linked lists.
- */
-public class MemoryElementDescriptor<K, V>
- extends DoubleLinkedListNode<ICacheElement<K, V>>
-{
- /** Don't change */
- private static final long serialVersionUID = -1905161209035522460L;
-
- /**
- * Constructs a usable MemoryElementDescriptor.
- * <p>
- * @param ce
- */
- public MemoryElementDescriptor( ICacheElement<K, V> ce )
- {
- super( ce );
- }
-
- /**
- * Get the cache element
- *
- * @return the ce
- */
- public ICacheElement<K, V> getCacheElement()
- {
- return getPayload();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/util/SoftReferenceElementDescriptor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/util/SoftReferenceElementDescriptor.java
deleted file mode 100644
index 89edf02..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/util/SoftReferenceElementDescriptor.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.apache.commons.jcs.engine.memory.util;
-
-/*
- * 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.
- */
-
-import java.lang.ref.SoftReference;
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-/**
- * This wrapper is needed for double linked lists.
- */
-public class SoftReferenceElementDescriptor<K, V>
- extends MemoryElementDescriptor<K, V>
-{
- /** Don't change */
- private static final long serialVersionUID = -1905161209035522460L;
-
- /** The CacheElement wrapped by this descriptor */
- private final SoftReference<ICacheElement<K, V>> srce;
-
- /**
- * Constructs a usable MemoryElementDescriptor.
- * <p>
- * @param ce
- */
- public SoftReferenceElementDescriptor( ICacheElement<K, V> ce )
- {
- super( null );
- this.srce = new SoftReference<>(ce);
- }
-
- /**
- * @return the ce
- */
- @Override
- public ICacheElement<K, V> getCacheElement()
- {
- if (srce != null)
- {
- return srce.get();
- }
-
- return null;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/stats/CacheStats.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/stats/CacheStats.java
deleted file mode 100644
index eacede7..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/stats/CacheStats.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package org.apache.commons.jcs.engine.stats;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.stats.behavior.ICacheStats;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-
-import java.util.List;
-
-/**
- * This class stores cache historical and statistics data for a region.
- * <p>
- * Only the composite cache knows what the hit count across all auxiliaries is.
- */
-public class CacheStats
- extends Stats
- implements ICacheStats
-{
- /** Don't change. */
- private static final long serialVersionUID = 529914708798168590L;
-
- /** The region */
- private String regionName = null;
-
- /** What that auxiliaries are reporting. */
- private List<IStats> auxStats = null;
-
- /**
- * Stats are for a region, though auxiliary data may be for more.
- * <p>
- * @return The region name
- */
- @Override
- public String getRegionName()
- {
- return regionName;
- }
-
- /**
- * Stats are for a region, though auxiliary data may be for more.
- * <p>
- * @param name - The region name
- */
- @Override
- public void setRegionName( String name )
- {
- regionName = name;
- }
-
- /**
- * @return IStats[]
- */
- @Override
- public List<IStats> getAuxiliaryCacheStats()
- {
- return auxStats;
- }
-
- /**
- * @param stats
- */
- @Override
- public void setAuxiliaryCacheStats( List<IStats> stats )
- {
- auxStats = stats;
- }
-
- /**
- * @return readable string that can be logged.
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
-
- buf.append( "Region Name = " + regionName );
-
- if ( getStatElements() != null )
- {
- for ( Object stat : getStatElements() )
- {
- buf.append( "\n" );
- buf.append( stat );
- }
- }
-
- if ( auxStats != null )
- {
- for ( Object auxStat : auxStats )
- {
- buf.append( "\n" );
- buf.append( "---------------------------" );
- buf.append( auxStat );
- }
- }
-
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/stats/StatElement.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/stats/StatElement.java
deleted file mode 100644
index fd2b345..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/stats/StatElement.java
+++ /dev/null
@@ -1,104 +0,0 @@
-package org.apache.commons.jcs.engine.stats;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-
-/**
- * This is a stat data holder.
- */
-public class StatElement<V>
- implements IStatElement<V>
-{
- /** Don't change */
- private static final long serialVersionUID = -2982373725267618092L;
-
- /** name of the stat */
- private String name = null;
-
- /** the data */
- private V data = null;
-
- /**
- * Constructor
- *
- * @param name
- * @param data
- */
- public StatElement(String name, V data)
- {
- super();
- this.name = name;
- this.data = data;
- }
-
- /**
- * Get the name of the stat element, ex. HitCount
- * <p>
- * @return the stat element name
- */
- @Override
- public String getName()
- {
- return name;
- }
-
- /**
- * @param name
- */
- @Override
- public void setName( String name )
- {
- this.name = name;
- }
-
- /**
- * Get the data, ex. for hit count you would get a value for some number.
- * <p>
- * @return data
- */
- @Override
- public V getData()
- {
- return data;
- }
-
- /**
- * Set the data for this element.
- * <p>
- * @param data
- */
- @Override
- public void setData( V data )
- {
- this.data = data;
- }
-
- /**
- * @return a readable string.
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( name ).append(" = ").append( data );
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/stats/Stats.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/stats/Stats.java
deleted file mode 100644
index dfbf388..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/stats/Stats.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package org.apache.commons.jcs.engine.stats;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-
-import java.util.List;
-
-/**
- * @author aaronsm
- */
-public class Stats
- implements IStats
-{
- /** Don't change */
- private static final long serialVersionUID = 227327902875154010L;
-
- /** The stats */
- private List<IStatElement<?>> stats = null;
-
- /** The type of stat */
- private String typeName = null;
-
- /**
- * @return IStatElement[]
- */
- @Override
- public List<IStatElement<?>> getStatElements()
- {
- return stats;
- }
-
- /**
- * @param stats
- */
- @Override
- public void setStatElements( List<IStatElement<?>> stats )
- {
- this.stats = stats;
- }
-
- /**
- * @return typeName
- */
- @Override
- public String getTypeName()
- {
- return typeName;
- }
-
- /**
- * @param name
- */
- @Override
- public void setTypeName( String name )
- {
- typeName = name;
- }
-
- /**
- * @return the stats in a readable string
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
-
- buf.append( typeName );
-
- if ( stats != null )
- {
- for (Object stat : stats)
- {
- buf.append( "\n" );
- buf.append( stat );
- }
- }
-
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/stats/behavior/ICacheStats.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/stats/behavior/ICacheStats.java
deleted file mode 100644
index 4efd282..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/stats/behavior/ICacheStats.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.apache.commons.jcs.engine.stats.behavior;
-
-import java.util.List;
-
-/*
- * 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.
- */
-
-/**
- * This holds stat information on a region. It contains both auxiliary and core stats.
- */
-public interface ICacheStats
- extends IStats
-{
- /**
- * Stats are for a region, though auxiliary data may be for more.
- * <p>
- * @return The region name
- */
- String getRegionName();
-
- /**
- * @param name
- */
- void setRegionName( String name );
-
- /**
- * @return IStats[]
- */
- List<IStats> getAuxiliaryCacheStats();
-
- /**
- * @param stats
- */
- void setAuxiliaryCacheStats( List<IStats> stats );
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/stats/behavior/IStatElement.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/stats/behavior/IStatElement.java
deleted file mode 100644
index 64139df..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/stats/behavior/IStatElement.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package org.apache.commons.jcs.engine.stats.behavior;
-
-import java.io.Serializable;
-
-/*
- * 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.
- */
-
-/**
- * IAuxiliaryCacheStats will hold these IStatElements.
- */
-public interface IStatElement<V> extends Serializable
-{
- /**
- * Get the name of the stat element, ex. HitCount
- * <p>
- * @return the stat element name
- */
- String getName();
-
- /**
- * @param name
- */
- void setName( String name );
-
- /**
- * Get the data, ex. for hit count you would get a value for some number.
- * <p>
- * @return data
- */
- V getData();
-
- /**
- * Set the data for this element.
- * <p>
- * @param data
- */
- void setData( V data );
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/stats/behavior/IStats.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/stats/behavior/IStats.java
deleted file mode 100644
index 352225a..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/stats/behavior/IStats.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package org.apache.commons.jcs.engine.stats.behavior;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-import java.util.List;
-
-/**
- * This interface defines the common behavior for a stats holder.
- *
- * @author aaronsm
- *
- */
-public interface IStats
- extends Serializable
-{
-
- /**
- * Return generic statistical or historical data.
- *
- * @return list of IStatElements
- */
- List<IStatElement<?>> getStatElements();
-
- /**
- * Set the generic statistical or historical data.
- *
- * @param stats
- */
- void setStatElements( List<IStatElement<?>> stats );
-
- /**
- * Get the type name, such as "LRU Memory Cache." No formal type is defined.
- *
- * @return String
- */
- String getTypeName();
-
- /**
- * Set the type name, such as "LRU Memory Cache." No formal type is defined.
- * If we need formal types, we can use the cachetype param
- *
- * @param name
- */
- void setTypeName( String name );
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/io/ObjectInputStreamClassLoaderAware.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/io/ObjectInputStreamClassLoaderAware.java
deleted file mode 100644
index 09c8f55..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/io/ObjectInputStreamClassLoaderAware.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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.apache.commons.jcs.io;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectStreamClass;
-import java.lang.reflect.Proxy;
-
-public class ObjectInputStreamClassLoaderAware extends ObjectInputStream {
- private final ClassLoader classLoader;
-
- public ObjectInputStreamClassLoaderAware(final InputStream in, final ClassLoader classLoader) throws IOException {
- super(in);
- this.classLoader = classLoader != null ? classLoader : Thread.currentThread().getContextClassLoader();
- }
-
- @Override
- protected Class<?> resolveClass(final ObjectStreamClass desc) throws ClassNotFoundException {
- return Class.forName(BlacklistClassResolver.DEFAULT.check(desc.getName()), false, classLoader);
- }
-
- @Override
- protected Class<?> resolveProxyClass(final String[] interfaces) throws IOException, ClassNotFoundException {
- final Class<?>[] cinterfaces = new Class[interfaces.length];
- for (int i = 0; i < interfaces.length; i++) {
- cinterfaces[i] = Class.forName(interfaces[i], false, classLoader);
- }
-
- try {
- return Proxy.getProxyClass(classLoader, cinterfaces);
- } catch (IllegalArgumentException e) {
- throw new ClassNotFoundException(null, e);
- }
- }
-
- private static class BlacklistClassResolver {
- private static final BlacklistClassResolver DEFAULT = new BlacklistClassResolver(
- toArray(System.getProperty(
- "jcs.serialization.class.blacklist",
- "org.codehaus.groovy.runtime.,org.apache.commons.collections.functors.,org.apache.xalan")),
- toArray(System.getProperty("jcs.serialization.class.whitelist")));
-
- private final String[] blacklist;
- private final String[] whitelist;
-
- protected BlacklistClassResolver(final String[] blacklist, final String[] whitelist) {
- this.whitelist = whitelist;
- this.blacklist = blacklist;
- }
-
- protected boolean isBlacklisted(final String name) {
- return (whitelist != null && !contains(whitelist, name)) || contains(blacklist, name);
- }
-
- public final String check(final String name) {
- if (isBlacklisted(name)) {
- throw new SecurityException(name + " is not whitelisted as deserialisable, prevented before loading.");
- }
- return name;
- }
-
- private static String[] toArray(final String property) {
- return property == null ? null : property.split(" *, *");
- }
-
- private static boolean contains(final String[] list, String name) {
- if (list != null) {
- for (final String white : list) {
- if (name.startsWith(white)) {
- return true;
- }
- }
- }
- return false;
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/JulLogAdapter.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/JulLogAdapter.java
deleted file mode 100644
index fba069f..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/JulLogAdapter.java
+++ /dev/null
@@ -1,574 +0,0 @@
-package org.apache.commons.jcs.log;
-
-import java.util.function.Supplier;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/*
- * 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.
- */
-
-/**
- * This is a wrapper around the <code>java.util.logging.Logger</code> implementing our own
- * <code>Log</code> interface.
- * <p>
- * This is the mapping of the log levels
- * </p>
- * <pre>
- * Java Level Log Level
- * SEVERE FATAL
- * SEVERE ERROR
- * WARNING WARN
- * INFO INFO
- * FINE DEBUG
- * FINER TRACE
- * </pre>
- */
-public class JulLogAdapter implements Log
-{
- private Logger logger;
-
- /**
- * Construct a JUL Logger wrapper
- *
- * @param logger the JUL Logger
- */
- public JulLogAdapter(Logger logger)
- {
- super();
- this.logger = logger;
- }
-
- private void log(Level level, String message)
- {
- if (logger.isLoggable(level))
- {
- logger.logp(level, logger.getName(), "", message);
- }
- }
-
- private void log(Level level, Object message)
- {
- if (logger.isLoggable(level))
- {
- if (message instanceof Throwable)
- {
- logger.logp(level, logger.getName(), "", "Exception:", (Throwable) message);
- }
- else
- {
- logger.logp(level, logger.getName(), "",
- message == null ? null : message.toString());
- }
- }
- }
-
- private void log(Level level, String message, Throwable t)
- {
- if (logger.isLoggable(level))
- {
- logger.logp(level, logger.getName(), "", message, t);
- }
- }
-
- private void log(Level level, String message, Object... params)
- {
- if (logger.isLoggable(level))
- {
- MessageFormatter formatter = new MessageFormatter(message, params);
- if (formatter.hasThrowable())
- {
- logger.logp(level, logger.getName(), "",
- formatter.getFormattedMessage(), formatter.getThrowable());
- }
- else
- {
- logger.logp(level, logger.getName(), "",
- formatter.getFormattedMessage());
- }
- }
- }
-
- private void log(Level level, String message, Supplier<?>... paramSuppliers)
- {
- if (logger.isLoggable(level))
- {
- MessageFormatter formatter = new MessageFormatter(message, paramSuppliers);
- if (formatter.hasThrowable())
- {
- logger.logp(level, logger.getName(), "",
- formatter.getFormattedMessage(), formatter.getThrowable());
- }
- else
- {
- logger.logp(level, logger.getName(), "",
- formatter.getFormattedMessage());
- }
- }
- }
-
- /**
- * Logs a message object with the DEBUG level.
- *
- * @param message the message string to log.
- */
- @Override
- public void debug(String message)
- {
- log(Level.FINE, message);
- }
-
- /**
- * Logs a message object with the DEBUG level.
- *
- * @param message the message object to log.
- */
- @Override
- public void debug(Object message)
- {
- log(Level.FINE, message);
- }
-
- /**
- * Logs a message with parameters at the DEBUG level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param params parameters to the message.
- * @see #getMessageFactory()
- */
- @Override
- public void debug(String message, Object... params)
- {
- log(Level.FINE, message, params);
- }
-
- /**
- * Logs a message with parameters which are only to be constructed if the
- * logging level is the DEBUG level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param paramSuppliers An array of functions, which when called,
- * produce the desired log message parameters.
- */
- @Override
- public void debug(String message, Supplier<?>... paramSuppliers)
- {
- log(Level.FINE, message, paramSuppliers);
- }
-
- /**
- * Logs a message at the DEBUG level including the stack trace of the {@link Throwable}
- * <code>t</code> passed as parameter.
- *
- * @param message the message to log.
- * @param t the exception to log, including its stack trace.
- */
- @Override
- public void debug(String message, Throwable t)
- {
- log(Level.FINE, message, t);
- }
-
- /**
- * Logs a message object with the ERROR level.
- *
- * @param message the message string to log.
- */
- @Override
- public void error(String message)
- {
- log(Level.SEVERE, message);
- }
-
- /**
- * Logs a message object with the ERROR level.
- *
- * @param message the message object to log.
- */
- @Override
- public void error(Object message)
- {
- log(Level.SEVERE, message);
- }
-
- /**
- * Logs a message with parameters at the ERROR level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param params parameters to the message.
- */
- @Override
- public void error(String message, Object... params)
- {
- log(Level.SEVERE, message, params);
- }
-
- /**
- * Logs a message with parameters which are only to be constructed if the
- * logging level is the ERROR level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param paramSuppliers An array of functions, which when called, produce
- * the desired log message parameters.
- * @since 2.4
- */
- @Override
- public void error(String message, Supplier<?>... paramSuppliers)
- {
- log(Level.SEVERE, message, paramSuppliers);
- }
-
- /**
- * Logs a message at the ERROR level including the stack trace of the {@link Throwable}
- * <code>t</code> passed as parameter.
- *
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- */
- @Override
- public void error(String message, Throwable t)
- {
- log(Level.SEVERE, message, t);
- }
-
- /**
- * Logs a message object with the FATAL level.
- *
- * @param message the message string to log.
- */
- @Override
- public void fatal(String message)
- {
- log(Level.SEVERE, message);
- }
-
- /**
- * Logs a message object with the FATAL level.
- *
- * @param message the message object to log.
- */
- @Override
- public void fatal(Object message)
- {
- log(Level.SEVERE, message);
- }
-
- /**
- * Logs a message with parameters at the FATAL level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param params parameters to the message.
- */
- @Override
- public void fatal(String message, Object... params)
- {
- log(Level.SEVERE, message, params);
- }
-
- /**
- * Logs a message with parameters which are only to be constructed if the
- * logging level is the FATAL level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param paramSuppliers An array of functions, which when called, produce the
- * desired log message parameters.
- */
- @Override
- public void fatal(String message, Supplier<?>... paramSuppliers)
- {
- log(Level.SEVERE, message, paramSuppliers);
- }
-
- /**
- * Logs a message at the FATAL level including the stack trace of the {@link Throwable}
- * <code>t</code> passed as parameter.
- *
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- */
- @Override
- public void fatal(String message, Throwable t)
- {
- log(Level.SEVERE, message, t);
- }
-
- /**
- * Gets the logger name.
- *
- * @return the logger name.
- */
- @Override
- public String getName()
- {
- return logger.getName();
- }
-
- /**
- * Logs a message object with the INFO level.
- *
- * @param message the message string to log.
- */
- @Override
- public void info(String message)
- {
- log(Level.INFO, message);
- }
-
- /**
- * Logs a message object with the INFO level.
- *
- * @param message the message object to log.
- */
- @Override
- public void info(Object message)
- {
- log(Level.INFO, message);
- }
-
- /**
- * Logs a message with parameters at the INFO level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param params parameters to the message.
- */
- @Override
- public void info(String message, Object... params)
- {
- log(Level.INFO, message, params);
- }
-
- /**
- * Logs a message with parameters which are only to be constructed if the
- * logging level is the INFO level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param paramSuppliers An array of functions, which when called, produce
- * the desired log message parameters.
- */
- @Override
- public void info(String message, Supplier<?>... paramSuppliers)
- {
- log(Level.INFO, message, paramSuppliers);
- }
-
- /**
- * Logs a message at the INFO level including the stack trace of the {@link Throwable}
- * <code>t</code> passed as parameter.
- *
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- */
- @Override
- public void info(String message, Throwable t)
- {
- log(Level.INFO, message, t);
- }
-
- /**
- * Checks whether this Logger is enabled for the DEBUG Level.
- *
- * @return boolean - {@code true} if this Logger is enabled for level DEBUG, {@code false}
- * otherwise.
- */
- @Override
- public boolean isDebugEnabled()
- {
- return logger.isLoggable(Level.FINE);
- }
-
- /**
- * Checks whether this Logger is enabled for the ERROR Level.
- *
- * @return boolean - {@code true} if this Logger is enabled for level ERROR, {@code false}
- * otherwise.
- */
- @Override
- public boolean isErrorEnabled()
- {
- return logger.isLoggable(Level.SEVERE);
- }
-
- /**
- * Checks whether this Logger is enabled for the FATAL Level.
- *
- * @return boolean - {@code true} if this Logger is enabled for level FATAL, {@code false}
- * otherwise.
- */
- @Override
- public boolean isFatalEnabled()
- {
- return logger.isLoggable(Level.SEVERE);
- }
-
- /**
- * Checks whether this Logger is enabled for the INFO Level.
- *
- * @return boolean - {@code true} if this Logger is enabled for level INFO, {@code false}
- * otherwise.
- */
- @Override
- public boolean isInfoEnabled()
- {
- return logger.isLoggable(Level.INFO);
- }
-
- /**
- * Checks whether this Logger is enabled for the TRACE level.
- *
- * @return boolean - {@code true} if this Logger is enabled for level TRACE, {@code false}
- * otherwise.
- */
- @Override
- public boolean isTraceEnabled()
- {
- return logger.isLoggable(Level.FINER);
- }
-
- /**
- * Checks whether this Logger is enabled for the WARN Level.
- *
- * @return boolean - {@code true} if this Logger is enabled for level WARN, {@code false}
- * otherwise.
- */
- @Override
- public boolean isWarnEnabled()
- {
- return logger.isLoggable(Level.WARNING);
- }
-
- /**
- * Logs a message object with the TRACE level.
- *
- * @param message the message string to log.
- */
- @Override
- public void trace(String message)
- {
- log(Level.FINER, message);
- }
-
- /**
- * Logs a message object with the TRACE level.
- *
- * @param message the message object to log.
- */
- @Override
- public void trace(Object message)
- {
- log(Level.FINER, message);
- }
-
- /**
- * Logs a message with parameters at the TRACE level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param params parameters to the message.
- */
- @Override
- public void trace(String message, Object... params)
- {
- log(Level.FINER, message, params);
- }
-
- /**
- * Logs a message with parameters which are only to be constructed if the
- * logging level is the TRACE level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param paramSuppliers An array of functions, which when called, produce
- * the desired log message parameters.
- */
- @Override
- public void trace(String message, Supplier<?>... paramSuppliers)
- {
- log(Level.FINER, message, paramSuppliers);
- }
-
- /**
- * Logs a message at the TRACE level including the stack trace of the {@link Throwable}
- * <code>t</code> passed as parameter.
- *
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- * @see #debug(String)
- */
- @Override
- public void trace(String message, Throwable t)
- {
- log(Level.FINER, message, t);
- }
-
- /**
- * Logs a message object with the WARN level.
- *
- * @param message the message string to log.
- */
- @Override
- public void warn(String message)
- {
- log(Level.WARNING, message);
- }
-
- /**
- * Logs a message object with the WARN level.
- *
- * @param message the message object to log.
- */
- @Override
- public void warn(Object message)
- {
- log(Level.WARNING, message);
- }
-
- /**
- * Logs a message with parameters at the WARN level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param params parameters to the message.
- */
- @Override
- public void warn(String message, Object... params)
- {
- log(Level.WARNING, message, params);
- }
-
- /**
- * Logs a message with parameters which are only to be constructed if the
- * logging level is the WARN level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param paramSuppliers An array of functions, which when called, produce
- * the desired log message parameters.
- */
- @Override
- public void warn(String message, Supplier<?>... paramSuppliers)
- {
- log(Level.WARNING, message, paramSuppliers);
- }
-
- /**
- * Logs a message at the WARN level including the stack trace of the {@link Throwable}
- * <code>t</code> passed as parameter.
- *
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- */
- @Override
- public void warn(String message, Throwable t)
- {
- log(Level.WARNING, message, t);
- }
-}
\ No newline at end of file
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/JulLogFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/JulLogFactory.java
deleted file mode 100644
index c1e21eb..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/JulLogFactory.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package org.apache.commons.jcs.log;
-
-import java.util.logging.Logger;
-
-/*
- * 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.
- */
-
-/**
- * This is a SPI factory implementation for java.util.logging
- */
-public class JulLogFactory implements LogFactory
-{
- /**
- * Return the name of the Log subsystem managed by this factory
- *
- * @return the name of the log subsystem
- */
- @Override
- public String getName()
- {
- return "jul";
- }
-
- /**
- * Shutdown the logging system if the logging system supports it.
- */
- @Override
- public void shutdown()
- {
- // do nothing
- }
-
- /**
- * Returns a Log using the fully qualified name of the Class as the Log
- * name.
- *
- * @param clazz
- * The Class whose name should be used as the Log name.
- *
- * @return The Log.
- */
- @Override
- public Log getLog(final Class<?> clazz)
- {
- Logger logger = Logger.getLogger(clazz.getName());
- return new JulLogAdapter(logger);
- }
-
- /**
- * Returns a Log with the specified name.
- *
- * @param name
- * The logger name.
- * @return The Log.
- */
- @Override
- public Log getLog(final String name)
- {
- Logger logger = Logger.getLogger(name);
- return new JulLogAdapter(logger);
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/Log.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/Log.java
deleted file mode 100644
index b548db4..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/Log.java
+++ /dev/null
@@ -1,343 +0,0 @@
-package org.apache.commons.jcs.log;
-
-/*
- * 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.
- */
-
-import java.util.function.Supplier;
-
-/**
- * This is a borrowed and stripped-down version of the log4j2 Logger interface.
- * All logging operations, except configuration, are done through this interface.
- *
- * <p>
- * The canonical way to obtain a Logger for a class is through {@link LogManager#getLog()}.
- * Typically, each class should get its own Log named after its fully qualified class name
- * </p>
- *
- * <pre>
- * public class MyClass {
- * private static final Log log = LogManager.getLog(MyClass.class);
- * // ...
- * }
- * </pre>
- */
-public interface Log
-{
- /**
- * Logs a message object with the DEBUG level.
- *
- * @param message the message string to log.
- */
- void debug(String message);
-
- /**
- * Logs a message object with the DEBUG level.
- *
- * @param message the message object to log.
- */
- void debug(Object message);
-
- /**
- * Logs a message with parameters at the DEBUG level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param params parameters to the message.
- */
- void debug(String message, Object... params);
-
- /**
- * Logs a message with parameters which are only to be constructed if the
- * logging level is the DEBUG level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param paramSuppliers An array of functions, which when called, produce
- * the desired log message parameters.
- */
- void debug(String message, Supplier<?>... paramSuppliers);
-
- /**
- * Logs a message at the DEBUG level including the stack trace of the {@link Throwable}
- * <code>t</code> passed as parameter.
- *
- * @param message the message to log.
- * @param t the exception to log, including its stack trace.
- */
- void debug(String message, Throwable t);
-
- /**
- * Logs a message object with the ERROR level.
- *
- * @param message the message string to log.
- */
- void error(String message);
-
- /**
- * Logs a message object with the ERROR level.
- *
- * @param message the message object to log.
- */
- void error(Object message);
-
- /**
- * Logs a message with parameters at the ERROR level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param params parameters to the message.
- */
- void error(String message, Object... params);
-
- /**
- * Logs a message with parameters which are only to be constructed if the
- * logging level is the ERROR level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param paramSuppliers An array of functions, which when called, produce
- * the desired log message parameters.
- */
- void error(String message, Supplier<?>... paramSuppliers);
-
- /**
- * Logs a message at the ERROR level including the stack trace of the {@link Throwable}
- * <code>t</code> passed as parameter.
- *
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- */
- void error(String message, Throwable t);
-
- /**
- * Logs a message object with the FATAL level.
- *
- * @param message the message string to log.
- */
- void fatal(String message);
-
- /**
- * Logs a message object with the FATAL level.
- *
- * @param message the message object to log.
- */
- void fatal(Object message);
-
- /**
- * Logs a message with parameters at the FATAL level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param params parameters to the message.
- */
- void fatal(String message, Object... params);
-
- /**
- * Logs a message with parameters which are only to be constructed if the
- * logging level is the FATAL level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param paramSuppliers An array of functions, which when called, produce
- * the desired log message parameters.
- */
- void fatal(String message, Supplier<?>... paramSuppliers);
-
- /**
- * Logs a message at the FATAL level including the stack trace of the {@link Throwable}
- * <code>t</code> passed as parameter.
- *
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- */
- void fatal(String message, Throwable t);
-
- /**
- * Gets the logger name.
- *
- * @return the logger name.
- */
- String getName();
-
- /**
- * Logs a message object with the INFO level.
- *
- * @param message the message string to log.
- */
- void info(String message);
-
- /**
- * Logs a message object with the INFO level.
- *
- * @param message the message object to log.
- */
- void info(Object message);
-
- /**
- * Logs a message with parameters at the INFO level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param params parameters to the message.
- */
- void info(String message, Object... params);
-
- /**
- * Logs a message with parameters which are only to be constructed if the
- * logging level is the INFO level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param paramSuppliers An array of functions, which when called, produce
- * the desired log message parameters.
- */
- void info(String message, Supplier<?>... paramSuppliers);
-
- /**
- * Logs a message at the INFO level including the stack trace of the {@link Throwable}
- * <code>t</code> passed as parameter.
- *
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- */
- void info(String message, Throwable t);
-
- /**
- * Checks whether this Logger is enabled for the DEBUG Level.
- *
- * @return boolean - {@code true} if this Logger is enabled for level DEBUG, {@code false}
- * otherwise.
- */
- boolean isDebugEnabled();
-
- /**
- * Checks whether this Logger is enabled for the ERROR Level.
- *
- * @return boolean - {@code true} if this Logger is enabled for level ERROR, {@code false}
- * otherwise.
- */
- boolean isErrorEnabled();
-
- /**
- * Checks whether this Logger is enabled for the FATAL Level.
- *
- * @return boolean - {@code true} if this Logger is enabled for level FATAL, {@code false}
- * otherwise.
- */
- boolean isFatalEnabled();
-
- /**
- * Checks whether this Logger is enabled for the INFO Level.
- *
- * @return boolean - {@code true} if this Logger is enabled for level INFO, {@code false}
- * otherwise.
- */
- boolean isInfoEnabled();
-
- /**
- * Checks whether this Logger is enabled for the TRACE level.
- *
- * @return boolean - {@code true} if this Logger is enabled for level TRACE, {@code false}
- * otherwise.
- */
- boolean isTraceEnabled();
-
- /**
- * Checks whether this Logger is enabled for the WARN Level.
- *
- * @return boolean - {@code true} if this Logger is enabled for level WARN, {@code false}
- * otherwise.
- */
- boolean isWarnEnabled();
-
- /**
- * Logs a message object with the TRACE level.
- *
- * @param message the message string to log.
- */
- void trace(String message);
-
- /**
- * Logs a message object with the TRACE level.
- *
- * @param message the message object to log.
- */
- void trace(Object message);
-
- /**
- * Logs a message with parameters at the TRACE level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param params parameters to the message.
- * @see #getMessageFactory()
- */
- void trace(String message, Object... params);
-
- /**
- * Logs a message with parameters which are only to be constructed if the
- * logging level is the TRACE level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param paramSuppliers An array of functions, which when called, produce
- * the desired log message parameters.
- */
- void trace(String message, Supplier<?>... paramSuppliers);
-
- /**
- * Logs a message at the TRACE level including the stack trace of the {@link Throwable}
- * <code>t</code> passed as parameter.
- *
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- * @see #debug(String)
- */
- void trace(String message, Throwable t);
-
- /**
- * Logs a message object with the WARN level.
- *
- * @param message the message string to log.
- */
- void warn(String message);
-
- /**
- * Logs a message object with the WARN level.
- *
- * @param message the message object to log.
- */
- void warn(Object message);
-
- /**
- * Logs a message with parameters at the WARN level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param params parameters to the message.
- * @see #getMessageFactory()
- */
- void warn(String message, Object... params);
-
- /**
- * Logs a message with parameters which are only to be constructed if the
- * logging level is the WARN level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param paramSuppliers An array of functions, which when called, produce
- * the desired log message parameters.
- */
- void warn(String message, Supplier<?>... paramSuppliers);
-
- /**
- * Logs a message at the WARN level including the stack trace of the {@link Throwable}
- * <code>t</code> passed as parameter.
- *
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- */
- void warn(String message, Throwable t);
-}
\ No newline at end of file
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/Log4j2Factory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/Log4j2Factory.java
deleted file mode 100644
index 0f56364..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/Log4j2Factory.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package org.apache.commons.jcs.log;
-
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.message.MessageFactory;
-import org.apache.logging.log4j.message.MessageFormatMessageFactory;
-
-/*
- * 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.
- */
-
-/**
- * This is a SPI factory implementation for log4j2
- */
-public class Log4j2Factory implements LogFactory
-{
- /** Use java.text.MessageFormat for log messages */
- private MessageFactory messageFactory = new MessageFormatMessageFactory();
-
- /**
- * Return the name of the Log subsystem managed by this factory
- *
- * @return the name of the log subsystem
- */
- @Override
- public String getName()
- {
- return "log4j2";
- }
-
- /**
- * Shutdown the logging system if the logging system supports it.
- */
- @Override
- public void shutdown()
- {
- org.apache.logging.log4j.LogManager.shutdown();
- }
-
- /**
- * Returns a Log using the fully qualified name of the Class as the Log
- * name.
- *
- * @param clazz
- * The Class whose name should be used as the Log name. If null
- * it will default to the calling class.
- * @return The Log.
- * @throws UnsupportedOperationException
- * if {@code clazz} is {@code null} and the calling class cannot
- * be determined.
- */
- @Override
- public Log getLog(final Class<?> clazz)
- {
- Logger logger = org.apache.logging.log4j.LogManager.getLogger(clazz, messageFactory);
- return new Log4j2LogAdapter(logger);
- }
-
- /**
- * Returns a Log with the specified name.
- *
- * @param name
- * The logger name. If null the name of the calling class will be
- * used.
- * @return The Log.
- * @throws UnsupportedOperationException
- * if {@code name} is {@code null} and the calling class cannot
- * be determined.
- */
- @Override
- public Log getLog(final String name)
- {
- Logger logger = org.apache.logging.log4j.LogManager.getLogger(name, messageFactory);
- return new Log4j2LogAdapter(logger);
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/Log4j2LogAdapter.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/Log4j2LogAdapter.java
deleted file mode 100644
index 2f437fe..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/Log4j2LogAdapter.java
+++ /dev/null
@@ -1,531 +0,0 @@
-package org.apache.commons.jcs.log;
-
-/*
- * 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.
- */
-
-import java.util.function.Supplier;
-
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.Logger;
-
-/**
- * This is a wrapper around the <code>org.apache.logging.log4j.Logger</code> implementing our own
- * <code>Log</code> interface.
- */
-public class Log4j2LogAdapter implements Log
-{
- private Logger logger;
-
- /**
- * Construct a Log4j Logger wrapper
- *
- * @param logger the log4j Logger
- */
- public Log4j2LogAdapter(Logger logger)
- {
- super();
- this.logger = logger;
- }
-
- private void log(Level level, String message, Supplier<?>... paramSuppliers)
- {
- if (logger.isEnabled(level))
- {
- if (paramSuppliers == null)
- {
- logger.log(level, message);
- }
- else
- {
- switch (paramSuppliers.length)
- {
- case 1: logger.log(level, message, paramSuppliers[0].get());
- break;
- case 2: logger.log(level, message, paramSuppliers[0].get(),
- paramSuppliers[1].get());
- break;
- case 3: logger.log(level, message, paramSuppliers[0].get(),
- paramSuppliers[1].get(), paramSuppliers[2].get());
- break;
- case 4: logger.log(level, message, paramSuppliers[0].get(),
- paramSuppliers[1].get(), paramSuppliers[2].get(),
- paramSuppliers[3].get());
- break;
- case 5: logger.log(level, message, paramSuppliers[0].get(),
- paramSuppliers[1].get(), paramSuppliers[2].get(),
- paramSuppliers[3].get(), paramSuppliers[4].get());
- break;
- default: logger.log(level, message, paramSuppliers[0].get(),
- paramSuppliers[1].get(), paramSuppliers[2].get(),
- paramSuppliers[3].get(), paramSuppliers[4].get(),
- paramSuppliers[5].get());
- break;
- }
- }
- }
- }
-
- /**
- * Logs a message object with the DEBUG level.
- *
- * @param message the message string to log.
- */
- @Override
- public void debug(String message)
- {
- logger.debug(message);
- }
-
- /**
- * Logs a message object with the DEBUG level.
- *
- * @param message the message object to log.
- */
- @Override
- public void debug(Object message)
- {
- logger.debug(message);
- }
-
- /**
- * Logs a message with parameters at the DEBUG level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param params parameters to the message.
- */
- @Override
- public void debug(String message, Object... params)
- {
- logger.debug(message, params);
- }
-
- /**
- * Logs a message with parameters which are only to be constructed if the
- * logging level is the DEBUG level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param paramSuppliers An array of functions, which when called, produce
- * the desired log message parameters.
- */
- @Override
- public void debug(String message, Supplier<?>... paramSuppliers)
- {
- log(Level.DEBUG, message, paramSuppliers);
- }
-
- /**
- * Logs a message at the DEBUG level including the stack trace of the {@link Throwable}
- * <code>t</code> passed as parameter.
- *
- * @param message the message to log.
- * @param t the exception to log, including its stack trace.
- */
- @Override
- public void debug(String message, Throwable t)
- {
- logger.debug(message, t);
- }
-
- /**
- * Logs a message object with the ERROR level.
- *
- * @param message the message string to log.
- */
- @Override
- public void error(String message)
- {
- logger.error(message);
- }
-
- /**
- * Logs a message object with the ERROR level.
- *
- * @param message the message object to log.
- */
- @Override
- public void error(Object message)
- {
- logger.error(message);
- }
-
- /**
- * Logs a message with parameters at the ERROR level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param params parameters to the message.
- */
- @Override
- public void error(String message, Object... params)
- {
- logger.error(message, params);
- }
-
- /**
- * Logs a message with parameters which are only to be constructed if the
- * logging level is the ERROR level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param paramSuppliers An array of functions, which when called, produce
- * the desired log message parameters.
- */
- @Override
- public void error(String message, Supplier<?>... paramSuppliers)
- {
- log(Level.ERROR, message, paramSuppliers);
- }
-
- /**
- * Logs a message at the ERROR level including the stack trace of the {@link Throwable}
- * <code>t</code> passed as parameter.
- *
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- */
- @Override
- public void error(String message, Throwable t)
- {
- logger.error(message, t);
- }
-
- /**
- * Logs a message object with the FATAL level.
- *
- * @param message the message string to log.
- */
- @Override
- public void fatal(String message)
- {
- logger.fatal(message);
- }
-
- /**
- * Logs a message object with the FATAL level.
- *
- * @param message the message object to log.
- */
- @Override
- public void fatal(Object message)
- {
- logger.fatal(message);
- }
-
- /**
- * Logs a message with parameters at the FATAL level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param params parameters to the message.
- */
- @Override
- public void fatal(String message, Object... params)
- {
- logger.fatal(message, params);
- }
-
- /**
- * Logs a message with parameters which are only to be constructed if the
- * logging level is the FATAL level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param paramSuppliers An array of functions, which when called, produce
- * the desired log message parameters.
- */
- @Override
- public void fatal(String message, Supplier<?>... paramSuppliers)
- {
- log(Level.FATAL, message, paramSuppliers);
- }
-
- /**
- * Logs a message at the FATAL level including the stack trace of the {@link Throwable}
- * <code>t</code> passed as parameter.
- *
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- */
- @Override
- public void fatal(String message, Throwable t)
- {
- logger.fatal(message, t);
- }
-
- /**
- * Gets the logger name.
- *
- * @return the logger name.
- */
- @Override
- public String getName()
- {
- return logger.getName();
- }
-
- /**
- * Logs a message object with the INFO level.
- *
- * @param message the message string to log.
- */
- @Override
- public void info(String message)
- {
- logger.info(message);
- }
-
- /**
- * Logs a message object with the INFO level.
- *
- * @param message the message object to log.
- */
- @Override
- public void info(Object message)
- {
- logger.info(message);
- }
-
- /**
- * Logs a message with parameters at the INFO level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param params parameters to the message.
- */
- @Override
- public void info(String message, Object... params)
- {
- logger.info(message, params);
- }
-
- /**
- * Logs a message with parameters which are only to be constructed if the
- * logging level is the INFO level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param paramSuppliers An array of functions, which when called, produce
- * the desired log message parameters.
- */
- @Override
- public void info(String message, Supplier<?>... paramSuppliers)
- {
- log(Level.INFO, message, paramSuppliers);
- }
-
- /**
- * Logs a message at the INFO level including the stack trace of the {@link Throwable}
- * <code>t</code> passed as parameter.
- *
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- */
- @Override
- public void info(String message, Throwable t)
- {
- logger.info(message, t);
- }
-
- /**
- * Checks whether this Logger is enabled for the DEBUG Level.
- *
- * @return boolean - {@code true} if this Logger is enabled for level DEBUG, {@code false}
- * otherwise.
- */
- @Override
- public boolean isDebugEnabled()
- {
- return logger.isDebugEnabled();
- }
-
- /**
- * Checks whether this Logger is enabled for the ERROR Level.
- *
- * @return boolean - {@code true} if this Logger is enabled for level ERROR, {@code false}
- * otherwise.
- */
- @Override
- public boolean isErrorEnabled()
- {
- return logger.isErrorEnabled();
- }
-
- /**
- * Checks whether this Logger is enabled for the FATAL Level.
- *
- * @return boolean - {@code true} if this Logger is enabled for level FATAL, {@code false}
- * otherwise.
- */
- @Override
- public boolean isFatalEnabled()
- {
- return logger.isFatalEnabled();
- }
-
- /**
- * Checks whether this Logger is enabled for the INFO Level.
- *
- * @return boolean - {@code true} if this Logger is enabled for level INFO, {@code false}
- * otherwise.
- */
- @Override
- public boolean isInfoEnabled()
- {
- return logger.isInfoEnabled();
- }
-
- /**
- * Checks whether this Logger is enabled for the TRACE level.
- *
- * @return boolean - {@code true} if this Logger is enabled for level TRACE, {@code false}
- * otherwise.
- */
- @Override
- public boolean isTraceEnabled()
- {
- return logger.isTraceEnabled();
- }
-
- /**
- * Checks whether this Logger is enabled for the WARN Level.
- *
- * @return boolean - {@code true} if this Logger is enabled for level WARN, {@code false}
- * otherwise.
- */
- @Override
- public boolean isWarnEnabled()
- {
- return logger.isWarnEnabled();
- }
-
- /**
- * Logs a message object with the TRACE level.
- *
- * @param message the message string to log.
- */
- @Override
- public void trace(String message)
- {
- logger.trace(message);
- }
-
- /**
- * Logs a message object with the TRACE level.
- *
- * @param message the message object to log.
- */
- @Override
- public void trace(Object message)
- {
- logger.trace(message);
- }
-
- /**
- * Logs a message with parameters at the TRACE level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param params parameters to the message.
- */
- @Override
- public void trace(String message, Object... params)
- {
- logger.trace(message, params);
- }
-
- /**
- * Logs a message with parameters which are only to be constructed if the
- * logging level is the TRACE level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param paramSuppliers An array of functions, which when called, produce
- * the desired log message parameters.
- */
- @Override
- public void trace(String message, Supplier<?>... paramSuppliers)
- {
- log(Level.TRACE, message, paramSuppliers);
- }
-
- /**
- * Logs a message at the TRACE level including the stack trace of the {@link Throwable}
- * <code>t</code> passed as parameter.
- *
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- * @see #debug(String)
- */
- @Override
- public void trace(String message, Throwable t)
- {
- logger.trace(message, t);
- }
-
- /**
- * Logs a message object with the WARN level.
- *
- * @param message the message string to log.
- */
- @Override
- public void warn(String message)
- {
- logger.warn(message);
- }
-
- /**
- * Logs a message object with the WARN level.
- *
- * @param message the message object to log.
- */
- @Override
- public void warn(Object message)
- {
- logger.warn(message);
- }
-
- /**
- * Logs a message with parameters at the WARN level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param params parameters to the message.
- */
- @Override
- public void warn(String message, Object... params)
- {
- logger.warn(message, params);
- }
-
- /**
- * Logs a message with parameters which are only to be constructed if the
- * logging level is the WARN level.
- *
- * @param message the message to log; the format depends on the message factory.
- * @param paramSuppliers An array of functions, which when called, produce
- * the desired log message parameters.
- */
- @Override
- public void warn(String message, Supplier<?>... paramSuppliers)
- {
- log(Level.WARN, message, paramSuppliers);
- }
-
- /**
- * Logs a message at the WARN level including the stack trace of the {@link Throwable}
- * <code>t</code> passed as parameter.
- *
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- */
- @Override
- public void warn(String message, Throwable t)
- {
- logger.warn(message, t);
- }
-}
\ No newline at end of file
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/LogFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/LogFactory.java
deleted file mode 100644
index c328293..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/LogFactory.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.apache.commons.jcs.log;
-
-/*
- * 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.
- */
-
-/**
- * This is a SPI factory interface for specialized Log objects
- */
-public interface LogFactory
-{
- /**
- * The name of the root Log.
- */
- String ROOT_LOGGER_NAME = "";
-
- /**
- * Return the name of the Log subsystem managed by this factory
- *
- * @return the name of the log subsystem
- */
- String getName();
-
- /**
- * Shutdown the logging system if the logging system supports it.
- */
- void shutdown();
-
- /**
- * Returns a Log using the fully qualified name of the Class as the Log
- * name.
- *
- * @param clazz
- * The Class whose name should be used as the Log name. If null
- * it will default to the calling class.
- * @return The Log.
- * @throws UnsupportedOperationException
- * if {@code clazz} is {@code null} and the calling class cannot
- * be determined.
- */
- Log getLog(final Class<?> clazz);
-
- /**
- * Returns a Log with the specified name.
- *
- * @param name
- * The logger name. If null the name of the calling class will be
- * used.
- * @return The Log.
- * @throws UnsupportedOperationException
- * if {@code name} is {@code null} and the calling class cannot
- * be determined.
- */
- Log getLog(final String name);
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/LogManager.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/LogManager.java
deleted file mode 100644
index 4256d12..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/LogManager.java
+++ /dev/null
@@ -1,139 +0,0 @@
-package org.apache.commons.jcs.log;
-
-/*
- * 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.
- */
-
-import java.util.ServiceLoader;
-
-/**
- * This is a borrowed and stripped-down version of the log4j2 LogManager class.
- *
- * The anchor point for the JCS logging system. The most common usage of this
- * class is to obtain a named {@link Log}.
- */
-public class LogManager
-{
- /**
- * The name of log subsystem
- */
- private static String logSystem = null;
-
- /**
- * The SPI LogFactory
- */
- private static class LogFactoryHolder
- {
- static final LogFactory INSTANCE = createLogFactory();
-
- /**
- * Scans the classpath to find a logging implementation.
- *
- * @return the LogFactory
- * @throws RuntimeException, if no factory implementation could be found
- */
- private static LogFactory createLogFactory()
- {
- ServiceLoader<LogFactory> factories = ServiceLoader.load(LogFactory.class);
- if (LogManager.logSystem == null)
- {
- LogManager.logSystem = System.getProperty("jcs.logSystem", "jul");
- }
-
- for (LogFactory factory : factories)
- {
- if (logSystem.equalsIgnoreCase(factory.getName()))
- {
- return factory;
- }
- }
-
- throw new RuntimeException("Could not find factory implementation for log subsystem " + logSystem);
- }
- }
-
- /**
- * Set the log system. Must be called before getLog is called
- *
- * @param logSystem the logSystem to set
- */
- public static void setLogSystem(String logSystem)
- {
- LogManager.logSystem = logSystem;
- }
-
- /**
- * Return the LogFactory
- */
- private static LogFactory getLogFactory()
- {
- return LogFactoryHolder.INSTANCE;
- }
-
- /**
- * Prevents instantiation
- */
- protected LogManager()
- {
- }
-
- /**
- * Shutdown the logging system if the logging system supports it.
- */
- public static void shutdown()
- {
- getLogFactory().shutdown();
- }
-
- /**
- * Returns a Log using the fully qualified name of the Class as the Log
- * name.
- *
- * @param clazz
- * The Class whose name should be used as the Log name.
- * @return The Log.
- * @throws UnsupportedOperationException
- * if {@code clazz} is {@code null}
- */
- public static Log getLog(final Class<?> clazz)
- {
- return getLogFactory().getLog(clazz);
- }
-
- /**
- * Returns a Log with the specified name.
- *
- * @param name
- * The logger name.
- * @return The Log.
- * @throws UnsupportedOperationException
- * if {@code name} is {@code null}
- */
- public static Log getLog(final String name)
- {
- return getLogFactory().getLog(name);
- }
-
- /**
- * Returns the root logger.
- *
- * @return the root logger, named {@link LogFactory.ROOT_LOGGER_NAME}.
- */
- public static Log getRootLogger()
- {
- return getLog(LogFactory.ROOT_LOGGER_NAME);
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/MessageFormatter.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/MessageFormatter.java
deleted file mode 100644
index f8e7fc6..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/log/MessageFormatter.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package org.apache.commons.jcs.log;
-
-/*
- * 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.
- */
-
-import java.text.MessageFormat;
-import java.util.Arrays;
-import java.util.IllegalFormatException;
-import java.util.function.Supplier;
-
-/**
- * Handles messages that consist of a format string conforming to
- * java.text.MessageFormat. (Borrowed from log4j2)
- */
-public class MessageFormatter
-{
- private String messagePattern;
- private transient Object[] parameters;
- private transient String formattedMessage;
- private transient Throwable throwable;
-
- /**
- * Constructs a message formatter.
- *
- * @param messagePattern
- * the pattern for this message format
- * @param parameters
- * The objects to format
- */
- public MessageFormatter(final String messagePattern, final Object... parameters)
- {
- this.messagePattern = messagePattern;
- this.parameters = parameters;
- final int length = parameters == null ? 0 : parameters.length;
- if (length > 0 && parameters[length - 1] instanceof Throwable)
- {
- this.throwable = (Throwable) parameters[length - 1];
- }
- }
-
- /**
- * Constructs a message formatter.
- *
- * @param messagePattern
- * the pattern for this message format
- * @param paramSuppliers
- * An array of functions, which when called, produce the desired
- * log message parameters.
- */
- public MessageFormatter(final String messagePattern, final Supplier<?>... paramSuppliers)
- {
- this.messagePattern = messagePattern;
- this.parameters = Arrays.stream(paramSuppliers)
- .map(s -> s.get())
- .toArray();
-
- final int length = parameters == null ? 0 : parameters.length;
- if (length > 0 && parameters[length - 1] instanceof Throwable)
- {
- this.throwable = (Throwable) parameters[length - 1];
- }
- }
-
- /**
- * Returns the formatted message.
- *
- * @return the formatted message.
- */
- public String getFormattedMessage()
- {
- if (formattedMessage == null)
- {
- formattedMessage = formatMessage(messagePattern, parameters);
- }
- return formattedMessage;
- }
-
- protected String formatMessage(final String msgPattern, final Object... args)
- {
- try
- {
- final MessageFormat temp = new MessageFormat(msgPattern);
- return temp.format(args);
- }
- catch (final IllegalFormatException ife)
- {
- return msgPattern;
- }
- }
-
- @Override
- public String toString()
- {
- return getFormattedMessage();
- }
-
- /**
- * Return the throwable passed to the Message.
- *
- * @return the Throwable.
- */
- public Throwable getThrowable()
- {
- return throwable;
- }
-
- /**
- * Return true, if the parameters list contains a Throwable.
- *
- * @return true, if the parameters list contains a Throwable.
- */
- public boolean hasThrowable()
- {
- return throwable != null;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/access/AbstractJCSWorkerHelper.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/access/AbstractJCSWorkerHelper.java
deleted file mode 100644
index 88b97b2..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/access/AbstractJCSWorkerHelper.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.apache.commons.jcs.utils.access;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/*
- * 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.
- */
-
-/**
- * This is an abstract template for JCSWorkerHelper implementations. it simple has a convenience
- * method for setting the finished flag.
- * <p>
- * @author tsavo
- */
-public abstract class AbstractJCSWorkerHelper<V> implements JCSWorkerHelper<V>
-{
- /** finished flag. Can't we use wait notify? */
- private final AtomicBoolean finished = new AtomicBoolean(false);
-
- /**
- * Default
- */
- public AbstractJCSWorkerHelper()
- {
- super();
- }
-
- /**
- * @return finished
- */
- @Override
- public boolean isFinished()
- {
- return finished.get();
- }
-
- /**
- * @param isFinished
- */
- @Override
- public void setFinished( boolean isFinished )
- {
- finished.set(isFinished);
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/access/JCSWorker.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/access/JCSWorker.java
deleted file mode 100644
index d1c2e3b..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/access/JCSWorker.java
+++ /dev/null
@@ -1,286 +0,0 @@
-package org.apache.commons.jcs.utils.access;
-
-/*
- * 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.
- */
-
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.access.GroupCacheAccess;
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * Utility class to encapsulate doing a piece of work, and caching the results
- * in JCS. Simply construct this class with the region name for the Cache and
- * keep a static reference to it instead of the JCS itself. Then make a new
- * org.apache.commons.jcs.utils.access.AbstractJCSWorkerHelper and implement Object
- * doWork() and do the work in there, returning the object to be cached. Then
- * call .getResult() with the key and the AbstractJCSWorkerHelper to get the
- * result of the work. If the object isn't already in the Cache,
- * AbstractJCSWorkerHelper.doWork() will get called, and the result will be put
- * into the cache. If the object is already in cache, the cached result will be
- * returned instead.
- * <p>
- * As an added bonus, multiple JCSWorkers with the same region, and key won't do
- * the work multiple times: The first JCSWorker to get started will do the work,
- * and all subsequent workers with the same region, group, and key will wait on
- * the first one and use his resulting work instead of doing the work
- * themselves.
- * <p>
- * This is ideal when the work being done is a query to the database where the
- * results may take time to be retrieved.
- * <p>
- * For example:
- *
- * <pre>
- * public static JCSWorker cachingWorker = new JCSWorker("example region");
- * public Object getSomething(Serializable aKey){
- * JCSWorkerHelper helper = new AbstractJCSWorkerHelper(){
- * public Object doWork(){
- * // Do some (DB?) work here which results in a list
- * // This only happens if the cache dosn't have a item in this region for aKey
- * // Note this is especially useful with Hibernate, which will cache indiviual
- * // Objects, but not entire query result sets.
- * List results = query.list();
- * // Whatever we return here get's cached with aKey, and future calls to
- * // getResult() on a CachedWorker with the same region and key will return that instead.
- * return results;
- * };
- * List result = worker.getResult(aKey, helper);
- * }
- * </pre>
- *
- * This is essentially the same as doing:
- *
- * <pre>
- * JCS jcs = JCS.getInstance( "exampleregion" );
- * List results = (List) jcs.get( aKey );
- * if ( results != null )
- * {
- * //do the work here
- * results = query.list();
- * jcs.put( aKey, results );
- * }
- * </pre>
- *
- * <p>
- * But has the added benefit of the work-load sharing; under normal
- * circumstances if multiple threads all tried to do the same query at the same
- * time, the same query would happen multiple times on the database, and the
- * resulting object would get put into JCS multiple times.
- * <p>
- * @author Travis Savo
- */
-public class JCSWorker<K, V>
-{
- /** The logger */
- private static final Log logger = LogManager.getLog( JCSWorker.class );
-
- /** The cache we are working with */
- private CacheAccess<K, V> cache;
-
- /** The cache we are working with */
- private GroupCacheAccess<K, V> groupCache;
-
- /**
- * Map to hold who's doing work presently.
- */
- private volatile ConcurrentMap<String, JCSWorkerHelper<V>> map = new ConcurrentHashMap<>();
-
- /**
- * Region for the JCS cache.
- */
- private final String region;
-
- /**
- * Constructor which takes a region for the JCS cache.
- * @param aRegion
- * The Region to use for the JCS cache.
- */
- public JCSWorker( final String aRegion )
- {
- region = aRegion;
- try
- {
- cache = JCS.getInstance( aRegion );
- groupCache = JCS.getGroupCacheInstance( aRegion );
- }
- catch ( CacheException e )
- {
- throw new RuntimeException( e.getMessage() );
- }
- }
-
- /**
- * Getter for the region of the JCS Cache.
- * @return The JCS region in which the result will be cached.
- */
- public String getRegion()
- {
- return region;
- }
-
- /**
- * Gets the cached result for this region/key OR does the work and caches
- * the result, returning the result. If the result has not been cached yet,
- * this calls doWork() on the JCSWorkerHelper to do the work and cache the
- * result. This is also an opportunity to do any post processing of the
- * result in your CachedWorker implementation.
- * @param aKey
- * The key to get/put with on the Cache.
- * @param aWorker
- * The JCSWorkerHelper implementing Object doWork(). This gets
- * called if the cache get misses, and the result is put into
- * cache.
- * @return The result of doing the work, or the cached result.
- * @throws Exception
- * Throws an exception if anything goes wrong while doing the
- * work.
- */
- public V getResult( K aKey, JCSWorkerHelper<V> aWorker )
- throws Exception
- {
- return run( aKey, null, aWorker );
- }
-
- /**
- * Gets the cached result for this region/key OR does the work and caches
- * the result, returning the result. If the result has not been cached yet,
- * this calls doWork() on the JCSWorkerHelper to do the work and cache the
- * result. This is also an opportunity to do any post processing of the
- * result in your CachedWorker implementation.
- * @param aKey
- * The key to get/put with on the Cache.
- * @param aGroup
- * The cache group to put the result in.
- * @param aWorker
- * The JCSWorkerHelper implementing Object doWork(). This gets
- * called if the cache get misses, and the result is put into
- * cache.
- * @return The result of doing the work, or the cached result.
- * @throws Exception
- * Throws an exception if anything goes wrong while doing the
- * work.
- */
- public V getResult( K aKey, String aGroup, JCSWorkerHelper<V> aWorker )
- throws Exception
- {
- return run( aKey, aGroup, aWorker );
- }
-
- /**
- * Try and get the object from the cache, and if it's not there, do the work
- * and cache it. This also ensures that only one CachedWorker is doing the
- * work and subsequent calls to a CachedWorker with identical
- * region/key/group will wait on the results of this call. It will call the
- * JCSWorkerHelper.doWork() if the cache misses, and will put the result.
- * @param aKey
- * @param aGroup
- * @param aHelper
- * @return Either the result of doing the work, or the cached result.
- * @throws Exception
- * If something goes wrong while doing the work, throw an
- * exception.
- */
- private V run( K aKey, String aGroup, JCSWorkerHelper<V> aHelper )
- throws Exception
- {
- V result = null;
- // long start = 0;
- // long dbTime = 0;
- JCSWorkerHelper<V> helper = map.putIfAbsent(getRegion() + aKey, aHelper);
-
- if ( helper != null )
- {
- synchronized ( helper )
- {
- logger.debug( "Found a worker already doing this work ({0}:{1}).",
- () -> getRegion(), () -> aKey );
- while ( !helper.isFinished() )
- {
- try
- {
- helper.wait();
- }
- catch (InterruptedException e)
- {
- // expected
- }
- }
- logger.debug( "Another thread finished our work for us. Using "
- + "those results instead. ({0}:{1}).",
- () -> getRegion(), () -> aKey );
- }
- }
- // Do the work
- try
- {
- logger.debug( "{0} is doing the work.", () -> getRegion() );
-
- // Try to get the item from the cache
- if ( aGroup != null )
- {
- result = groupCache.getFromGroup( aKey, aGroup );
- }
- else
- {
- result = cache.get( aKey );
- }
- // If the cache dosn't have it, do the work.
- if ( result == null )
- {
- result = aHelper.doWork();
- logger.debug( "Work Done, caching: key:{0}, group:{1}, result:{2}.",
- aKey, aGroup, result );
- // Stick the result of the work in the cache.
- if ( aGroup != null )
- {
- groupCache.putInGroup( aKey, aGroup, result );
- }
- else
- {
- cache.put( aKey, result );
- }
- }
- // return the result
- return result;
- }
- finally
- {
- logger.debug( "{0}:{1} entered finally.", () -> getRegion(),
- () -> aKey );
-
- // Remove ourselves as the worker.
- if ( helper == null )
- {
- map.remove( getRegion() + aKey );
- }
- synchronized ( aHelper )
- {
- aHelper.setFinished( true );
- // Wake everyone waiting on us
- aHelper.notifyAll();
- }
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/access/JCSWorkerHelper.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/access/JCSWorkerHelper.java
deleted file mode 100644
index c20ed7b..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/access/JCSWorkerHelper.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.apache.commons.jcs.utils.access;
-
-/*
- * 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.
- */
-
-/**
- * Interface for doing a piece of work which is expected to be cached. This is
- * meant to be used in conjunction with JCSWorker.
- * <p>
- * Implement doWork() to return the work being done. isFinished() should return
- * false until setFinished(true) is called, after which time it should return
- * true.
- * <p>
- * @author tsavo
- */
-public interface JCSWorkerHelper<V>
-{
- /**
- * Tells us whether or not the work has been completed. This will be called
- * automatically by JCSWorker. You should not call it yourself.
- * <p>
- * @return True if the work has already been done, otherwise false.
- */
- boolean isFinished();
-
- /**
- * Sets whether or not the work has been done.
- * <p>
- * @param isFinished
- * True if the work has already been done, otherwise false.
- */
- void setFinished( boolean isFinished );
-
- /**
- * The method to implement to do the work that should be cached. JCSWorker
- * will call this itself! You should not call this directly.
- * <p>
- * @return The result of doing the work to be cached.
- * @throws Exception
- * If anything goes wrong while doing the work, an Exception
- * should be thrown.
- */
- V doWork() throws Exception;
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/config/OptionConverter.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/config/OptionConverter.java
deleted file mode 100644
index 1a9dab0..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/config/OptionConverter.java
+++ /dev/null
@@ -1,423 +0,0 @@
-package org.apache.commons.jcs.utils.config;
-
-/*
- * 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.
- */
-
-import java.util.Properties;
-
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This class is based on the log4j class org.apache.log4j.helpers.OptionConverter that was made by
- * Ceki Gülcü Simon Kitching; Avy Sharell (sharell@online.fr) Anders Kristensen Matthieu
- * Verbert (mve@zurich.ibm.com) A convenience class to convert property values to specific types.
- */
-public class OptionConverter
-{
- /** The logger */
- private static final Log log = LogManager.getLog( OptionConverter.class );
-
- /** System property delimter */
- private static final String DELIM_START = "${";
-
- /** System property delimter */
- private static final char DELIM_STOP = '}';
-
- /** System property delimter start length */
- private static final int DELIM_START_LEN = 2;
-
- /** System property delimter end length */
- private static final int DELIM_STOP_LEN = 1;
-
- /** No instances please. */
- private OptionConverter()
- {
- super();
- }
-
- /**
- * Combines two arrays.
- * @param l
- * @param r
- * @return String[]
- */
- public static String[] concatanateArrays( String[] l, String[] r )
- {
- int len = l.length + r.length;
- String[] a = new String[len];
-
- System.arraycopy( l, 0, a, 0, l.length );
- System.arraycopy( r, 0, a, l.length, r.length );
-
- return a;
- }
-
- /**
- * Escapes special characters.
- *
- * @param s
- * @return String
- */
- public static String convertSpecialChars( String s )
- {
- char c;
- int len = s.length();
- StringBuilder sb = new StringBuilder( len );
-
- int i = 0;
- while ( i < len )
- {
- c = s.charAt( i++ );
- if ( c == '\\' )
- {
- c = s.charAt( i++ );
- if ( c == 'n' )
- {
- c = '\n';
- }
- else if ( c == 'r' )
- {
- c = '\r';
- }
- else if ( c == 't' )
- {
- c = '\t';
- }
- else if ( c == 'f' )
- {
- c = '\f';
- }
- else if ( c == '\b' )
- {
- c = '\b';
- }
- else if ( c == '\"' )
- {
- c = '\"';
- }
- else if ( c == '\'' )
- {
- c = '\'';
- }
- else if ( c == '\\' )
- {
- c = '\\';
- }
- }
- sb.append( c );
- }
- return sb.toString();
- }
-
- /**
- * Very similar to <code>System.getProperty</code> except that the {@link SecurityException} is
- * hidden.
- * @param key The key to search for.
- * @param def The default value to return.
- * @return the string value of the system property, or the default value if there is no property
- * with that key.
- * @since 1.1
- */
-
- public static String getSystemProperty( String key, String def )
- {
- try
- {
- return System.getProperty( key, def );
- }
- catch ( Throwable e )
- {
- // MS-Java throws com.ms.security.SecurityExceptionEx
- log.debug( "Was not allowed to read system property \"{0}\".", key );
- return def;
- }
- }
-
- /**
- * Creates an object for the className value of the key.
- *
- * @param props
- * @param key
- * @param defaultValue
- * @return Object that was created
- */
- public static <T> T instantiateByKey( Properties props, String key, T defaultValue )
- {
-
- // Get the value of the property in string form
- String className = findAndSubst( key, props );
- if ( className == null )
- {
- log.trace( "Could not find value for key {0}", key );
- return defaultValue;
- }
- // Trim className to avoid trailing spaces that cause problems.
- return OptionConverter.instantiateByClassName( className.trim(), defaultValue );
- }
-
- /**
- * If <code>value</code> is "true", then <code>true</code> is returned. If <code>value</code> is
- * "false", then <code>true</code> is returned. Otherwise, <code>default</code> is returned.
- *
- * Case of value is unimportant.
- * @param value
- * @param defaultValue
- * @return Object
- */
- public static boolean toBoolean( String value, boolean defaultValue )
- {
- if ( value == null )
- {
- return defaultValue;
- }
- String trimmedVal = value.trim();
- if ( "true".equalsIgnoreCase( trimmedVal ) )
- {
- return true;
- }
- if ( "false".equalsIgnoreCase( trimmedVal ) )
- {
- return false;
- }
- return defaultValue;
- }
-
- /**
- * Converts to int.
- *
- * @param value
- * @param defaultValue
- * @return int
- */
- public static int toInt( String value, int defaultValue )
- {
- if ( value != null )
- {
- String s = value.trim();
- try
- {
- return Integer.parseInt(s);
- }
- catch ( NumberFormatException e )
- {
- log.error( "[{0}] is not in proper int form.", s, e );
- }
- }
- return defaultValue;
- }
-
- /**
- * @param value
- * @param defaultValue
- * @return long
- */
- public static long toFileSize( String value, long defaultValue )
- {
- if ( value == null )
- {
- return defaultValue;
- }
-
- String s = value.trim().toUpperCase();
- long multiplier = 1;
- int index;
-
- if ( ( index = s.indexOf( "KB" ) ) != -1 )
- {
- multiplier = 1024;
- s = s.substring( 0, index );
- }
- else if ( ( index = s.indexOf( "MB" ) ) != -1 )
- {
- multiplier = 1024 * 1024;
- s = s.substring( 0, index );
- }
- else if ( ( index = s.indexOf( "GB" ) ) != -1 )
- {
- multiplier = 1024 * 1024 * 1024;
- s = s.substring( 0, index );
- }
- if ( s != null )
- {
- try
- {
- return Long.parseLong(s) * multiplier;
- }
- catch ( NumberFormatException e )
- {
- log.error( "[{0}] is not in proper int form.", s);
- log.error( "[{0}] not in expected format", value, e );
- }
- }
- return defaultValue;
- }
-
- /**
- * Find the value corresponding to <code>key</code> in <code>props</code>. Then perform variable
- * substitution on the found value.
- *
- * @param key
- * @param props
- * @return substituted string
- */
-
- public static String findAndSubst( String key, Properties props )
- {
- String value = props.getProperty( key );
- if ( value == null )
- {
- return null;
- }
-
- try
- {
- return substVars( value, props );
- }
- catch ( IllegalArgumentException e )
- {
- log.error( "Bad option value [{0}]", value, e );
- return value;
- }
- }
-
- /**
- * Instantiate an object given a class name. Check that the <code>className</code> is a subclass
- * of <code>superClass</code>. If that test fails or the object could not be instantiated, then
- * <code>defaultValue</code> is returned.
- *
- * @param className The fully qualified class name of the object to instantiate.
- * @param defaultValue The object to return in case of non-fulfillment
- * @return instantiated object
- */
-
- public static <T> T instantiateByClassName( String className, T defaultValue )
- {
- if ( className != null )
- {
- try
- {
- Class<?> classObj = Class.forName( className );
- Object o = classObj.newInstance();
-
- try
- {
- @SuppressWarnings("unchecked") // CCE catched
- T t = (T) o;
- return t;
- }
- catch (ClassCastException e)
- {
- log.error( "A \"{0}\" object is not assignable to the "
- + "generic variable.", className );
- return defaultValue;
- }
- }
- catch ( ClassNotFoundException | InstantiationException | IllegalAccessException e )
- {
- log.error( "Could not instantiate class [{0}]", className, e );
- }
- }
- return defaultValue;
- }
-
- /**
- * Perform variable substitution in string <code>val</code> from the values of keys found in the
- * system properties.
- *
- * The variable substitution delimiters are <b>${ </b> and <b>} </b>.
- *
- * For example, if the System properties contains "key=value", then the call
- *
- * <pre>
- * String s = OptionConverter.substituteVars( "Value of key is ${key}." );
- * </pre>
- *
- * will set the variable <code>s</code> to "Value of key is value.".
- *
- * If no value could be found for the specified key, then the <code>props</code> parameter is
- * searched, if the value could not be found there, then substitution defaults to the empty
- * string.
- *
- * For example, if system properties contains no value for the key "inexistentKey", then the call
- *
- * <pre>
- * String s = OptionConverter.subsVars( "Value of inexistentKey is [${inexistentKey}]" );
- * </pre>
- *
- * will set <code>s</code> to "Value of inexistentKey is []"
- * <p>
- * An {@link java.lang.IllegalArgumentException}is thrown if <code>val</code> contains a start
- * delimiter "${" which is not balanced by a stop delimiter "}".
- * </p>
- * <p>
- * <b>Author </b> Avy Sharell
- * </p>
- * @param val The string on which variable substitution is performed.
- * @param props
- * @return String
- * @throws IllegalArgumentException if <code>val</code> is malformed.
- */
-
- public static String substVars( String val, Properties props )
- throws IllegalArgumentException
- {
- StringBuilder sbuf = new StringBuilder();
-
- int i = 0;
- int j;
- int k;
-
- while ( true )
- {
- j = val.indexOf( DELIM_START, i );
- if ( j == -1 )
- {
- if ( i == 0 )
- {
- return val;
- }
- sbuf.append( val.substring( i, val.length() ) );
- return sbuf.toString();
- }
- sbuf.append( val.substring( i, j ) );
- k = val.indexOf( DELIM_STOP, j );
- if ( k == -1 )
- {
- throw new IllegalArgumentException( '"' + val + "\" has no closing brace. Opening brace at position "
- + j + '.' );
- }
- j += DELIM_START_LEN;
- String key = val.substring( j, k );
- // first try in System properties
- String replacement = getSystemProperty( key, null );
- // then try props parameter
- if ( replacement == null && props != null )
- {
- replacement = props.getProperty( key );
- }
-
- if ( replacement != null )
- {
- sbuf.append( replacement );
- }
- i = k + DELIM_STOP_LEN;
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/config/PropertySetter.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/config/PropertySetter.java
deleted file mode 100644
index e188bd8..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/config/PropertySetter.java
+++ /dev/null
@@ -1,299 +0,0 @@
-package org.apache.commons.jcs.utils.config;
-
-import java.beans.BeanInfo;
-import java.beans.IntrospectionException;
-import java.beans.Introspector;
-import java.beans.PropertyDescriptor;
-import java.io.File;
-import java.lang.reflect.Method;
-import java.util.Enumeration;
-import java.util.Properties;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This class is based on the log4j class org.apache.log4j.config.PropertySetter that was made by
- * Anders Kristensen
- * <p>
- * General purpose Object property setter. Clients repeatedly invokes {@link #setProperty
- * setProperty(name,value)} in order to invoke setters on the Object specified in the constructor.
- * This class relies on the JavaBeans {@link Introspector}to analyze the given Object Class using
- * reflection.
- * <p>
- * Usage:
- *
- * <pre>
- * PropertySetter ps = new PropertySetter( anObject );
- * ps.set( "name", "Joe" );
- * ps.set( "age", "32" );
- * ps.set( "isMale", "true" );
- * </pre>
- *
- * will cause the invocations anObject.setName("Joe"), anObject.setAge(32), and setMale(true) if
- * such methods exist with those signatures. Otherwise an {@link IntrospectionException}are thrown.
- */
-public class PropertySetter
-{
- /** Logger */
- private static final Log log = LogManager.getLog( PropertySetter.class );
-
- /** Description of the Field */
- private final Object obj;
-
- /** Description of the Field */
- private PropertyDescriptor[] props;
-
- /**
- * Create a new PropertySetter for the specified Object. This is done in preparation for invoking
- * {@link #setProperty}one or more times.
- * @param obj the object for which to set properties
- */
- public PropertySetter( Object obj )
- {
- this.obj = obj;
- }
-
- /**
- * Uses JavaBeans {@link Introspector}to compute setters of object to be configured.
- */
- protected void introspect()
- {
- try
- {
- BeanInfo bi = Introspector.getBeanInfo( obj.getClass() );
- props = bi.getPropertyDescriptors();
- }
- catch ( IntrospectionException ex )
- {
- log.error( "Failed to introspect {0}", obj, ex );
- props = new PropertyDescriptor[0];
- }
- }
-
- /**
- * Set the properties of an object passed as a parameter in one go. The <code>properties</code>
- * are parsed relative to a <code>prefix</code>.
- * <p>
- * @param obj The object to configure.
- * @param properties A java.util.Properties containing keys and values.
- * @param prefix Only keys having the specified prefix will be set.
- */
- public static void setProperties( Object obj, Properties properties, String prefix )
- {
- new PropertySetter( obj ).setProperties( properties, prefix );
- }
-
- /**
- * Set the properties for the object that match the <code>prefix</code> passed as parameter.
- * <p>
- * @param properties The new properties value
- * @param prefix The new properties value
- */
- public void setProperties( Properties properties, String prefix )
- {
- int len = prefix.length();
-
- for ( Enumeration<?> e = properties.propertyNames(); e.hasMoreElements(); )
- {
- String key = (String) e.nextElement();
-
- // handle only properties that start with the desired prefix.
- if ( key.startsWith( prefix ) )
- {
-
- // ignore key if it contains dots after the prefix
- if ( key.indexOf( '.', len + 1 ) > 0 )
- {
- //System.err.println("----------Ignoring---["+key
- // +"], prefix=["+prefix+"].");
- continue;
- }
-
- String value = OptionConverter.findAndSubst( key, properties );
- key = key.substring( len );
-
- setProperty( key, value );
- }
- }
-
- }
-
- /**
- * Set a property on this PropertySetter's Object. If successful, this method will invoke a
- * setter method on the underlying Object. The setter is the one for the specified property name
- * and the value is determined partly from the setter argument type and partly from the value
- * specified in the call to this method.
- * <p>
- * If the setter expects a String no conversion is necessary. If it expects an int, then an
- * attempt is made to convert 'value' to an int using Integer.valueOf(value). If the setter expects
- * a boolean, the conversion is by Boolean.valueOf(value).
- * @param name name of the property
- * @param value String value of the property
- */
-
- public void setProperty( String name, String value )
- {
- if ( value == null )
- {
- return;
- }
-
- name = Introspector.decapitalize( name );
- PropertyDescriptor prop = getPropertyDescriptor( name );
-
- //log.debug("---------Key: "+name+", type="+prop.getPropertyType());
-
- if ( prop == null )
- {
- log.warn( "No such property [{0}] in {1}.", name, obj.getClass().getName() );
- }
- else
- {
- try
- {
- setProperty( prop, name, value );
- }
- catch ( PropertySetterException ex )
- {
- log.warn( "Failed to set property {0} to value \"{1}\".", name, value, ex );
- }
- }
- }
-
- /**
- * Set the named property given a {@link PropertyDescriptor}.
- * @param prop A PropertyDescriptor describing the characteristics of the property to set.
- * @param name The named of the property to set.
- * @param value The value of the property.
- * @throws PropertySetterException
- */
-
- public void setProperty( PropertyDescriptor prop, String name, String value )
- throws PropertySetterException
- {
- Method setter = prop.getWriteMethod();
- if ( setter == null )
- {
- throw new PropertySetterException( "No setter for property" );
- }
- Class<?>[] paramTypes = setter.getParameterTypes();
- if ( paramTypes.length != 1 )
- {
- throw new PropertySetterException( "#params for setter != 1" );
- }
-
- Object arg;
- try
- {
- arg = convertArg( value, paramTypes[0] );
- }
- catch ( Throwable t )
- {
- throw new PropertySetterException( "Conversion to type [" + paramTypes[0] + "] failed. Reason: " + t );
- }
- if ( arg == null )
- {
- throw new PropertySetterException( "Conversion to type [" + paramTypes[0] + "] failed." );
- }
- log.debug( "Setting property [{0}] to [{1}].", name, arg );
- try
- {
- setter.invoke( obj, new Object[] { arg } );
- }
- catch ( Exception ex )
- {
- throw new PropertySetterException( ex );
- }
- }
-
- /**
- * Convert <code>val</code> a String parameter to an object of a given type.
- * @param val
- * @param type
- * @return Object
- */
- protected Object convertArg( String val, Class<?> type )
- {
- if ( val == null )
- {
- return null;
- }
-
- String v = val.trim();
- if ( String.class.isAssignableFrom( type ) )
- {
- return val;
- }
- else if ( Integer.TYPE.isAssignableFrom( type ) )
- {
- return Integer.valueOf( v );
- }
- else if ( Long.TYPE.isAssignableFrom( type ) )
- {
- return Long.valueOf( v );
- }
- else if ( Boolean.TYPE.isAssignableFrom( type ) )
- {
- if ( "true".equalsIgnoreCase( v ) )
- {
- return Boolean.TRUE;
- }
- else if ( "false".equalsIgnoreCase( v ) )
- {
- return Boolean.FALSE;
- }
- }
- else if( type.isEnum() )
- {
- Enum<?> en = Enum.valueOf(type.asSubclass(Enum.class), v );
- return en;
- }
- else if ( File.class.isAssignableFrom( type ) )
- {
- return new File( v );
- }
- return null;
- }
-
- /**
- * Gets the propertyDescriptor attribute of the PropertySetter object
- * @param name
- * @return The propertyDescriptor value
- */
- protected PropertyDescriptor getPropertyDescriptor( String name )
- {
- if ( props == null )
- {
- introspect();
- }
-
- for ( int i = 0; i < props.length; i++ )
- {
- if ( name.equals( props[i].getName() ) )
- {
- return props[i];
- }
- }
- return null;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/config/PropertySetterException.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/config/PropertySetterException.java
deleted file mode 100644
index 0898a54..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/config/PropertySetterException.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package org.apache.commons.jcs.utils.config;
-
-/*
- * 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.
- */
-
-/**
- * This class is based on the log4j class org.apache.log4j.config.PropertySetter that was made by
- * Anders Kristensen
- * <p>
- * Thrown when an error is encountered whilst attempting to set a property using the
- * {@link PropertySetter}utility class.
- */
-public class PropertySetterException
- extends Exception
-{
- /** DOn't change */
- private static final long serialVersionUID = -210271658004609028L;
-
- /** Description of the Field */
- private final Throwable rootCause;
-
- /**
- * Constructor for the PropertySetterException object
- * <p>
- * @param msg
- */
- public PropertySetterException( String msg )
- {
- super( msg );
- this.rootCause = null;
- }
-
- /**
- * Constructor for the PropertySetterException object
- * <p>
- * @param rootCause
- */
- public PropertySetterException( Throwable rootCause )
- {
- super();
- this.rootCause = rootCause;
- }
-
- /**
- * Returns descriptive text on the cause of this exception.
- * <p>
- * @return The message value
- */
- @Override
- public String getMessage()
- {
- String msg = super.getMessage();
- if ( msg == null && rootCause != null )
- {
- msg = rootCause.getMessage();
- }
- return msg;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/DiscoveredService.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/DiscoveredService.java
deleted file mode 100644
index cbfd737..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/DiscoveredService.java
+++ /dev/null
@@ -1,183 +0,0 @@
-package org.apache.commons.jcs.utils.discovery;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-import java.util.ArrayList;
-
-/**
- * This contains info about a discovered service. These objects are stored in a set in the
- * UDPDiscoveryService.
- * <p>
- * @author Aaron Smuts
- */
-public class DiscoveredService
- implements Serializable
-{
- /** For serialization. Don't change. */
- private static final long serialVersionUID = -7810164772089509751L;
-
- /** region names */
- private ArrayList<String> cacheNames;
-
- /** service address */
- private String serviceAddress;
-
- /** service port */
- private int servicePort;
-
- /** last time we heard from this service? */
- private long lastHearFromTime = 0;
-
- /**
- * @param cacheNames the cacheNames to set
- */
- public void setCacheNames( ArrayList<String> cacheNames )
- {
- this.cacheNames = cacheNames;
- }
-
- /**
- * @return the cacheNames
- */
- public ArrayList<String> getCacheNames()
- {
- return cacheNames;
- }
-
- /**
- * @param serviceAddress The serviceAddress to set.
- */
- public void setServiceAddress( String serviceAddress )
- {
- this.serviceAddress = serviceAddress;
- }
-
- /**
- * @return Returns the serviceAddress.
- */
- public String getServiceAddress()
- {
- return serviceAddress;
- }
-
- /**
- * @param servicePort The servicePort to set.
- */
- public void setServicePort( int servicePort )
- {
- this.servicePort = servicePort;
- }
-
- /**
- * @return Returns the servicePort.
- */
- public int getServicePort()
- {
- return servicePort;
- }
-
- /**
- * @param lastHearFromTime The lastHearFromTime to set.
- */
- public void setLastHearFromTime( long lastHearFromTime )
- {
- this.lastHearFromTime = lastHearFromTime;
- }
-
- /**
- * @return Returns the lastHearFromTime.
- */
- public long getLastHearFromTime()
- {
- return lastHearFromTime;
- }
-
- /** @return hashcode based on address/port */
- @Override
- public int hashCode()
- {
- final int prime = 31;
- int result = 1;
- result = prime * result
- + ((serviceAddress == null) ? 0 : serviceAddress.hashCode());
- result = prime * result + servicePort;
- return result;
- }
-
- /**
- * NOTE - this object is often put into sets, so equals needs to be overridden.
- * <p>
- * We can't use cache names as part of the equals unless we manually only use the address and
- * port in a contains check. So that we can use normal set functionality, I've kept the cache
- * names out.
- * <p>
- * @param otherArg other
- * @return equality based on the address/port
- */
- @Override
- public boolean equals(Object otherArg)
- {
- if (this == otherArg)
- {
- return true;
- }
- if (otherArg == null)
- {
- return false;
- }
- if (!(otherArg instanceof DiscoveredService))
- {
- return false;
- }
- DiscoveredService other = (DiscoveredService) otherArg;
- if (serviceAddress == null)
- {
- if (other.serviceAddress != null)
- {
- return false;
- }
- } else if (!serviceAddress.equals(other.serviceAddress))
- {
- return false;
- }
- if (servicePort != other.servicePort)
- {
- return false;
- }
-
- return true;
- }
-
- /**
- * @return string for debugging purposes.
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\n DiscoveredService" );
- buf.append( "\n CacheNames = [" + getCacheNames() + "]" );
- buf.append( "\n ServiceAddress = [" + getServiceAddress() + "]" );
- buf.append( "\n ServicePort = [" + getServicePort() + "]" );
- buf.append( "\n LastHearFromTime = [" + getLastHearFromTime() + "]" );
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPCleanupRunner.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPCleanupRunner.java
deleted file mode 100644
index 4a216cb..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPCleanupRunner.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package org.apache.commons.jcs.utils.discovery;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This class periodically check the lastHeardFrom time on the services.
- * <p>
- * If they exceed the configurable limit, it removes them from the set.
- * <p>
- * @author Aaron Smuts
- */
-public class UDPCleanupRunner
- implements Runnable
-{
- /** log instance */
- private static final Log log = LogManager.getLog( UDPCleanupRunner.class );
-
- /** UDP discovery service */
- private final UDPDiscoveryService discoveryService;
-
- /** default for max idle time, in seconds */
- private static final long DEFAULT_MAX_IDLE_TIME_SECONDS = 180;
-
- /** The configured max idle time, in seconds */
- private final long maxIdleTimeSeconds = DEFAULT_MAX_IDLE_TIME_SECONDS;
-
- /**
- * @param service UDPDiscoveryService
- */
- public UDPCleanupRunner( UDPDiscoveryService service )
- {
- this.discoveryService = service;
- }
-
- /**
- * This goes through the list of services and removes those that we haven't heard from in longer
- * than the max idle time.
- * <p>
- * @see java.lang.Runnable#run()
- */
- @Override
- public void run()
- {
- long now = System.currentTimeMillis();
-
- // iterate through the set
- // it is thread safe
- // TODO this should get a copy. you can't simply remove from this.
- // the listeners need to be notified.
- Set<DiscoveredService> toRemove = new HashSet<>();
- // can't remove via the iterator. must remove directly
- for (DiscoveredService service : discoveryService.getDiscoveredServices())
- {
- if ( ( now - service.getLastHearFromTime() ) > ( maxIdleTimeSeconds * 1000 ) )
- {
- log.info( "Removing service, since we haven't heard from it in "
- + "{0} seconds. service = {1}", maxIdleTimeSeconds, service );
- toRemove.add( service );
- }
- }
-
- // remove the bad ones
- for (DiscoveredService service : toRemove)
- {
- // call this so the listeners get notified
- discoveryService.removeDiscoveredService( service );
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryAttributes.java
deleted file mode 100644
index 1cf3962..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryAttributes.java
+++ /dev/null
@@ -1,269 +0,0 @@
-package org.apache.commons.jcs.utils.discovery;
-
-/*
- * 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.
- */
-
-/**
- * Configuration properties for UDP discover service.
- * <p>
- * The service will allow out applications to find each other.
- * <p>
- * @author Aaron Smuts
- */
-public final class UDPDiscoveryAttributes
- implements Cloneable
-{
- /** service name */
- private String serviceName;
-
- /** service address */
- private String serviceAddress;
-
- /** service port */
- private int servicePort;
-
- /**
- * false -> this service instance is not ready to receive requests. true -> ready for use
- */
- private boolean isDark;
-
- /** default udp discovery address */
- private static final String DEFAULT_UDP_DISCOVERY_ADDRESS = "228.4.5.6";
-
- /** default udp discovery port */
- private static final int DEFAULT_UDP_DISCOVERY_PORT = 5678;
-
- /** udp discovery address */
- private String udpDiscoveryAddr = DEFAULT_UDP_DISCOVERY_ADDRESS;
-
- /** udp discovery network interface */
- private String udpDiscoveryInterface = null;
-
- /** udp discovery port */
- private int udpDiscoveryPort = DEFAULT_UDP_DISCOVERY_PORT;
-
- /** udp datagram TTL */
- private int udpTTL = 0;
-
- /** default delay between sending passive broadcasts */
- private static final int DEFAULT_SEND_DELAY_SEC = 60;
-
- /** delay between sending passive broadcasts */
- private int sendDelaySec = DEFAULT_SEND_DELAY_SEC;
-
- /** default amount of time before we remove services that we haven't heard from */
- private static final int DEFAULT_MAX_IDLE_TIME_SEC = 180;
-
- /** amount of time before we remove services that we haven't heard from */
- private int maxIdleTimeSec = DEFAULT_MAX_IDLE_TIME_SEC;
-
- /**
- * @param serviceName The serviceName to set.
- */
- public void setServiceName( String serviceName )
- {
- this.serviceName = serviceName;
- }
-
- /**
- * @return Returns the serviceName.
- */
- public String getServiceName()
- {
- return serviceName;
- }
-
- /**
- * @param serviceAddress The serviceAddress to set.
- */
- public void setServiceAddress( String serviceAddress )
- {
- this.serviceAddress = serviceAddress;
- }
-
- /**
- * @return Returns the serviceAddress.
- */
- public String getServiceAddress()
- {
- return serviceAddress;
- }
-
- /**
- * @param servicePort The servicePort to set.
- */
- public void setServicePort( int servicePort )
- {
- this.servicePort = servicePort;
- }
-
- /**
- * @return Returns the servicePort.
- */
- public int getServicePort()
- {
- return servicePort;
- }
-
- /**
- * @param udpDiscoveryAddr The udpDiscoveryAddr to set.
- */
- public void setUdpDiscoveryAddr( String udpDiscoveryAddr )
- {
- this.udpDiscoveryAddr = udpDiscoveryAddr;
- }
-
- /**
- * @return Returns the udpDiscoveryAddr.
- */
- public String getUdpDiscoveryAddr()
- {
- return udpDiscoveryAddr;
- }
-
- /**
- * @param udpDiscoveryInterface The udpDiscoveryInterface to set.
- */
- public void setUdpDiscoveryInterface( String udpDiscoveryInterface )
- {
- this.udpDiscoveryInterface = udpDiscoveryInterface;
- }
-
- /**
- * @return Returns the udpDiscoveryInterface.
- */
- public String getUdpDiscoveryInterface()
- {
- return udpDiscoveryInterface;
- }
-
- /**
- * @param udpDiscoveryPort The udpDiscoveryPort to set.
- */
- public void setUdpDiscoveryPort( int udpDiscoveryPort )
- {
- this.udpDiscoveryPort = udpDiscoveryPort;
- }
-
- /**
- * @return Returns the udpTTL.
- */
- public int getUdpTTL()
- {
- return udpTTL;
- }
-
- /**
- * @param udpTTL The udpTTL to set.
- */
- public void setUdpTTL( int udpTTL )
- {
- this.udpTTL = udpTTL;
- }
-
- /**
- * @return Returns the udpDiscoveryPort.
- */
- public int getUdpDiscoveryPort()
- {
- return udpDiscoveryPort;
- }
-
- /**
- * @param sendDelaySec The sendDelaySec to set.
- */
- public void setSendDelaySec( int sendDelaySec )
- {
- this.sendDelaySec = sendDelaySec;
- }
-
- /**
- * @return Returns the sendDelaySec.
- */
- public int getSendDelaySec()
- {
- return sendDelaySec;
- }
-
- /**
- * @param maxIdleTimeSec The maxIdleTimeSec to set.
- */
- public void setMaxIdleTimeSec( int maxIdleTimeSec )
- {
- this.maxIdleTimeSec = maxIdleTimeSec;
- }
-
- /**
- * @return Returns the maxIdleTimeSec.
- */
- public int getMaxIdleTimeSec()
- {
- return maxIdleTimeSec;
- }
-
- /**
- * @return Returns the isDark.
- */
- public boolean isDark()
- {
- return isDark;
- }
-
- /**
- * @param isDark The isDark to set.
- */
- public void setDark( boolean isDark )
- {
- this.isDark = isDark;
- }
-
- /** @return a clone of this object */
- @Override
- public UDPDiscoveryAttributes clone()
- {
- UDPDiscoveryAttributes attributes = new UDPDiscoveryAttributes();
- attributes.setSendDelaySec( this.getSendDelaySec() );
- attributes.setMaxIdleTimeSec( this.getMaxIdleTimeSec() );
- attributes.setServiceName( this.getServiceName() );
- attributes.setServicePort( this.getServicePort() );
- attributes.setUdpDiscoveryAddr( this.getUdpDiscoveryAddr() );
- attributes.setUdpDiscoveryPort( this.getUdpDiscoveryPort() );
- attributes.setDark( this.isDark() );
- return attributes;
- }
-
- /**
- * @return string for debugging purposes.
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\n UDPDiscoveryAttributes" );
- buf.append( "\n ServiceName = [" + getServiceName() + "]" );
- buf.append( "\n ServiceAddress = [" + getServiceAddress() + "]" );
- buf.append( "\n ServicePort = [" + getServicePort() + "]" );
- buf.append( "\n UdpDiscoveryAddr = [" + getUdpDiscoveryAddr() + "]" );
- buf.append( "\n UdpDiscoveryPort = [" + getUdpDiscoveryPort() + "]" );
- buf.append( "\n SendDelaySec = [" + getSendDelaySec() + "]" );
- buf.append( "\n MaxIdleTimeSec = [" + getMaxIdleTimeSec() + "]" );
- buf.append( "\n IsDark = [" + isDark() + "]" );
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryManager.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryManager.java
deleted file mode 100644
index b24732e..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryManager.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package org.apache.commons.jcs.utils.discovery;
-
-/*
- * 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.
- */
-
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IProvideScheduler;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This manages UDPDiscovery Services. We should end up with one service per Lateral Cache Manager
- * Instance. One service works for multiple regions. We don't want a connection for each region.
- * <p>
- * @author Aaron Smuts
- */
-public class UDPDiscoveryManager
-{
- /** The logger */
- private static final Log log = LogManager.getLog( UDPDiscoveryManager.class );
-
- /** Singleton instance */
- private static UDPDiscoveryManager INSTANCE = new UDPDiscoveryManager();
-
- /** Known services */
- private final ConcurrentMap<String, UDPDiscoveryService> services = new ConcurrentHashMap<>();
-
- /** private for singleton */
- private UDPDiscoveryManager()
- {
- // noopt
- }
-
- /**
- * Singleton
- * <p>
- * @return UDPDiscoveryManager
- */
- public static UDPDiscoveryManager getInstance()
- {
- return INSTANCE;
- }
-
- /**
- * Creates a service for the address and port if one doesn't exist already.
- * <p>
- * We need to key this using the listener port too. TODO think of making one discovery service
- * work for multiple types of clients.
- * <p>
- * @param discoveryAddress
- * @param discoveryPort
- * @param servicePort
- * @param cacheMgr
- * @return UDPDiscoveryService
- */
- public UDPDiscoveryService getService( String discoveryAddress, int discoveryPort, int servicePort,
- ICompositeCacheManager cacheMgr )
- {
- String key = discoveryAddress + ":" + discoveryPort + ":" + servicePort;
-
- UDPDiscoveryService service = services.computeIfAbsent(key, k -> {
- log.info( "Creating service for address:port:servicePort [{0}]", key );
-
- UDPDiscoveryAttributes attributes = new UDPDiscoveryAttributes();
- attributes.setUdpDiscoveryAddr( discoveryAddress );
- attributes.setUdpDiscoveryPort( discoveryPort );
- attributes.setServicePort( servicePort );
-
- UDPDiscoveryService newService = new UDPDiscoveryService( attributes );
-
- // register for shutdown notification
- cacheMgr.registerShutdownObserver( newService );
-
- // inject scheduler
- if ( cacheMgr instanceof IProvideScheduler)
- {
- newService.setScheduledExecutorService(((IProvideScheduler)cacheMgr)
- .getScheduledExecutorService());
- }
-
- newService.startup();
- return newService;
- });
-
- log.debug( "Returning service [{0}] for key [{1}]", service, key );
-
- return service;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryMessage.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryMessage.java
deleted file mode 100644
index b71e6e0..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryMessage.java
+++ /dev/null
@@ -1,166 +0,0 @@
-package org.apache.commons.jcs.utils.discovery;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-import java.util.ArrayList;
-
-/**
- * The message sent by the discovery mechanism.
- */
-public class UDPDiscoveryMessage
- implements Serializable
-{
- /** Don't change */
- private static final long serialVersionUID = -5332377899560951793L;
-
- public enum BroadcastType
- {
- /**
- * This is the periodic broadcast of a servers location. This type of message is also sent in
- * response to a REQUEST_BROADCAST.
- */
- PASSIVE,
-
- /**
- * This asks recipients to broadcast their location. This is used on startup.
- */
- REQUEST,
-
- /**
- * This message instructs the receiver to remove this service from its list.
- */
- REMOVE
- }
-
- /** The message type */
- private BroadcastType messageType = BroadcastType.PASSIVE;
-
- /** udp port */
- private int port = 6789;
-
- /** UDP host */
- private String host = "228.5.6.7";
-
- /** Id of the requester, allows self-filtration */
- private long requesterId;
-
- /** Names of regions */
- private ArrayList<String> cacheNames = new ArrayList<>();
-
- /**
- * @param port The port to set.
- */
- public void setPort( int port )
- {
- this.port = port;
- }
-
- /**
- * @return Returns the port.
- */
- public int getPort()
- {
- return port;
- }
-
- /**
- * @param host The host to set.
- */
- public void setHost( String host )
- {
- this.host = host;
- }
-
- /**
- * @return Returns the host.
- */
- public String getHost()
- {
- return host;
- }
-
- /**
- * @param requesterId The requesterId to set.
- */
- public void setRequesterId( long requesterId )
- {
- this.requesterId = requesterId;
- }
-
- /**
- * @return Returns the requesterId.
- */
- public long getRequesterId()
- {
- return requesterId;
- }
-
- /**
- * @param messageType The messageType to set.
- */
- public void setMessageType( BroadcastType messageType )
- {
- this.messageType = messageType;
- }
-
- /**
- * @return Returns the messageType.
- */
- public BroadcastType getMessageType()
- {
- return messageType;
- }
-
- /**
- * @param cacheNames The cacheNames to set.
- */
- public void setCacheNames( ArrayList<String> cacheNames )
- {
- this.cacheNames = cacheNames;
- }
-
- /**
- * @return Returns the cacheNames.
- */
- public ArrayList<String> getCacheNames()
- {
- return cacheNames;
- }
-
- /**
- * @return debugging string
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\n host = [" + host + "]" );
- buf.append( "\n port = [" + port + "]" );
- buf.append( "\n requesterId = [" + requesterId + "]" );
- buf.append( "\n messageType = [" + messageType + "]" );
- buf.append( "\n Cache Names" );
- for (String name : cacheNames)
- {
- buf.append( " cacheName = [" + name + "]" );
- }
- return buf.toString();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryReceiver.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryReceiver.java
deleted file mode 100644
index 7d2ea6a..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryReceiver.java
+++ /dev/null
@@ -1,366 +0,0 @@
-package org.apache.commons.jcs.utils.discovery;
-
-/*
- * 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.
- */
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.net.DatagramPacket;
-import java.net.InetAddress;
-import java.net.MulticastSocket;
-import java.net.NetworkInterface;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.commons.jcs.engine.CacheInfo;
-import org.apache.commons.jcs.engine.behavior.IShutdownObserver;
-import org.apache.commons.jcs.io.ObjectInputStreamClassLoaderAware;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.discovery.UDPDiscoveryMessage.BroadcastType;
-import org.apache.commons.jcs.utils.net.HostNameUtil;
-import org.apache.commons.jcs.utils.threadpool.PoolConfiguration;
-import org.apache.commons.jcs.utils.threadpool.PoolConfiguration.WhenBlockedPolicy;
-import org.apache.commons.jcs.utils.threadpool.ThreadPoolManager;
-
-/** Receives UDP Discovery messages. */
-public class UDPDiscoveryReceiver
- implements Runnable, IShutdownObserver
-{
- /** The log factory */
- private static final Log log = LogManager.getLog( UDPDiscoveryReceiver.class );
-
- /** buffer */
- private final byte[] mBuffer = new byte[65536];
-
- /** The socket used for communication. */
- private MulticastSocket mSocket;
-
- /**
- * TODO: Consider using the threadpool manager to get this thread pool. For now place a tight
- * restriction on the pool size
- */
- private static final int maxPoolSize = 2;
-
- /** The processor */
- private final ExecutorService pooledExecutor;
-
- /** number of messages received. For debugging and testing. */
- private AtomicInteger cnt = new AtomicInteger(0);
-
- /** Service to get cache names and handle request broadcasts */
- private final UDPDiscoveryService service;
-
- /** Multicast address */
- private final InetAddress multicastAddress;
-
- /** Is it shutdown. */
- private boolean shutdown = false;
-
- /**
- * Constructor for the LateralUDPReceiver object.
- * <p>
- * We determine out own host using InetAddress
- *<p>
- * @param service
- * @param multicastInterfaceString
- * @param multicastAddressString
- * @param multicastPort
- * @throws IOException
- */
- public UDPDiscoveryReceiver( UDPDiscoveryService service, String multicastInterfaceString,
- String multicastAddressString, int multicastPort )
- throws IOException
- {
- this.service = service;
- this.multicastAddress = InetAddress.getByName( multicastAddressString );
-
- // create a small thread pool to handle a barrage
- this.pooledExecutor = ThreadPoolManager.getInstance().createPool(
- new PoolConfiguration(false, 0, maxPoolSize, maxPoolSize, 0,
- WhenBlockedPolicy.DISCARDOLDEST, maxPoolSize),
- "JCS-UDPDiscoveryReceiver-", Thread.MIN_PRIORITY);
-
- log.info( "Constructing listener, [{0}:{1}]", multicastAddress, multicastPort );
-
- createSocket( multicastInterfaceString, multicastAddress, multicastPort );
- }
-
- /**
- * Creates the socket for this class.
- * <p>
- * @param multicastInterfaceString
- * @param multicastAddress
- * @param multicastPort
- * @throws IOException
- */
- private void createSocket( String multicastInterfaceString, InetAddress multicastAddress,
- int multicastPort )
- throws IOException
- {
- try
- {
- mSocket = new MulticastSocket( multicastPort );
- if (log.isInfoEnabled())
- {
- log.info( "Joining Group: [{0}]", multicastAddress );
- }
-
- // Use dedicated interface if specified
- NetworkInterface multicastInterface = null;
- if (multicastInterfaceString != null)
- {
- multicastInterface = NetworkInterface.getByName(multicastInterfaceString);
- }
- else
- {
- multicastInterface = HostNameUtil.getMulticastNetworkInterface();
- }
- if (multicastInterface != null)
- {
- log.info("Using network interface {0}", multicastInterface.getDisplayName());
- mSocket.setNetworkInterface(multicastInterface);
- }
-
- mSocket.joinGroup( multicastAddress );
- }
- catch ( IOException e )
- {
- log.error( "Could not bind to multicast address [{0}:{1}]", multicastAddress,
- multicastPort, e );
- throw e;
- }
- }
-
- /**
- * Highly unreliable. If it is processing one message while another comes in, the second
- * message is lost. This is for low concurrency peppering.
- * <p>
- * @return the object message
- * @throws IOException
- */
- public Object waitForMessage()
- throws IOException
- {
- final DatagramPacket packet = new DatagramPacket( mBuffer, mBuffer.length );
- Object obj = null;
- try
- {
- log.debug( "Waiting for message." );
-
- mSocket.receive( packet );
-
- log.debug( "Received packet from address [{0}]",
- () -> packet.getSocketAddress() );
-
- try (ByteArrayInputStream byteStream = new ByteArrayInputStream(mBuffer, 0, packet.getLength());
- ObjectInputStream objectStream = new ObjectInputStreamClassLoaderAware(byteStream, null))
- {
- obj = objectStream.readObject();
- }
-
- if ( obj instanceof UDPDiscoveryMessage )
- {
- // Ensure that the address we're supposed to send to is, indeed, the address
- // of the machine on the other end of this connection. This guards against
- // instances where we don't exactly get the right local host address
- UDPDiscoveryMessage msg = (UDPDiscoveryMessage) obj;
- msg.setHost(packet.getAddress().getHostAddress());
-
- log.debug( "Read object from address [{0}], object=[{1}]",
- packet.getSocketAddress(), obj );
- }
- }
- catch ( Exception e )
- {
- log.error( "Error receiving multicast packet", e );
- }
-
- return obj;
- }
-
- /** Main processing method for the LateralUDPReceiver object */
- @Override
- public void run()
- {
- try
- {
- while ( !shutdown )
- {
- Object obj = waitForMessage();
-
- cnt.incrementAndGet();
-
- log.debug( "{0} messages received.", () -> getCnt() );
-
- UDPDiscoveryMessage message = null;
-
- try
- {
- message = (UDPDiscoveryMessage) obj;
- // check for null
- if ( message != null )
- {
- MessageHandler handler = new MessageHandler( message );
-
- pooledExecutor.execute( handler );
-
- log.debug( "Passed handler to executor." );
- }
- else
- {
- log.warn( "message is null" );
- }
- }
- catch ( ClassCastException cce )
- {
- log.warn( "Received unknown message type", cce.getMessage() );
- }
- } // end while
- }
- catch ( IOException e )
- {
- log.error( "Unexpected exception in UDP receiver.", e );
- try
- {
- Thread.sleep( 100 );
- // TODO consider some failure count so we don't do this
- // forever.
- }
- catch ( InterruptedException e2 )
- {
- log.error( "Problem sleeping", e2 );
- }
- }
- }
-
- /**
- * @param cnt The cnt to set.
- */
- public void setCnt( int cnt )
- {
- this.cnt.set(cnt);
- }
-
- /**
- * @return Returns the cnt.
- */
- public int getCnt()
- {
- return cnt.get();
- }
-
- /**
- * Separate thread run when a command comes into the UDPDiscoveryReceiver.
- */
- public class MessageHandler
- implements Runnable
- {
- /** The message to handle. Passed in during construction. */
- private UDPDiscoveryMessage message = null;
-
- /**
- * @param message
- */
- public MessageHandler( UDPDiscoveryMessage message )
- {
- this.message = message;
- }
-
- /**
- * Process the message.
- */
- @SuppressWarnings("synthetic-access")
- @Override
- public void run()
- {
- // consider comparing ports here instead.
- if ( message.getRequesterId() == CacheInfo.listenerId )
- {
- log.debug( "Ignoring message sent from self" );
- }
- else
- {
- log.debug( "Process message sent from another" );
- log.debug( "Message = {0}", message );
-
- if ( message.getHost() == null || message.getCacheNames() == null || message.getCacheNames().isEmpty() )
- {
- log.debug( "Ignoring invalid message: {0}", message );
- }
- else
- {
- processMessage();
- }
- }
- }
-
- /**
- * Process the incoming message.
- */
- @SuppressWarnings("synthetic-access")
- private void processMessage()
- {
- DiscoveredService discoveredService = new DiscoveredService();
- discoveredService.setServiceAddress( message.getHost() );
- discoveredService.setCacheNames( message.getCacheNames() );
- discoveredService.setServicePort( message.getPort() );
- discoveredService.setLastHearFromTime( System.currentTimeMillis() );
-
- // if this is a request message, have the service handle it and
- // return
- if ( message.getMessageType() == BroadcastType.REQUEST )
- {
- log.debug( "Message is a Request Broadcast, will have the service handle it." );
- service.serviceRequestBroadcast();
- return;
- }
- else if ( message.getMessageType() == BroadcastType.REMOVE )
- {
- log.debug( "Removing service from set {0}", discoveredService );
- service.removeDiscoveredService( discoveredService );
- }
- else
- {
- service.addOrUpdateService( discoveredService );
- }
- }
- }
-
- /** Shuts down the socket. */
- @Override
- public void shutdown()
- {
- if (!shutdown)
- {
- try
- {
- shutdown = true;
- mSocket.leaveGroup( multicastAddress );
- mSocket.close();
- pooledExecutor.shutdownNow();
- }
- catch ( IOException e )
- {
- log.error( "Problem closing socket" );
- }
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoverySender.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoverySender.java
deleted file mode 100644
index 6f4f9fe..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoverySender.java
+++ /dev/null
@@ -1,260 +0,0 @@
-package org.apache.commons.jcs.utils.discovery;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.net.DatagramPacket;
-import java.net.InetAddress;
-import java.net.MulticastSocket;
-import java.util.ArrayList;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.CacheInfo;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.discovery.UDPDiscoveryMessage.BroadcastType;
-import org.apache.commons.jcs.utils.serialization.StandardSerializer;
-
-/**
- * This is a generic sender for the UDPDiscovery process.
- * <p>
- * @author Aaron Smuts
- */
-public class UDPDiscoverySender implements AutoCloseable
-{
- /** The logger. */
- private static final Log log = LogManager.getLog( UDPDiscoverySender.class );
-
- /** The socket */
- private final MulticastSocket localSocket;
-
- /** The address */
- private final InetAddress multicastAddress;
-
- /** The port */
- private final int multicastPort;
-
- /** Used to serialize messages */
- private final StandardSerializer serializer = new StandardSerializer();
-
- /**
- * Constructor for the UDPDiscoverySender object
- * <p>
- * This sender can be used to send multiple messages.
- * <p>
- * When you are done sending, you should destroy the socket sender.
- * <p>
- * @param host
- * @param port
- * @param udpTTL the Datagram packet time-to-live
- * @throws IOException
- */
- public UDPDiscoverySender( String host, int port, int udpTTL )
- throws IOException
- {
- try
- {
- log.debug( "Constructing socket for sender on port [{0}]", port );
- localSocket = new MulticastSocket( port );
- if (udpTTL > 0)
- {
- log.debug( "Setting datagram TTL to [{0}]", udpTTL );
- localSocket.setTimeToLive(udpTTL);
- }
-
- // Remote address.
- multicastAddress = InetAddress.getByName( host );
- }
- catch ( IOException e )
- {
- log.error( "Could not bind to multicast address [{0}]", host, e );
- throw e;
- }
-
- this.multicastPort = port;
- }
-
- /**
- * Closes the socket connection.
- */
- @Override
- public void close()
- {
- if ( this.localSocket != null && !this.localSocket.isClosed() )
- {
- this.localSocket.close();
- }
- }
-
- /**
- * Send messages.
- * <p>
- * @param message
- * @throws IOException
- */
- public void send( UDPDiscoveryMessage message )
- throws IOException
- {
- if ( this.localSocket == null )
- {
- throw new IOException( "Socket is null, cannot send message." );
- }
-
- if ( this.localSocket.isClosed() )
- {
- throw new IOException( "Socket is closed, cannot send message." );
- }
-
- log.debug( "sending UDPDiscoveryMessage, address [{0}], port [{1}], "
- + "message = {2}", multicastAddress, multicastPort, message );
-
- try
- {
- final byte[] bytes = serializer.serialize( message );
-
- // put the byte array in a packet
- final DatagramPacket packet = new DatagramPacket( bytes, bytes.length, multicastAddress, multicastPort );
-
- log.debug( "Sending DatagramPacket. bytes.length [{0}] to {1}:{2}",
- bytes.length, multicastAddress, multicastPort );
-
- localSocket.send( packet );
- }
- catch ( IOException e )
- {
- log.error( "Error sending message", e );
- throw e;
- }
- }
-
- /**
- * Ask other to broadcast their info the the multicast address. If a lateral is non receiving it
- * can use this. This is also called on startup so we can get info.
- * <p>
- * @throws IOException
- */
- public void requestBroadcast()
- throws IOException
- {
- log.debug( "sending requestBroadcast" );
-
- UDPDiscoveryMessage message = new UDPDiscoveryMessage();
- message.setRequesterId( CacheInfo.listenerId );
- message.setMessageType( BroadcastType.REQUEST );
- send( message );
- }
-
- /**
- * This sends a message broadcasting out that the host and port is available for connections.
- * <p>
- * It uses the vmid as the requesterDI
- * @param host
- * @param port
- * @param cacheNames
- * @throws IOException
- */
- public void passiveBroadcast( String host, int port, ArrayList<String> cacheNames )
- throws IOException
- {
- passiveBroadcast( host, port, cacheNames, CacheInfo.listenerId );
- }
-
- /**
- * This allows you to set the sender id. This is mainly for testing.
- * <p>
- * @param host
- * @param port
- * @param cacheNames names of the cache regions
- * @param listenerId
- * @throws IOException
- */
- protected void passiveBroadcast( String host, int port, ArrayList<String> cacheNames, long listenerId )
- throws IOException
- {
- log.debug( "sending passiveBroadcast" );
-
- UDPDiscoveryMessage message = new UDPDiscoveryMessage();
- message.setHost( host );
- message.setPort( port );
- message.setCacheNames( cacheNames );
- message.setRequesterId( listenerId );
- message.setMessageType( BroadcastType.PASSIVE );
- send( message );
- }
-
- /**
- * This sends a message broadcasting our that the host and port is no longer available.
- * <p>
- * It uses the vmid as the requesterID
- * <p>
- * @param host host
- * @param port port
- * @param cacheNames names of the cache regions
- * @throws IOException on error
- */
- public void removeBroadcast( String host, int port, ArrayList<String> cacheNames )
- throws IOException
- {
- removeBroadcast( host, port, cacheNames, CacheInfo.listenerId );
- }
-
- /**
- * This allows you to set the sender id. This is mainly for testing.
- * <p>
- * @param host host
- * @param port port
- * @param cacheNames names of the cache regions
- * @param listenerId listener ID
- * @throws IOException on error
- */
- protected void removeBroadcast( String host, int port, ArrayList<String> cacheNames, long listenerId )
- throws IOException
- {
- log.debug( "sending removeBroadcast" );
-
- UDPDiscoveryMessage message = new UDPDiscoveryMessage();
- message.setHost( host );
- message.setPort( port );
- message.setCacheNames( cacheNames );
- message.setRequesterId( listenerId );
- message.setMessageType( BroadcastType.REMOVE );
- send( message );
- }
-}
-
-/**
- * This allows us to get the byte array from an output stream.
- * <p>
- * @author asmuts
- * @created January 15, 2002
- */
-
-class MyByteArrayOutputStream
- extends ByteArrayOutputStream
-{
- /**
- * Gets the bytes attribute of the MyByteArrayOutputStream object
- * @return The bytes value
- */
- public byte[] getBytes()
- {
- return buf;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoverySenderThread.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoverySenderThread.java
deleted file mode 100644
index 6c7c2a5..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoverySenderThread.java
+++ /dev/null
@@ -1,147 +0,0 @@
-package org.apache.commons.jcs.utils.discovery;
-
-import java.io.IOException;
-import java.util.ArrayList;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * Used to periodically broadcast our location to other caches that might be listening.
- */
-public class UDPDiscoverySenderThread
- implements Runnable
-{
- /** The logger. */
- private static final Log log = LogManager.getLog( UDPDiscoverySenderThread.class );
-
- /**
- * details of the host, port, and service being advertised to listen for TCP socket connections
- */
- private final UDPDiscoveryAttributes attributes;
-
- /** List of known regions. */
- private ArrayList<String> cacheNames = new ArrayList<>();
-
- /**
- * @param cacheNames The cacheNames to set.
- */
- protected void setCacheNames( ArrayList<String> cacheNames )
- {
- log.info( "Resetting cacheNames = [{0}]", cacheNames );
- this.cacheNames = cacheNames;
- }
-
- /**
- * @return Returns the cacheNames.
- */
- protected ArrayList<String> getCacheNames()
- {
- return cacheNames;
- }
-
- /**
- * Constructs the sender with the port to tell others to connect to.
- * <p>
- * On construction the sender will request that the other caches let it know their addresses.
- * @param attributes host, port, etc.
- * @param cacheNames List of strings of the names of the region participating.
- */
- public UDPDiscoverySenderThread( UDPDiscoveryAttributes attributes, ArrayList<String> cacheNames )
- {
- this.attributes = attributes;
-
- this.cacheNames = cacheNames;
-
- log.debug( "Creating sender thread for discoveryAddress = [{0}] and "
- + "discoveryPort = [{1}] myHostName = [{2}] and port = [{3}]",
- () -> attributes.getUdpDiscoveryAddr(),
- () -> attributes.getUdpDiscoveryPort(),
- () -> attributes.getServiceAddress(),
- () -> attributes.getServicePort() );
-
- try (UDPDiscoverySender sender = new UDPDiscoverySender(
- attributes.getUdpDiscoveryAddr(),
- attributes.getUdpDiscoveryPort(),
- attributes.getUdpTTL()))
- {
- // move this to the run method and determine how often to call it.
- sender.requestBroadcast();
-
- log.debug( "Sent a request broadcast to the group" );
- }
- catch ( IOException e )
- {
- log.error( "Problem sending a Request Broadcast", e );
- }
- }
-
- /**
- * Send a message.
- */
- @Override
- public void run()
- {
- // create this connection each time.
- // more robust
- try (UDPDiscoverySender sender = new UDPDiscoverySender(
- attributes.getUdpDiscoveryAddr(),
- attributes.getUdpDiscoveryPort(),
- attributes.getUdpTTL()))
- {
- sender.passiveBroadcast( attributes.getServiceAddress(), attributes.getServicePort(), cacheNames );
-
- // todo we should consider sending a request broadcast every so
- // often.
-
- log.debug( "Called sender to issue a passive broadcast" );
- }
- catch ( IOException e )
- {
- log.error( "Problem calling the UDP Discovery Sender [{0}:{1}]",
- attributes.getUdpDiscoveryAddr(),
- attributes.getUdpDiscoveryPort(), e );
- }
- }
-
- /**
- * Issues a remove broadcast to the others.
- */
- protected void shutdown()
- {
- // create this connection each time.
- // more robust
- try (UDPDiscoverySender sender = new UDPDiscoverySender(
- attributes.getUdpDiscoveryAddr(),
- attributes.getUdpDiscoveryPort(),
- attributes.getUdpTTL()))
- {
- sender.removeBroadcast( attributes.getServiceAddress(), attributes.getServicePort(), cacheNames );
-
- log.debug( "Called sender to issue a remove broadcast in shudown." );
- }
- catch ( IOException e )
- {
- log.error( "Problem calling the UDP Discovery Sender", e );
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryService.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryService.java
deleted file mode 100644
index 1f8fc68..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryService.java
+++ /dev/null
@@ -1,372 +0,0 @@
-package org.apache.commons.jcs.utils.discovery;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.commons.jcs.engine.behavior.IRequireScheduler;
-import org.apache.commons.jcs.engine.behavior.IShutdownObserver;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.discovery.behavior.IDiscoveryListener;
-import org.apache.commons.jcs.utils.net.HostNameUtil;
-
-/**
- * This service creates a listener that can create lateral caches and add them to the no wait list.
- * <p>
- * It also creates a sender that periodically broadcasts its availability.
- * <p>
- * The sender also broadcasts a request for other caches to broadcast their addresses.
- * <p>
- * @author Aaron Smuts
- */
-public class UDPDiscoveryService
- implements IShutdownObserver, IRequireScheduler
-{
- /** The logger */
- private static final Log log = LogManager.getLog( UDPDiscoveryService.class );
-
- /** thread that listens for messages */
- private Thread udpReceiverThread;
-
- /** the runnable that the receiver thread runs */
- private UDPDiscoveryReceiver receiver;
-
- /** the runnable that sends messages via the clock daemon */
- private UDPDiscoverySenderThread sender = null;
-
- /** attributes */
- private UDPDiscoveryAttributes udpDiscoveryAttributes = null;
-
- /** is this shut down? */
- private boolean shutdown = false;
-
- /** This is a set of services that have been discovered. */
- private final Set<DiscoveredService> discoveredServices = new CopyOnWriteArraySet<>();
-
- /** This a list of regions that are configured to use discovery. */
- private final Set<String> cacheNames = new CopyOnWriteArraySet<>();
-
- /** Set of listeners. */
- private final Set<IDiscoveryListener> discoveryListeners = new CopyOnWriteArraySet<>();
-
- /**
- * @param attributes
- */
- public UDPDiscoveryService( UDPDiscoveryAttributes attributes)
- {
- udpDiscoveryAttributes = attributes.clone();
-
- try
- {
- // todo, you should be able to set this
- udpDiscoveryAttributes.setServiceAddress( HostNameUtil.getLocalHostAddress() );
- }
- catch ( UnknownHostException e )
- {
- log.error( "Couldn't get localhost address", e );
- }
-
- try
- {
- // todo need some kind of recovery here.
- receiver = new UDPDiscoveryReceiver( this,
- getUdpDiscoveryAttributes().getUdpDiscoveryInterface(),
- getUdpDiscoveryAttributes().getUdpDiscoveryAddr(),
- getUdpDiscoveryAttributes().getUdpDiscoveryPort() );
- }
- catch ( IOException e )
- {
- log.error( "Problem creating UDPDiscoveryReceiver, address [{0}] "
- + "port [{1}] we won't be able to find any other caches",
- getUdpDiscoveryAttributes().getUdpDiscoveryAddr(),
- getUdpDiscoveryAttributes().getUdpDiscoveryPort(), e );
- }
-
- // create a sender thread
- sender = new UDPDiscoverySenderThread( getUdpDiscoveryAttributes(), getCacheNames() );
- }
-
- /**
- * @see org.apache.commons.jcs.engine.behavior.IRequireScheduler#setScheduledExecutorService(java.util.concurrent.ScheduledExecutorService)
- */
- @Override
- public void setScheduledExecutorService(ScheduledExecutorService scheduledExecutor)
- {
- if (sender != null)
- {
- scheduledExecutor.scheduleAtFixedRate(sender, 0, 15, TimeUnit.SECONDS);
- }
-
- /** removes things that have been idle for too long */
- UDPCleanupRunner cleanup = new UDPCleanupRunner( this );
- // I'm going to use this as both, but it could happen
- // that something could hang around twice the time using this as the
- // delay and the idle time.
- scheduledExecutor.scheduleAtFixedRate(cleanup, 0, getUdpDiscoveryAttributes().getMaxIdleTimeSec(), TimeUnit.SECONDS);
- }
-
- /**
- * Send a passive broadcast in response to a request broadcast. Never send a request for a
- * request. We can respond to our own requests, since a request broadcast is not intended as a
- * connection request. We might want to only send messages, so we would send a request, but
- * never a passive broadcast.
- */
- protected void serviceRequestBroadcast()
- {
- // create this connection each time.
- // more robust
- try (UDPDiscoverySender sender = new UDPDiscoverySender(
- getUdpDiscoveryAttributes().getUdpDiscoveryAddr(),
- getUdpDiscoveryAttributes().getUdpDiscoveryPort(),
- getUdpDiscoveryAttributes().getUdpTTL()))
- {
- sender.passiveBroadcast( getUdpDiscoveryAttributes().getServiceAddress(), getUdpDiscoveryAttributes()
- .getServicePort(), this.getCacheNames() );
-
- // todo we should consider sending a request broadcast every so
- // often.
-
- log.debug( "Called sender to issue a passive broadcast" );
- }
- catch ( IOException e )
- {
- log.error( "Problem calling the UDP Discovery Sender, address [{0}] "
- + "port [{1}]",
- getUdpDiscoveryAttributes().getUdpDiscoveryAddr(),
- getUdpDiscoveryAttributes().getUdpDiscoveryPort(), e );
- }
- }
-
- /**
- * Adds a region to the list that is participating in discovery.
- * <p>
- * @param cacheName
- */
- public void addParticipatingCacheName( String cacheName )
- {
- cacheNames.add( cacheName );
- sender.setCacheNames( getCacheNames() );
- }
-
- /**
- * Removes the discovered service from the list and calls the discovery listener.
- * <p>
- * @param service
- */
- public void removeDiscoveredService( DiscoveredService service )
- {
- boolean contained = getDiscoveredServices().remove( service );
-
- if ( contained )
- {
- log.info( "Removing {0}", service );
- }
-
- for (IDiscoveryListener listener : getDiscoveryListeners())
- {
- listener.removeDiscoveredService( service );
- }
- }
-
- /**
- * Add a service to the list. Update the held copy if we already know about it.
- * <p>
- * @param discoveredService discovered service
- */
- protected void addOrUpdateService( DiscoveredService discoveredService )
- {
- Set<DiscoveredService> discoveredServices = getDiscoveredServices();
- // Since this is a set we can add it over an over.
- // We want to replace the old one, since we may add info that is not part of the equals.
- // The equals method on the object being added is intentionally restricted.
- if ( !discoveredServices.contains( discoveredService ) )
- {
- log.info( "Set does not contain service. I discovered {0}", discoveredService );
- log.debug( "Adding service in the set {0}", discoveredService );
- discoveredServices.add( discoveredService );
- }
- else
- {
- log.debug( "Set contains service." );
- log.debug( "Updating service in the set {0}", discoveredService );
-
- // Update the list of cache names if it has changed.
- DiscoveredService theOldServiceInformation = null;
- // need to update the time this sucks. add has no effect convert to a map
- for (DiscoveredService service1 : discoveredServices)
- {
- if ( discoveredService.equals( service1 ) )
- {
- theOldServiceInformation = service1;
- break;
- }
- }
- if ( theOldServiceInformation != null )
- {
- if ( !theOldServiceInformation.getCacheNames().equals(
- discoveredService.getCacheNames() ) )
- {
- log.info( "List of cache names changed for service: {0}",
- discoveredService );
- }
- }
-
- // replace it, we want to reset the payload and the last heard from time.
- discoveredServices.remove( discoveredService );
- discoveredServices.add( discoveredService );
- }
-
- // Always Notify the listeners
- // If we don't do this, then if a region using the default config is initialized after notification,
- // it will never get the service in it's no wait list.
- // Leave it to the listeners to decide what to do.
- for (IDiscoveryListener listener : getDiscoveryListeners())
- {
- listener.addDiscoveredService( discoveredService );
- }
- }
-
- /**
- * Get all the cache names we have facades for.
- * <p>
- * @return ArrayList
- */
- protected ArrayList<String> getCacheNames()
- {
- ArrayList<String> names = new ArrayList<>();
- names.addAll( cacheNames );
- return names;
- }
-
- /**
- * @param attr The UDPDiscoveryAttributes to set.
- */
- public void setUdpDiscoveryAttributes( UDPDiscoveryAttributes attr )
- {
- this.udpDiscoveryAttributes = attr;
- }
-
- /**
- * @return Returns the lca.
- */
- public UDPDiscoveryAttributes getUdpDiscoveryAttributes()
- {
- return this.udpDiscoveryAttributes;
- }
-
- /**
- * Start necessary receiver thread
- */
- public void startup()
- {
- udpReceiverThread = new Thread(receiver);
- udpReceiverThread.setDaemon(true);
- // udpReceiverThread.setName( t.getName() + "--UDPReceiver" );
- udpReceiverThread.start();
- }
-
- /**
- * Shuts down the receiver.
- */
- @Override
- public void shutdown()
- {
- if ( !shutdown )
- {
- shutdown = true;
-
- // no good way to do this right now.
- if (receiver != null)
- {
- log.info( "Shutting down UDP discovery service receiver." );
- receiver.shutdown();
- udpReceiverThread.interrupt();
- }
-
- if (sender != null)
- {
- log.info( "Shutting down UDP discovery service sender." );
- // also call the shutdown on the sender thread itself, which
- // will result in a remove command.
- sender.shutdown();
- }
- }
- else
- {
- log.debug( "Shutdown already called." );
- }
- }
-
- /**
- * @return Returns the discoveredServices.
- */
- public Set<DiscoveredService> getDiscoveredServices()
- {
- return discoveredServices;
- }
-
- /**
- * @return the discoveryListeners
- */
- private Set<IDiscoveryListener> getDiscoveryListeners()
- {
- return discoveryListeners;
- }
-
- /**
- * @return the discoveryListeners
- */
- public Set<IDiscoveryListener> getCopyOfDiscoveryListeners()
- {
- Set<IDiscoveryListener> copy = new HashSet<>();
- copy.addAll( getDiscoveryListeners() );
- return copy;
- }
-
- /**
- * Adds a listener.
- * <p>
- * @param listener
- * @return true if it wasn't already in the set
- */
- public boolean addDiscoveryListener( IDiscoveryListener listener )
- {
- return getDiscoveryListeners().add( listener );
- }
-
- /**
- * Removes a listener.
- * <p>
- * @param listener
- * @return true if it was in the set
- */
- public boolean removeDiscoveryListener( IDiscoveryListener listener )
- {
- return getDiscoveryListeners().remove( listener );
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/behavior/IDiscoveryListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/behavior/IDiscoveryListener.java
deleted file mode 100644
index 8a0d9d9..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/behavior/IDiscoveryListener.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.apache.commons.jcs.utils.discovery.behavior;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.utils.discovery.DiscoveredService;
-
-/**
- * Interface for things that want to listen to discovery events. This will allow discovery to be
- * used outside of the TCP lateral.
- */
-public interface IDiscoveryListener
-{
- /**
- * Add the service if needed. This does not necessarily mean that the service is not already
- * added. This can be called if there is a change in service information, such as the cacheNames.
- * <p>
- * @param service the service to add
- */
- void addDiscoveredService( DiscoveredService service );
-
- /**
- * Remove the service from the list.
- * <p>
- * @param service the service to remove
- */
- void removeDiscoveredService( DiscoveredService service );
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/net/HostNameUtil.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/net/HostNameUtil.java
deleted file mode 100644
index 2c3bce6..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/net/HostNameUtil.java
+++ /dev/null
@@ -1,195 +0,0 @@
-package org.apache.commons.jcs.utils.net;
-
-/*
- * 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.
- */
-
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.util.Enumeration;
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * Simple utility for getting the local host name.
- * <p>
- * @author Aaron Smuts
- */
-public class HostNameUtil
-{
- /** The logger. */
- private static final Log log = LogManager.getLog( HostNameUtil.class );
-
- /**
- * Gets the address for the local machine.
- * <p>
- * @return InetAddress.getLocalHost().getHostAddress()
- * @throws UnknownHostException
- */
- public static String getLocalHostAddress() throws UnknownHostException
- {
- try
- {
- String hostAddress = getLocalHostLANAddress().getHostAddress();
- log.debug( "hostAddress = [{0}]", hostAddress );
- return hostAddress;
- }
- catch ( UnknownHostException e1 )
- {
- log.error( "Couldn't get localhost address", e1 );
- throw e1;
- }
- }
-
- /**
- * Returns an <code>InetAddress</code> object encapsulating what is most likely the machine's
- * LAN IP address.
- * <p>
- * This method is intended for use as a replacement of JDK method
- * <code>InetAddress.getLocalHost</code>, because that method is ambiguous on Linux systems.
- * Linux systems enumerate the loopback network interface the same way as regular LAN network
- * interfaces, but the JDK <code>InetAddress.getLocalHost</code> method does not specify the
- * algorithm used to select the address returned under such circumstances, and will often return
- * the loopback address, which is not valid for network communication. Details <a
- * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4665037">here</a>.
- * <p>
- * This method will scan all IP addresses on all network interfaces on the host machine to
- * determine the IP address most likely to be the machine's LAN address. If the machine has
- * multiple IP addresses, this method will prefer a site-local IP address (e.g. 192.168.x.x or
- * 10.10.x.x, usually IPv4) if the machine has one (and will return the first site-local address
- * if the machine has more than one), but if the machine does not hold a site-local address,
- * this method will return simply the first non-loopback address found (IPv4 or IPv6).</p>
- * <p>
- * If this method cannot find a non-loopback address using this selection algorithm, it will
- * fall back to calling and returning the result of JDK method
- * <code>InetAddress.getLocalHost</code>.
- * <p>
- * <a href="http://issues.apache.org/jira/browse/JCS-40">JIR ISSUE JCS-40</a>
- * <p>
- * @return InetAddress
- * @throws UnknownHostException If the LAN address of the machine cannot be found.
- */
- public static InetAddress getLocalHostLANAddress()
- throws UnknownHostException
- {
- try
- {
- InetAddress candidateAddress = null;
- // Iterate all NICs (network interface cards)...
- for ( Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); )
- {
- NetworkInterface iface = ifaces.nextElement();
- // Iterate all IP addresses assigned to each card...
- for ( Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); )
- {
- InetAddress inetAddr = inetAddrs.nextElement();
- if ( !inetAddr.isLoopbackAddress() )
- {
- if ( inetAddr.isSiteLocalAddress() )
- {
- // Found non-loopback site-local address. Return it immediately...
- return inetAddr;
- }
- else if ( candidateAddress == null )
- {
- // Found non-loopback address, but not necessarily site-local.
- // Store it as a candidate to be returned if site-local address is not subsequently found...
- candidateAddress = inetAddr;
- // Note that we don't repeatedly assign non-loopback non-site-local addresses as candidates,
- // only the first. For subsequent iterations, candidate will be non-null.
- }
- }
- }
- }
- if ( candidateAddress != null )
- {
- // We did not find a site-local address, but we found some other non-loopback address.
- // Server might have a non-site-local address assigned to its NIC (or it might be running
- // IPv6 which deprecates the "site-local" concept).
- // Return this non-loopback candidate address...
- return candidateAddress;
- }
- // At this point, we did not find a non-loopback address.
- // Fall back to returning whatever InetAddress.getLocalHost() returns...
- InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
- if ( jdkSuppliedAddress == null )
- {
- throw new UnknownHostException( "The JDK InetAddress.getLocalHost() method unexpectedly returned null." );
- }
- return jdkSuppliedAddress;
- }
- catch ( SocketException e )
- {
- UnknownHostException unknownHostException = new UnknownHostException( "Failed to determine LAN address: "
- + e );
- unknownHostException.initCause( e );
- throw unknownHostException;
- }
- }
-
- /**
- * On systems with multiple network interfaces and mixed IPv6/IPv4 get a valid network
- * interface for binding to multicast
- *
- * @return a network interface suitable for multicast
- * @throws SocketException if a problem occurs while reading the network interfaces
- */
- public static NetworkInterface getMulticastNetworkInterface() throws SocketException
- {
- Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
- while (networkInterfaces.hasMoreElements())
- {
- NetworkInterface networkInterface = networkInterfaces.nextElement();
- Enumeration<InetAddress> addressesFromNetworkInterface = networkInterface.getInetAddresses();
- while (addressesFromNetworkInterface.hasMoreElements())
- {
- InetAddress inetAddress = addressesFromNetworkInterface.nextElement();
- if (inetAddress.isSiteLocalAddress()
- && !inetAddress.isAnyLocalAddress()
- && !inetAddress.isLinkLocalAddress()
- && !inetAddress.isLoopbackAddress()
- && !inetAddress.isMulticastAddress())
- {
- return networkInterface;
- }
- }
- }
-
- return null;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/serialization/CompressingSerializer.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/serialization/CompressingSerializer.java
deleted file mode 100644
index bbc0ee9..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/serialization/CompressingSerializer.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package org.apache.commons.jcs.utils.serialization;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-
-import org.apache.commons.jcs.utils.zip.CompressionUtil;
-
-/**
- * Performs default serialization and de-serialization. It gzips the value.
- */
-public class CompressingSerializer extends StandardSerializer
-{
- /**
- * Serializes an object using default serialization. Compresses the byte array.
- * <p>
- * @param obj object
- * @return byte[]
- * @throws IOException on i/o problem
- */
- @Override
- public <T> byte[] serialize( T obj )
- throws IOException
- {
- byte[] uncompressed = super.serialize(obj);
- byte[] compressed = CompressionUtil.compressByteArray( uncompressed );
- return compressed;
- }
-
- /**
- * Uses default de-serialization to turn a byte array into an object. Decompresses the value
- * first. All exceptions are converted into IOExceptions.
- * <p>
- * @param data data bytes
- * @param loader class loader to use
- * @return Object
- * @throws IOException on i/o problem
- * @throws ClassNotFoundException if class is not found during deserialization
- */
- @Override
- public <T> T deSerialize( byte[] data, ClassLoader loader )
- throws IOException, ClassNotFoundException
- {
- if ( data == null )
- {
- return null;
- }
-
- byte[] decompressedByteArray = CompressionUtil.decompressByteArray( data );
- return super.deSerialize(decompressedByteArray, loader);
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/serialization/SerializationConversionUtil.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/serialization/SerializationConversionUtil.java
deleted file mode 100644
index e179044..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/serialization/SerializationConversionUtil.java
+++ /dev/null
@@ -1,149 +0,0 @@
-package org.apache.commons.jcs.utils.serialization;
-
-import java.io.IOException;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.CacheElementSerialized;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElementSerialized;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This uses a supplied Serializer to convert to and from cache elements.
- * <p>
- * @author Aaron Smuts
- */
-public class SerializationConversionUtil
-{
- /** The logger */
- private static final Log log = LogManager.getLog( SerializationConversionUtil.class );
-
- /**
- * This returns a wrapper that has a serialized version of the value instead
- * of the value.
- * <p>
- * @param element
- * @param elementSerializer
- * the serializer to be used.
- * @return null for null;
- * @throws IOException
- */
- public static <K, V> ICacheElementSerialized<K, V> getSerializedCacheElement( ICacheElement<K, V> element,
- IElementSerializer elementSerializer )
- throws IOException
- {
- if ( element == null )
- {
- return null;
- }
-
- byte[] serializedValue = null;
-
- // if it has already been serialized, don't do it again.
- if ( element instanceof ICacheElementSerialized )
- {
- serializedValue = ( (ICacheElementSerialized<K, V>) element ).getSerializedValue();
- }
- else
- {
- if ( elementSerializer != null )
- {
- try
- {
- serializedValue = elementSerializer.serialize(element.getVal());
-
- // update size in bytes
- element.getElementAttributes().setSize(serializedValue.length);
- }
- catch ( IOException e )
- {
- log.error( "Problem serializing object.", e );
- throw e;
- }
- }
- else
- {
- // we could just use the default.
- throw new IOException( "Could not serialize object. The ElementSerializer is null." );
- }
- }
- ICacheElementSerialized<K, V> serialized = new CacheElementSerialized<>(
- element.getCacheName(), element.getKey(), serializedValue, element.getElementAttributes() );
-
- return serialized;
- }
-
- /**
- * This returns a wrapper that has a de-serialized version of the value
- * instead of the serialized value.
- * <p>
- * @param serialized
- * @param elementSerializer
- * the serializer to be used.
- * @return null for null;
- * @throws IOException
- * @throws ClassNotFoundException
- */
- public static <K, V> ICacheElement<K, V> getDeSerializedCacheElement( ICacheElementSerialized<K, V> serialized,
- IElementSerializer elementSerializer )
- throws IOException, ClassNotFoundException
- {
- if ( serialized == null )
- {
- return null;
- }
-
- V deSerializedValue = null;
-
- if ( elementSerializer != null )
- {
- try
- {
- try
- {
- deSerializedValue = elementSerializer.deSerialize( serialized.getSerializedValue(), null );
- }
- catch ( ClassNotFoundException e )
- {
- log.error( "Problem de-serializing object.", e );
- throw e;
- }
- }
- catch ( IOException e )
- {
- log.error( "Problem de-serializing object.", e );
- throw e;
- }
- }
- else
- {
- // we could just use the default.
- throw new IOException( "Could not de-serialize object. The ElementSerializer is null." );
- }
- ICacheElement<K, V> deSerialized = new CacheElement<>( serialized.getCacheName(), serialized.getKey(), deSerializedValue );
- deSerialized.setElementAttributes( serialized.getElementAttributes() );
-
- return deSerialized;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/serialization/StandardSerializer.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/serialization/StandardSerializer.java
deleted file mode 100644
index 0915800..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/serialization/StandardSerializer.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package org.apache.commons.jcs.utils.serialization;
-
-/*
- * 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.
- */
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.io.ObjectInputStreamClassLoaderAware;
-
-/**
- * Performs default serialization and de-serialization.
- * <p>
- * @author Aaron Smuts
- */
-public class StandardSerializer
- implements IElementSerializer
-{
- /**
- * Serializes an object using default serialization.
- * <p>
- * @param obj
- * @return byte[]
- * @throws IOException
- */
- @Override
- public <T> byte[] serialize(T obj)
- throws IOException
- {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
- try (ObjectOutputStream oos = new ObjectOutputStream(baos))
- {
- oos.writeObject(obj);
- }
-
- return baos.toByteArray();
- }
-
- /**
- * Uses default de-serialization to turn a byte array into an object. All exceptions are
- * converted into IOExceptions.
- * <p>
- * @param data data bytes
- * @param loader class loader to use
- * @return Object
- * @throws IOException
- * @throws ClassNotFoundException
- */
- @Override
- public <T> T deSerialize(byte[] data, ClassLoader loader)
- throws IOException, ClassNotFoundException
- {
- try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
- ObjectInputStream ois = new ObjectInputStreamClassLoaderAware(bais, loader))
- {
- @SuppressWarnings("unchecked") // Need to cast from Object
- T readObject = (T) ois.readObject();
- return readObject;
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/servlet/JCSServletContextListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/servlet/JCSServletContextListener.java
deleted file mode 100644
index 03d01b1..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/servlet/JCSServletContextListener.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package org.apache.commons.jcs.utils.servlet;
-
-/*
- * 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.
- */
-
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * If you add this to the context listeners section of your web.xml file, this will shutdown JCS
- * gracefully.
- * <p>
- * Add the following to the top of your web.xml file.
- *
- * <pre>
- * <listener>
- * <listener-class>
- * org.apache.commons.jcs.utils.servlet.JCSServletContextListener
- * </listener-class>
- * </listener>
- * </pre>
- * @author Aaron Smuts
- */
-public class JCSServletContextListener
- implements ServletContextListener
-{
- /** The logger */
- private static final Log log = LogManager.getLog( JCSServletContextListener.class );
-
- /**
- * This does nothing. We don't want to initialize the cache here.
- * <p>
- * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
- */
- @Override
- public void contextInitialized( ServletContextEvent arg0 )
- {
- log.debug( "contextInitialized" );
- }
-
- /**
- * Shutdown JCS.
- * <p>
- * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
- */
- @Override
- public void contextDestroyed( ServletContextEvent arg0 )
- {
- log.debug( "contextDestroyed, shutting down JCS." );
-
- JCS.shutdown();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java
deleted file mode 100644
index bdb12e3..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java
+++ /dev/null
@@ -1,542 +0,0 @@
-package org.apache.commons.jcs.utils.struct;
-
-/*
- * 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.
- */
-
-import java.util.AbstractMap;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.stream.Collectors;
-
-import org.apache.commons.jcs.engine.control.group.GroupAttrName;
-import org.apache.commons.jcs.engine.stats.StatElement;
-import org.apache.commons.jcs.engine.stats.Stats;
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This is a simple LRUMap. It implements most of the map methods. It is not recommended that you
- * use any but put, get, remove, and clear.
- * <p>
- * Children can implement the processRemovedLRU method if they want to handle the removal of the
- * least recently used item.
- * <p>
- * This class was abstracted out of the LRU Memory cache. Put, remove, and get should be thread
- * safe. It uses a hashtable and our own double linked list.
- * <p>
- * Locking is done on the instance.
- * <p>
- * @author aaron smuts
- */
-public abstract class AbstractLRUMap<K, V>
- implements Map<K, V>
-{
- /** The logger */
- private static final Log log = LogManager.getLog( AbstractLRUMap.class );
-
- /** double linked list for lru */
- private final DoubleLinkedList<LRUElementDescriptor<K, V>> list;
-
- /** Map where items are stored by key. */
- private final Map<K, LRUElementDescriptor<K, V>> map;
-
- /** lock to keep map and list synchronous */
- private final Lock lock = new ReentrantLock();
-
- /** stats */
- private long hitCnt = 0;
-
- /** stats */
- private long missCnt = 0;
-
- /** stats */
- private long putCnt = 0;
-
- /**
- * This creates an unbounded version. Setting the max objects will result in spooling on
- * subsequent puts.
- */
- public AbstractLRUMap()
- {
- list = new DoubleLinkedList<>();
-
- // normal hashtable is faster for
- // sequential keys.
- map = new ConcurrentHashMap<>();
- }
-
-
- /**
- * This simply returns the number of elements in the map.
- * <p>
- * @see java.util.Map#size()
- */
- @Override
- public int size()
- {
- return map.size();
- }
-
- /**
- * This removes all the items. It clears the map and the double linked list.
- * <p>
- * @see java.util.Map#clear()
- */
- @Override
- public void clear()
- {
- lock.lock();
- try
- {
- map.clear();
- list.removeAll();
- }
- finally
- {
- lock.unlock();
- }
- }
-
- /**
- * Returns true if the map is empty.
- * <p>
- * @see java.util.Map#isEmpty()
- */
- @Override
- public boolean isEmpty()
- {
- return map.isEmpty();
- }
-
- /**
- * Returns true if the map contains an element for the supplied key.
- * <p>
- * @see java.util.Map#containsKey(java.lang.Object)
- */
- @Override
- public boolean containsKey( Object key )
- {
- return map.containsKey( key );
- }
-
- /**
- * This is an expensive operation that determines if the object supplied is mapped to any key.
- * <p>
- * @see java.util.Map#containsValue(java.lang.Object)
- */
- @Override
- public boolean containsValue( Object value )
- {
- return map.containsValue( value );
- }
-
- /**
- * @return map.values();
- */
- @Override
- public Collection<V> values()
- {
- return map.values().stream()
- .map(value -> value.getPayload())
- .collect(Collectors.toList());
- }
-
- /**
- * @param source
- */
- @Override
- public void putAll( Map<? extends K, ? extends V> source )
- {
- if ( source != null )
- {
- source.entrySet()
- .forEach(entry -> put(entry.getKey(), entry.getValue()));
- }
- }
-
- /**
- * @param key
- * @return Object
- */
- @Override
- public V get( Object key )
- {
- V retVal;
-
- log.debug( "getting item for key {0}", key );
-
- LRUElementDescriptor<K, V> me = map.get( key );
-
- if ( me == null )
- {
- missCnt++;
- retVal = null;
- }
- else
- {
- hitCnt++;
- retVal = me.getPayload();
- list.makeFirst( me );
- }
-
- if ( me == null )
- {
- log.debug( "LRUMap miss for {0}", key );
- }
- else
- {
- log.debug( "LRUMap hit for {0}", key );
- }
-
- // verifyCache();
- return retVal;
- }
-
- /**
- * This gets an element out of the map without adjusting it's position in the LRU. In other
- * words, this does not count as being used. If the element is the last item in the list, it
- * will still be the last time in the list.
- * <p>
- * @param key
- * @return Object
- */
- public V getQuiet( Object key )
- {
- V ce = null;
- LRUElementDescriptor<K, V> me = map.get( key );
-
- if ( me != null )
- {
- ce = me.getPayload();
- }
-
- if ( me == null )
- {
- log.debug( "LRUMap quiet miss for {0}", key );
- }
- else
- {
- log.debug( "LRUMap quiet hit for {0}", key );
- }
-
- return ce;
- }
-
- /**
- * @param key
- * @return Object removed
- */
- @Override
- public V remove( Object key )
- {
- log.debug( "removing item for key: {0}", key );
-
- // remove single item.
- lock.lock();
- try
- {
- LRUElementDescriptor<K, V> me = map.remove(key);
-
- if (me != null)
- {
- list.remove(me);
- return me.getPayload();
- }
- }
- finally
- {
- lock.unlock();
- }
-
- return null;
- }
-
- /**
- * @param key
- * @param value
- * @return Object
- */
- @Override
- public V put(K key, V value)
- {
- putCnt++;
-
- LRUElementDescriptor<K, V> old = null;
- LRUElementDescriptor<K, V> me = new LRUElementDescriptor<>(key, value);
-
- lock.lock();
- try
- {
- list.addFirst( me );
- old = map.put(key, me);
-
- // If the node was the same as an existing node, remove it.
- if ( old != null && key.equals(old.getKey()))
- {
- list.remove( old );
- }
- }
- finally
- {
- lock.unlock();
- }
-
- // If the element limit is reached, we need to spool
- if (shouldRemove())
- {
- log.debug( "In memory limit reached, removing least recently used." );
-
- // The spool will put them in a disk event queue, so there is no
- // need to pre-queue the queuing. This would be a bit wasteful
- // and wouldn't save much time in this synchronous call.
- while (shouldRemove())
- {
- lock.lock();
- try
- {
- LRUElementDescriptor<K, V> last = list.getLast();
- if (last != null)
- {
- processRemovedLRU(last.getKey(), last.getPayload());
- if (map.remove(last.getKey()) == null)
- {
- log.warn("update: remove failed for key: {0}",
- () -> last.getKey());
- verifyCache();
- }
- list.removeLast();
- }
- else
- {
- verifyCache();
- throw new Error("update: last is null!");
- }
- }
- finally
- {
- lock.unlock();
- }
- }
-
- log.debug( "update: After spool map size: {0}", () -> map.size() );
- if ( map.size() != list.size() )
- {
- log.error("update: After spool, size mismatch: map.size() = {0}, "
- + "linked list size = {1}",
- () -> map.size(), () -> list.size());
- }
- }
-
- if ( old != null )
- {
- return old.getPayload();
- }
- return null;
- }
-
- protected abstract boolean shouldRemove();
-
- /**
- * Dump the cache entries from first to list for debugging.
- */
- @SuppressWarnings("unchecked") // No generics for public fields
- public void dumpCacheEntries()
- {
- if (log.isTraceEnabled())
- {
- log.trace("dumpingCacheEntries");
- for (LRUElementDescriptor<K, V> me = list.getFirst(); me != null; me = (LRUElementDescriptor<K, V>) me.next)
- {
- log.trace("dumpCacheEntries> key={0}, val={1}", me.getKey(), me.getPayload());
- }
- }
- }
-
- /**
- * Dump the cache map for debugging.
- */
- public void dumpMap()
- {
- if (log.isTraceEnabled())
- {
- log.trace("dumpingMap");
- map.entrySet().forEach(e ->
- log.trace("dumpMap> key={0}, val={1}", e.getKey(), e.getValue().getPayload()));
- }
- }
-
- /**
- * Checks to see if all the items that should be in the cache are. Checks consistency between
- * List and map.
- */
- @SuppressWarnings("unchecked") // No generics for public fields
- protected void verifyCache()
- {
- if ( !log.isTraceEnabled() )
- {
- return;
- }
-
- log.trace( "verifycache: mapContains {0} elements, linked list "
- + "contains {1} elements", map.size(), list.size() );
- log.trace( "verifycache: checking linked list by key" );
- for (LRUElementDescriptor<K, V> li = list.getFirst(); li != null; li = (LRUElementDescriptor<K, V>) li.next )
- {
- K key = li.getKey();
- if ( !map.containsKey( key ) )
- {
- log.error( "verifycache: map does not contain key : {0}", li.getKey() );
- log.error( "li.hashcode={0}", li.getKey().hashCode() );
- log.error( "key class={0}", key.getClass() );
- log.error( "key hashcode={0}", key.hashCode() );
- log.error( "key toString={0}", key.toString() );
- if ( key instanceof GroupAttrName )
- {
- GroupAttrName<?> name = (GroupAttrName<?>) key;
- log.error( "GroupID hashcode={0}", name.groupId.hashCode() );
- log.error( "GroupID.class={0}", name.groupId.getClass() );
- log.error( "AttrName hashcode={0}", name.attrName.hashCode() );
- log.error( "AttrName.class={0}", name.attrName.getClass() );
- }
- dumpMap();
- }
- else if ( map.get( li.getKey() ) == null )
- {
- log.error( "verifycache: linked list retrieval returned null for key: {0}",
- li.getKey() );
- }
- }
-
- log.trace( "verifycache: checking linked list by value " );
- for (LRUElementDescriptor<K, V> li3 = list.getFirst(); li3 != null; li3 = (LRUElementDescriptor<K, V>) li3.next )
- {
- if ( map.containsValue( li3 ) == false )
- {
- log.error( "verifycache: map does not contain value : {0}", li3 );
- dumpMap();
- }
- }
-
- log.trace( "verifycache: checking via keysets!" );
- map.forEach((key, value) -> {
- boolean found = false;
-
- for (LRUElementDescriptor<K, V> li2 = list.getFirst(); li2 != null; li2 = (LRUElementDescriptor<K, V>) li2.next )
- {
- if ( key.equals( li2.getKey() ) )
- {
- found = true;
- break;
- }
- }
- if ( !found )
- {
- log.error( "verifycache: key not found in list : {0}", key );
- dumpCacheEntries();
- if ( map.containsKey( key ) )
- {
- log.error( "verifycache: map contains key" );
- }
- else
- {
- log.error( "verifycache: map does NOT contain key, what the HECK!" );
- }
- }
- });
- }
-
- /**
- * This is called when an item is removed from the LRU. We just log some information.
- * <p>
- * Children can implement this method for special behavior.
- * @param key
- * @param value
- */
- protected void processRemovedLRU(K key, V value )
- {
- log.debug( "Removing key: [{0}] from LRUMap store, value = [{1}]", key, value );
- log.debug( "LRUMap store size: \"{0}\".", this.size() );
- }
-
- /**
- * @return IStats
- */
- public IStats getStatistics()
- {
- IStats stats = new Stats();
- stats.setTypeName( "LRUMap" );
-
- ArrayList<IStatElement<?>> elems = new ArrayList<>();
-
- elems.add(new StatElement<>( "List Size", Integer.valueOf(list.size()) ) );
- elems.add(new StatElement<>( "Map Size", Integer.valueOf(map.size()) ) );
- elems.add(new StatElement<>( "Put Count", Long.valueOf(putCnt) ) );
- elems.add(new StatElement<>( "Hit Count", Long.valueOf(hitCnt) ) );
- elems.add(new StatElement<>( "Miss Count", Long.valueOf(missCnt) ) );
-
- stats.setStatElements( elems );
-
- return stats;
- }
-
- /**
- * This returns a set of entries. Our LRUMapEntry is used since the value stored in the
- * underlying map is a node in the double linked list. We wouldn't want to return this to the
- * client, so we construct a new entry with the payload of the node.
- * <p>
- * TODO we should return out own set wrapper, so we can avoid the extra object creation if it
- * isn't necessary.
- * <p>
- * @see java.util.Map#entrySet()
- */
- @Override
- public Set<Map.Entry<K, V>> entrySet()
- {
- lock.lock();
- try
- {
- return map.entrySet().stream()
- .map(entry -> new AbstractMap.SimpleEntry<K, V>(
- entry.getKey(), entry.getValue().getPayload()))
- .collect(Collectors.toSet());
- }
- finally
- {
- lock.unlock();
- }
- }
-
- /**
- * @return map.keySet();
- */
- @Override
- public Set<K> keySet()
- {
- return map.values().stream()
- .map(value -> value.getKey())
- .collect(Collectors.toSet());
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/DoubleLinkedList.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/DoubleLinkedList.java
deleted file mode 100644
index 0736c32..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/DoubleLinkedList.java
+++ /dev/null
@@ -1,291 +0,0 @@
-package org.apache.commons.jcs.utils.struct;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * This is a generic thread safe double linked list. It's very simple and all the operations are so
- * quick that course grained synchronization is more than acceptable.
- */
-@SuppressWarnings({ "unchecked", "rawtypes" }) // Don't know how to resolve this with generics
-public class DoubleLinkedList<T extends DoubleLinkedListNode>
-{
- /** record size to avoid having to iterate */
- private int size = 0;
-
- /** The logger */
- private static final Log log = LogManager.getLog( DoubleLinkedList.class );
-
- /** LRU double linked list head node */
- private T first;
-
- /** LRU double linked list tail node */
- private T last;
-
- /**
- * Default constructor.
- */
- public DoubleLinkedList()
- {
- super();
- }
-
- /**
- * Adds a new node to the end of the link list.
- * <p>
- * @param me The feature to be added to the Last
- */
- public synchronized void addLast(T me)
- {
- if ( first == null )
- {
- // empty list.
- first = me;
- }
- else
- {
- last.next = me;
- me.prev = last;
- }
- last = me;
- size++;
- }
-
- /**
- * Adds a new node to the start of the link list.
- * <p>
- * @param me The feature to be added to the First
- */
- public synchronized void addFirst(T me)
- {
- if ( last == null )
- {
- // empty list.
- last = me;
- }
- else
- {
- first.prev = me;
- me.next = first;
- }
- first = me;
- size++;
- }
-
- /**
- * Returns the last node from the link list, if there are any nodes.
- * <p>
- * @return The last node.
- */
- public synchronized T getLast()
- {
- log.debug( "returning last node" );
- return last;
- }
-
- /**
- * Removes the specified node from the link list.
- * <p>
- * @return DoubleLinkedListNode, the first node.
- */
- public synchronized T getFirst()
- {
- log.debug( "returning first node" );
- return first;
- }
-
- /**
- * Moves an existing node to the start of the link list.
- * <p>
- * @param ln The node to set as the head.
- */
- public synchronized void makeFirst(T ln)
- {
- if ( ln.prev == null )
- {
- // already the first node. or not a node
- return;
- }
- // splice: remove it from the list
- ln.prev.next = ln.next;
-
- if ( ln.next == null )
- {
- // last but not the first.
- last = (T) ln.prev;
- last.next = null;
- }
- else
- {
- // neither the last nor the first.
- ln.next.prev = ln.prev;
- }
- first.prev = ln;
- ln.next = first;
- ln.prev = null;
- first = ln;
- }
-
- /**
- * Moves an existing node to the end of the link list.
- * <p>
- * @param ln The node to set as the head.
- */
- public synchronized void makeLast(T ln)
- {
- if ( ln.next == null )
- {
- // already the last node. or not a node
- return;
- }
- // splice: remove it from the list
- if ( ln.prev != null )
- {
- ln.prev.next = ln.next;
- }
- else
- {
- // first
- first = last;
- }
-
- if ( last != null )
- {
- last.next = ln;
- }
- ln.prev = last;
- ln.next = null;
- last = ln;
- }
-
- /**
- * Remove all of the elements from the linked list implementation.
- */
- public synchronized void removeAll()
- {
- for (T me = first; me != null; )
- {
- if ( me.prev != null )
- {
- me.prev = null;
- }
- T next = (T) me.next;
- me = next;
- }
- first = last = null;
- // make sure this will work, could be add while this is happening.
- size = 0;
- }
-
- /**
- * Removes the specified node from the link list.
- * <p>
- * @param me Description of the Parameter
- * @return true if an element was removed.
- */
- public synchronized boolean remove(T me)
- {
- log.debug( "removing node" );
-
- if ( me.next == null )
- {
- if ( me.prev == null )
- {
- // Make sure it really is the only node before setting head and
- // tail to null. It is possible that we will be passed a node
- // which has already been removed from the list, in which case
- // we should ignore it
-
- if ( me == first && me == last )
- {
- first = last = null;
- }
- }
- else
- {
- // last but not the first.
- last = (T) me.prev;
- last.next = null;
- me.prev = null;
- }
- }
- else if ( me.prev == null )
- {
- // first but not the last.
- first = (T) me.next;
- first.prev = null;
- me.next = null;
- }
- else
- {
- // neither the first nor the last.
- me.prev.next = me.next;
- me.next.prev = me.prev;
- me.prev = me.next = null;
- }
- size--;
-
- return true;
- }
-
- /**
- * Removes the specified node from the link list.
- * <p>
- * @return The last node if there was one to remove.
- */
- public synchronized T removeLast()
- {
- log.debug( "removing last node" );
- T temp = last;
- if ( last != null )
- {
- remove( last );
- }
- return temp;
- }
-
- /**
- * Returns the size of the list.
- * <p>
- * @return int
- */
- public synchronized int size()
- {
- return size;
- }
-
- // ///////////////////////////////////////////////////////////////////
- /**
- * Dump the cache entries from first to list for debugging.
- */
- public synchronized void debugDumpEntries()
- {
- if ( log.isDebugEnabled() )
- {
- log.debug( "dumping Entries" );
- for (T me = first; me != null; me = (T) me.next)
- {
- log.debug( "dump Entries> payload= \"{0}\"", me.getPayload() );
- }
- }
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/DoubleLinkedListNode.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/DoubleLinkedListNode.java
deleted file mode 100644
index 26d080e..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/DoubleLinkedListNode.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.apache.commons.jcs.utils.struct;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-
-/**
- * This serves as a placeholder in a double linked list. You can extend this to
- * add functionality. This allows you to remove in constant time from a linked
- * list.
- * <p>
- * It simply holds the payload and a reference to the items before and after it
- * in the list.
- */
-public class DoubleLinkedListNode<T>
- implements Serializable
-{
- /** Dont' change. */
- private static final long serialVersionUID = -1114934407695836097L;
-
- /** The object in the node. */
- private final T payload;
-
- /** Double Linked list references */
- public DoubleLinkedListNode<T> prev;
-
- /** Double Linked list references */
- public DoubleLinkedListNode<T> next;
-
- /**
- * @param payloadP
- */
- public DoubleLinkedListNode(T payloadP)
- {
- payload = payloadP;
- }
-
- /**
- * @return Object
- */
- public T getPayload()
- {
- return payload;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUElementDescriptor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUElementDescriptor.java
deleted file mode 100644
index f728466..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUElementDescriptor.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.apache.commons.jcs.utils.struct;
-
-/*
- * 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.
- */
-
-/**
- * This is a node in the double linked list. It is stored as the value in the underlying map used by
- * the LRUMap class.
- */
-public class LRUElementDescriptor<K, V>
- extends DoubleLinkedListNode<V>
-{
- /** Don't change. */
- private static final long serialVersionUID = 8249555756363020156L;
-
- /** The key value */
- private K key;
-
- /**
- * @param key
- * @param payloadP
- */
- public LRUElementDescriptor(K key, V payloadP)
- {
- super(payloadP);
- this.setKey(key);
- }
-
- /**
- * @param key The key to set.
- */
- public void setKey(K key)
- {
- this.key = key;
- }
-
- /**
- * @return Returns the key.
- */
- public K getKey()
- {
- return key;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUMap.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUMap.java
deleted file mode 100644
index 84ff231..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUMap.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package org.apache.commons.jcs.utils.struct;
-
-/*
- * 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.
- */
-
-/**
- *
- * @author Wiktor Niesiobędzki
- *
- * Simple LRUMap implementation that keeps the number of the objects below or equal maxObjects
- *
- * @param <K>
- * @param <V>
- */
-public class LRUMap<K, V> extends AbstractLRUMap<K, V>
-{
- /** if the max is less than 0, there is no limit! */
- private int maxObjects = -1;
-
- public LRUMap()
- {
- super();
- }
-
- /**
- *
- * @param maxObjects
- * maximum number to keep in the map
- */
- public LRUMap(int maxObjects)
- {
- this();
- this.maxObjects = maxObjects;
- }
-
- @Override
- public boolean shouldRemove()
- {
- return maxObjects > 0 && this.size() > maxObjects;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/DaemonThreadFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/DaemonThreadFactory.java
deleted file mode 100644
index e1ec271..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/DaemonThreadFactory.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package org.apache.commons.jcs.utils.threadpool;
-
-/*
- * 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.
- */
-
-import java.util.concurrent.ThreadFactory;
-
-/**
- * Allows us to set the daemon status on the threads.
- * <p>
- * @author aaronsm
- */
-public class DaemonThreadFactory
- implements ThreadFactory
-{
- private String prefix;
- private boolean threadIsDaemon = true;
- private int threadPriority = Thread.NORM_PRIORITY;
-
- /**
- * Constructor
- *
- * @param prefix thread name prefix
- */
- public DaemonThreadFactory(String prefix)
- {
- this(prefix, Thread.NORM_PRIORITY);
- }
-
- /**
- * Constructor
- *
- * @param prefix thread name prefix
- * @param threadPriority set thread priority
- */
- public DaemonThreadFactory(String prefix, int threadPriority)
- {
- this.prefix = prefix;
- this.threadPriority = threadPriority;
- }
-
- /**
- * Sets the thread to daemon.
- * <p>
- * @param runner
- * @return a daemon thread
- */
- @Override
- public Thread newThread( Runnable runner )
- {
- Thread t = new Thread( runner );
- String oldName = t.getName();
- t.setName( prefix + oldName );
- t.setDaemon(threadIsDaemon);
- t.setPriority(threadPriority);
- return t;
- }
-}
\ No newline at end of file
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/PoolConfiguration.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/PoolConfiguration.java
deleted file mode 100644
index f4e886d..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/PoolConfiguration.java
+++ /dev/null
@@ -1,293 +0,0 @@
-package org.apache.commons.jcs.utils.threadpool;
-
-/*
- * 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.
- */
-
-/**
- * This object holds configuration data for a thread pool.
- * <p>
- * @author Aaron Smuts
- */
-public final class PoolConfiguration
- implements Cloneable
-{
- /**
- * DEFAULT SETTINGS
- */
- private static final boolean DEFAULT_USE_BOUNDARY = true;
-
- /** Default queue size limit */
- private static final int DEFAULT_BOUNDARY_SIZE = 2000;
-
- /** Default max size */
- private static final int DEFAULT_MAXIMUM_POOL_SIZE = 150;
-
- /** Default min */
- private static final int DEFAULT_MINIMUM_POOL_SIZE = Runtime.getRuntime().availableProcessors();
-
- /** Default keep alive */
- private static final int DEFAULT_KEEPALIVE_TIME = 1000 * 60 * 5;
-
- /** Default when blocked */
- private static final WhenBlockedPolicy DEFAULT_WHEN_BLOCKED_POLICY = WhenBlockedPolicy.RUN;
-
- /** Default startup size */
- private static final int DEFAULT_STARTUP_SIZE = DEFAULT_MINIMUM_POOL_SIZE;
-
- /** Should we bound the queue */
- private boolean useBoundary = DEFAULT_USE_BOUNDARY;
-
- /** If the queue is bounded, how big can it get */
- private int boundarySize = DEFAULT_BOUNDARY_SIZE;
-
- /** only has meaning if a boundary is used */
- private int maximumPoolSize = DEFAULT_MAXIMUM_POOL_SIZE;
-
- /**
- * the exact number that will be used in a boundless queue. If the queue has a boundary, more
- * will be created if the queue fills.
- */
- private int minimumPoolSize = DEFAULT_MINIMUM_POOL_SIZE;
-
- /** How long idle threads above the minimum should be kept alive. */
- private int keepAliveTime = DEFAULT_KEEPALIVE_TIME;
-
- public enum WhenBlockedPolicy {
- /** abort when queue is full and max threads is reached. */
- ABORT,
-
- /** block when queue is full and max threads is reached. */
- BLOCK,
-
- /** run in current thread when queue is full and max threads is reached. */
- RUN,
-
- /** wait when queue is full and max threads is reached. */
- WAIT,
-
- /** discard oldest when queue is full and max threads is reached. */
- DISCARDOLDEST
- }
-
- /** should be ABORT, BLOCK, RUN, WAIT, DISCARDOLDEST, */
- private WhenBlockedPolicy whenBlockedPolicy = DEFAULT_WHEN_BLOCKED_POLICY;
-
- /** The number of threads to create on startup */
- private int startUpSize = DEFAULT_MINIMUM_POOL_SIZE;
-
- /**
- * @param useBoundary The useBoundary to set.
- */
- public void setUseBoundary( boolean useBoundary )
- {
- this.useBoundary = useBoundary;
- }
-
- /**
- * @return Returns the useBoundary.
- */
- public boolean isUseBoundary()
- {
- return useBoundary;
- }
-
- /**
- * Default
- */
- public PoolConfiguration()
- {
- this( DEFAULT_USE_BOUNDARY, DEFAULT_BOUNDARY_SIZE, DEFAULT_MAXIMUM_POOL_SIZE,
- DEFAULT_MINIMUM_POOL_SIZE, DEFAULT_KEEPALIVE_TIME,
- DEFAULT_WHEN_BLOCKED_POLICY, DEFAULT_STARTUP_SIZE );
- }
-
- /**
- * Construct a completely configured instance.
- * <p>
- * @param useBoundary
- * @param boundarySize
- * @param maximumPoolSize
- * @param minimumPoolSize
- * @param keepAliveTime
- * @param whenBlockedPolicy
- * @param startUpSize
- */
- public PoolConfiguration( boolean useBoundary, int boundarySize, int maximumPoolSize, int minimumPoolSize,
- int keepAliveTime, WhenBlockedPolicy whenBlockedPolicy, int startUpSize )
- {
- setUseBoundary( useBoundary );
- setBoundarySize( boundarySize );
- setMaximumPoolSize( maximumPoolSize );
- setMinimumPoolSize( minimumPoolSize );
- setKeepAliveTime( keepAliveTime );
- setWhenBlockedPolicy( whenBlockedPolicy );
- setStartUpSize( startUpSize );
- }
-
- /**
- * @param boundarySize The boundarySize to set.
- */
- public void setBoundarySize( int boundarySize )
- {
- this.boundarySize = boundarySize;
- }
-
- /**
- * @return Returns the boundarySize.
- */
- public int getBoundarySize()
- {
- return boundarySize;
- }
-
- /**
- * @param maximumPoolSize The maximumPoolSize to set.
- */
- public void setMaximumPoolSize( int maximumPoolSize )
- {
- this.maximumPoolSize = maximumPoolSize;
- }
-
- /**
- * @return Returns the maximumPoolSize.
- */
- public int getMaximumPoolSize()
- {
- return maximumPoolSize;
- }
-
- /**
- * @param minimumPoolSize The minimumPoolSize to set.
- */
- public void setMinimumPoolSize( int minimumPoolSize )
- {
- this.minimumPoolSize = minimumPoolSize;
- }
-
- /**
- * @return Returns the minimumPoolSize.
- */
- public int getMinimumPoolSize()
- {
- return minimumPoolSize;
- }
-
- /**
- * @param keepAliveTime The keepAliveTime to set.
- */
- public void setKeepAliveTime( int keepAliveTime )
- {
- this.keepAliveTime = keepAliveTime;
- }
-
- /**
- * @return Returns the keepAliveTime.
- */
- public int getKeepAliveTime()
- {
- return keepAliveTime;
- }
-
- /**
- * @param whenBlockedPolicy The whenBlockedPolicy to set.
- */
- public void setWhenBlockedPolicy( String whenBlockedPolicy )
- {
- if ( whenBlockedPolicy != null )
- {
- WhenBlockedPolicy policy = WhenBlockedPolicy.valueOf(whenBlockedPolicy.trim().toUpperCase());
- setWhenBlockedPolicy(policy);
- }
- else
- {
- // the value is null, default to RUN
- this.whenBlockedPolicy = WhenBlockedPolicy.RUN;
- }
- }
-
- /**
- * @param whenBlockedPolicy The whenBlockedPolicy to set.
- */
- public void setWhenBlockedPolicy( WhenBlockedPolicy whenBlockedPolicy )
- {
- if ( whenBlockedPolicy != null )
- {
- this.whenBlockedPolicy = whenBlockedPolicy;
- }
- else
- {
- // the value is null, default to RUN
- this.whenBlockedPolicy = WhenBlockedPolicy.RUN;
- }
- }
-
- /**
- * @return Returns the whenBlockedPolicy.
- */
- public WhenBlockedPolicy getWhenBlockedPolicy()
- {
- return whenBlockedPolicy;
- }
-
- /**
- * @param startUpSize The startUpSize to set.
- */
- public void setStartUpSize( int startUpSize )
- {
- this.startUpSize = startUpSize;
- }
-
- /**
- * @return Returns the startUpSize.
- */
- public int getStartUpSize()
- {
- return startUpSize;
- }
-
- /**
- * To string for debugging purposes.
- * @return String
- */
- @Override
- public String toString()
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "useBoundary = [" + isUseBoundary() + "] " );
- buf.append( "boundarySize = [" + boundarySize + "] " );
- buf.append( "maximumPoolSize = [" + maximumPoolSize + "] " );
- buf.append( "minimumPoolSize = [" + minimumPoolSize + "] " );
- buf.append( "keepAliveTime = [" + keepAliveTime + "] " );
- buf.append( "whenBlockedPolicy = [" + getWhenBlockedPolicy() + "] " );
- buf.append( "startUpSize = [" + startUpSize + "]" );
- return buf.toString();
- }
-
- /**
- * Copies the instance variables to another instance.
- * <p>
- * @return PoolConfiguration
- */
- @Override
- public PoolConfiguration clone()
- {
- return new PoolConfiguration( isUseBoundary(), boundarySize, maximumPoolSize, minimumPoolSize, keepAliveTime,
- getWhenBlockedPolicy(), startUpSize );
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManager.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManager.java
deleted file mode 100644
index 3c143be..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManager.java
+++ /dev/null
@@ -1,338 +0,0 @@
-package org.apache.commons.jcs.utils.threadpool;
-
-/*
- * 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.
- */
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-import org.apache.commons.jcs.utils.config.PropertySetter;
-
-/**
- * This manages threadpools for an application
- * <p>
- * It is a singleton since threads need to be managed vm wide.
- * <p>
- * This manager forces you to use a bounded queue. By default it uses the current thread for
- * execution when the buffer is full and no free threads can be created.
- * <p>
- * You can specify the props file to use or pass in a properties object prior to configuration.
- * <p>
- * If set, the Properties object will take precedence.
- * <p>
- * If a value is not set for a particular pool, the hard coded defaults in <code>PoolConfiguration</code> will be used.
- * You can configure default settings by specifying <code>thread_pool.default</code> in the properties, ie "cache.ccf"
- * <p>
- * @author Aaron Smuts
- */
-public class ThreadPoolManager
-{
- /** The logger */
- private static final Log log = LogManager.getLog( ThreadPoolManager.class );
-
- /** The default config, created using property defaults if present, else those above. */
- private PoolConfiguration defaultConfig;
-
- /** The default scheduler config, created using property defaults if present, else those above. */
- private PoolConfiguration defaultSchedulerConfig;
-
- /** the root property name */
- private static final String PROP_NAME_ROOT = "thread_pool";
-
- /** default property file name */
- private static final String DEFAULT_PROP_NAME_ROOT = "thread_pool.default";
-
- /** the scheduler root property name */
- private static final String PROP_NAME_SCHEDULER_ROOT = "scheduler_pool";
-
- /** default scheduler property file name */
- private static final String DEFAULT_PROP_NAME_SCHEDULER_ROOT = "scheduler_pool.default";
-
- /**
- * You can specify the properties to be used to configure the thread pool. Setting this post
- * initialization will have no effect.
- */
- private static volatile Properties props = null;
-
- /** Map of names to pools. */
- private ConcurrentHashMap<String, ExecutorService> pools;
-
- /** Map of names to scheduler pools. */
- private ConcurrentHashMap<String, ScheduledExecutorService> schedulerPools;
-
- /**
- * The ThreadPoolManager instance (holder pattern)
- */
- private static class ThreadPoolManagerHolder
- {
- static final ThreadPoolManager INSTANCE = new ThreadPoolManager();
- }
-
- /**
- * No instances please. This is a singleton.
- */
- private ThreadPoolManager()
- {
- this.pools = new ConcurrentHashMap<>();
- this.schedulerPools = new ConcurrentHashMap<>();
- configure();
- }
-
- /**
- * Creates a pool based on the configuration info.
- * <p>
- * @param config the pool configuration
- * @param threadNamePrefix prefix for the thread names of the pool
- * @return A ThreadPool wrapper
- */
- public ExecutorService createPool( PoolConfiguration config, String threadNamePrefix)
- {
- return createPool(config, threadNamePrefix, Thread.NORM_PRIORITY);
- }
-
- /**
- * Creates a pool based on the configuration info.
- * <p>
- * @param config the pool configuration
- * @param threadNamePrefix prefix for the thread names of the pool
- * @param threadPriority the priority of the created threads
- * @return A ThreadPool wrapper
- */
- public ExecutorService createPool( PoolConfiguration config, String threadNamePrefix, int threadPriority )
- {
- BlockingQueue<Runnable> queue = null;
- if ( config.isUseBoundary() )
- {
- log.debug( "Creating a Bounded Buffer to use for the pool" );
- queue = new LinkedBlockingQueue<>(config.getBoundarySize());
- }
- else
- {
- log.debug( "Creating a non bounded Linked Queue to use for the pool" );
- queue = new LinkedBlockingQueue<>();
- }
-
- ThreadPoolExecutor pool = new ThreadPoolExecutor(
- config.getStartUpSize(),
- config.getMaximumPoolSize(),
- config.getKeepAliveTime(),
- TimeUnit.MILLISECONDS,
- queue,
- new DaemonThreadFactory(threadNamePrefix, threadPriority));
-
- // when blocked policy
- switch (config.getWhenBlockedPolicy())
- {
- case ABORT:
- pool.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
- break;
-
- case RUN:
- pool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
- break;
-
- case WAIT:
- throw new RuntimeException("POLICY_WAIT no longer supported");
-
- case DISCARDOLDEST:
- pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
- break;
-
- default:
- break;
- }
-
- pool.prestartAllCoreThreads();
-
- return pool;
- }
-
- /**
- * Creates a scheduler pool based on the configuration info.
- * <p>
- * @param config the pool configuration
- * @param threadNamePrefix prefix for the thread names of the pool
- * @param threadPriority the priority of the created threads
- * @return A ScheduledExecutorService
- */
- public ScheduledExecutorService createSchedulerPool( PoolConfiguration config, String threadNamePrefix, int threadPriority )
- {
- ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(
- config.getMaximumPoolSize(),
- new DaemonThreadFactory(threadNamePrefix, threadPriority));
-
- return scheduler;
- }
-
- /**
- * Returns a configured instance of the ThreadPoolManger To specify a configuration file or
- * Properties object to use call the appropriate setter prior to calling getInstance.
- * <p>
- * @return The single instance of the ThreadPoolManager
- */
- public static ThreadPoolManager getInstance()
- {
- return ThreadPoolManagerHolder.INSTANCE;
- }
-
- /**
- * Dispose of the instance of the ThreadPoolManger and shut down all thread pools
- */
- public static void dispose()
- {
- for ( Iterator<Map.Entry<String, ExecutorService>> i =
- getInstance().pools.entrySet().iterator(); i.hasNext(); )
- {
- Map.Entry<String, ExecutorService> entry = i.next();
- try
- {
- entry.getValue().shutdownNow();
- }
- catch (Throwable t)
- {
- log.warn("Failed to close pool {0}", entry.getKey(), t);
- }
- i.remove();
- }
-
- for ( Iterator<Map.Entry<String, ScheduledExecutorService>> i =
- getInstance().schedulerPools.entrySet().iterator(); i.hasNext(); )
- {
- Map.Entry<String, ScheduledExecutorService> entry = i.next();
- try
- {
- entry.getValue().shutdownNow();
- }
- catch (Throwable t)
- {
- log.warn("Failed to close pool {0}", entry.getKey(), t);
- }
- i.remove();
- }
- }
-
- /**
- * Returns an executor service by name. If a service by this name does not exist in the configuration file or
- * properties, one will be created using the default values.
- * <p>
- * Services are lazily created.
- * <p>
- * @param name
- * @return The executor service configured for the name.
- */
- public ExecutorService getExecutorService( String name )
- {
- ExecutorService pool = pools.computeIfAbsent(name, key -> {
- log.debug( "Creating pool for name [{0}]", key );
- PoolConfiguration config = loadConfig( PROP_NAME_ROOT + "." + key, defaultConfig );
- return createPool( config, "JCS-ThreadPoolManager-" + key + "-" );
- });
-
- return pool;
- }
-
- /**
- * Returns a scheduler pool by name. If a pool by this name does not exist in the configuration file or
- * properties, one will be created using the default values.
- * <p>
- * Pools are lazily created.
- * <p>
- * @param name
- * @return The scheduler pool configured for the name.
- */
- public ScheduledExecutorService getSchedulerPool( String name )
- {
- ScheduledExecutorService pool = schedulerPools.computeIfAbsent(name, key -> {
- log.debug( "Creating scheduler pool for name [{0}]", key );
- PoolConfiguration config = loadConfig( PROP_NAME_SCHEDULER_ROOT + "." + key,
- defaultSchedulerConfig );
- return createSchedulerPool( config, "JCS-ThreadPoolManager-" + key + "-", Thread.NORM_PRIORITY );
- });
-
- return pool;
- }
-
- /**
- * Returns the names of all configured pools.
- * <p>
- * @return ArrayList of string names
- */
- protected Set<String> getPoolNames()
- {
- return pools.keySet();
- }
-
- /**
- * This will be used if it is not null on initialization. Setting this post initialization will
- * have no effect.
- * <p>
- * @param props The props to set.
- */
- public static void setProps( Properties props )
- {
- ThreadPoolManager.props = props;
- }
-
- /**
- * Initialize the ThreadPoolManager and create all the pools defined in the configuration.
- */
- private void configure()
- {
- log.debug( "Initializing ThreadPoolManager" );
-
- if ( props == null )
- {
- log.warn( "No configuration settings found. Using hardcoded default values for all pools." );
- props = new Properties();
- }
-
- // set initial default and then override if new settings are available
- defaultConfig = loadConfig( DEFAULT_PROP_NAME_ROOT, new PoolConfiguration() );
- defaultSchedulerConfig = loadConfig( DEFAULT_PROP_NAME_SCHEDULER_ROOT, new PoolConfiguration() );
- }
-
- /**
- * Configures the PoolConfiguration settings.
- * <p>
- * @param root the configuration key prefix
- * @param defaultPoolConfiguration the default configuration
- * @return PoolConfiguration
- */
- private PoolConfiguration loadConfig( String root, PoolConfiguration defaultPoolConfiguration )
- {
- PoolConfiguration config = defaultPoolConfiguration.clone();
- PropertySetter.setProperties( config, props, root + "." );
-
- log.debug( "{0} PoolConfiguration = {1}", root, config );
-
- return config;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/timing/ElapsedTimer.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/timing/ElapsedTimer.java
deleted file mode 100644
index bd728e9..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/timing/ElapsedTimer.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package org.apache.commons.jcs.utils.timing;
-
-/*
- * 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.
- */
-
-/**
- * This is a simple timer utility.
- */
-public class ElapsedTimer
-{
- /** display suffix describing the unit of measure. */
- private static final String SUFFIX = "ms.";
-
- /**
- * Sets the start time when created.
- */
- private long timeStamp = System.currentTimeMillis();
-
- /**
- * Gets the time elapsed between the start time and now. The start time is reset to now.
- * Subsequent calls will get the time between then and now.
- * <p>
- * @return the elapsed time
- */
- public long getElapsedTime()
- {
- long now = System.currentTimeMillis();
- long elapsed = now - timeStamp;
- timeStamp = now;
- return elapsed;
- }
-
- /**
- * Returns the elapsed time with the display suffix.
- * <p>
- * @return formatted elapsed Time
- */
- public String getElapsedTimeString()
- {
- return String.valueOf( getElapsedTime() ) + SUFFIX;
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/zip/CompressionUtil.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/zip/CompressionUtil.java
deleted file mode 100644
index 5ef5954..0000000
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/zip/CompressionUtil.java
+++ /dev/null
@@ -1,203 +0,0 @@
-package org.apache.commons.jcs.utils.zip;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.zip.DataFormatException;
-import java.util.zip.Deflater;
-import java.util.zip.GZIPInputStream;
-import java.util.zip.Inflater;
-
-/** Compress / Decompress. */
-public final class CompressionUtil
-{
- /** The logger */
- private static final Log log = LogManager.getLog( CompressionUtil.class );
-
- /**
- * no instances.
- */
- private CompressionUtil()
- {
- // NO OP
- }
-
- /**
- * Decompress the byte array passed using a default buffer length of 1024.
- * <p>
- * @param input compressed byte array webservice response
- * @return uncompressed byte array
- */
- public static byte[] decompressByteArray( final byte[] input )
- {
- return decompressByteArray( input, 1024 );
- }
-
- /**
- * Decompress the byte array passed
- * <p>
- * @param input compressed byte array webservice response
- * @param bufferLength buffer length
- * @return uncompressed byte array
- */
- public static byte[] decompressByteArray( final byte[] input, final int bufferLength )
- {
- if ( null == input )
- {
- throw new IllegalArgumentException( "Input was null" );
- }
-
- // Create the decompressor and give it the data to compress
- final Inflater decompressor = new Inflater();
-
- decompressor.setInput( input );
-
- // Create an expandable byte array to hold the decompressed data
- final ByteArrayOutputStream baos = new ByteArrayOutputStream( input.length );
-
- // Decompress the data
- final byte[] buf = new byte[bufferLength];
-
- try
- {
- while ( !decompressor.finished() )
- {
- int count = decompressor.inflate( buf );
- baos.write( buf, 0, count );
- }
- }
- catch ( DataFormatException ex )
- {
- log.error( "Problem decompressing.", ex );
- }
-
- decompressor.end();
-
- try
- {
- baos.close();
- }
- catch ( IOException ex )
- {
- log.error( "Problem closing stream.", ex );
- }
-
- return baos.toByteArray();
- }
-
- /**
- * Compress the byte array passed
- * <p>
- * @param input byte array
- * @return compressed byte array
- * @throws IOException thrown if we can't close the output stream
- */
- public static byte[] compressByteArray( byte[] input )
- throws IOException
- {
- return compressByteArray( input, 1024 );
- }
-
- /**
- * Compress the byte array passed
- * <p>
- * @param input byte array
- * @param bufferLength buffer length
- * @return compressed byte array
- * @throws IOException thrown if we can't close the output stream
- */
- public static byte[] compressByteArray( byte[] input, int bufferLength )
- throws IOException
- {
- // Compressor with highest level of compression
- Deflater compressor = new Deflater();
- compressor.setLevel( Deflater.BEST_COMPRESSION );
-
- // Give the compressor the data to compress
- compressor.setInput( input );
- compressor.finish();
-
- // Create an expandable byte array to hold the compressed data.
- // It is not necessary that the compressed data will be smaller than
- // the uncompressed data.
- ByteArrayOutputStream bos = new ByteArrayOutputStream( input.length );
-
- // Compress the data
- byte[] buf = new byte[bufferLength];
- while ( !compressor.finished() )
- {
- int count = compressor.deflate( buf );
- bos.write( buf, 0, count );
- }
-
- // JCS-136 ( Details here : http://www.devguli.com/blog/eng/java-deflater-and-outofmemoryerror/ )
- compressor.end();
- bos.close();
-
- // Get the compressed data
- return bos.toByteArray();
-
- }
-
- /**
- * decompress a gzip byte array, using a default buffer length of 1024
- * <p>
- * @param compressedByteArray gzip-compressed byte array
- * @return decompressed byte array
- * @throws IOException thrown if there was a failure to construct the GzipInputStream
- */
- public static byte[] decompressGzipByteArray( byte[] compressedByteArray )
- throws IOException
- {
- return decompressGzipByteArray( compressedByteArray, 1024 );
- }
-
- /**
- * decompress a gzip byte array, using a default buffer length of 1024
- * <p>
- * @param compressedByteArray gzip-compressed byte array
- * @param bufferlength size of the buffer in bytes
- * @return decompressed byte array
- * @throws IOException thrown if there was a failure to construct the GzipInputStream
- */
- public static byte[] decompressGzipByteArray( byte[] compressedByteArray, int bufferlength )
- throws IOException
- {
- ByteArrayOutputStream uncompressedStream = new ByteArrayOutputStream();
-
- GZIPInputStream compressedStream = new GZIPInputStream( new ByteArrayInputStream( compressedByteArray ) );
-
- byte[] buffer = new byte[bufferlength];
-
- int index = -1;
-
- while ( ( index = compressedStream.read( buffer ) ) != -1 )
- {
- uncompressedStream.write( buffer, 0, index );
- }
-
- return uncompressedStream.toByteArray();
- }
-}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/JCS.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/JCS.java
new file mode 100644
index 0000000..e0dd191
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/JCS.java
@@ -0,0 +1,210 @@
+package org.apache.commons.jcs3;
+
+/*
+ * 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.
+ */
+
+import java.util.Properties;
+
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.access.GroupCacheAccess;
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+import org.apache.commons.jcs3.engine.control.group.GroupAttrName;
+
+/**
+ * Simple class for using JCS. To use JCS in your application, you can use the static methods of
+ * this class to get access objects (instances of this class) for your cache regions. One CacheAccess
+ * object should be created for each region you want to access. If you have several regions, then
+ * get instances for each. For best performance the getInstance call should be made in an
+ * initialization method.
+ */
+public abstract class JCS
+{
+ /** cache.ccf alternative. */
+ private static String configFilename = null;
+
+ /** alternative configuration properties */
+ private static Properties configProps = null;
+
+ /** Cache manager use by the various forms of defineRegion and getAccess */
+ private static CompositeCacheManager cacheMgr;
+
+ /**
+ * Set the filename that the cache manager will be initialized with. Only matters before the
+ * instance is initialized.
+ * <p>
+ * @param configFilename
+ */
+ public static void setConfigFilename( String configFilename )
+ {
+ JCS.configFilename = configFilename;
+ }
+
+ /**
+ * Set the properties that the cache manager will be initialized with. Only
+ * matters before the instance is initialized.
+ *
+ * @param configProps
+ */
+ public static void setConfigProperties( Properties configProps )
+ {
+ JCS.configProps = configProps;
+ }
+
+ /**
+ * Shut down the cache manager and set the instance to null
+ */
+ public static void shutdown()
+ {
+ synchronized ( JCS.class )
+ {
+ if ( cacheMgr != null && cacheMgr.isInitialized())
+ {
+ cacheMgr.shutDown();
+ }
+
+ cacheMgr = null;
+ }
+ }
+
+ /**
+ * Helper method which checks to make sure the cacheMgr class field is set, and if not requests
+ * an instance from CacheManagerFactory.
+ *
+ * @throws CacheException if the configuration cannot be loaded
+ */
+ private static CompositeCacheManager getCacheManager() throws CacheException
+ {
+ synchronized ( JCS.class )
+ {
+ if ( cacheMgr == null || !cacheMgr.isInitialized())
+ {
+ if ( configProps != null )
+ {
+ cacheMgr = CompositeCacheManager.getUnconfiguredInstance();
+ cacheMgr.configure( configProps );
+ }
+ else if ( configFilename != null )
+ {
+ cacheMgr = CompositeCacheManager.getUnconfiguredInstance();
+ cacheMgr.configure( configFilename );
+ }
+ else
+ {
+ cacheMgr = CompositeCacheManager.getInstance();
+ }
+ }
+
+ return cacheMgr;
+ }
+ }
+
+ /**
+ * Get a CacheAccess which accesses the provided region.
+ * <p>
+ * @param region Region that return CacheAccess will provide access to
+ * @return A CacheAccess which provides access to a given region.
+ * @throws CacheException
+ */
+ public static <K, V> CacheAccess<K, V> getInstance( String region )
+ throws CacheException
+ {
+ CompositeCache<K, V> cache = getCacheManager().getCache( region );
+ return new CacheAccess<>( cache );
+ }
+
+ /**
+ * Get a CacheAccess which accesses the provided region.
+ * <p>
+ * @param region Region that return CacheAccess will provide access to
+ * @param icca CacheAttributes for region
+ * @return A CacheAccess which provides access to a given region.
+ * @throws CacheException
+ */
+ public static <K, V> CacheAccess<K, V> getInstance( String region, ICompositeCacheAttributes icca )
+ throws CacheException
+ {
+ CompositeCache<K, V> cache = getCacheManager().getCache( region, icca );
+ return new CacheAccess<>( cache );
+ }
+
+ /**
+ * Get a CacheAccess which accesses the provided region.
+ * <p>
+ * @param region Region that return CacheAccess will provide access to
+ * @param icca CacheAttributes for region
+ * @param eattr ElementAttributes for the region
+ * @return A CacheAccess which provides access to a given region.
+ * @throws CacheException
+ */
+ public static <K, V> CacheAccess<K, V> getInstance( String region, ICompositeCacheAttributes icca, IElementAttributes eattr )
+ throws CacheException
+ {
+ CompositeCache<K, V> cache = getCacheManager().getCache( region, icca, eattr );
+ return new CacheAccess<>( cache );
+ }
+
+ /**
+ * Get a GroupCacheAccess which accesses the provided region.
+ * <p>
+ * @param region Region that return GroupCacheAccess will provide access to
+ * @return A GroupCacheAccess which provides access to a given region.
+ * @throws CacheException
+ */
+ public static <K, V> GroupCacheAccess<K, V> getGroupCacheInstance( String region )
+ throws CacheException
+ {
+ CompositeCache<GroupAttrName<K>, V> cache = getCacheManager().getCache( region );
+ return new GroupCacheAccess<>( cache );
+ }
+
+ /**
+ * Get a GroupCacheAccess which accesses the provided region.
+ * <p>
+ * @param region Region that return GroupCacheAccess will provide access to
+ * @param icca CacheAttributes for region
+ * @return A GroupCacheAccess which provides access to a given region.
+ * @throws CacheException
+ */
+ public static <K, V> GroupCacheAccess<K, V> getGroupCacheInstance( String region, ICompositeCacheAttributes icca )
+ throws CacheException
+ {
+ CompositeCache<GroupAttrName<K>, V> cache = getCacheManager().getCache( region, icca );
+ return new GroupCacheAccess<>( cache );
+ }
+
+ /**
+ * Get a GroupCacheAccess which accesses the provided region.
+ * <p>
+ * @param region Region that return CacheAccess will provide access to
+ * @param icca CacheAttributes for region
+ * @param eattr ElementAttributes for the region
+ * @return A GroupCacheAccess which provides access to a given region.
+ * @throws CacheException
+ */
+ public static <K, V> GroupCacheAccess<K, V> getGroupCacheInstance( String region, ICompositeCacheAttributes icca, IElementAttributes eattr )
+ throws CacheException
+ {
+ CompositeCache<GroupAttrName<K>, V> cache = getCacheManager().getCache( region, icca, eattr );
+ return new GroupCacheAccess<>( cache );
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/AbstractCacheAccess.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/AbstractCacheAccess.java
new file mode 100644
index 0000000..2c28555
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/AbstractCacheAccess.java
@@ -0,0 +1,203 @@
+package org.apache.commons.jcs3.access;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.access.behavior.ICacheAccessManagement;
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.stats.behavior.ICacheStats;
+
+/**
+ * This class provides the common methods for all types of access to the cache.
+ * <p>
+ * An instance of this class is tied to a specific cache region. Static methods are provided to get
+ * such instances.
+ * <p>
+ * Using this class you can retrieve an item, the item's wrapper, and the element's configuration. You can also put an
+ * item in the cache, remove an item, and clear a region.
+ * <p>
+ * The JCS class is the preferred way to access these methods.
+ */
+public abstract class AbstractCacheAccess<K, V>
+ implements ICacheAccessManagement
+{
+ /**
+ * The cache that a given instance of this class provides access to.
+ * <p>
+ * TODO Should this be the interface?
+ */
+ private final CompositeCache<K, V> cacheControl;
+
+ /**
+ * Constructor for the CacheAccess object.
+ * <p>
+ * @param cacheControl The cache which the created instance accesses
+ */
+ protected AbstractCacheAccess( CompositeCache<K, V> cacheControl )
+ {
+ this.cacheControl = cacheControl;
+ }
+
+ /**
+ * Removes all of the elements from a region.
+ * <p>
+ * @throws CacheException
+ */
+ @Override
+ public void clear()
+ throws CacheException
+ {
+ try
+ {
+ this.getCacheControl().removeAll();
+ }
+ catch ( IOException e )
+ {
+ throw new CacheException( e );
+ }
+ }
+
+ /**
+ * This method is does not reset the attributes for items already in the cache. It could
+ * potentially do this for items in memory, and maybe on disk (which would be slow) but not
+ * remote items. Rather than have unpredictable behavior, this method just sets the default
+ * attributes. Items subsequently put into the cache will use these defaults if they do not
+ * specify specific attributes.
+ * <p>
+ * @param attr the default attributes.
+ * @throws CacheException if something goes wrong.
+ */
+ @Override
+ public void setDefaultElementAttributes( IElementAttributes attr )
+ throws CacheException
+ {
+ this.getCacheControl().setElementAttributes( attr );
+ }
+
+ /**
+ * Retrieves A COPY OF the default element attributes used by this region. This does not provide
+ * a reference to the element attributes.
+ * <p>
+ * Each time an element is added to the cache without element attributes, the default element
+ * attributes are cloned.
+ * <p>
+ * @return the default element attributes used by this region.
+ * @throws CacheException
+ */
+ @Override
+ public IElementAttributes getDefaultElementAttributes()
+ throws CacheException
+ {
+ return this.getCacheControl().getElementAttributes();
+ }
+
+ /**
+ * This returns the ICacheStats object with information on this region and its auxiliaries.
+ * <p>
+ * This data can be formatted as needed.
+ * <p>
+ * @return ICacheStats
+ */
+ @Override
+ public ICacheStats getStatistics()
+ {
+ return this.getCacheControl().getStatistics();
+ }
+
+ /**
+ * @return A String version of the stats.
+ */
+ @Override
+ public String getStats()
+ {
+ return this.getCacheControl().getStats();
+ }
+
+ /**
+ * Dispose this region. Flushes objects to and closes auxiliary caches. This is a shutdown
+ * command!
+ * <p>
+ * To simply remove all elements from the region use clear().
+ */
+ @Override
+ public void dispose()
+ {
+ this.getCacheControl().dispose();
+ }
+
+ /**
+ * Gets the ICompositeCacheAttributes of the cache region.
+ * <p>
+ * @return ICompositeCacheAttributes, the controllers config info, defined in the top section of
+ * a region definition.
+ */
+ @Override
+ public ICompositeCacheAttributes getCacheAttributes()
+ {
+ return this.getCacheControl().getCacheAttributes();
+ }
+
+ /**
+ * Sets the ICompositeCacheAttributes of the cache region.
+ * <p>
+ * @param cattr The new ICompositeCacheAttribute value
+ */
+ @Override
+ public void setCacheAttributes( ICompositeCacheAttributes cattr )
+ {
+ this.getCacheControl().setCacheAttributes( cattr );
+ }
+
+ /**
+ * This instructs the memory cache to remove the <i>numberToFree</i> according to its eviction
+ * policy. For example, the LRUMemoryCache will remove the <i>numberToFree</i> least recently
+ * used items. These will be spooled to disk if a disk auxiliary is available.
+ * <p>
+ * @param numberToFree
+ * @return the number that were removed. if you ask to free 5, but there are only 3, you will
+ * get 3.
+ * @throws CacheException
+ */
+ @Override
+ public int freeMemoryElements( int numberToFree )
+ throws CacheException
+ {
+ int numFreed = -1;
+ try
+ {
+ numFreed = this.getCacheControl().getMemoryCache().freeElements( numberToFree );
+ }
+ catch ( IOException ioe )
+ {
+ String message = "Failure freeing memory elements.";
+ throw new CacheException( message, ioe );
+ }
+ return numFreed;
+ }
+
+ public CompositeCache<K, V> getCacheControl() {
+ return cacheControl;
+ }
+
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/CacheAccess.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/CacheAccess.java
new file mode 100644
index 0000000..7bf290c
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/CacheAccess.java
@@ -0,0 +1,332 @@
+package org.apache.commons.jcs3.access;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import org.apache.commons.jcs3.access.behavior.ICacheAccess;
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.access.exception.InvalidArgumentException;
+import org.apache.commons.jcs3.access.exception.InvalidHandleException;
+import org.apache.commons.jcs3.access.exception.ObjectExistsException;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+
+/**
+ * This class provides an interface for all types of access to the cache.
+ * <p>
+ * An instance of this class is tied to a specific cache region. Static methods are provided to get
+ * such instances.
+ * <p>
+ * Using this class you can retrieve an item, the item's wrapper, and the element's configuration. You can also put an
+ * item in the cache, remove an item, and clear a region.
+ * <p>
+ * The JCS class is the preferred way to access these methods.
+ */
+public class CacheAccess<K, V>
+ extends AbstractCacheAccess<K, V>
+ implements ICacheAccess<K, V>
+{
+ /**
+ * Constructor for the CacheAccess object.
+ * <p>
+ * @param cacheControl The cache which the created instance accesses
+ */
+ public CacheAccess( CompositeCache<K, V> cacheControl )
+ {
+ super(cacheControl);
+ }
+
+ /**
+ * Retrieve an object from the cache region this instance provides access to.
+ * <p>
+ * @param name Key the object is stored as
+ * @return The object if found or null
+ */
+ @Override
+ public V get( K name )
+ {
+ ICacheElement<K, V> element = this.getCacheControl().get( name );
+
+ return ( element != null ) ? element.getVal() : null;
+ }
+
+ /**
+ * Retrieve an object from the cache region this instance provides access to.
+ * If the object cannot be found in the cache, it will be retrieved by
+ * calling the supplier and subsequently storing it in the cache.
+ * <p>
+ * @param name
+ * @param supplier supplier to be called if the value is not found
+ * @return Object.
+ */
+ @Override
+ public V get(K name, Supplier<V> supplier)
+ {
+ V value = get(name);
+
+ if (value == null)
+ {
+ value = supplier.get();
+ put(name, value);
+ }
+
+ return value;
+ }
+
+ /**
+ * Retrieve matching objects from the cache region this instance provides access to.
+ * <p>
+ * @param pattern - a key pattern for the objects stored
+ * @return A map of key to values. These are stripped from the wrapper.
+ */
+ @Override
+ public Map<K, V> getMatching( String pattern )
+ {
+ Map<K, V> unwrappedResults;
+
+ Map<K, ICacheElement<K, V>> wrappedResults = this.getCacheControl().getMatching( pattern );
+
+ if ( wrappedResults == null )
+ {
+ unwrappedResults = new HashMap<>();
+ }
+ else
+ {
+ unwrappedResults = wrappedResults.entrySet()
+ .stream()
+ .filter(entry -> entry.getValue() != null)
+ .collect(Collectors.toMap(
+ entry -> entry.getKey(),
+ entry -> entry.getValue().getVal()));
+ }
+
+ return unwrappedResults;
+ }
+
+ /**
+ * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other
+ * attributes.
+ * <p>
+ * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
+ * defensive copy is made.
+ * <p>
+ * This method is most useful if you want to determine things such as the how long the element
+ * has been in the cache.
+ * <p>
+ * The last access time in the ElementAttributes should be current.
+ * <p>
+ * @param name Key the Serializable is stored as
+ * @return The ICacheElement<K, V> if the object is found or null
+ */
+ @Override
+ public ICacheElement<K, V> getCacheElement( K name )
+ {
+ return this.getCacheControl().get( name );
+ }
+
+ /**
+ * Get multiple elements from the cache based on a set of cache keys.
+ * <p>
+ * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other
+ * attributes.
+ * <p>
+ * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
+ * defensive copy is made.
+ * <p>
+ * This method is most useful if you want to determine things such as the how long the element
+ * has been in the cache.
+ * <p>
+ * The last access time in the ElementAttributes should be current.
+ * <p>
+ * @param names set of Serializable cache keys
+ * @return a map of K key to ICacheElement<K, V> element, or empty map if none of the keys are present
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getCacheElements( Set<K> names )
+ {
+ return this.getCacheControl().getMultiple( names );
+ }
+
+ /**
+ * Get multiple elements from the cache based on a set of cache keys.
+ * <p>
+ * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other
+ * attributes.
+ * <p>
+ * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
+ * defensive copy is made.
+ * <p>
+ * This method is most useful if you want to determine things such as the how long the element
+ * has been in the cache.
+ * <p>
+ * The last access time in the ElementAttributes should be current.
+ * <p>
+ * @param pattern key search pattern
+ * @return a map of K key to ICacheElement<K, V> element, or empty map if no keys match the pattern
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatchingCacheElements( String pattern )
+ {
+ return this.getCacheControl().getMatching( pattern );
+ }
+
+ /**
+ * Place a new object in the cache, associated with key name. If there is currently an object
+ * associated with name in the region an ObjectExistsException is thrown. Names are scoped to a
+ * region so they must be unique within the region they are placed.
+ * <p>
+ * @param key Key object will be stored with
+ * @param value Object to store
+ * @throws CacheException and ObjectExistsException is thrown if the item is already in the
+ * cache.
+ */
+ @Override
+ public void putSafe( K key, V value )
+ {
+ if ( this.getCacheControl().get( key ) != null )
+ {
+ throw new ObjectExistsException( "putSafe failed. Object exists in the cache for key [" + key
+ + "]. Remove first or use a non-safe put to override the value." );
+ }
+ put( key, value );
+ }
+
+ /**
+ * Place a new object in the cache, associated with key name. If there is currently an object
+ * associated with name in the region it is replaced. Names are scoped to a region so they must
+ * be unique within the region they are placed.
+ * @param name Key object will be stored with
+ * @param obj Object to store
+ */
+ @Override
+ public void put( K name, V obj )
+ {
+ // Call put with a copy of the contained caches default attributes.
+ // the attributes are copied by the cacheControl
+ put( name, obj, this.getCacheControl().getElementAttributes() );
+ }
+
+ /**
+ * Constructs a cache element with these attributes, and puts it into the cache.
+ * <p>
+ * If the key or the value is null, and InvalidArgumentException is thrown.
+ * <p>
+ * @see org.apache.commons.jcs3.access.behavior.ICacheAccess#put(Object, Object, IElementAttributes)
+ */
+ @Override
+ public void put( K key, V val, IElementAttributes attr )
+ {
+ if ( key == null )
+ {
+ throw new InvalidArgumentException( "Key must not be null" );
+ }
+
+ if ( val == null )
+ {
+ throw new InvalidArgumentException( "Value must not be null" );
+ }
+
+ // Create the element and update. This may throw an IOException which
+ // should be wrapped by cache access.
+ try
+ {
+ CacheElement<K, V> ce = new CacheElement<>( this.getCacheControl().getCacheName(), key,
+ val );
+
+ ce.setElementAttributes( attr );
+
+ this.getCacheControl().update( ce );
+ }
+ catch ( IOException e )
+ {
+ throw new CacheException( e );
+ }
+ }
+
+ /**
+ * Removes a single item by name.
+ * <p>
+ * @param name the name of the item to remove.
+ */
+ @Override
+ public void remove( K name )
+ {
+ this.getCacheControl().remove( name );
+ }
+
+ /**
+ * Reset attributes for a particular element in the cache. NOTE: this method is currently not
+ * implemented.
+ * <p>
+ * @param name Key of object to reset attributes for
+ * @param attr New attributes for the object
+ * @throws InvalidHandleException if the item does not exist.
+ */
+ @Override
+ public void resetElementAttributes( K name, IElementAttributes attr )
+ {
+ ICacheElement<K, V> element = this.getCacheControl().get( name );
+
+ if ( element == null )
+ {
+ throw new InvalidHandleException( "Object for name [" + name + "] is not in the cache" );
+ }
+
+ // Although it will work currently, don't assume pass by reference here,
+ // i.e. don't do this:
+ // element.setElementAttributes( attr );
+ // Another reason to call put is to force the changes to be distributed.
+
+ put( element.getKey(), element.getVal(), attr );
+ }
+
+ /**
+ * GetElementAttributes will return an attribute object describing the current attributes
+ * associated with the object name. The name object must override the Object.equals and
+ * Object.hashCode methods.
+ * <p>
+ * @param name Key of object to get attributes for
+ * @return Attributes for the object, null if object not in cache
+ */
+ @Override
+ public IElementAttributes getElementAttributes( K name ) throws CacheException
+ {
+ IElementAttributes attr = null;
+
+ try
+ {
+ attr = this.getCacheControl().getElementAttributes( name );
+ }
+ catch ( IOException ioe )
+ {
+ throw new CacheException("Failure getting element attributes", ioe);
+ }
+
+ return attr;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/GroupCacheAccess.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/GroupCacheAccess.java
new file mode 100644
index 0000000..cad9082
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/GroupCacheAccess.java
@@ -0,0 +1,206 @@
+package org.apache.commons.jcs3.access;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.commons.jcs3.access.behavior.IGroupCacheAccess;
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.access.exception.InvalidArgumentException;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.control.group.GroupAttrName;
+import org.apache.commons.jcs3.engine.control.group.GroupId;
+
+/**
+ * Access for groups.
+ */
+public class GroupCacheAccess<K, V>
+ extends AbstractCacheAccess<GroupAttrName<K>, V>
+ implements IGroupCacheAccess<K, V>
+{
+ /**
+ * Constructor for the GroupCacheAccess object
+ * <p>
+ * @param cacheControl
+ */
+ public GroupCacheAccess( CompositeCache<GroupAttrName<K>, V> cacheControl )
+ {
+ super(cacheControl);
+ }
+
+ /**
+ * Gets an item out of the cache that is in a specified group.
+ * <p>
+ * @param name
+ * The key name.
+ * @param group
+ * The group name.
+ * @return The cached value, null if not found.
+ */
+ @Override
+ public V getFromGroup( K name, String group )
+ {
+ ICacheElement<GroupAttrName<K>, V> element = this.getCacheControl().get( getGroupAttrName( group, name ) );
+ return ( element != null ) ? element.getVal() : null;
+ }
+
+ /**
+ * Internal method used for group functionality.
+ * <p>
+ * @param group
+ * @param name
+ * @return GroupAttrName
+ */
+ private GroupAttrName<K> getGroupAttrName( String group, K name )
+ {
+ GroupId gid = new GroupId( this.getCacheControl().getCacheName(), group );
+ return new GroupAttrName<>( gid, name );
+ }
+
+ /**
+ * Allows the user to put an object into a group within a particular cache
+ * region. This method sets the object's attributes to the default for the
+ * region.
+ * <p>
+ * @param name
+ * The key name.
+ * @param groupName
+ * The group name.
+ * @param value
+ * The object to cache
+ * @throws CacheException
+ */
+ @Override
+ public void putInGroup( K name, String groupName, V value )
+ throws CacheException
+ {
+ putInGroup( name, groupName, value, null );
+ }
+
+ /**
+ * Allows the user to put an object into a group within a particular cache
+ * region. This method allows the object's attributes to be individually
+ * specified.
+ * <p>
+ * @param name
+ * The key name.
+ * @param groupName
+ * The group name.
+ * @param value
+ * The object to cache
+ * @param attr
+ * The objects attributes.
+ * @throws CacheException
+ */
+ @Override
+ public void putInGroup( K name, String groupName, V value, IElementAttributes attr )
+ throws CacheException
+ {
+ if ( name == null )
+ {
+ throw new InvalidArgumentException( "Key must not be null" );
+ }
+
+ if ( value == null )
+ {
+ throw new InvalidArgumentException( "Value must not be null" );
+ }
+
+ // Create the element and update. This may throw an IOException which
+ // should be wrapped by cache access.
+ try
+ {
+ GroupAttrName<K> key = getGroupAttrName( groupName, name );
+ CacheElement<GroupAttrName<K>, V> ce =
+ new CacheElement<>( this.getCacheControl().getCacheName(), key, value );
+
+ IElementAttributes attributes = (attr == null) ? this.getCacheControl().getElementAttributes() : attr;
+ ce.setElementAttributes( attributes );
+
+ this.getCacheControl().update( ce );
+ }
+ catch ( IOException e )
+ {
+ throw new CacheException( e );
+ }
+
+ }
+
+ /**
+ * Removes a single item by name from a group.
+ *
+ * @param name
+ * @param group
+ */
+ @Override
+ public void removeFromGroup( K name, String group )
+ {
+ GroupAttrName<K> key = getGroupAttrName( group, name );
+ this.getCacheControl().remove( key );
+ }
+
+ /**
+ * Gets the set of keys of objects currently in the group.
+ * <p>
+ * @param group
+ * @return A Set of keys.
+ */
+ @Override
+ public Set<K> getGroupKeys( String group )
+ {
+ GroupId groupId = new GroupId( this.getCacheControl().getCacheName(), group );
+
+ return this.getCacheControl().getKeySet()
+ .stream()
+ .filter(gan -> gan.groupId.equals(groupId))
+ .map(gan -> gan.attrName)
+ .collect(Collectors.toSet());
+ }
+
+ /**
+ * Gets the set of group names in the cache
+ * <p>
+ * @return A Set of group names.
+ */
+ public Set<String> getGroupNames()
+ {
+ return this.getCacheControl().getKeySet()
+ .stream()
+ .map(gan -> gan.groupId.groupName)
+ .collect(Collectors.toSet());
+ }
+
+ /**
+ * Invalidates a group: remove all the group members
+ * <p>
+ * @param group
+ * The name of the group to invalidate
+ */
+ @Override
+ public void invalidateGroup( String group )
+ {
+ this.getCacheControl().remove(getGroupAttrName(group, null));
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/behavior/ICacheAccess.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/behavior/ICacheAccess.java
new file mode 100644
index 0000000..5d1808e
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/behavior/ICacheAccess.java
@@ -0,0 +1,178 @@
+package org.apache.commons.jcs3.access.behavior;
+
+/*
+ * 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.
+ */
+
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+
+/**
+ * ICacheAccess defines the behavior for client access.
+ */
+public interface ICacheAccess<K, V>
+ extends ICacheAccessManagement
+{
+ /**
+ * Basic get method.
+ * <p>
+ * @param name
+ * @return Object or null if not found.
+ */
+ V get(K name);
+
+ /**
+ * Basic get method. If the object cannot be found in the cache, it will be
+ * retrieved by calling the supplier and subsequently storing it in the cache.
+ * <p>
+ * @param name
+ * @param supplier supplier to be called if the value is not found
+ * @return Object.
+ */
+ V get(K name, Supplier<V> supplier);
+
+ /**
+ * Retrieve matching objects from the cache region this instance provides access to.
+ * <p>
+ * @param pattern - a key pattern for the objects stored
+ * @return A map of key to values. These are stripped from the wrapper.
+ */
+ Map<K, V> getMatching(String pattern);
+
+ /**
+ * Puts in cache if an item does not exist with the name in that region.
+ * <p>
+ * @param name
+ * @param obj
+ * @throws CacheException
+ */
+ void putSafe(K name, V obj)
+ throws CacheException;
+
+ /**
+ * Puts and/or overrides an element with the name in that region.
+ * <p>
+ * @param name
+ * @param obj
+ * @throws CacheException
+ */
+ void put(K name, V obj)
+ throws CacheException;
+
+ /**
+ * Description of the Method
+ * <p>
+ * @param name
+ * @param obj
+ * @param attr
+ * @throws CacheException
+ */
+ void put(K name, V obj, IElementAttributes attr)
+ throws CacheException;
+
+ /**
+ * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other
+ * attributes.
+ * <p>
+ * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
+ * defensive copy is made.
+ * <p>
+ * This method is most useful if you want to determine things such as the how long the element
+ * has been in the cache.
+ * <p>
+ * The last access time in the ElementAttributes should be current.
+ * <p>
+ * @param name Key the object is stored as
+ * @return The ICacheElement<K, V> if the object is found or null
+ */
+ ICacheElement<K, V> getCacheElement(K name);
+
+ /**
+ * Get multiple elements from the cache based on a set of cache keys.
+ * <p>
+ * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other
+ * attributes.
+ * <p>
+ * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
+ * defensive copy is made.
+ * <p>
+ * This method is most useful if you want to determine things such as the how long the element
+ * has been in the cache.
+ * <p>
+ * The last access time in the ElementAttributes should be current.
+ * <p>
+ * @param names set of Object cache keys
+ * @return a map of Object key to ICacheElement<K, V> element, or empty map if none of the keys are
+ * present
+ */
+ Map<K, ICacheElement<K, V>> getCacheElements(Set<K> names);
+
+ /**
+ * Get multiple elements from the cache based on a set of cache keys.
+ * <p>
+ * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other
+ * attributes.
+ * <p>
+ * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
+ * defensive copy is made.
+ * <p>
+ * This method is most useful if you want to determine things such as the how long the element
+ * has been in the cache.
+ * <p>
+ * The last access time in the ElementAttributes should be current.
+ * <p>
+ * @param pattern key search pattern
+ * @return a map of Object key to ICacheElement<K, V> element, or empty map if no keys match the
+ * pattern
+ */
+ Map<K, ICacheElement<K, V>> getMatchingCacheElements(String pattern);
+
+ /**
+ * Remove an object for this key if one exists, else do nothing.
+ * <p>
+ * @param name
+ * @throws CacheException
+ */
+ void remove(K name)
+ throws CacheException;
+
+ /**
+ * Reset the attributes on the object matching this key name.
+ * <p>
+ * @param name
+ * @param attributes
+ * @throws CacheException
+ */
+ void resetElementAttributes(K name, IElementAttributes attributes)
+ throws CacheException;
+
+ /**
+ * Gets the elementAttributes attribute of the ICacheAccess object
+ * <p>
+ * @param name
+ * @return The elementAttributes value
+ * @throws CacheException
+ */
+ IElementAttributes getElementAttributes(K name)
+ throws CacheException;
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/behavior/ICacheAccessManagement.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/behavior/ICacheAccessManagement.java
new file mode 100644
index 0000000..d3a9c18
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/behavior/ICacheAccessManagement.java
@@ -0,0 +1,111 @@
+package org.apache.commons.jcs3.access.behavior;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.stats.behavior.ICacheStats;
+
+/**
+ * ICacheAccessManagement defines the methods for cache management, cleanup and shutdown.
+ */
+public interface ICacheAccessManagement
+{
+ /**
+ * Dispose this region. Flushes objects to and closes auxiliary caches. This is a shutdown
+ * command!
+ * <p>
+ * To simply remove all elements from the region use clear().
+ */
+ void dispose();
+
+ /**
+ * Removes all of the elements from a region.
+ * <p>
+ * @throws CacheException
+ */
+ void clear() throws CacheException;
+
+ /**
+ * GetElementAttributes will return an attribute object describing the current attributes
+ * associated with the object name. If no name parameter is available, the attributes for the
+ * region will be returned. The name object must override the Object.equals and Object.hashCode
+ * methods.
+ * <p>
+ * @return The elementAttributes value
+ * @throws CacheException
+ */
+ IElementAttributes getDefaultElementAttributes()
+ throws CacheException;
+
+ /**
+ * This method is does not reset the attributes for items already in the cache. It could
+ * potentially do this for items in memory, and maybe on disk (which would be slow) but not
+ * remote items. Rather than have unpredictable behavior, this method just sets the default
+ * attributes. Items subsequently put into the cache will use these defaults if they do not
+ * specify specific attributes.
+ * <p>
+ * @param attr the default attributes.
+ * @throws CacheException if something goes wrong.
+ */
+ void setDefaultElementAttributes( IElementAttributes attr ) throws CacheException;
+
+ /**
+ * Gets the ICompositeCacheAttributes of the cache region
+ * <p>
+ * @return ICompositeCacheAttributes
+ */
+ ICompositeCacheAttributes getCacheAttributes();
+
+ /**
+ * Sets the ICompositeCacheAttributes of the cache region
+ * <p>
+ * @param cattr The new ICompositeCacheAttribute value
+ */
+ void setCacheAttributes( ICompositeCacheAttributes cattr );
+
+ /**
+ * This instructs the memory cache to remove the <i>numberToFree</i> according to its eviction
+ * policy. For example, the LRUMemoryCache will remove the <i>numberToFree</i> least recently
+ * used items. These will be spooled to disk if a disk auxiliary is available.
+ * <p>
+ * @param numberToFree
+ * @return the number that were removed. if you ask to free 5, but there are only 3, you will
+ * get 3.
+ * @throws CacheException
+ */
+ int freeMemoryElements( int numberToFree )
+ throws CacheException;
+
+ /**
+ * This returns the ICacheStats object with information on this region and its auxiliaries.
+ * <p>
+ * This data can be formatted as needed.
+ * <p>
+ * @return ICacheStats
+ */
+ ICacheStats getStatistics();
+
+ /**
+ * @return A String version of the stats.
+ */
+ String getStats();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/behavior/IGroupCacheAccess.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/behavior/IGroupCacheAccess.java
new file mode 100644
index 0000000..ca09f8b
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/behavior/IGroupCacheAccess.java
@@ -0,0 +1,89 @@
+package org.apache.commons.jcs3.access.behavior;
+
+/*
+ * 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.
+ */
+
+import java.util.Set;
+
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+
+/**
+ * IGroupCacheAccess defines group specific behavior for the client access
+ * classes.
+ */
+public interface IGroupCacheAccess<K, V>
+ extends ICacheAccessManagement
+{
+ /**
+ * Gets the g attribute of the IGroupCacheAccess object
+ * <p>
+ * @param name
+ * @param group
+ * the name of the group to associate this with.
+ * @return The object that is keyed by the name in the group
+ */
+ V getFromGroup( K name, String group );
+
+ /**
+ * Puts an item in the cache associated with this group.
+ * <p>
+ * @param key
+ * @param group
+ * @param obj
+ * @throws CacheException
+ */
+ void putInGroup( K key, String group, V obj )
+ throws CacheException;
+
+ /**
+ * Put in the cache associated with this group using these attributes.
+ * <p>
+ * @param key
+ * @param group
+ * @param obj
+ * @param attr
+ * @throws CacheException
+ */
+ void putInGroup( K key, String group, V obj, IElementAttributes attr )
+ throws CacheException;
+
+ /**
+ * Remove the item from this group in this region by this name.
+ * <p>
+ * @param name
+ * @param group
+ */
+ void removeFromGroup( K name, String group );
+
+ /**
+ * Gets the set of keys of objects currently in the group
+ * <p>
+ * @param group
+ * @return the set of group keys.
+ */
+ Set<K> getGroupKeys( String group );
+
+ /**
+ * Invalidates a group
+ * <p>
+ * @param group
+ */
+ void invalidateGroup( String group );
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/CacheException.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/CacheException.java
new file mode 100644
index 0000000..91e5a72
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/CacheException.java
@@ -0,0 +1,66 @@
+package org.apache.commons.jcs3.access.exception;
+
+/*
+ * 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.
+ */
+
+/**
+ * This is the most general exception the cache throws.
+ */
+public class CacheException
+ extends RuntimeException
+{
+ /** Don't change. */
+ private static final long serialVersionUID = 8725795372935590265L;
+
+ /**
+ * Default
+ */
+ public CacheException()
+ {
+ super();
+ }
+
+ /**
+ * Constructor for the CacheException object
+ * @param nested a nested exception
+ */
+ public CacheException( Throwable nested )
+ {
+ super(nested);
+ }
+
+ /**
+ * Constructor for the CacheException object
+ * @param message the exception message
+ */
+ public CacheException( String message )
+ {
+ super(message);
+ }
+
+ /**
+ * Constructor for the CacheException object
+ * @param message the exception message
+ * @param nested a nested exception
+ */
+ public CacheException(String message, Throwable nested)
+ {
+ super(message, nested);
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/ConfigurationException.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/ConfigurationException.java
new file mode 100644
index 0000000..add6932
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/ConfigurationException.java
@@ -0,0 +1,44 @@
+package org.apache.commons.jcs3.access.exception;
+
+/*
+ * 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.
+ */
+
+/** Thrown if there is some severe configuration problem that makes the cache nonfunctional. */
+public class ConfigurationException
+ extends CacheException
+{
+ /** Don't change. */
+ private static final long serialVersionUID = 6881044536186097055L;
+
+ /** Constructor for the ConfigurationException object */
+ public ConfigurationException()
+ {
+ super();
+ }
+
+ /**
+ * Constructor for the ConfigurationException object.
+ * <p>
+ * @param message
+ */
+ public ConfigurationException( String message )
+ {
+ super( message );
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/InvalidArgumentException.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/InvalidArgumentException.java
new file mode 100644
index 0000000..e3f3d00
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/InvalidArgumentException.java
@@ -0,0 +1,47 @@
+package org.apache.commons.jcs3.access.exception;
+
+/*
+ * 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.
+ */
+
+/**
+ * InvalidArgumentException is thrown if an argument is passed to the cache that is invalid. For
+ * instance, null values passed to put result in this exception.
+ */
+public class InvalidArgumentException
+ extends CacheException
+{
+ /** Don't change. */
+ private static final long serialVersionUID = -6058373692208755562L;
+
+ /** Constructor for the InvalidArgumentException object */
+ public InvalidArgumentException()
+ {
+ super();
+ }
+
+ /**
+ * Constructor for the InvalidArgumentException object.
+ * <p>
+ * @param message
+ */
+ public InvalidArgumentException( String message )
+ {
+ super( message );
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/InvalidGroupException.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/InvalidGroupException.java
new file mode 100644
index 0000000..2e50513
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/InvalidGroupException.java
@@ -0,0 +1,47 @@
+package org.apache.commons.jcs3.access.exception;
+
+/*
+ * 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.
+ */
+
+/**
+ * InvalidGroupException
+ */
+public class InvalidGroupException
+ extends CacheException
+{
+ /** Don't change. */
+ private static final long serialVersionUID = -5219807114008843480L;
+
+ /** Constructor for the InvalidGroupException object */
+ public InvalidGroupException()
+ {
+ super();
+ }
+
+ /**
+ * Constructor for the InvalidGroupException object
+ * <p>
+ * @param message
+ */
+ public InvalidGroupException( String message )
+ {
+ super( message );
+ }
+
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/InvalidHandleException.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/InvalidHandleException.java
new file mode 100644
index 0000000..b16c828
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/InvalidHandleException.java
@@ -0,0 +1,48 @@
+package org.apache.commons.jcs3.access.exception;
+
+/*
+ * 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.
+ */
+
+/**
+ * InvalidHandleException is not used.
+ */
+public class InvalidHandleException
+ extends CacheException
+{
+ /** Don't change. */
+ private static final long serialVersionUID = -5947822454839845924L;
+
+ /** Constructor for the InvalidHandleException object */
+ public InvalidHandleException()
+ {
+ // nothing
+ super();
+ }
+
+ /**
+ * Constructor for the InvalidHandleException object.
+ * <p>
+ * @param message
+ */
+ public InvalidHandleException( String message )
+ {
+ super( message );
+ }
+
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/ObjectExistsException.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/ObjectExistsException.java
new file mode 100644
index 0000000..10207e0
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/ObjectExistsException.java
@@ -0,0 +1,53 @@
+package org.apache.commons.jcs3.access.exception;
+
+/*
+ * 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.
+ */
+
+/**
+ * The putSafe method on the JCS convenience class throws this exception if the object is already
+ * present in the cache.
+ * <p>
+ * I'm removing this exception from normal use.
+ * <p>
+ * The overhead of throwing exceptions and the cumbersomeness of coding around exceptions warrants
+ * removal. Exceptions like this don't make sense to throw in the course of normal operations to
+ * signify a normal and expected condition. Returning null if an object isn't found is sufficient.
+ */
+public class ObjectExistsException
+ extends CacheException
+{
+ /** Don't change. */
+ private static final long serialVersionUID = -3779745827993383872L;
+
+ /** Constructor for the ObjectExistsException object */
+ public ObjectExistsException()
+ {
+ super();
+ }
+
+ /**
+ * Constructor for the ObjectExistsException object
+ * @param message
+ */
+ public ObjectExistsException( String message )
+ {
+ super( message );
+ }
+
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/ObjectNotFoundException.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/ObjectNotFoundException.java
new file mode 100644
index 0000000..b234efe
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/exception/ObjectNotFoundException.java
@@ -0,0 +1,51 @@
+package org.apache.commons.jcs3.access.exception;
+
+/*
+ * 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.
+ */
+
+/**
+ * ObjectNotFoundException
+ * <p>
+ * TODO see if we can remove this.
+ * <p>
+ * This is thrown from the composite cache if you as for the element attributes and the element does
+ * not exist.
+ */
+public class ObjectNotFoundException
+ extends CacheException
+{
+ /** Don't change. */
+ private static final long serialVersionUID = 5684353421076546842L;
+
+ /** Constructor for the ObjectNotFoundException object */
+ public ObjectNotFoundException()
+ {
+ super();
+ }
+
+ /**
+ * Constructor for the ObjectNotFoundException object
+ * @param message
+ */
+ public ObjectNotFoundException( String message )
+ {
+ super( message );
+ }
+
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/access/package.html b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/package.html
similarity index 100%
rename from commons-jcs-core/src/main/java/org/apache/commons/jcs/access/package.html
rename to commons-jcs-core/src/main/java/org/apache/commons/jcs3/access/package.html
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/admin/CacheElementInfo.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/admin/CacheElementInfo.java
new file mode 100644
index 0000000..88d3813
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/admin/CacheElementInfo.java
@@ -0,0 +1,124 @@
+package org.apache.commons.jcs3.admin;
+
+/*
+ * 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.
+ */
+
+import java.beans.ConstructorProperties;
+
+
+/**
+ * Stores info on a cache element for the template
+ */
+public class CacheElementInfo
+{
+ /** element key */
+ private final String key;
+
+ /** is it eternal */
+ private final boolean eternal;
+
+ /** when it was created */
+ private final String createTime;
+
+ /** max life */
+ private final long maxLifeSeconds;
+
+ /** when it will expire */
+ private final long expiresInSeconds;
+
+ /**
+ * Parameterized constructor
+ *
+ * @param key element key
+ * @param eternal is it eternal
+ * @param createTime when it was created
+ * @param maxLifeSeconds max life
+ * @param expiresInSeconds when it will expire
+ */
+ @ConstructorProperties({"key", "eternal", "createTime", "maxLifeSeconds", "expiresInSeconds"})
+ public CacheElementInfo(String key, boolean eternal, String createTime,
+ long maxLifeSeconds, long expiresInSeconds)
+ {
+ super();
+ this.key = key;
+ this.eternal = eternal;
+ this.createTime = createTime;
+ this.maxLifeSeconds = maxLifeSeconds;
+ this.expiresInSeconds = expiresInSeconds;
+ }
+
+ /**
+ * @return a string representation of the key
+ */
+ public String getKey()
+ {
+ return this.key;
+ }
+
+ /**
+ * @return true if the item does not expire
+ */
+ public boolean isEternal()
+ {
+ return this.eternal;
+ }
+
+ /**
+ * @return the time the object was created
+ */
+ public String getCreateTime()
+ {
+ return this.createTime;
+ }
+
+ /**
+ * Ignored if isEternal
+ * @return the longest this object can live.
+ */
+ public long getMaxLifeSeconds()
+ {
+ return this.maxLifeSeconds;
+ }
+
+ /**
+ * Ignored if isEternal
+ * @return how many seconds until this object expires.
+ */
+ public long getExpiresInSeconds()
+ {
+ return this.expiresInSeconds;
+ }
+
+ /**
+ * @return string info on the item
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\nCacheElementInfo " );
+ buf.append( "\n Key [" ).append( getKey() ).append( "]" );
+ buf.append( "\n Eternal [" ).append( isEternal() ).append( "]" );
+ buf.append( "\n CreateTime [" ).append( getCreateTime() ).append( "]" );
+ buf.append( "\n MaxLifeSeconds [" ).append( getMaxLifeSeconds() ).append( "]" );
+ buf.append( "\n ExpiresInSeconds [" ).append( getExpiresInSeconds() ).append( "]" );
+
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/admin/CacheRegionInfo.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/admin/CacheRegionInfo.java
new file mode 100644
index 0000000..11dfce5
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/admin/CacheRegionInfo.java
@@ -0,0 +1,180 @@
+package org.apache.commons.jcs3.admin;
+
+/*
+ * 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.
+ */
+
+import java.beans.ConstructorProperties;
+
+
+
+/**
+ * Stores info on a cache region for the template
+ */
+public class CacheRegionInfo
+{
+ /** The name of the cache region */
+ private final String cacheName;
+
+ /** The size of the cache region */
+ private final int cacheSize;
+
+ /** The status of the cache region */
+ private final String cacheStatus;
+
+ /** The statistics of the cache region */
+ private final String cacheStatistics;
+
+ /** The number of memory hits in the cache region */
+ private final long hitCountRam;
+
+ /** The number of auxiliary hits in the cache region */
+ private final long hitCountAux;
+
+ /** The number of misses in the cache region because the items were not found */
+ private final long missCountNotFound;
+
+ /** The number of misses in the cache region because the items were expired */
+ private final long missCountExpired;
+
+ /** The number of bytes counted so far, will be a total of all items */
+ private final long byteCount;
+
+ /**
+ * Parameterized constructor
+ *
+ * @param cacheName The name of the cache region
+ * @param cacheSize The size of the cache region
+ * @param cacheStatus The status of the cache region
+ * @param cacheStatistics The statistics of the cache region
+ * @param hitCountRam The number of memory hits in the cache region
+ * @param hitCountAux The number of auxiliary hits in the cache region
+ * @param missCountNotFound The number of misses in the cache region because the items were not found
+ * @param missCountExpired The number of misses in the cache region because the items were expired
+ * @param byteCount The number of bytes counted so far, will be a total of all items
+ */
+ @ConstructorProperties({"cacheName", "cacheSize", "cacheStatus", "cacheStatistics",
+ "hitCountRam", "hitCountAux", "missCountNotFound", "missCountExpired", "byteCount"})
+ public CacheRegionInfo(String cacheName, int cacheSize, String cacheStatus,
+ String cacheStatistics, long hitCountRam, long hitCountAux,
+ long missCountNotFound, long missCountExpired, long byteCount)
+ {
+ super();
+ this.cacheName = cacheName;
+ this.cacheSize = cacheSize;
+ this.cacheStatus = cacheStatus;
+ this.cacheStatistics = cacheStatistics;
+ this.hitCountRam = hitCountRam;
+ this.hitCountAux = hitCountAux;
+ this.missCountNotFound = missCountNotFound;
+ this.missCountExpired = missCountExpired;
+ this.byteCount = byteCount;
+ }
+
+ /**
+ * @return the cacheName
+ */
+ public String getCacheName()
+ {
+ return this.cacheName;
+ }
+
+ /**
+ * @return the cacheSize
+ */
+ public int getCacheSize()
+ {
+ return this.cacheSize;
+ }
+
+ /**
+ * @return a status string
+ */
+ public String getCacheStatus()
+ {
+ return this.cacheStatus;
+ }
+
+ /**
+ * Return the statistics for the region.
+ * <p>
+ * @return String
+ */
+ public String getCacheStatistics()
+ {
+ return this.cacheStatistics;
+ }
+
+ /**
+ * @return the hitCountRam
+ */
+ public long getHitCountRam()
+ {
+ return hitCountRam;
+ }
+
+ /**
+ * @return the hitCountAux
+ */
+ public long getHitCountAux()
+ {
+ return hitCountAux;
+ }
+
+ /**
+ * @return the missCountNotFound
+ */
+ public long getMissCountNotFound()
+ {
+ return missCountNotFound;
+ }
+
+ /**
+ * @return the missCountExpired
+ */
+ public long getMissCountExpired()
+ {
+ return missCountExpired;
+ }
+
+ /**
+ * @return total byte count
+ */
+ public long getByteCount()
+ {
+ return this.byteCount;
+ }
+
+ /**
+ * @return string info on the region
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\nCacheRegionInfo " );
+ if ( cacheName != null )
+ {
+ buf.append( "\n CacheName [" + cacheName + "]" );
+ buf.append( "\n Status [" + cacheStatus + "]" );
+ }
+ buf.append( "\n ByteCount [" + getByteCount() + "]" );
+
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/admin/CountingOnlyOutputStream.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/admin/CountingOnlyOutputStream.java
new file mode 100644
index 0000000..3ee9736
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/admin/CountingOnlyOutputStream.java
@@ -0,0 +1,84 @@
+package org.apache.commons.jcs3.admin;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Keeps track of the number of bytes written to it, but doesn't write them anywhere.
+ */
+public class CountingOnlyOutputStream
+ extends OutputStream
+{
+ /** number of bytes passed through */
+ private int count; // TODO should this be long?
+
+ /**
+ * count as we write.
+ * <p>
+ * @param b
+ * @throws IOException
+ */
+ @Override
+ public void write( byte[] b )
+ throws IOException
+ {
+ this.count += b.length;
+ }
+
+ /**
+ * count as we write.
+ * <p>
+ * @param b
+ * @param off
+ * @param len
+ * @throws IOException
+ */
+ @Override
+ public void write( byte[] b, int off, int len )
+ throws IOException
+ {
+ this.count += len;
+ }
+
+ /**
+ * count as we write.
+ * <p>
+ * @param b
+ * @throws IOException
+ */
+ @Override
+ public void write( int b )
+ throws IOException
+ {
+ this.count++;
+ }
+
+ /**
+ * The number of bytes that have passed through this stream.
+ * <p>
+ * @return int
+ */
+ public int getCount()
+ {
+ return this.count;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/admin/JCSAdmin.jsp b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/admin/JCSAdmin.jsp
new file mode 100644
index 0000000..b01bef0
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/admin/JCSAdmin.jsp
@@ -0,0 +1,310 @@
+<%--
+ 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.
+--%>
+<%@page import="org.apache.commons.jcs3.JCS"%>
+<%@page import="org.apache.commons.jcs3.access.CacheAccess" %>
+<%@page import="org.apache.commons.jcs3.admin.CacheElementInfo" %>
+<%@page import="org.apache.commons.jcs3.admin.CacheRegionInfo" %>
+<%@page import="java.io.Serializable" %>
+<%@page import="java.util.HashMap" %>
+
+<jsp:useBean id="jcsBean" scope="request" class="org.apache.commons.jcs3.admin.JCSAdminBean" />
+
+<html>
+<head>
+
+<SCRIPT LANGUAGE="Javascript">
+ function decision( message, url )
+ {
+ if( confirm(message) )
+ {
+ location.href = url;
+ }
+ }
+</SCRIPT>
+
+<title> JCS Admin Servlet </title>
+
+</head>
+
+<body>
+
+<%
+ String CACHE_NAME_PARAM = "cacheName";
+ String ACTION_PARAM = "action";
+ String CLEAR_ALL_REGIONS_ACTION = "clearAllRegions";
+ String CLEAR_REGION_ACTION = "clearRegion";
+ String REMOVE_ACTION = "remove";
+ String DETAIL_ACTION = "detail";
+ String REGION_SUMMARY_ACTION = "regionSummary";
+ String ITEM_ACTION = "item";
+ String KEY_PARAM = "key";
+ String SILENT_PARAM = "silent";
+
+ String DEFAULT_TEMPLATE_NAME = "DEFAULT";
+ String REGION_DETAIL_TEMPLATE_NAME = "DETAIL";
+ String ITEM_TEMPLATE_NAME = "ITEM";
+ String REGION_SUMMARY_TEMPLATE_NAME = "SUMMARY";
+
+ String templateName = DEFAULT_TEMPLATE_NAME;
+
+ HashMap<String, Object> context = new HashMap<String, Object>();
+
+ // Get cacheName for actions from request (might be null)
+ String cacheName = request.getParameter( CACHE_NAME_PARAM );
+
+ if ( cacheName != null )
+ {
+ cacheName = cacheName.trim();
+ }
+
+ // If an action was provided, handle it
+ String action = request.getParameter( ACTION_PARAM );
+
+ if ( action != null )
+ {
+ if ( action.equals( CLEAR_ALL_REGIONS_ACTION ) )
+ {
+ jcsBean.clearAllRegions();
+ }
+ else if ( action.equals( CLEAR_REGION_ACTION ) )
+ {
+ if ( cacheName == null )
+ {
+ // Not Allowed
+ }
+ else
+ {
+ jcsBean.clearRegion( cacheName );
+ }
+ }
+ else if ( action.equals( REMOVE_ACTION ) )
+ {
+ String[] keys = request.getParameterValues( KEY_PARAM );
+
+ for ( int i = 0; i < keys.length; i++ )
+ {
+ jcsBean.removeItem( cacheName, keys[ i ] );
+ }
+
+ templateName = REGION_DETAIL_TEMPLATE_NAME;
+ }
+ else if ( action.equals( DETAIL_ACTION ) )
+ {
+ templateName = REGION_DETAIL_TEMPLATE_NAME;
+ }
+ else if ( action.equals( ITEM_ACTION ) )
+ {
+ templateName = ITEM_TEMPLATE_NAME;
+ }
+ else if ( action.equals( REGION_SUMMARY_ACTION ) )
+ {
+ templateName = REGION_SUMMARY_TEMPLATE_NAME;
+ }
+ }
+
+ if ( request.getParameter( SILENT_PARAM ) != null )
+ {
+ // If silent parameter was passed, no output should be produced.
+ //return null;
+ }
+ else
+ {
+ // Populate the context based on the template
+ if ( templateName == REGION_DETAIL_TEMPLATE_NAME )
+ {
+ //context.put( "cacheName", cacheName );
+ context.put( "elementInfoRecords", jcsBean.buildElementInfo( cacheName ) );
+ }
+ else if ( templateName == DEFAULT_TEMPLATE_NAME )
+ {
+ context.put( "cacheInfoRecords", jcsBean.buildCacheInfo() );
+ }
+ }
+
+///////////////////////////////////////////////////////////////////////////////////
+ //handle display
+
+ if ( templateName == ITEM_TEMPLATE_NAME )
+ {
+ String key = request.getParameter( KEY_PARAM );
+
+ if ( key != null )
+ {
+ key = key.trim();
+ }
+
+ CacheAccess<Serializable, Serializable> cache = JCS.getInstance( cacheName );
+ org.apache.commons.jcs3.engine.behavior.ICacheElement<?, ?> element = cache.getCacheElement( key );
+%>
+<h1> Item for key [<%=key%>] in region [<%=cacheName%>] </h1>
+
+<a href="JCSAdmin.jsp?action=detail&cacheName=<%=cacheName%>">Region Detail</a>
+| <a href="JCSAdmin.jsp">All Regions</a>
+
+ <pre>
+ <%=element%>
+ </pre>
+<%
+ }
+ else if ( templateName == REGION_SUMMARY_TEMPLATE_NAME )
+ {
+%>
+
+<h1> Summary for region [<%=cacheName%>] </h1>
+
+<a href="JCSAdmin.jsp">All Regions</a>
+
+<%
+ CacheAccess<?, ?> cache = JCS.getInstance( cacheName );
+ String stats = cache.getStats();
+%>
+
+ <br>
+<b> Stats for region [<%=cacheName%>] </b>
+
+ <pre>
+ <%=stats%>
+ </pre>
+
+<%
+ }
+ else if ( templateName == REGION_DETAIL_TEMPLATE_NAME )
+ {
+%>
+
+<h1> Detail for region [<%=cacheName%>] </h1>
+
+<a href="JCSAdmin.jsp">All Regions</a>
+
+<table border="1" cellpadding="5" >
+ <tr>
+ <th> Key </th>
+ <th> Eternal? </th>
+ <th> Create time </th>
+ <th> Max Life (s) </th>
+ <th> Till Expiration (s) </th>
+ </tr>
+<%
+ CacheElementInfo[] list = (CacheElementInfo[]) context.get( "elementInfoRecords" );
+ for (CacheElementInfo element : list)
+ {
+%>
+ <tr>
+ <td> <%=element.getKey()%> </td>
+ <td> <%=element.isEternal()%> </td>
+ <td> <%=element.getCreateTime()%> </td>
+ <td> <%=element.getMaxLifeSeconds()%> </td>
+ <td> <%=element.getExpiresInSeconds()%> </td>
+ <td>
+ <a href="JCSAdmin.jsp?action=item&cacheName=<%=cacheName%>&key=<%=element.getKey()%>"> View </a>
+ | <a href="JCSAdmin.jsp?action=remove&cacheName=<%=cacheName%>&key=<%=element.getKey()%>"> Remove </a>
+ </td>
+ </tr>
+<%
+ }
+
+ CacheAccess<?, ?> cache = JCS.getInstance( cacheName );
+ String stats = cache.getStats();
+%>
+ </table>
+
+ <br>
+<b> Stats for region [<%=cacheName%>] </b>
+
+ <pre>
+ <%=stats%>
+ </pre>
+<%
+ }
+ else
+ {
+%>
+
+<h1> Cache Regions </h1>
+
+<p>
+These are the regions which are currently defined in the cache. 'Items' and
+'Bytes' refer to the elements currently in memory (not spooled). You can clear
+all items for a region by selecting 'Remove all' next to the desired region
+below. You can also <a href="javascript:decision('Clicking OK will clear all the data from all regions!','JCSAdmin.jsp?action=clearAllRegions')">Clear all regions</a>
+which empties the entire cache.
+</p>
+<p>
+ <form action="JCSAdmin.jsp">
+ <input type="hidden" name="action" value="item">
+ Retrieve (key) <input type="text" name="key">
+ (region) <select name="cacheName">
+<%
+ CacheRegionInfo[] listSelect = (CacheRegionInfo[]) context.get( "cacheInfoRecords" );
+ for (CacheRegionInfo record : listSelect)
+ {
+ %>
+ <option value="<%=record.getCacheName()%>"><%=record.getCacheName()%></option>
+ <%
+ }
+%>
+ </select>
+ <input type="submit">
+ </form>
+</p>
+
+<table border="1" cellpadding="5" >
+ <tr>
+ <th> Cache Name </th>
+ <th> Items </th>
+ <th> Bytes </th>
+ <th> Status </th>
+ <th> Memory Hits </th>
+ <th> Aux Hits </th>
+ <th> Not Found Misses </th>
+ <th> Expired Misses </th>
+ </tr>
+
+<%
+ CacheRegionInfo[] list = (CacheRegionInfo[]) context.get( "cacheInfoRecords" );
+ for (CacheRegionInfo record : listSelect)
+ {
+%>
+ <tr>
+ <td> <%=record.getCacheName()%> </td>
+ <td> <%=record.getCacheSize()%> </td>
+ <td> <%=record.getByteCount()%> </td>
+ <td> <%=record.getCacheStatus()%> </td>
+ <td> <%=record.getHitCountRam()%> </td>
+ <td> <%=record.getHitCountAux()%> </td>
+ <td> <%=record.getMissCountNotFound()%> </td>
+ <td> <%=record.getMissCountExpired()%> </td>
+ <td>
+ <a href="JCSAdmin.jsp?action=regionSummary&cacheName=<%=record.getCacheName()%>"> Summary </a>
+ | <a href="JCSAdmin.jsp?action=detail&cacheName=<%=record.getCacheName()%>"> Detail </a>
+ | <a href="javascript:decision('Clicking OK will remove all the data from the region [<%=record.getCacheName()%>]!','JCSAdmin.jsp?action=clearRegion&cacheName=<%=record.getCacheName()%>')"> Clear </a>
+ </td>
+ </tr>
+<%
+ }
+%>
+ </table>
+<%
+ }
+%>
+
+
+</body>
+
+</html>
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/admin/JCSAdminBean.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/admin/JCSAdminBean.java
new file mode 100644
index 0000000..d1468a7
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/admin/JCSAdminBean.java
@@ -0,0 +1,391 @@
+package org.apache.commons.jcs3.admin;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.auxiliary.remote.server.RemoteCacheServer;
+import org.apache.commons.jcs3.auxiliary.remote.server.RemoteCacheServerFactory;
+import org.apache.commons.jcs3.engine.CacheElementSerialized;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+import org.apache.commons.jcs3.engine.memory.behavior.IMemoryCache;
+
+/**
+ * A servlet which provides HTTP access to JCS. Allows a summary of regions to be viewed, and
+ * removeAll to be run on individual regions or all regions. Also provides the ability to remove
+ * items (any number of key arguments can be provided with action 'remove'). Should be initialized
+ * with a properties file that provides at least a classpath resource loader.
+ */
+public class JCSAdminBean implements JCSJMXBean
+{
+ /** The cache manager. */
+ private final CompositeCacheManager cacheHub;
+
+ /**
+ * Default constructor
+ */
+ public JCSAdminBean()
+ {
+ super();
+ try
+ {
+ this.cacheHub = CompositeCacheManager.getInstance();
+ }
+ catch (CacheException e)
+ {
+ throw new RuntimeException("Could not retrieve cache manager instance", e);
+ }
+ }
+
+ /**
+ * Parameterized constructor
+ *
+ * @param cacheHub the cache manager instance
+ */
+ public JCSAdminBean(CompositeCacheManager cacheHub)
+ {
+ super();
+ this.cacheHub = cacheHub;
+ }
+
+ /**
+ * Builds up info about each element in a region.
+ * <p>
+ * @param cacheName
+ * @return List of CacheElementInfo objects
+ * @throws IOException
+ */
+ @Override
+ public List<CacheElementInfo> buildElementInfo( String cacheName )
+ throws IOException
+ {
+ CompositeCache<Object, Object> cache = cacheHub.getCache( cacheName );
+
+ // Convert all keys to string, store in a sorted map
+ TreeMap<String, ?> keys = new TreeMap<>(cache.getMemoryCache().getKeySet()
+ .stream()
+ .collect(Collectors.toMap(k -> k.toString(), k -> k)));
+
+ LinkedList<CacheElementInfo> records = new LinkedList<>();
+
+ DateFormat format = DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT );
+
+ long now = System.currentTimeMillis();
+
+ for (Map.Entry<String, ?> key : keys.entrySet())
+ {
+ ICacheElement<?, ?> element = cache.getMemoryCache().getQuiet( key.getValue() );
+
+ IElementAttributes attributes = element.getElementAttributes();
+
+ CacheElementInfo elementInfo = new CacheElementInfo(
+ key.getKey(),
+ attributes.getIsEternal(),
+ format.format(new Date(attributes.getCreateTime())),
+ attributes.getMaxLife(),
+ (now - attributes.getCreateTime() - attributes.getMaxLife() * 1000 ) / -1000);
+
+ records.add( elementInfo );
+ }
+
+ return records;
+ }
+
+ /**
+ * Builds up data on every region.
+ * <p>
+ * TODO we need a most light weight method that does not count bytes. The byte counting can
+ * really swamp a server.
+ * @return List of CacheRegionInfo objects
+ */
+ @Override
+ public List<CacheRegionInfo> buildCacheInfo()
+ {
+ TreeSet<String> cacheNames = new TreeSet<>(cacheHub.getCacheNames());
+
+ LinkedList<CacheRegionInfo> cacheInfo = new LinkedList<>();
+
+ for (String cacheName : cacheNames)
+ {
+ CompositeCache<?, ?> cache = cacheHub.getCache( cacheName );
+
+ CacheRegionInfo regionInfo = new CacheRegionInfo(
+ cache.getCacheName(),
+ cache.getSize(),
+ cache.getStatus().toString(),
+ cache.getStats(),
+ cache.getHitCountRam(),
+ cache.getHitCountAux(),
+ cache.getMissCountNotFound(),
+ cache.getMissCountExpired(),
+ getByteCount( cache ));
+
+ cacheInfo.add( regionInfo );
+ }
+
+ return cacheInfo;
+ }
+
+
+ /**
+ * Tries to estimate how much data is in a region. This is expensive. If there are any non serializable objects in
+ * the region or an error occurs, suppresses exceptions and returns 0.
+ * <p>
+ *
+ * @return int The size of the region in bytes.
+ */
+ @Override
+ public long getByteCount(String cacheName)
+ {
+ return getByteCount(cacheHub.getCache(cacheName));
+ }
+
+ /**
+ * Tries to estimate how much data is in a region. This is expensive. If there are any non serializable objects in
+ * the region or an error occurs, suppresses exceptions and returns 0.
+ * <p>
+ *
+ * @return int The size of the region in bytes.
+ */
+ public <K, V> long getByteCount(CompositeCache<K, V> cache)
+ {
+ if (cache == null)
+ {
+ throw new IllegalArgumentException("The cache object specified was null.");
+ }
+
+ long size = 0;
+ IMemoryCache<K, V> memCache = cache.getMemoryCache();
+
+ for (K key : memCache.getKeySet())
+ {
+ ICacheElement<K, V> ice = null;
+ try
+ {
+ ice = memCache.get(key);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("IOException while trying to get a cached element", e);
+ }
+
+ if (ice == null)
+ {
+ continue;
+ }
+
+ if (ice instanceof CacheElementSerialized)
+ {
+ size += ((CacheElementSerialized<K, V>) ice).getSerializedValue().length;
+ }
+ else
+ {
+ Object element = ice.getVal();
+
+ //CountingOnlyOutputStream: Keeps track of the number of bytes written to it, but doesn't write them anywhere.
+ CountingOnlyOutputStream counter = new CountingOnlyOutputStream();
+ try (ObjectOutputStream out = new ObjectOutputStream(counter);)
+ {
+ out.writeObject(element);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("IOException while trying to measure the size of the cached element", e);
+ }
+ finally
+ {
+ try
+ {
+ counter.close();
+ }
+ catch (IOException e)
+ {
+ // ignore
+ }
+ }
+
+ // 4 bytes lost for the serialization header
+ size += counter.getCount() - 4;
+ }
+ }
+
+ return size;
+ }
+
+ /**
+ * Clears all regions in the cache.
+ * <p>
+ * If this class is running within a remote cache server, clears all regions via the <code>RemoteCacheServer</code>
+ * API, so that removes will be broadcast to client machines. Otherwise clears all regions in the cache directly via
+ * the usual cache API.
+ */
+ @Override
+ public void clearAllRegions() throws IOException
+ {
+ RemoteCacheServer<?, ?> remoteCacheServer = RemoteCacheServerFactory.getRemoteCacheServer();
+
+ if (remoteCacheServer == null)
+ {
+ // Not running in a remote cache server.
+ // Remove objects from the cache directly, as no need to broadcast removes to client machines...
+ for (String name : cacheHub.getCacheNames())
+ {
+ cacheHub.getCache(name).removeAll();
+ }
+ }
+ else
+ {
+ // Running in a remote cache server.
+ // Remove objects via the RemoteCacheServer API, so that removes will be broadcast to client machines...
+ // Call remoteCacheServer.removeAll(String) for each cacheName...
+ for (String name : cacheHub.getCacheNames())
+ {
+ remoteCacheServer.removeAll(name);
+ }
+ }
+ }
+
+ /**
+ * Clears a particular cache region.
+ * <p>
+ * If this class is running within a remote cache server, clears the region via the <code>RemoteCacheServer</code>
+ * API, so that removes will be broadcast to client machines. Otherwise clears the region directly via the usual
+ * cache API.
+ */
+ @Override
+ public void clearRegion(String cacheName) throws IOException
+ {
+ if (cacheName == null)
+ {
+ throw new IllegalArgumentException("The cache name specified was null.");
+ }
+ if (RemoteCacheServerFactory.getRemoteCacheServer() == null)
+ {
+ // Not running in a remote cache server.
+ // Remove objects from the cache directly, as no need to broadcast removes to client machines...
+ cacheHub.getCache(cacheName).removeAll();
+ }
+ else
+ {
+ // Running in a remote cache server.
+ // Remove objects via the RemoteCacheServer API, so that removes will be broadcast to client machines...
+ try
+ {
+ // Call remoteCacheServer.removeAll(String)...
+ RemoteCacheServer<?, ?> remoteCacheServer = RemoteCacheServerFactory.getRemoteCacheServer();
+ remoteCacheServer.removeAll(cacheName);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("Failed to remove all elements from cache region [" + cacheName + "]: " + e, e);
+ }
+ }
+ }
+
+ /**
+ * Removes a particular item from a particular region.
+ * <p>
+ * If this class is running within a remote cache server, removes the item via the <code>RemoteCacheServer</code>
+ * API, so that removes will be broadcast to client machines. Otherwise clears the region directly via the usual
+ * cache API.
+ *
+ * @param cacheName
+ * @param key
+ *
+ * @throws IOException
+ */
+ @Override
+ public void removeItem(String cacheName, String key) throws IOException
+ {
+ if (cacheName == null)
+ {
+ throw new IllegalArgumentException("The cache name specified was null.");
+ }
+ if (key == null)
+ {
+ throw new IllegalArgumentException("The key specified was null.");
+ }
+ if (RemoteCacheServerFactory.getRemoteCacheServer() == null)
+ {
+ // Not running in a remote cache server.
+ // Remove objects from the cache directly, as no need to broadcast removes to client machines...
+ cacheHub.getCache(cacheName).remove(key);
+ }
+ else
+ {
+ // Running in a remote cache server.
+ // Remove objects via the RemoteCacheServer API, so that removes will be broadcast to client machines...
+ try
+ {
+ Object keyToRemove = null;
+ CompositeCache<?, ?> cache = CompositeCacheManager.getInstance().getCache(cacheName);
+
+ // A String key was supplied, but to remove elements via the RemoteCacheServer API, we need the
+ // actual key object as stored in the cache (i.e. a Serializable object). To find the key in this form,
+ // we iterate through all keys stored in the memory cache until we find one whose toString matches
+ // the string supplied...
+ Set<?> allKeysInCache = cache.getMemoryCache().getKeySet();
+ for (Object keyInCache : allKeysInCache)
+ {
+ if (keyInCache.toString().equals(key))
+ {
+ if (keyToRemove == null)
+ {
+ keyToRemove = keyInCache;
+ }
+ else
+ {
+ // A key matching the one specified was already found...
+ throw new IllegalStateException("Unexpectedly found duplicate keys in the cache region matching the key specified.");
+ }
+ }
+ }
+ if (keyToRemove == null)
+ {
+ throw new IllegalStateException("No match for this key could be found in the set of keys retrieved from the memory cache.");
+ }
+ // At this point, we have retrieved the matching K key.
+
+ // Call remoteCacheServer.remove(String, Serializable)...
+ RemoteCacheServer<Serializable, Serializable> remoteCacheServer = RemoteCacheServerFactory.getRemoteCacheServer();
+ remoteCacheServer.remove(cacheName, key);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("Failed to remove element with key [" + key + ", " + key.getClass() + "] from cache region [" + cacheName + "]: " + e, e);
+ }
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/admin/JCSJMXBean.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/admin/JCSJMXBean.java
new file mode 100644
index 0000000..a686d42
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/admin/JCSJMXBean.java
@@ -0,0 +1,91 @@
+package org.apache.commons.jcs3.admin;
+
+import java.io.IOException;
+import java.util.List;
+
+/*
+ * 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.
+ */
+
+import javax.management.MXBean;
+
+/**
+ * A MXBean to expose the JCS statistics to JMX
+ */
+@MXBean
+public interface JCSJMXBean
+{
+ /**
+ * Builds up info about each element in a region.
+ * <p>
+ * @param cacheName
+ * @return List of CacheElementInfo objects
+ * @throws IOException
+ */
+ List<CacheElementInfo> buildElementInfo( String cacheName ) throws IOException;
+
+ /**
+ * Builds up data on every region.
+ * <p>
+ * TODO we need a most light weight method that does not count bytes. The byte counting can
+ * really swamp a server.
+ * @return List of CacheRegionInfo objects
+ */
+ List<CacheRegionInfo> buildCacheInfo();
+
+ /**
+ * Tries to estimate how much data is in a region. This is expensive. If there are any non serializable objects in
+ * the region or an error occurs, suppresses exceptions and returns 0.
+ * <p>
+ *
+ * @return long The size of the region in bytes.
+ */
+ long getByteCount(String cacheName);
+
+ /**
+ * Clears all regions in the cache.
+ * <p>
+ * If this class is running within a remote cache server, clears all regions via the <code>RemoteCacheServer</code>
+ * API, so that removes will be broadcast to client machines. Otherwise clears all regions in the cache directly via
+ * the usual cache API.
+ */
+ void clearAllRegions() throws IOException;
+
+ /**
+ * Clears a particular cache region.
+ * <p>
+ * If this class is running within a remote cache server, clears the region via the <code>RemoteCacheServer</code>
+ * API, so that removes will be broadcast to client machines. Otherwise clears the region directly via the usual
+ * cache API.
+ */
+ void clearRegion(String cacheName) throws IOException;
+
+ /**
+ * Removes a particular item from a particular region.
+ * <p>
+ * If this class is running within a remote cache server, removes the item via the <code>RemoteCacheServer</code>
+ * API, so that removes will be broadcast to client machines. Otherwise clears the region directly via the usual
+ * cache API.
+ *
+ * @param cacheName
+ * @param key
+ *
+ * @throws IOException
+ */
+ void removeItem(String cacheName, String key) throws IOException;
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AbstractAuxiliaryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AbstractAuxiliaryCache.java
new file mode 100644
index 0000000..8a1ed09
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AbstractAuxiliaryCache.java
@@ -0,0 +1,257 @@
+package org.apache.commons.jcs3.auxiliary;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.logging.CacheEvent;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEvent;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.engine.match.KeyMatcherPatternImpl;
+import org.apache.commons.jcs3.engine.match.behavior.IKeyMatcher;
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+
+/** This holds convenience methods used by most auxiliary caches. */
+public abstract class AbstractAuxiliaryCache<K, V>
+ implements AuxiliaryCache<K, V>
+{
+ /** An optional event logger */
+ private ICacheEventLogger cacheEventLogger;
+
+ /** The serializer. Uses a standard serializer by default. */
+ private IElementSerializer elementSerializer = new StandardSerializer();
+
+ /** Key matcher used by the getMatching API */
+ private IKeyMatcher<K> keyMatcher = new KeyMatcherPatternImpl<>();
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ *
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ */
+ protected Map<K, ICacheElement<K, V>> processGetMultiple(Set<K> keys) throws IOException
+ {
+ if (keys != null)
+ {
+ return keys.stream()
+ .map(key -> {
+ try
+ {
+ return get(key);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ })
+ .filter(element -> element != null)
+ .collect(Collectors.toMap(
+ element -> element.getKey(),
+ element -> element));
+ }
+
+ return new HashMap<>();
+ }
+
+ /**
+ * Gets the item from the cache.
+ *
+ * @param key
+ * @return ICacheElement, a wrapper around the key, value, and attributes
+ * @throws IOException
+ */
+ @Override
+ public abstract ICacheElement<K, V> get( K key ) throws IOException;
+
+ /**
+ * Logs an event if an event logger is configured.
+ * <p>
+ * @param item
+ * @param eventName
+ * @return ICacheEvent
+ */
+ protected ICacheEvent<K> createICacheEvent( ICacheElement<K, V> item, String eventName )
+ {
+ if ( cacheEventLogger == null )
+ {
+ return new CacheEvent<>();
+ }
+ String diskLocation = getEventLoggingExtraInfo();
+ String regionName = null;
+ K key = null;
+ if ( item != null )
+ {
+ regionName = item.getCacheName();
+ key = item.getKey();
+ }
+ return cacheEventLogger.createICacheEvent( getAuxiliaryCacheAttributes().getName(), regionName, eventName,
+ diskLocation, key );
+ }
+
+ /**
+ * Logs an event if an event logger is configured.
+ * <p>
+ * @param regionName
+ * @param key
+ * @param eventName
+ * @return ICacheEvent
+ */
+ protected <T> ICacheEvent<T> createICacheEvent( String regionName, T key, String eventName )
+ {
+ if ( cacheEventLogger == null )
+ {
+ return new CacheEvent<>();
+ }
+ String diskLocation = getEventLoggingExtraInfo();
+ return cacheEventLogger.createICacheEvent( getAuxiliaryCacheAttributes().getName(), regionName, eventName,
+ diskLocation, key );
+
+ }
+
+ /**
+ * Logs an event if an event logger is configured.
+ * <p>
+ * @param cacheEvent
+ */
+ protected <T> void logICacheEvent( ICacheEvent<T> cacheEvent )
+ {
+ if ( cacheEventLogger != null )
+ {
+ cacheEventLogger.logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Logs an event if an event logger is configured.
+ * <p>
+ * @param source
+ * @param eventName
+ * @param optionalDetails
+ */
+ protected void logApplicationEvent( String source, String eventName, String optionalDetails )
+ {
+ if ( cacheEventLogger != null )
+ {
+ cacheEventLogger.logApplicationEvent( source, eventName, optionalDetails );
+ }
+ }
+
+ /**
+ * Logs an event if an event logger is configured.
+ * <p>
+ * @param source
+ * @param eventName
+ * @param errorMessage
+ */
+ protected void logError( String source, String eventName, String errorMessage )
+ {
+ if ( cacheEventLogger != null )
+ {
+ cacheEventLogger.logError( source, eventName, errorMessage );
+ }
+ }
+
+ /**
+ * Gets the extra info for the event log.
+ * <p>
+ * @return IP, or disk location, etc.
+ */
+ public abstract String getEventLoggingExtraInfo();
+
+ /**
+ * Allows it to be injected.
+ * <p>
+ * @param cacheEventLogger
+ */
+ @Override
+ public void setCacheEventLogger( ICacheEventLogger cacheEventLogger )
+ {
+ this.cacheEventLogger = cacheEventLogger;
+ }
+
+ /**
+ * Allows it to be injected.
+ * <p>
+ * @return cacheEventLogger
+ */
+ public ICacheEventLogger getCacheEventLogger()
+ {
+ return this.cacheEventLogger;
+ }
+
+ /**
+ * Allows you to inject a custom serializer. A good example would be a compressing standard
+ * serializer.
+ * <p>
+ * Does not allow you to set it to null.
+ * <p>
+ * @param elementSerializer
+ */
+ @Override
+ public void setElementSerializer( IElementSerializer elementSerializer )
+ {
+ if ( elementSerializer != null )
+ {
+ this.elementSerializer = elementSerializer;
+ }
+ }
+
+ /**
+ * Allows it to be injected.
+ * <p>
+ * @return elementSerializer
+ */
+ public IElementSerializer getElementSerializer()
+ {
+ return this.elementSerializer;
+ }
+
+ /**
+ * Sets the key matcher used by get matching.
+ * <p>
+ * @param keyMatcher
+ */
+ @Override
+ public void setKeyMatcher( IKeyMatcher<K> keyMatcher )
+ {
+ if ( keyMatcher != null )
+ {
+ this.keyMatcher = keyMatcher;
+ }
+ }
+
+ /**
+ * Returns the key matcher used by get matching.
+ * <p>
+ * @return keyMatcher
+ */
+ public IKeyMatcher<K> getKeyMatcher()
+ {
+ return this.keyMatcher;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AbstractAuxiliaryCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AbstractAuxiliaryCacheAttributes.java
new file mode 100644
index 0000000..8792615
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AbstractAuxiliaryCacheAttributes.java
@@ -0,0 +1,146 @@
+package org.apache.commons.jcs3.auxiliary;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheEventQueue;
+
+/*
+ * 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.
+ */
+
+/**
+ * This has common attributes used by all auxiliaries.
+ */
+public abstract class AbstractAuxiliaryCacheAttributes
+ implements AuxiliaryCacheAttributes
+{
+ /** Don't change */
+ private static final long serialVersionUID = -6594609334959187673L;
+
+ /** cacheName */
+ private String cacheName;
+
+ /** name */
+ private String name;
+
+ /** eventQueueType -- pooled, or single threaded */
+ private ICacheEventQueue.QueueType eventQueueType;
+
+ /** Named when pooled */
+ private String eventQueuePoolName;
+
+ /**
+ * @param name
+ */
+ @Override
+ public void setCacheName( String name )
+ {
+ this.cacheName = name;
+ }
+
+ /**
+ * Gets the cacheName attribute of the AuxiliaryCacheAttributes object
+ * <p>
+ * @return The cacheName value
+ */
+ @Override
+ public String getCacheName()
+ {
+ return this.cacheName;
+ }
+
+ /**
+ * This is the name of the auxiliary in configuration file.
+ * <p>
+ * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes#setName(java.lang.String)
+ */
+ @Override
+ public void setName( String s )
+ {
+ this.name = s;
+ }
+
+ /**
+ * Gets the name attribute of the AuxiliaryCacheAttributes object
+ * <p>
+ * @return The name value
+ */
+ @Override
+ public String getName()
+ {
+ return this.name;
+ }
+
+ /**
+ * SINGLE is the default. If you choose POOLED, the value of EventQueuePoolName will be used
+ * <p>
+ * @param queueType SINGLE or POOLED
+ */
+ @Override
+ public void setEventQueueType( ICacheEventQueue.QueueType queueType )
+ {
+ this.eventQueueType = queueType;
+ }
+
+ /**
+ * @return SINGLE or POOLED
+ */
+ @Override
+ public ICacheEventQueue.QueueType getEventQueueType()
+ {
+ return eventQueueType;
+ }
+
+ /**
+ * If you choose a POOLED event queue type, the value of EventQueuePoolName will be used. This
+ * is ignored if the pool type is SINGLE
+ * <p>
+ * @param s SINGLE or POOLED
+ */
+ @Override
+ public void setEventQueuePoolName( String s )
+ {
+ eventQueuePoolName = s;
+ }
+
+ /**
+ * Sets the pool name to use. If a pool is not found by this name, the thread pool manager will
+ * return a default configuration.
+ * <p>
+ * @return name of thread pool to use for this auxiliary
+ */
+ @Override
+ public String getEventQueuePoolName()
+ {
+ return eventQueuePoolName;
+ }
+
+ /**
+ * @see java.lang.Object#clone()
+ */
+ @Override
+ public AbstractAuxiliaryCacheAttributes clone()
+ {
+ try
+ {
+ return (AbstractAuxiliaryCacheAttributes)super.clone();
+ }
+ catch (CloneNotSupportedException e)
+ {
+ throw new RuntimeException("Clone not supported. This should never happen.", e);
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AbstractAuxiliaryCacheEventLogging.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AbstractAuxiliaryCacheEventLogging.java
new file mode 100644
index 0000000..8b78f3b
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AbstractAuxiliaryCacheEventLogging.java
@@ -0,0 +1,342 @@
+package org.apache.commons.jcs3.auxiliary;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEvent;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+
+/**
+ * All ICacheEvents are defined as final. Children must implement process events. These are wrapped
+ * in event log parent calls.
+ *
+ * You can override the public method, but if you don't, the default will call getWithTiming.
+ */
+public abstract class AbstractAuxiliaryCacheEventLogging<K, V>
+ extends AbstractAuxiliaryCache<K, V>
+{
+ /**
+ * Puts an item into the cache.
+ *
+ * @param cacheElement
+ * @throws IOException
+ */
+ @Override
+ public void update( ICacheElement<K, V> cacheElement )
+ throws IOException
+ {
+ updateWithEventLogging( cacheElement );
+ }
+
+ /**
+ * Puts an item into the cache. Wrapped in logging.
+ *
+ * @param cacheElement
+ * @throws IOException
+ */
+ protected final void updateWithEventLogging( ICacheElement<K, V> cacheElement )
+ throws IOException
+ {
+ ICacheEvent<K> cacheEvent = createICacheEvent( cacheElement, ICacheEventLogger.UPDATE_EVENT );
+ try
+ {
+ processUpdate( cacheElement );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Implementation of put.
+ *
+ * @param cacheElement
+ * @throws IOException
+ */
+ protected abstract void processUpdate( ICacheElement<K, V> cacheElement )
+ throws IOException;
+
+ /**
+ * Gets the item from the cache.
+ *
+ * @param key
+ * @return ICacheElement, a wrapper around the key, value, and attributes
+ * @throws IOException
+ */
+ @Override
+ public ICacheElement<K, V> get( K key )
+ throws IOException
+ {
+ return getWithEventLogging( key );
+ }
+
+ /**
+ * Gets the item from the cache. Wrapped in logging.
+ *
+ * @param key
+ * @return ICacheElement, a wrapper around the key, value, and attributes
+ * @throws IOException
+ */
+ protected final ICacheElement<K, V> getWithEventLogging( K key )
+ throws IOException
+ {
+ ICacheEvent<K> cacheEvent = createICacheEvent( getCacheName(), key, ICacheEventLogger.GET_EVENT );
+ try
+ {
+ return processGet( key );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Implementation of get.
+ *
+ * @param key
+ * @return ICacheElement, a wrapper around the key, value, and attributes
+ * @throws IOException
+ */
+ protected abstract ICacheElement<K, V> processGet( K key )
+ throws IOException;
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ *
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
+ throws IOException
+ {
+ return getMultipleWithEventLogging( keys );
+ }
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ *
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ * @throws IOException
+ */
+ protected final Map<K, ICacheElement<K, V>> getMultipleWithEventLogging(Set<K> keys )
+ throws IOException
+ {
+ ICacheEvent<Serializable> cacheEvent = createICacheEvent( getCacheName(), (Serializable) keys,
+ ICacheEventLogger.GETMULTIPLE_EVENT );
+ try
+ {
+ return processGetMultiple( keys );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Gets items from the cache matching the given pattern. Items from memory will replace those
+ * from remote sources.
+ *
+ * This only works with string keys. It's too expensive to do a toString on every key.
+ *
+ * Auxiliaries will do their best to handle simple expressions. For instance, the JDBC disk
+ * cache will convert * to % and . to _
+ *
+ * @param pattern
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data matching the pattern.
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching( String pattern )
+ throws IOException
+ {
+ return getMatchingWithEventLogging( pattern );
+ }
+
+ /**
+ * Gets matching items from the cache based on the given pattern.
+ *
+ * @param pattern
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data matching the pattern.
+ * @throws IOException
+ */
+ protected final Map<K, ICacheElement<K, V>> getMatchingWithEventLogging( String pattern )
+ throws IOException
+ {
+ ICacheEvent<String> cacheEvent = createICacheEvent( getCacheName(), pattern, ICacheEventLogger.GETMATCHING_EVENT );
+ try
+ {
+ return processGetMatching( pattern );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Implementation of getMatching.
+ *
+ * @param pattern
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data matching the pattern.
+ * @throws IOException
+ */
+ protected abstract Map<K, ICacheElement<K, V>> processGetMatching( String pattern )
+ throws IOException;
+
+ /**
+ * Removes the item from the cache. Wraps the remove in event logs.
+ *
+ * @param key
+ * @return boolean, whether or not the item was removed
+ * @throws IOException
+ */
+ @Override
+ public boolean remove( K key )
+ throws IOException
+ {
+ return removeWithEventLogging( key );
+ }
+
+ /**
+ * Removes the item from the cache. Wraps the remove in event logs.
+ *
+ * @param key
+ * @return boolean, whether or not the item was removed
+ * @throws IOException
+ */
+ protected final boolean removeWithEventLogging( K key )
+ throws IOException
+ {
+ ICacheEvent<K> cacheEvent = createICacheEvent( getCacheName(), key, ICacheEventLogger.REMOVE_EVENT );
+ try
+ {
+ return processRemove( key );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Specific implementation of remove.
+ *
+ * @param key
+ * @return boolean, whether or not the item was removed
+ * @throws IOException
+ */
+ protected abstract boolean processRemove( K key )
+ throws IOException;
+
+ /**
+ * Removes all from the region. Wraps the removeAll in event logs.
+ *
+ * @throws IOException
+ */
+ @Override
+ public void removeAll()
+ throws IOException
+ {
+ removeAllWithEventLogging();
+ }
+
+ /**
+ * Removes all from the region. Wraps the removeAll in event logs.
+ *
+ * @throws IOException
+ */
+ protected final void removeAllWithEventLogging()
+ throws IOException
+ {
+ ICacheEvent<String> cacheEvent = createICacheEvent( getCacheName(), "all", ICacheEventLogger.REMOVEALL_EVENT );
+ try
+ {
+ processRemoveAll();
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Specific implementation of removeAll.
+ *
+ * @throws IOException
+ */
+ protected abstract void processRemoveAll()
+ throws IOException;
+
+ /**
+ * Synchronously dispose the remote cache; if failed, replace the remote handle with a zombie.
+ *
+ * @throws IOException
+ */
+ @Override
+ public void dispose()
+ throws IOException
+ {
+ disposeWithEventLogging();
+ }
+
+ /**
+ * Synchronously dispose the remote cache; if failed, replace the remote handle with a zombie.
+ * Wraps the removeAll in event logs.
+ *
+ * @throws IOException
+ */
+ protected final void disposeWithEventLogging()
+ throws IOException
+ {
+ ICacheEvent<String> cacheEvent = createICacheEvent( getCacheName(), "none", ICacheEventLogger.DISPOSE_EVENT );
+ try
+ {
+ processDispose();
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Specific implementation of dispose.
+ *
+ * @throws IOException
+ */
+ protected abstract void processDispose()
+ throws IOException;
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AbstractAuxiliaryCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AbstractAuxiliaryCacheFactory.java
new file mode 100644
index 0000000..1399e4f
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AbstractAuxiliaryCacheFactory.java
@@ -0,0 +1,72 @@
+package org.apache.commons.jcs3.auxiliary;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheFactory;
+
+/**
+ * Base class for auxiliary cache factories.
+ */
+public abstract class AbstractAuxiliaryCacheFactory
+ implements AuxiliaryCacheFactory
+{
+ /** The auxiliary name. The composite cache manager keeps this in a map, keyed by name. */
+ private String name = this.getClass().getSimpleName();
+
+ /**
+ * Initialize this factory
+ */
+ @Override
+ public void initialize()
+ {
+ // empty
+ }
+
+ /**
+ * Dispose of this factory, clean up shared resources
+ */
+ @Override
+ public void dispose()
+ {
+ // empty
+ }
+
+ /**
+ * Gets the name attribute of the DiskCacheFactory object
+ * <p>
+ * @return The name value
+ */
+ @Override
+ public String getName()
+ {
+ return this.name;
+ }
+
+ /**
+ * Sets the name attribute of the DiskCacheFactory object
+ * <p>
+ * @param name The new name value
+ */
+ @Override
+ public void setName( String name )
+ {
+ this.name = name;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AbstractAuxiliaryCacheMonitor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AbstractAuxiliaryCacheMonitor.java
new file mode 100644
index 0000000..2595ddd
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AbstractAuxiliaryCacheMonitor.java
@@ -0,0 +1,197 @@
+package org.apache.commons.jcs3.auxiliary;
+
+/*
+ * 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.
+ */
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * Used to monitor and repair any failed connection for the lateral cache service. By default the
+ * monitor operates in a failure driven mode. That is, it goes into a wait state until there is an
+ * error. Upon the notification of a connection error, the monitor changes to operate in a time
+ * driven mode. That is, it attempts to recover the connections on a periodic basis. When all failed
+ * connections are restored, it changes back to the failure driven mode.
+ */
+public abstract class AbstractAuxiliaryCacheMonitor extends Thread
+{
+ /** The logger */
+ protected final Log log = LogManager.getLog( this.getClass() );
+
+ /** How long to wait between runs */
+ protected static long idlePeriod = 20 * 1000;
+
+ /**
+ * Must make sure AbstractAuxiliaryCacheMonitor is started before any error can be detected!
+ */
+ protected AtomicBoolean allright = new AtomicBoolean(true);
+
+ /**
+ * shutdown flag
+ */
+ private final AtomicBoolean shutdown = new AtomicBoolean(false);
+
+ /** Synchronization helper lock */
+ private final Lock lock = new ReentrantLock();
+
+ /** Synchronization helper condition */
+ private final Condition trigger = lock.newCondition();
+
+ /**
+ * Constructor
+ *
+ * @param name the thread name
+ */
+ public AbstractAuxiliaryCacheMonitor(String name)
+ {
+ super(name);
+ }
+
+ /**
+ * Configures the idle period between repairs.
+ * <p>
+ * @param idlePeriod The new idlePeriod value
+ */
+ public static void setIdlePeriod( long idlePeriod )
+ {
+ if ( idlePeriod > AbstractAuxiliaryCacheMonitor.idlePeriod )
+ {
+ AbstractAuxiliaryCacheMonitor.idlePeriod = idlePeriod;
+ }
+ }
+
+ /**
+ * Notifies the cache monitor that an error occurred, and kicks off the error recovery process.
+ */
+ public void notifyError()
+ {
+ if (allright.compareAndSet(true, false))
+ {
+ signalTrigger();
+ }
+ }
+
+ /**
+ * Notifies the cache monitor that the service shall shut down
+ */
+ public void notifyShutdown()
+ {
+ if (shutdown.compareAndSet(false, true))
+ {
+ signalTrigger();
+ }
+ }
+
+ // Trigger continuation of loop
+ private void signalTrigger()
+ {
+ try
+ {
+ lock.lock();
+ trigger.signal();
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Clean up all resources before shutdown
+ */
+ protected abstract void dispose();
+
+ /**
+ * do actual work
+ */
+ protected abstract void doWork();
+
+ /**
+ * Main processing method for the AbstractAuxiliaryCacheMonitor object
+ */
+ @Override
+ public void run()
+ {
+ do
+ {
+ if ( allright.get() )
+ {
+ log.debug( "ERROR DRIVEN MODE: allright = true, cache monitor will wait for an error." );
+ }
+ else
+ {
+ log.debug( "ERROR DRIVEN MODE: allright = false cache monitor running." );
+ }
+
+ if ( allright.get() )
+ {
+ // Failure driven mode.
+ try
+ {
+ lock.lock();
+ trigger.await();
+ // wake up only if there is an error.
+ }
+ catch ( InterruptedException ignore )
+ {
+ //no op, this is expected
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+
+ // check for requested shutdown
+ if ( shutdown.get() )
+ {
+ log.info( "Shutting down cache monitor" );
+ dispose();
+ return;
+ }
+
+ // The "allright" flag must be false here.
+ // Simply presume we can fix all the errors until proven otherwise.
+ allright.set(true);
+
+ log.debug( "Cache monitor running." );
+
+ doWork();
+
+ try
+ {
+ // don't want to sleep after waking from an error
+ // run immediately and sleep here.
+ log.debug( "Cache monitor sleeping for {0} between runs.", idlePeriod );
+
+ Thread.sleep( idlePeriod );
+ }
+ catch ( InterruptedException ex )
+ {
+ // ignore;
+ }
+ }
+ while ( true );
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AuxiliaryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AuxiliaryCache.java
new file mode 100644
index 0000000..72ab8ce
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AuxiliaryCache.java
@@ -0,0 +1,77 @@
+package org.apache.commons.jcs3.auxiliary;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.Set;
+
+import org.apache.commons.jcs3.engine.behavior.ICache;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+
+/**
+ * Tag interface for auxiliary caches. Currently this provides no additional methods over what is in
+ * ICache, but I anticipate that will change. For example, there will be a mechanism for determining
+ * the type (disk/lateral/remote) of the auxiliary here -- and the existing getCacheType will be
+ * removed from ICache.
+ */
+public interface AuxiliaryCache<K, V>
+ extends ICache<K, V>
+{
+ /**
+ * Get a set of the keys for all elements in the auxiliary cache.
+ * <p>
+ * @return a set of the key type
+ * TODO This should probably be done in chunks with a range passed in. This
+ * will be a problem if someone puts a 1,000,000 or so items in a
+ * region.
+ * @throws IOException if access to the auxiliary cache fails
+ */
+ Set<K> getKeySet() throws IOException;
+
+ /**
+ * @return the historical and statistical data for a region's auxiliary cache.
+ */
+ IStats getStatistics();
+
+ /**
+ * This returns the generic attributes for an auxiliary cache. Most implementations will cast
+ * this to a more specific type.
+ * <p>
+ * @return the attributes for the auxiliary cache
+ */
+ AuxiliaryCacheAttributes getAuxiliaryCacheAttributes();
+
+ /**
+ * Allows you to inject a custom serializer. A good example would be a compressing standard
+ * serializer.
+ * <p>
+ * @param elementSerializer
+ */
+ void setElementSerializer( IElementSerializer elementSerializer );
+
+ /**
+ * Every Auxiliary must allow for the use of an event logger.
+ * <p>
+ * @param cacheEventLogger
+ */
+ void setCacheEventLogger( ICacheEventLogger cacheEventLogger );
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AuxiliaryCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AuxiliaryCacheAttributes.java
new file mode 100644
index 0000000..314831a
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AuxiliaryCacheAttributes.java
@@ -0,0 +1,93 @@
+package org.apache.commons.jcs3.auxiliary;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheEventQueue;
+
+/**
+ * This is a nominal interface that auxiliary cache attributes should implement. This allows the
+ * auxiliary mangers to share a common interface.
+ */
+public interface AuxiliaryCacheAttributes
+ extends Serializable, Cloneable
+{
+ /**
+ * Sets the name of the cache, referenced by the appropriate manager.
+ * <p>
+ * @param s The new cacheName value
+ */
+ void setCacheName( String s );
+
+ /**
+ * Gets the cacheName attribute of the AuxiliaryCacheAttributes object
+ * <p>
+ * @return The cacheName value
+ */
+ String getCacheName();
+
+ /**
+ * Name known by by configurator
+ * <p>
+ * @param s The new name value
+ */
+ void setName( String s );
+
+ /**
+ * Gets the name attribute of the AuxiliaryCacheAttributes object
+ * <p>
+ * @return The name value
+ */
+ String getName();
+
+ /**
+ * SINGLE is the default. If you choose POOLED, the value of EventQueuePoolName will be used
+ * <p>
+ * @param s SINGLE or POOLED
+ */
+ void setEventQueueType( ICacheEventQueue.QueueType s );
+
+ /**
+ * @return SINGLE or POOLED
+ */
+ ICacheEventQueue.QueueType getEventQueueType();
+
+ /**
+ * If you choose a POOLED event queue type, the value of EventQueuePoolName will be used. This
+ * is ignored if the pool type is SINGLE
+ * <p>
+ * @param s SINGLE or POOLED
+ */
+ void setEventQueuePoolName( String s );
+
+ /**
+ * Sets the pool name to use. If a pool is not found by this name, the thread pool manager will
+ * return a default configuration.
+ * <p>
+ * @return name of thread pool to use for this auxiliary
+ */
+ String getEventQueuePoolName();
+
+ /**
+ * Clone object
+ */
+ AuxiliaryCacheAttributes clone();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AuxiliaryCacheConfigurator.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AuxiliaryCacheConfigurator.java
new file mode 100644
index 0000000..2610785
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AuxiliaryCacheConfigurator.java
@@ -0,0 +1,117 @@
+package org.apache.commons.jcs3.auxiliary;
+
+/*
+ * 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.
+ */
+
+import java.util.Properties;
+
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.config.OptionConverter;
+import org.apache.commons.jcs3.utils.config.PropertySetter;
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+
+/**
+ * Configuration util for auxiliary caches. I plan to move the auxiliary configuration from the
+ * composite cache configurator here.
+ */
+public class AuxiliaryCacheConfigurator
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog( AuxiliaryCacheConfigurator.class );
+
+ /** .attributes */
+ public static final String ATTRIBUTE_PREFIX = ".attributes";
+
+ /**
+ * jcs.auxiliary.NAME.cacheeventlogger=CLASSNAME
+ * <p>
+ * jcs.auxiliary.NAME.cacheeventlogger.attributes.CUSTOMPROPERTY=VALUE
+ */
+ public static final String CACHE_EVENT_LOGGER_PREFIX = ".cacheeventlogger";
+
+ /**
+ * jcs.auxiliary.NAME.serializer=CLASSNAME
+ * <p>
+ * jcs.auxiliary.NAME.serializer.attributes.CUSTOMPROPERTY=VALUE
+ */
+ public static final String SERIALIZER_PREFIX = ".serializer";
+
+ /**
+ * Parses the event logger config, if there is any for the auxiliary.
+ * <p>
+ * @param props
+ * @param auxPrefix - ex. AUXILIARY_PREFIX + auxName
+ * @return cacheEventLogger
+ */
+ public static ICacheEventLogger parseCacheEventLogger( Properties props, String auxPrefix )
+ {
+ ICacheEventLogger cacheEventLogger = null;
+
+ // auxFactory was not previously initialized.
+ String eventLoggerClassName = auxPrefix + CACHE_EVENT_LOGGER_PREFIX;
+ cacheEventLogger = OptionConverter.instantiateByKey( props, eventLoggerClassName, null );
+ if ( cacheEventLogger != null )
+ {
+ String cacheEventLoggerAttributePrefix = auxPrefix + CACHE_EVENT_LOGGER_PREFIX + ATTRIBUTE_PREFIX;
+ PropertySetter.setProperties( cacheEventLogger, props, cacheEventLoggerAttributePrefix + "." );
+ log.info( "Using custom cache event logger [{0}] for auxiliary [{1}]",
+ cacheEventLogger, auxPrefix );
+ }
+ else
+ {
+ log.info( "No cache event logger defined for auxiliary [{0}]", auxPrefix );
+ }
+ return cacheEventLogger;
+ }
+
+ /**
+ * Parses the element config, if there is any for the auxiliary.
+ * <p>
+ * @param props
+ * @param auxPrefix - ex. AUXILIARY_PREFIX + auxName
+ * @return cacheEventLogger
+ */
+ public static IElementSerializer parseElementSerializer( Properties props, String auxPrefix )
+ {
+ // TODO take in the entire prop key
+ IElementSerializer elementSerializer = null;
+
+ // auxFactory was not previously initialized.
+ String elementSerializerClassName = auxPrefix + SERIALIZER_PREFIX;
+ elementSerializer = OptionConverter.instantiateByKey( props, elementSerializerClassName, null );
+ if ( elementSerializer != null )
+ {
+ String attributePrefix = auxPrefix + SERIALIZER_PREFIX + ATTRIBUTE_PREFIX;
+ PropertySetter.setProperties( elementSerializer, props, attributePrefix + "." );
+ log.info( "Using custom element serializer [{0}] for auxiliary [{1}]",
+ elementSerializer, auxPrefix );
+ }
+ else
+ {
+ // use the default standard serializer
+ elementSerializer = new StandardSerializer();
+ log.info( "Using standard serializer [{0}] for auxiliary [{1}]",
+ elementSerializer, auxPrefix );
+ }
+ return elementSerializer;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AuxiliaryCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AuxiliaryCacheFactory.java
new file mode 100644
index 0000000..ffaf2ae
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/AuxiliaryCacheFactory.java
@@ -0,0 +1,71 @@
+package org.apache.commons.jcs3.auxiliary;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+
+/**
+ * All auxiliary caches must have a factory that the cache configurator can use to create instances.
+ */
+public interface AuxiliaryCacheFactory
+{
+ /**
+ * Creates an auxiliary using the supplied attributes. Adds it to the composite cache manager.
+ *
+ * @param attr
+ * @param cacheMgr This allows auxiliaries to reference the manager without assuming that it is
+ * a singleton. This will allow JCS to be a non-singleton. Also, it makes it easier to
+ * test.
+ * @param cacheEventLogger
+ * @param elementSerializer
+ * @return AuxiliaryCache
+ * @throws Exception if cache instance could not be created
+ */
+ <K, V> AuxiliaryCache<K, V> createCache(
+ AuxiliaryCacheAttributes attr, ICompositeCacheManager cacheMgr,
+ ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
+ throws Exception;
+
+ /**
+ * Initialize this factory
+ */
+ void initialize();
+
+ /**
+ * Dispose of this factory, clean up shared resources
+ */
+ void dispose();
+
+ /**
+ * Sets the name attribute of the AuxiliaryCacheFactory object
+ *
+ * @param s The new name value
+ */
+ void setName( String s );
+
+ /**
+ * Gets the name attribute of the AuxiliaryCacheFactory object
+ *
+ * @return The name value
+ */
+ String getName();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/AbstractDiskCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/AbstractDiskCache.java
new file mode 100644
index 0000000..d4c9308
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/AbstractDiskCache.java
@@ -0,0 +1,840 @@
+package org.apache.commons.jcs3.auxiliary.disk;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheEventLogging;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.disk.behavior.IDiskCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheEventQueueFactory;
+import org.apache.commons.jcs3.engine.CacheInfo;
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.behavior.ICache;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheEventQueue;
+import org.apache.commons.jcs3.engine.behavior.ICacheListener;
+import org.apache.commons.jcs3.engine.stats.StatElement;
+import org.apache.commons.jcs3.engine.stats.Stats;
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.struct.LRUMap;
+
+/**
+ * Abstract class providing a base implementation of a disk cache, which can be easily extended to
+ * implement a disk cache for a specific persistence mechanism.
+ *
+ * When implementing the abstract methods note that while this base class handles most things, it
+ * does not acquire or release any locks. Implementations should do so as necessary. This is mainly
+ * done to minimize the time spent in critical sections.
+ *
+ * Error handling in this class needs to be addressed. Currently if an exception is thrown by the
+ * persistence mechanism, this class destroys the event queue. Should it also destroy purgatory?
+ * Should it dispose itself?
+ */
+public abstract class AbstractDiskCache<K, V>
+ extends AbstractAuxiliaryCacheEventLogging<K, V>
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( AbstractDiskCache.class );
+
+ /** Generic disk cache attributes */
+ private IDiskCacheAttributes diskCacheAttributes = null;
+
+ /**
+ * Map where elements are stored between being added to this cache and actually spooled to disk.
+ * This allows puts to the disk cache to return quickly, and the more expensive operation of
+ * serializing the elements to persistent storage queued for later.
+ *
+ * If the elements are pulled into the memory cache while the are still in purgatory, writing to
+ * disk can be canceled.
+ */
+ private Map<K, PurgatoryElement<K, V>> purgatory;
+
+ /**
+ * The CacheEventQueue where changes will be queued for asynchronous updating of the persistent
+ * storage.
+ */
+ private final ICacheEventQueue<K, V> cacheEventQueue;
+
+ /**
+ * Indicates whether the cache is 'alive': initialized, but not yet disposed. Child classes must
+ * set this to true.
+ */
+ private boolean alive = false;
+
+ /** Every cache will have a name, subclasses must set this when they are initialized. */
+ private final String cacheName;
+
+ /** DEBUG: Keeps a count of the number of purgatory hits for debug messages */
+ private int purgHits = 0;
+
+ /**
+ * We lock here, so that we cannot get an update after a remove all. an individual removal locks
+ * the item.
+ */
+ private final ReentrantReadWriteLock removeAllLock = new ReentrantReadWriteLock();
+
+ // ----------------------------------------------------------- constructors
+
+ /**
+ * Construct the abstract disk cache, create event queues and purgatory. Child classes should
+ * set the alive flag to true after they are initialized.
+ *
+ * @param attr
+ */
+ protected AbstractDiskCache( IDiskCacheAttributes attr )
+ {
+ this.diskCacheAttributes = attr;
+ this.cacheName = attr.getCacheName();
+
+ // create queue
+ CacheEventQueueFactory<K, V> fact = new CacheEventQueueFactory<>();
+ this.cacheEventQueue = fact.createCacheEventQueue( new MyCacheListener(), CacheInfo.listenerId, cacheName,
+ diskCacheAttributes.getEventQueuePoolName(),
+ diskCacheAttributes.getEventQueueType() );
+
+ // create purgatory
+ initPurgatory();
+ }
+
+ /**
+ * @return true if the cache is alive
+ */
+ public boolean isAlive()
+ {
+ return alive;
+ }
+
+ /**
+ * @param alive set the alive status
+ */
+ public void setAlive(boolean alive)
+ {
+ this.alive = alive;
+ }
+
+ /**
+ * Purgatory size of -1 means to use a HashMap with no size limit. Anything greater will use an
+ * LRU map of some sort.
+ *
+ * TODO Currently setting this to 0 will cause nothing to be put to disk, since it will assume
+ * that if an item is not in purgatory, then it must have been plucked. We should make 0
+ * work, a way to not use purgatory.
+ */
+ private void initPurgatory()
+ {
+ // we need this so we can stop the updates from happening after a
+ // removeall
+ removeAllLock.writeLock().lock();
+
+ try
+ {
+ synchronized (this)
+ {
+ if ( diskCacheAttributes.getMaxPurgatorySize() >= 0 )
+ {
+ purgatory = new LRUMap<>( diskCacheAttributes.getMaxPurgatorySize() );
+ }
+ else
+ {
+ purgatory = new HashMap<>();
+ }
+ }
+ }
+ finally
+ {
+ removeAllLock.writeLock().unlock();
+ }
+ }
+
+ // ------------------------------------------------------- interface ICache
+
+ /**
+ * Adds the provided element to the cache. Element will be added to purgatory, and then queued
+ * for later writing to the serialized storage mechanism.
+ *
+ * An update results in a put event being created. The put event will call the handlePut method
+ * defined here. The handlePut method calls the implemented doPut on the child.
+ *
+ * @param cacheElement
+ * @throws IOException
+ * @see org.apache.commons.jcs3.engine.behavior.ICache#update
+ */
+ @Override
+ public final void update( ICacheElement<K, V> cacheElement )
+ throws IOException
+ {
+ log.debug( "Putting element in purgatory, cacheName: {0}, key: {1}",
+ () -> cacheName, () -> cacheElement.getKey() );
+
+ try
+ {
+ // Wrap the CacheElement in a PurgatoryElement
+ PurgatoryElement<K, V> pe = new PurgatoryElement<>( cacheElement );
+
+ // Indicates the the element is eligible to be spooled to disk,
+ // this will remain true unless the item is pulled back into
+ // memory.
+ pe.setSpoolable( true );
+
+ // Add the element to purgatory
+ synchronized ( purgatory )
+ {
+ purgatory.put( pe.getKey(), pe );
+ }
+
+ // Queue element for serialization
+ cacheEventQueue.addPutEvent( pe );
+ }
+ catch ( IOException ex )
+ {
+ log.error( "Problem adding put event to queue.", ex );
+
+ cacheEventQueue.destroy();
+ }
+ }
+
+ /**
+ * Check to see if the item is in purgatory. If so, return it. If not, check to see if we have
+ * it on disk.
+ *
+ * @param key
+ * @return ICacheElement<K, V> or null
+ * @see AuxiliaryCache#get
+ */
+ @Override
+ public final ICacheElement<K, V> get( K key )
+ {
+ // If not alive, always return null.
+
+ if ( !alive )
+ {
+ log.debug( "get was called, but the disk cache is not alive." );
+ return null;
+ }
+
+ PurgatoryElement<K, V> pe = null;
+ synchronized ( purgatory )
+ {
+ pe = purgatory.get( key );
+ }
+
+ // If the element was found in purgatory
+ if ( pe != null )
+ {
+ purgHits++;
+
+ if ( purgHits % 100 == 0 )
+ {
+ log.debug( "Purgatory hits = {0}", purgHits );
+ }
+
+ // Since the element will go back to the memory cache, we could set
+ // spoolable to false, which will prevent the queue listener from
+ // serializing the element. This would not match the disk cache
+ // behavior and the behavior of other auxiliaries. Gets never remove
+ // items from auxiliaries.
+ // Beyond consistency, the items should stay in purgatory and get
+ // spooled since the mem cache may be set to 0. If an item is
+ // active, it will keep getting put into purgatory and removed. The
+ // CompositeCache now does not put an item to memory from disk if
+ // the size is 0.
+ // Do not set spoolable to false. Just let it go to disk. This
+ // will allow the memory size = 0 setting to work well.
+
+ log.debug( "Found element in purgatory, cacheName: {0}, key: {1}",
+ cacheName, key );
+
+ return pe.getCacheElement();
+ }
+
+ // If we reach this point, element was not found in purgatory, so get
+ // it from the cache.
+ try
+ {
+ return doGet( key );
+ }
+ catch ( Exception e )
+ {
+ log.error( e );
+
+ cacheEventQueue.destroy();
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets items from the cache matching the given pattern. Items from memory will replace those
+ * from remote sources.
+ *
+ * This only works with string keys. It's too expensive to do a toString on every key.
+ *
+ * Auxiliaries will do their best to handle simple expressions. For instance, the JDBC disk
+ * cache will convert * to % and . to _
+ *
+ * @param pattern
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data matching the pattern.
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching( String pattern )
+ throws IOException
+ {
+ // Get the keys from purgatory
+ Set<K> keyArray = null;
+
+ // this avoids locking purgatory, but it uses more memory
+ synchronized ( purgatory )
+ {
+ keyArray = new HashSet<>(purgatory.keySet());
+ }
+
+ Set<K> matchingKeys = getKeyMatcher().getMatchingKeysFromArray( pattern, keyArray );
+
+ // call getMultiple with the set
+ Map<K, ICacheElement<K, V>> result = processGetMultiple( matchingKeys );
+
+ // Get the keys from disk
+ Map<K, ICacheElement<K, V>> diskMatches = doGetMatching( pattern );
+
+ result.putAll( diskMatches );
+
+ return result;
+ }
+
+ /**
+ * The keys in the cache.
+ *
+ * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCache#getKeySet()
+ */
+ @Override
+ public abstract Set<K> getKeySet() throws IOException;
+
+ /**
+ * Removes are not queued. A call to remove is immediate.
+ *
+ * @param key
+ * @return whether the item was present to be removed.
+ * @throws IOException
+ * @see org.apache.commons.jcs3.engine.behavior.ICache#remove
+ */
+ @Override
+ public final boolean remove( K key )
+ throws IOException
+ {
+ PurgatoryElement<K, V> pe = null;
+
+ synchronized ( purgatory )
+ {
+ // I'm getting the object, so I can lock on the element
+ // Remove element from purgatory if it is there
+ pe = purgatory.get( key );
+ }
+
+ if ( pe != null )
+ {
+ synchronized ( pe.getCacheElement() )
+ {
+ synchronized ( purgatory )
+ {
+ purgatory.remove( key );
+ }
+
+ // no way to remove from queue, just make sure it doesn't get on
+ // disk and then removed right afterwards
+ pe.setSpoolable( false );
+
+ // Remove from persistent store immediately
+ doRemove( key );
+ }
+ }
+ else
+ {
+ // Remove from persistent store immediately
+ doRemove( key );
+ }
+
+ return false;
+ }
+
+ /**
+ * @throws IOException
+ * @see org.apache.commons.jcs3.engine.behavior.ICache#removeAll
+ */
+ @Override
+ public final void removeAll()
+ throws IOException
+ {
+ if ( this.diskCacheAttributes.isAllowRemoveAll() )
+ {
+ // Replace purgatory with a new empty hashtable
+ initPurgatory();
+
+ // Remove all from persistent store immediately
+ doRemoveAll();
+ }
+ else
+ {
+ log.info( "RemoveAll was requested but the request was not "
+ + "fulfilled: allowRemoveAll is set to false." );
+ }
+ }
+
+ /**
+ * Adds a dispose request to the disk cache.
+ *
+ * Disposal proceeds in several steps.
+ * <ol>
+ * <li>Prior to this call the Composite cache dumped the memory into the disk cache. If it is
+ * large then we need to wait for the event queue to finish.</li>
+ * <li>Wait until the event queue is empty of until the configured ShutdownSpoolTimeLimit is
+ * reached.</li>
+ * <li>Call doDispose on the concrete impl.</li>
+ * </ol>
+ * @throws IOException
+ */
+ @Override
+ public final void dispose()
+ throws IOException
+ {
+ Thread t = new Thread(() ->
+ {
+ boolean keepGoing = true;
+ // long total = 0;
+ long interval = 100;
+ while ( keepGoing )
+ {
+ keepGoing = !cacheEventQueue.isEmpty();
+ try
+ {
+ Thread.sleep( interval );
+ // total += interval;
+ // log.info( "total = " + total );
+ }
+ catch ( InterruptedException e )
+ {
+ break;
+ }
+ }
+ log.info( "No longer waiting for event queue to finish: {0}",
+ () -> cacheEventQueue.getStatistics() );
+ });
+ t.start();
+ // wait up to 60 seconds for dispose and then quit if not done.
+ try
+ {
+ t.join( this.diskCacheAttributes.getShutdownSpoolTimeLimit() * 1000L );
+ }
+ catch ( InterruptedException ex )
+ {
+ log.error( "The Shutdown Spool Process was interrupted.", ex );
+ }
+
+ log.info( "In dispose, destroying event queue." );
+ // This stops the processor thread.
+ cacheEventQueue.destroy();
+
+ // Invoke any implementation specific disposal code
+ // need to handle the disposal first.
+ doDispose();
+
+ alive = false;
+ }
+
+ /**
+ * @return the region name.
+ * @see ICache#getCacheName
+ */
+ @Override
+ public String getCacheName()
+ {
+ return cacheName;
+ }
+
+ /**
+ * Gets basic stats for the abstract disk cache.
+ *
+ * @return String
+ */
+ @Override
+ public String getStats()
+ {
+ return getStatistics().toString();
+ }
+
+ /**
+ * Returns semi-structured data.
+ *
+ * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCache#getStatistics()
+ */
+ @Override
+ public IStats getStatistics()
+ {
+ IStats stats = new Stats();
+ stats.setTypeName( "Abstract Disk Cache" );
+
+ ArrayList<IStatElement<?>> elems = new ArrayList<>();
+
+ elems.add(new StatElement<>( "Purgatory Hits", Integer.valueOf(purgHits) ) );
+ elems.add(new StatElement<>( "Purgatory Size", Integer.valueOf(purgatory.size()) ) );
+
+ // get the stats from the event queue too
+ IStats eqStats = this.cacheEventQueue.getStatistics();
+ elems.addAll(eqStats.getStatElements());
+
+ stats.setStatElements( elems );
+
+ return stats;
+ }
+
+ /**
+ * @return the status -- alive or disposed from CacheConstants
+ * @see ICache#getStatus
+ */
+ @Override
+ public CacheStatus getStatus()
+ {
+ return ( alive ? CacheStatus.ALIVE : CacheStatus.DISPOSED );
+ }
+
+ /**
+ * Size cannot be determined without knowledge of the cache implementation, so subclasses will
+ * need to implement this method.
+ *
+ * @return the number of items.
+ * @see ICache#getSize
+ */
+ @Override
+ public abstract int getSize();
+
+ /**
+ * @see org.apache.commons.jcs3.engine.behavior.ICacheType#getCacheType
+ * @return Always returns DISK_CACHE since subclasses should all be of that type.
+ */
+ @Override
+ public CacheType getCacheType()
+ {
+ return CacheType.DISK_CACHE;
+ }
+
+ /**
+ * Cache that implements the CacheListener interface, and calls appropriate methods in its
+ * parent class.
+ */
+ protected class MyCacheListener
+ implements ICacheListener<K, V>
+ {
+ /** Id of the listener */
+ private long listenerId = 0;
+
+ /**
+ * @return cacheElement.getElementAttributes();
+ * @throws IOException
+ * @see ICacheListener#getListenerId
+ */
+ @Override
+ public long getListenerId()
+ throws IOException
+ {
+ return this.listenerId;
+ }
+
+ /**
+ * @param id
+ * @throws IOException
+ * @see ICacheListener#setListenerId
+ */
+ @Override
+ public void setListenerId( long id )
+ throws IOException
+ {
+ this.listenerId = id;
+ }
+
+ /**
+ * @param element
+ * @throws IOException
+ * @see ICacheListener#handlePut NOTE: This checks if the element is a puratory element and
+ * behaves differently depending. However since we have control over how elements are
+ * added to the cache event queue, that may not be needed ( they are always
+ * PurgatoryElements ).
+ */
+ @Override
+ public void handlePut( ICacheElement<K, V> element )
+ throws IOException
+ {
+ if ( alive )
+ {
+ // If the element is a PurgatoryElement<K, V> we must check to see
+ // if it is still spoolable, and remove it from purgatory.
+ if ( element instanceof PurgatoryElement )
+ {
+ PurgatoryElement<K, V> pe = (PurgatoryElement<K, V>) element;
+
+ synchronized ( pe.getCacheElement() )
+ {
+ // TODO consider a timeout.
+ // we need this so that we can have multiple update
+ // threads and still have removeAll requests come in that
+ // always win
+ removeAllLock.readLock().lock();
+
+ try
+ {
+ // TODO consider changing purgatory sync
+ // String keyAsString = element.getKey().toString();
+ synchronized ( purgatory )
+ {
+ // If the element has already been removed from
+ // purgatory do nothing
+ if ( !purgatory.containsKey( pe.getKey() ) )
+ {
+ return;
+ }
+
+ element = pe.getCacheElement();
+ }
+
+ // I took this out of the purgatory sync block.
+ // If the element is still eligible, spool it.
+ if ( pe.isSpoolable() )
+ {
+ doUpdate( element );
+ }
+ }
+ finally
+ {
+ removeAllLock.readLock().unlock();
+ }
+
+ synchronized ( purgatory )
+ {
+ // After the update has completed, it is safe to
+ // remove the element from purgatory.
+ purgatory.remove( element.getKey() );
+ }
+ }
+ }
+ else
+ {
+ // call the child's implementation
+ doUpdate( element );
+ }
+ }
+ else
+ {
+ /*
+ * The cache is not alive, hence the element should be removed from purgatory. All
+ * elements should be removed eventually. Perhaps, the alive check should have been
+ * done before it went in the queue. This block handles the case where the disk
+ * cache fails during normal operations.
+ */
+ synchronized ( purgatory )
+ {
+ purgatory.remove( element.getKey() );
+ }
+ }
+ }
+
+ /**
+ * @param cacheName
+ * @param key
+ * @throws IOException
+ * @see ICacheListener#handleRemove
+ */
+ @Override
+ public void handleRemove( String cacheName, K key )
+ throws IOException
+ {
+ if ( alive )
+ {
+ if ( doRemove( key ) )
+ {
+ log.debug( "Element removed, key: " + key );
+ }
+ }
+ }
+
+ /**
+ * @param cacheName
+ * @throws IOException
+ * @see ICacheListener#handleRemoveAll
+ */
+ @Override
+ public void handleRemoveAll( String cacheName )
+ throws IOException
+ {
+ if ( alive )
+ {
+ doRemoveAll();
+ }
+ }
+
+ /**
+ * @param cacheName
+ * @throws IOException
+ * @see ICacheListener#handleDispose
+ */
+ @Override
+ public void handleDispose( String cacheName )
+ throws IOException
+ {
+ if ( alive )
+ {
+ doDispose();
+ }
+ }
+ }
+
+ /**
+ * Before the event logging layer, the subclasses implemented the do* methods. Now the do*
+ * methods call the *WithEventLogging method on the super. The *WithEventLogging methods call
+ * the abstract process* methods. The children implement the process methods.
+ *
+ * ex. doGet calls getWithEventLogging, which calls processGet
+ */
+
+ /**
+ * Get a value from the persistent store.
+ *
+ * Before the event logging layer, the subclasses implemented the do* methods. Now the do*
+ * methods call the *EventLogging method on the super. The *WithEventLogging methods call the
+ * abstract process* methods. The children implement the process methods.
+ *
+ * @param key Key to locate value for.
+ * @return An object matching key, or null.
+ * @throws IOException
+ */
+ protected final ICacheElement<K, V> doGet( K key )
+ throws IOException
+ {
+ return super.getWithEventLogging( key );
+ }
+
+ /**
+ * Get a value from the persistent store.
+ *
+ * Before the event logging layer, the subclasses implemented the do* methods. Now the do*
+ * methods call the *EventLogging method on the super. The *WithEventLogging methods call the
+ * abstract process* methods. The children implement the process methods.
+ *
+ * @param pattern Used to match keys.
+ * @return A map of matches..
+ * @throws IOException
+ */
+ protected final Map<K, ICacheElement<K, V>> doGetMatching( String pattern )
+ throws IOException
+ {
+ return super.getMatchingWithEventLogging( pattern );
+ }
+
+ /**
+ * Add a cache element to the persistent store.
+ *
+ * Before the event logging layer, the subclasses implemented the do* methods. Now the do*
+ * methods call the *EventLogging method on the super. The *WithEventLogging methods call the
+ * abstract process* methods. The children implement the process methods.
+ *
+ * @param cacheElement
+ * @throws IOException
+ */
+ protected final void doUpdate( ICacheElement<K, V> cacheElement )
+ throws IOException
+ {
+ super.updateWithEventLogging( cacheElement );
+ }
+
+ /**
+ * Remove an object from the persistent store if found.
+ *
+ * Before the event logging layer, the subclasses implemented the do* methods. Now the do*
+ * methods call the *EventLogging method on the super. The *WithEventLogging methods call the
+ * abstract process* methods. The children implement the process methods.
+ *
+ * @param key Key of object to remove.
+ * @return whether or no the item was present when removed
+ * @throws IOException
+ */
+ protected final boolean doRemove( K key )
+ throws IOException
+ {
+ return super.removeWithEventLogging( key );
+ }
+
+ /**
+ * Remove all objects from the persistent store.
+ *
+ * Before the event logging layer, the subclasses implemented the do* methods. Now the do*
+ * methods call the *EventLogging method on the super. The *WithEventLogging methods call the
+ * abstract process* methods. The children implement the process methods.
+ *
+ * @throws IOException
+ */
+ protected final void doRemoveAll()
+ throws IOException
+ {
+ super.removeAllWithEventLogging();
+ }
+
+ /**
+ * Dispose of the persistent store. Note that disposal of purgatory and setting alive to false
+ * does NOT need to be done by this method.
+ *
+ * Before the event logging layer, the subclasses implemented the do* methods. Now the do*
+ * methods call the *EventLogging method on the super. The *WithEventLogging methods call the
+ * abstract process* methods. The children implement the process methods.
+ *
+ * @throws IOException
+ */
+ protected final void doDispose()
+ throws IOException
+ {
+ super.disposeWithEventLogging();
+ }
+
+ /**
+ * Gets the extra info for the event log.
+ *
+ * @return disk location
+ */
+ @Override
+ public String getEventLoggingExtraInfo()
+ {
+ return getDiskLocation();
+ }
+
+ /**
+ * This is used by the event logging.
+ *
+ * @return the location of the disk, either path or ip.
+ */
+ protected abstract String getDiskLocation();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/AbstractDiskCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/AbstractDiskCacheAttributes.java
new file mode 100644
index 0000000..266c922
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/AbstractDiskCacheAttributes.java
@@ -0,0 +1,221 @@
+package org.apache.commons.jcs3.auxiliary.disk;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.disk.behavior.IDiskCacheAttributes;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This has common attributes that any conceivable disk cache would need.
+ */
+public abstract class AbstractDiskCacheAttributes extends AbstractAuxiliaryCacheAttributes implements IDiskCacheAttributes
+{
+ /** Don't change. */
+ private static final long serialVersionUID = 8306631920391711229L;
+
+ /** The logger */
+ private static final Log log = LogManager.getLog(AbstractDiskCacheAttributes.class);
+
+ /** path to disk */
+ private File diskPath;
+
+ /** if this is false, we will not execute remove all */
+ private boolean allowRemoveAll = true;
+
+ /** default to 5000 */
+ private int maxPurgatorySize = MAX_PURGATORY_SIZE_DEFAULT;
+
+ /** Default amount of time to allow for key persistence on shutdown */
+ private static final int DEFAULT_shutdownSpoolTimeLimit = 60;
+
+ /**
+ * This default determines how long the shutdown will wait for the key spool and data defrag to
+ * finish.
+ */
+ private int shutdownSpoolTimeLimit = DEFAULT_shutdownSpoolTimeLimit;
+
+ /** Type of disk limit: SIZE or COUNT */
+ private DiskLimitType diskLimitType = DiskLimitType.COUNT;
+
+ /**
+ * Sets the diskPath attribute of the DiskCacheAttributes object
+ * <p>
+ *
+ * @param path
+ * The new diskPath value
+ */
+ @Override
+ public void setDiskPath(String path)
+ {
+ setDiskPath(new File(path));
+ }
+
+ /**
+ * Sets the diskPath attribute of the DiskCacheAttributes object
+ * <p>
+ *
+ * @param diskPath
+ * The new diskPath value
+ */
+ public void setDiskPath(File diskPath)
+ {
+ this.diskPath = diskPath;
+ boolean result = this.diskPath.isDirectory();
+
+ if (!result)
+ {
+ result = this.diskPath.mkdirs();
+ }
+ if (!result)
+ {
+ log.error("Failed to create directory {0}", diskPath);
+ }
+ }
+
+ /**
+ * Gets the diskPath attribute of the attributes object
+ * <p>
+ *
+ * @return The diskPath value
+ */
+ @Override
+ public File getDiskPath()
+ {
+ return this.diskPath;
+ }
+
+ /**
+ * Gets the maxKeySize attribute of the DiskCacheAttributes object
+ * <p>
+ *
+ * @return The maxPurgatorySize value
+ */
+ @Override
+ public int getMaxPurgatorySize()
+ {
+ return maxPurgatorySize;
+ }
+
+ /**
+ * Sets the maxPurgatorySize attribute of the DiskCacheAttributes object
+ * <p>
+ *
+ * @param maxPurgatorySize
+ * The new maxPurgatorySize value
+ */
+ @Override
+ public void setMaxPurgatorySize(int maxPurgatorySize)
+ {
+ this.maxPurgatorySize = maxPurgatorySize;
+ }
+
+ /**
+ * Get the amount of time in seconds we will wait for elements to move to disk during shutdown
+ * for a particular region.
+ * <p>
+ *
+ * @return the time in seconds.
+ */
+ @Override
+ public int getShutdownSpoolTimeLimit()
+ {
+ return this.shutdownSpoolTimeLimit;
+ }
+
+ /**
+ * Sets the amount of time in seconds we will wait for elements to move to disk during shutdown
+ * for a particular region.
+ * <p>
+ * This is how long we give the event queue to empty.
+ * <p>
+ * The default is 60 seconds.
+ * <p>
+ *
+ * @param shutdownSpoolTimeLimit
+ * the time in seconds
+ */
+ @Override
+ public void setShutdownSpoolTimeLimit(int shutdownSpoolTimeLimit)
+ {
+ this.shutdownSpoolTimeLimit = shutdownSpoolTimeLimit;
+ }
+
+ /**
+ * @param allowRemoveAll
+ * The allowRemoveAll to set.
+ */
+ @Override
+ public void setAllowRemoveAll(boolean allowRemoveAll)
+ {
+ this.allowRemoveAll = allowRemoveAll;
+ }
+
+ /**
+ * @return Returns the allowRemoveAll.
+ */
+ @Override
+ public boolean isAllowRemoveAll()
+ {
+ return allowRemoveAll;
+ }
+
+ /**
+ * Includes the common attributes for a debug message.
+ * <p>
+ *
+ * @return String
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder str = new StringBuilder();
+ str.append("AbstractDiskCacheAttributes ");
+ str.append("\n diskPath = " + getDiskPath());
+ str.append("\n maxPurgatorySize = " + getMaxPurgatorySize());
+ str.append("\n allowRemoveAll = " + isAllowRemoveAll());
+ str.append("\n ShutdownSpoolTimeLimit = " + getShutdownSpoolTimeLimit());
+ return str.toString();
+ }
+
+ @Override
+ public void setDiskLimitType(DiskLimitType diskLimitType)
+ {
+ this.diskLimitType = diskLimitType;
+ }
+
+ @Override
+ public void setDiskLimitTypeName(String diskLimitTypeName)
+ {
+ if (diskLimitTypeName != null)
+ {
+ diskLimitType = DiskLimitType.valueOf(diskLimitTypeName.trim());
+ }
+ }
+
+ @Override
+ public DiskLimitType getDiskLimitType()
+ {
+ return diskLimitType;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/PurgatoryElement.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/PurgatoryElement.java
new file mode 100644
index 0000000..f2babab
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/PurgatoryElement.java
@@ -0,0 +1,156 @@
+package org.apache.commons.jcs3.auxiliary.disk;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+
+/**
+ * Implementation of cache elements in purgatory.
+ *
+ * Elements are stored in purgatory when they are spooled to the auxiliary cache, but have not yet
+ * been written to disk.
+ */
+public class PurgatoryElement<K, V>
+ extends CacheElement<K, V>
+{
+ /** Don't change */
+ private static final long serialVersionUID = -8152034342684135628L;
+
+ /** Is the element ready to be spooled? */
+ private boolean spoolable = false;
+
+ /** Wrapped cache Element */
+ private final ICacheElement<K, V> cacheElement;
+
+ /**
+ * Constructor for the PurgatoryElement<K, V> object
+ *
+ * @param cacheElement CacheElement
+ */
+ public PurgatoryElement( ICacheElement<K, V> cacheElement )
+ {
+ super(cacheElement.getCacheName(),
+ cacheElement.getKey(), cacheElement.getVal(),
+ cacheElement.getElementAttributes());
+ this.cacheElement = cacheElement;
+ }
+
+ /**
+ * Gets the spoolable property.
+ *
+ * @return The spoolable value
+ */
+ public boolean isSpoolable()
+ {
+ return spoolable;
+ }
+
+ /**
+ * Sets the spoolable property.
+ *
+ * @param spoolable The new spoolable value
+ */
+ public void setSpoolable( boolean spoolable )
+ {
+ this.spoolable = spoolable;
+ }
+
+ /**
+ * Get the wrapped cache element.
+ *
+ * @return ICacheElement
+ */
+ public ICacheElement<K, V> getCacheElement()
+ {
+ return cacheElement;
+ }
+
+ // ------------------------------------------------ interface ICacheElement
+
+ /**
+ * @return cacheElement.getCacheName();
+ * @see ICacheElement#getCacheName
+ */
+ @Override
+ public String getCacheName()
+ {
+ return cacheElement.getCacheName();
+ }
+
+ /**
+ * @return cacheElement.getKey();
+ * @see ICacheElement#getKey
+ */
+ @Override
+ public K getKey()
+ {
+ return cacheElement.getKey();
+ }
+
+ /**
+ * @return cacheElement.getVal();
+ * @see ICacheElement#getVal
+ */
+ @Override
+ public V getVal()
+ {
+ return cacheElement.getVal();
+ }
+
+ /**
+ * @return cacheElement.getElementAttributes();
+ * @see ICacheElement#getElementAttributes
+ */
+ @Override
+ public IElementAttributes getElementAttributes()
+ {
+ return cacheElement.getElementAttributes();
+ }
+
+ /**
+ * @param attr
+ * @see ICacheElement#setElementAttributes
+ */
+ @Override
+ public void setElementAttributes( IElementAttributes attr )
+ {
+ cacheElement.setElementAttributes( attr );
+ }
+
+ /**
+ * @return debug string
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "[PurgatoryElement: " );
+ buf.append( " isSpoolable = " + isSpoolable() );
+ buf.append( " CacheElement = " + getCacheElement() );
+ buf.append( " CacheName = " + getCacheName() );
+ buf.append( " Key = " + getKey() );
+ buf.append( " Value = " + getVal() );
+ buf.append( " ElementAttributes = " + getElementAttributes() );
+ buf.append( "]" );
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/behavior/IDiskCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/behavior/IDiskCacheAttributes.java
new file mode 100644
index 0000000..7d52fef
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/behavior/IDiskCacheAttributes.java
@@ -0,0 +1,131 @@
+package org.apache.commons.jcs3.auxiliary.disk.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+
+/**
+ * Common disk cache attributes.
+ */
+public interface IDiskCacheAttributes
+ extends AuxiliaryCacheAttributes
+{
+ enum DiskLimitType {
+ /** limit elements by count (default) */
+ COUNT,
+ /** limit elements by their size */
+ SIZE
+ }
+ /**
+ * This is the default purgatory size limit. Purgatory is the area where
+ * items to be spooled are temporarily stored. It basically provides access
+ * to items on the to-be-spooled queue.
+ */
+ int MAX_PURGATORY_SIZE_DEFAULT = 5000;
+
+ /**
+ * Sets the diskPath attribute of the IJISPCacheAttributes object
+ * <p>
+ * @param path
+ * The new diskPath value
+ */
+ void setDiskPath( String path );
+
+ /**
+ * Gets the diskPath attribute of the attributes object
+ * <p>
+ * @return The diskPath value
+ */
+ File getDiskPath();
+
+ /**
+ * Gets the maxKeySize attribute of the DiskCacheAttributes object
+ * <p>
+ * @return The maxPurgatorySize value
+ */
+ int getMaxPurgatorySize();
+
+ /**
+ * Sets the maxPurgatorySize attribute of the DiskCacheAttributes object
+ * <p>
+ * @param maxPurgatorySize
+ * The new maxPurgatorySize value
+ */
+ void setMaxPurgatorySize( int maxPurgatorySize );
+
+ /**
+ * Get the amount of time in seconds we will wait for elements to move to
+ * disk during shutdown for a particular region.
+ * <p>
+ * @return the time in seconds.
+ */
+ int getShutdownSpoolTimeLimit();
+
+ /**
+ * Sets the amount of time in seconds we will wait for elements to move to
+ * disk during shutdown for a particular region.
+ * <p>
+ * This is how long we give the event queue to empty.
+ * <p>
+ * The default is 60 seconds.
+ * <p>
+ * @param shutdownSpoolTimeLimit
+ * the time in seconds
+ */
+ void setShutdownSpoolTimeLimit( int shutdownSpoolTimeLimit );
+
+ /**
+ * If this is true then remove all is not prohibited.
+ * <p>
+ * @return boolean
+ */
+ boolean isAllowRemoveAll();
+
+ /**
+ * If this is false, then remove all requests will not be honored.
+ * <p>
+ * This provides a safety mechanism for the persistent store.
+ * <p>
+ * @param allowRemoveAll
+ */
+ void setAllowRemoveAll( boolean allowRemoveAll );
+
+ /**
+ * set the type of the limit of the cache size
+ * @param diskLimitType COUNT - limit by count of the elements, SIZE, limit by sum of element's size
+ */
+ void setDiskLimitType(DiskLimitType diskLimitType);
+
+ /**
+ * Translates and stores String values of DiskLimitType
+ *
+ * Allowed values: "COUNT" and "SIZE"
+ * @param diskLimitTypeName
+ */
+ void setDiskLimitTypeName(String diskLimitTypeName);
+
+ /**
+ *
+ * @return active DiskLimitType
+ */
+ DiskLimitType getDiskLimitType();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDisk.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDisk.java
new file mode 100644
index 0000000..517a9bf
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDisk.java
@@ -0,0 +1,517 @@
+package org.apache.commons.jcs3.auxiliary.disk.block;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.StandardOpenOption;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+
+/**
+ * This class manages reading an writing data to disk. When asked to write a value, it returns a
+ * block array. It can read an object from the block numbers in a byte array.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class BlockDisk implements AutoCloseable
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog(BlockDisk.class);
+
+ /** The size of the header that indicates the amount of data stored in an occupied block. */
+ public static final byte HEADER_SIZE_BYTES = 4;
+ // N.B. 4 bytes is the size used for ByteBuffer.putInt(int value) and ByteBuffer.getInt()
+
+ /** defaults to 4kb */
+ private static final int DEFAULT_BLOCK_SIZE_BYTES = 4 * 1024;
+
+ /** Size of the blocks */
+ private final int blockSizeBytes;
+
+ /**
+ * the total number of blocks that have been used. If there are no free, we will use this to
+ * calculate the position of the next block.
+ */
+ private final AtomicInteger numberOfBlocks = new AtomicInteger(0);
+
+ /** Empty blocks that can be reused. */
+ private final ConcurrentLinkedQueue<Integer> emptyBlocks = new ConcurrentLinkedQueue<>();
+
+ /** The serializer. */
+ private final IElementSerializer elementSerializer;
+
+ /** Location of the spot on disk */
+ private final String filepath;
+
+ /** File channel for multiple concurrent reads and writes */
+ private final FileChannel fc;
+
+ /** How many bytes have we put to disk */
+ private final AtomicLong putBytes = new AtomicLong(0);
+
+ /** How many items have we put to disk */
+ private final AtomicLong putCount = new AtomicLong(0);
+
+ /**
+ * Constructor for the Disk object
+ * <p>
+ * @param file
+ * @param elementSerializer
+ * @throws IOException
+ */
+ public BlockDisk(File file, IElementSerializer elementSerializer)
+ throws IOException
+ {
+ this(file, DEFAULT_BLOCK_SIZE_BYTES, elementSerializer);
+ }
+
+ /**
+ * Creates the file and set the block size in bytes.
+ * <p>
+ * @param file
+ * @param blockSizeBytes
+ * @throws IOException
+ */
+ public BlockDisk(File file, int blockSizeBytes)
+ throws IOException
+ {
+ this(file, blockSizeBytes, new StandardSerializer());
+ }
+
+ /**
+ * Creates the file and set the block size in bytes.
+ * <p>
+ * @param file
+ * @param blockSizeBytes
+ * @param elementSerializer
+ * @throws IOException
+ */
+ public BlockDisk(File file, int blockSizeBytes, IElementSerializer elementSerializer)
+ throws IOException
+ {
+ this.filepath = file.getAbsolutePath();
+ this.fc = FileChannel.open(file.toPath(),
+ StandardOpenOption.CREATE,
+ StandardOpenOption.READ,
+ StandardOpenOption.WRITE);
+ this.numberOfBlocks.set((int) Math.ceil(1f * this.fc.size() / blockSizeBytes));
+
+ log.info("Constructing BlockDisk, blockSizeBytes [{0}]", blockSizeBytes);
+
+ this.blockSizeBytes = blockSizeBytes;
+ this.elementSerializer = elementSerializer;
+ }
+
+ /**
+ * Allocate a given number of blocks from the available set
+ *
+ * @param numBlocksNeeded
+ * @return an array of allocated blocks
+ */
+ private int[] allocateBlocks(int numBlocksNeeded)
+ {
+ assert numBlocksNeeded >= 1;
+
+ int[] blocks = new int[numBlocksNeeded];
+ // get them from the empty list or take the next one
+ for (int i = 0; i < numBlocksNeeded; i++)
+ {
+ Integer emptyBlock = emptyBlocks.poll();
+ if (emptyBlock == null)
+ {
+ emptyBlock = Integer.valueOf(numberOfBlocks.getAndIncrement());
+ }
+ blocks[i] = emptyBlock.intValue();
+ }
+
+ return blocks;
+ }
+
+ /**
+ * This writes an object to disk and returns the blocks it was stored in.
+ * <p>
+ * The program flow is as follows:
+ * <ol>
+ * <li>Serialize the object.</li>
+ * <li>Determine the number of blocks needed.</li>
+ * <li>Look for free blocks in the emptyBlock list.</li>
+ * <li>If there were not enough in the empty list. Take the nextBlock and increment it.</li>
+ * <li>If the data will not fit in one block, create sub arrays.</li>
+ * <li>Write the subarrays to disk.</li>
+ * <li>If the process fails we should decrement the block count if we took from it.</li>
+ * </ol>
+ * @param object
+ * @return the blocks we used.
+ * @throws IOException
+ */
+ protected <T> int[] write(T object)
+ throws IOException
+ {
+ // serialize the object
+ byte[] data = elementSerializer.serialize(object);
+
+ log.debug("write, total pre-chunking data.length = {0}", data.length);
+
+ this.putBytes.addAndGet(data.length);
+ this.putCount.incrementAndGet();
+
+ // figure out how many blocks we need.
+ int numBlocksNeeded = calculateTheNumberOfBlocksNeeded(data);
+
+ log.debug("numBlocksNeeded = {0}", numBlocksNeeded);
+
+ // allocate blocks
+ int[] blocks = allocateBlocks(numBlocksNeeded);
+
+ int offset = 0;
+ final int maxChunkSize = blockSizeBytes - HEADER_SIZE_BYTES;
+ ByteBuffer headerBuffer = ByteBuffer.allocate(HEADER_SIZE_BYTES);
+ ByteBuffer dataBuffer = ByteBuffer.wrap(data);
+
+ for (int i = 0; i < numBlocksNeeded; i++)
+ {
+ headerBuffer.clear();
+ int length = Math.min(maxChunkSize, data.length - offset);
+ headerBuffer.putInt(length);
+ headerBuffer.flip();
+
+ dataBuffer.position(offset).limit(offset + length);
+ ByteBuffer slice = dataBuffer.slice();
+
+ long position = calculateByteOffsetForBlockAsLong(blocks[i]);
+ // write the header
+ int written = fc.write(headerBuffer, position);
+ assert written == HEADER_SIZE_BYTES;
+
+ //write the data
+ written = fc.write(slice, position + HEADER_SIZE_BYTES);
+ assert written == length;
+
+ offset += length;
+ }
+
+ //fc.force(false);
+
+ return blocks;
+ }
+
+ /**
+ * Return the amount to put in each block. Fill them all the way, minus the header.
+ * <p>
+ * @param complete
+ * @param numBlocksNeeded
+ * @return byte[][]
+ */
+ protected byte[][] getBlockChunks(byte[] complete, int numBlocksNeeded)
+ {
+ byte[][] chunks = new byte[numBlocksNeeded][];
+
+ if (numBlocksNeeded == 1)
+ {
+ chunks[0] = complete;
+ }
+ else
+ {
+ int maxChunkSize = this.blockSizeBytes - HEADER_SIZE_BYTES;
+ int totalBytes = complete.length;
+ int totalUsed = 0;
+ for (short i = 0; i < numBlocksNeeded; i++)
+ {
+ // use the max that can be written to a block or whatever is left in the original
+ // array
+ int chunkSize = Math.min(maxChunkSize, totalBytes - totalUsed);
+ byte[] chunk = new byte[chunkSize];
+ // copy from the used position to the chunk size on the complete array to the chunk
+ // array.
+ System.arraycopy(complete, totalUsed, chunk, 0, chunkSize);
+ chunks[i] = chunk;
+ totalUsed += chunkSize;
+ }
+ }
+
+ return chunks;
+ }
+
+ /**
+ * Reads an object that is located in the specified blocks.
+ * <p>
+ * @param blockNumbers
+ * @return the object instance
+ * @throws IOException
+ * @throws ClassNotFoundException
+ */
+ protected <T> T read(int[] blockNumbers)
+ throws IOException, ClassNotFoundException
+ {
+ final ByteBuffer data;
+
+ if (blockNumbers.length == 1)
+ {
+ data = readBlock(blockNumbers[0]);
+ }
+ else
+ {
+ data = ByteBuffer.allocate(blockNumbers.length * getBlockSizeBytes());
+ // get all the blocks into data
+ for (short i = 0; i < blockNumbers.length; i++)
+ {
+ ByteBuffer chunk = readBlock(blockNumbers[i]);
+ data.put(chunk);
+ }
+
+ data.flip();
+ }
+
+ log.debug("read, total post combination data.length = {0}", () -> data.limit());
+
+ return elementSerializer.deSerialize(data.array(), null);
+ }
+
+ /**
+ * This reads the occupied data in a block.
+ * <p>
+ * The first four bytes of the record should tell us how long it is. The data is read into a
+ * byte array and then an object is constructed from the byte array.
+ * <p>
+ * @return byte[]
+ * @param block
+ * @throws IOException
+ */
+ private ByteBuffer readBlock(int block)
+ throws IOException
+ {
+ int datalen = 0;
+
+ String message = null;
+ boolean corrupted = false;
+ long fileLength = fc.size();
+
+ long position = calculateByteOffsetForBlockAsLong(block);
+// if (position > fileLength)
+// {
+// corrupted = true;
+// message = "Record " + position + " starts past EOF.";
+// }
+// else
+ {
+ ByteBuffer datalength = ByteBuffer.allocate(HEADER_SIZE_BYTES);
+ fc.read(datalength, position);
+ datalength.flip();
+ datalen = datalength.getInt();
+ if (position + datalen > fileLength)
+ {
+ corrupted = true;
+ message = "Record " + position + " exceeds file length.";
+ }
+ }
+
+ if (corrupted)
+ {
+ log.warn("\n The file is corrupt: \n {0}", message);
+ throw new IOException("The File Is Corrupt, need to reset");
+ }
+
+ ByteBuffer data = ByteBuffer.allocate(datalen);
+ fc.read(data, position + HEADER_SIZE_BYTES);
+ data.flip();
+
+ return data;
+ }
+
+ /**
+ * Add these blocks to the emptyBlock list.
+ * <p>
+ * @param blocksToFree
+ */
+ protected void freeBlocks(int[] blocksToFree)
+ {
+ if (blocksToFree != null)
+ {
+ for (short i = 0; i < blocksToFree.length; i++)
+ {
+ emptyBlocks.offer(Integer.valueOf(blocksToFree[i]));
+ }
+ }
+ }
+
+ /**
+ * Calculates the file offset for a particular block.
+ * <p>
+ * @param block number
+ * @return the byte offset for this block in the file as a long
+ * @since 2.0
+ */
+ protected long calculateByteOffsetForBlockAsLong(int block)
+ {
+ return (long) block * blockSizeBytes;
+ }
+
+ /**
+ * The number of blocks needed.
+ * <p>
+ * @param data
+ * @return the number of blocks needed to store the byte array
+ */
+ protected int calculateTheNumberOfBlocksNeeded(byte[] data)
+ {
+ int dataLength = data.length;
+
+ int oneBlock = blockSizeBytes - HEADER_SIZE_BYTES;
+
+ // takes care of 0 = HEADER_SIZE_BYTES + blockSizeBytes
+ if (dataLength <= oneBlock)
+ {
+ return 1;
+ }
+
+ int dividend = dataLength / oneBlock;
+
+ if (dataLength % oneBlock != 0)
+ {
+ dividend++;
+ }
+ return dividend;
+ }
+
+ /**
+ * Returns the file length.
+ * <p>
+ * @return the size of the file.
+ * @throws IOException
+ */
+ protected long length()
+ throws IOException
+ {
+ return fc.size();
+ }
+
+ /**
+ * Closes the file.
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ public void close()
+ throws IOException
+ {
+ this.numberOfBlocks.set(0);
+ this.emptyBlocks.clear();
+ fc.close();
+ }
+
+ /**
+ * Resets the file.
+ * <p>
+ * @throws IOException
+ */
+ protected synchronized void reset()
+ throws IOException
+ {
+ this.numberOfBlocks.set(0);
+ this.emptyBlocks.clear();
+ fc.truncate(0);
+ fc.force(true);
+ }
+
+ /**
+ * @return Returns the numberOfBlocks.
+ */
+ protected int getNumberOfBlocks()
+ {
+ return numberOfBlocks.get();
+ }
+
+ /**
+ * @return Returns the blockSizeBytes.
+ */
+ protected int getBlockSizeBytes()
+ {
+ return blockSizeBytes;
+ }
+
+ /**
+ * @return Returns the average size of the an element inserted.
+ */
+ protected long getAveragePutSizeBytes()
+ {
+ long count = this.putCount.get();
+
+ if (count == 0)
+ {
+ return 0;
+ }
+ return this.putBytes.get() / count;
+ }
+
+ /**
+ * @return Returns the number of empty blocks.
+ */
+ protected int getEmptyBlocks()
+ {
+ return this.emptyBlocks.size();
+ }
+
+ /**
+ * For debugging only.
+ * <p>
+ * @return String with details.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append("\nBlock Disk ");
+ buf.append("\n Filepath [" + filepath + "]");
+ buf.append("\n NumberOfBlocks [" + this.numberOfBlocks.get() + "]");
+ buf.append("\n BlockSizeBytes [" + this.blockSizeBytes + "]");
+ buf.append("\n Put Bytes [" + this.putBytes + "]");
+ buf.append("\n Put Count [" + this.putCount + "]");
+ buf.append("\n Average Size [" + getAveragePutSizeBytes() + "]");
+ buf.append("\n Empty Blocks [" + this.getEmptyBlocks() + "]");
+ try
+ {
+ buf.append("\n Length [" + length() + "]");
+ }
+ catch (IOException e)
+ {
+ // swallow
+ }
+ return buf.toString();
+ }
+
+ /**
+ * This is used for debugging.
+ * <p>
+ * @return the file path.
+ */
+ protected String getFilePath()
+ {
+ return filepath;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCache.java
new file mode 100644
index 0000000..54e6919
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCache.java
@@ -0,0 +1,709 @@
+package org.apache.commons.jcs3.auxiliary.disk.block;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.stream.Collectors;
+
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.behavior.IRequireScheduler;
+import org.apache.commons.jcs3.engine.control.group.GroupAttrName;
+import org.apache.commons.jcs3.engine.control.group.GroupId;
+import org.apache.commons.jcs3.engine.stats.StatElement;
+import org.apache.commons.jcs3.engine.stats.Stats;
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * There is one BlockDiskCache per region. It manages the key and data store.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class BlockDiskCache<K, V>
+ extends AbstractDiskCache<K, V>
+ implements IRequireScheduler
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog( BlockDiskCache.class );
+
+ /** The name to prefix all log messages with. */
+ private final String logCacheName;
+
+ /** The name of the file to store data. */
+ private final String fileName;
+
+ /** The data access object */
+ private BlockDisk dataFile;
+
+ /** Attributes governing the behavior of the block disk cache. */
+ private final BlockDiskCacheAttributes blockDiskCacheAttributes;
+
+ /** The root directory for keys and data. */
+ private final File rootDirectory;
+
+ /** Store, loads, and persists the keys */
+ private BlockDiskKeyStore<K> keyStore;
+
+ /**
+ * Use this lock to synchronize reads and writes to the underlying storage mechanism. We don't
+ * need a reentrant lock, since we only lock one level.
+ */
+ private final ReentrantReadWriteLock storageLock = new ReentrantReadWriteLock();
+
+ private ScheduledFuture<?> future;
+
+ /**
+ * Constructs the BlockDisk after setting up the root directory.
+ * <p>
+ * @param cacheAttributes
+ */
+ public BlockDiskCache( BlockDiskCacheAttributes cacheAttributes )
+ {
+ this( cacheAttributes, null );
+ }
+
+ /**
+ * Constructs the BlockDisk after setting up the root directory.
+ * <p>
+ * @param cacheAttributes
+ * @param elementSerializer used if supplied, the super's super will not set a null
+ */
+ public BlockDiskCache( BlockDiskCacheAttributes cacheAttributes, IElementSerializer elementSerializer )
+ {
+ super( cacheAttributes );
+ setElementSerializer( elementSerializer );
+
+ this.blockDiskCacheAttributes = cacheAttributes;
+ this.logCacheName = "Region [" + getCacheName() + "] ";
+
+ log.info("{0}: Constructing BlockDiskCache with attributes {1}", logCacheName, cacheAttributes );
+
+ // Make a clean file name
+ this.fileName = getCacheName().replaceAll("[^a-zA-Z0-9-_\\.]", "_");
+ this.rootDirectory = cacheAttributes.getDiskPath();
+
+ log.info("{0}: Cache file root directory: [{1}]", logCacheName, rootDirectory);
+
+ try
+ {
+ if ( this.blockDiskCacheAttributes.getBlockSizeBytes() > 0 )
+ {
+ this.dataFile = new BlockDisk( new File( rootDirectory, fileName + ".data" ),
+ this.blockDiskCacheAttributes.getBlockSizeBytes(),
+ getElementSerializer() );
+ }
+ else
+ {
+ this.dataFile = new BlockDisk( new File( rootDirectory, fileName + ".data" ),
+ getElementSerializer() );
+ }
+
+ keyStore = new BlockDiskKeyStore<>( this.blockDiskCacheAttributes, this );
+
+ boolean alright = verifyDisk();
+
+ if ( keyStore.size() == 0 || !alright )
+ {
+ this.reset();
+ }
+
+ // Initialization finished successfully, so set alive to true.
+ setAlive(true);
+ log.info("{0}: Block Disk Cache is alive.", logCacheName);
+ }
+ catch ( IOException e )
+ {
+ log.error("{0}: Failure initializing for fileName: {1} and root directory: {2}",
+ logCacheName, fileName, rootDirectory, e);
+ }
+ }
+
+ /**
+ * @see org.apache.commons.jcs3.engine.behavior.IRequireScheduler#setScheduledExecutorService(java.util.concurrent.ScheduledExecutorService)
+ */
+ @Override
+ public void setScheduledExecutorService(ScheduledExecutorService scheduledExecutor)
+ {
+ // add this region to the persistence thread.
+ // TODO we might need to stagger this a bit.
+ if ( this.blockDiskCacheAttributes.getKeyPersistenceIntervalSeconds() > 0 )
+ {
+ future = scheduledExecutor.scheduleAtFixedRate(keyStore::saveKeys,
+ this.blockDiskCacheAttributes.getKeyPersistenceIntervalSeconds(),
+ this.blockDiskCacheAttributes.getKeyPersistenceIntervalSeconds(),
+ TimeUnit.SECONDS);
+ }
+ }
+
+ /**
+ * We need to verify that the file on disk uses the same block size and that the file is the
+ * proper size.
+ * <p>
+ * @return true if it looks ok
+ */
+ protected boolean verifyDisk()
+ {
+ boolean alright = false;
+ // simply try to read a few. If it works, then the file is probably ok.
+ // TODO add more.
+
+ storageLock.readLock().lock();
+
+ try
+ {
+ this.keyStore.entrySet().stream()
+ .limit(100)
+ .forEach(entry -> {
+ try
+ {
+ Object data = this.dataFile.read(entry.getValue());
+ if ( data == null )
+ {
+ throw new IOException("Data is null");
+ }
+ }
+ catch (IOException | ClassNotFoundException e)
+ {
+ throw new RuntimeException(logCacheName
+ + " Couldn't find data for key [" + entry.getKey() + "]", e);
+ }
+ });
+ alright = true;
+ }
+ catch ( Exception e )
+ {
+ log.warn("{0}: Problem verifying disk.", logCacheName, e);
+ alright = false;
+ }
+ finally
+ {
+ storageLock.readLock().unlock();
+ }
+
+ return alright;
+ }
+
+ /**
+ * Return the keys in this cache.
+ * <p>
+ * @see org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache#getKeySet()
+ */
+ @Override
+ public Set<K> getKeySet() throws IOException
+ {
+ HashSet<K> keys = new HashSet<>();
+
+ storageLock.readLock().lock();
+
+ try
+ {
+ keys.addAll(this.keyStore.keySet());
+ }
+ finally
+ {
+ storageLock.readLock().unlock();
+ }
+
+ return keys;
+ }
+
+ /**
+ * Gets matching items from the cache.
+ * <p>
+ * @param pattern
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache matching keys
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> processGetMatching( String pattern )
+ {
+ Set<K> keyArray = null;
+ storageLock.readLock().lock();
+ try
+ {
+ keyArray = new HashSet<>(keyStore.keySet());
+ }
+ finally
+ {
+ storageLock.readLock().unlock();
+ }
+
+ Set<K> matchingKeys = getKeyMatcher().getMatchingKeysFromArray( pattern, keyArray );
+
+ Map<K, ICacheElement<K, V>> elements = matchingKeys.stream()
+ .collect(Collectors.toMap(
+ key -> key,
+ key -> processGet( key ))).entrySet().stream()
+ .filter(entry -> entry.getValue() != null)
+ .collect(Collectors.toMap(
+ entry -> entry.getKey(),
+ entry -> entry.getValue()));
+
+ return elements;
+ }
+
+ /**
+ * Returns the number of keys.
+ * <p>
+ * (non-Javadoc)
+ * @see org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache#getSize()
+ */
+ @Override
+ public int getSize()
+ {
+ return this.keyStore.size();
+ }
+
+ /**
+ * Gets the ICacheElement<K, V> for the key if it is in the cache. The program flow is as follows:
+ * <ol>
+ * <li>Make sure the disk cache is alive.</li> <li>Get a read lock.</li> <li>See if the key is
+ * in the key store.</li> <li>If we found a key, ask the BlockDisk for the object at the
+ * blocks..</li> <li>Release the lock.</li>
+ * </ol>
+ * @param key
+ * @return ICacheElement
+ * @see org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache#get(Object)
+ */
+ @Override
+ protected ICacheElement<K, V> processGet( K key )
+ {
+ if ( !isAlive() )
+ {
+ log.debug("{0}: No longer alive so returning null for key = {1}", logCacheName, key );
+ return null;
+ }
+
+ log.debug("{0}: Trying to get from disk: {1}", logCacheName, key );
+
+ ICacheElement<K, V> object = null;
+
+
+ try
+ {
+ storageLock.readLock().lock();
+ try {
+ int[] ded = this.keyStore.get( key );
+ if ( ded != null )
+ {
+ object = this.dataFile.read( ded );
+ }
+ } finally {
+ storageLock.readLock().unlock();
+ }
+
+ }
+ catch ( IOException ioe )
+ {
+ log.error("{0}: Failure getting from disk--IOException, key = {1}", logCacheName, key, ioe );
+ reset();
+ }
+ catch ( Exception e )
+ {
+ log.error("{0}: Failure getting from disk, key = {1}", logCacheName, key, e );
+ }
+ return object;
+ }
+
+ /**
+ * Writes an element to disk. The program flow is as follows:
+ * <ol>
+ * <li>Acquire write lock.</li> <li>See id an item exists for this key.</li> <li>If an item
+ * already exists, add its blocks to the remove list.</li> <li>Have the Block disk write the
+ * item.</li> <li>Create a descriptor and add it to the key map.</li> <li>Release the write
+ * lock.</li>
+ * </ol>
+ * @param element
+ * @see org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache#update(ICacheElement)
+ */
+ @Override
+ protected void processUpdate( ICacheElement<K, V> element )
+ {
+ if ( !isAlive() )
+ {
+ log.debug("{0}: No longer alive; aborting put of key = {1}",
+ () -> logCacheName, () -> element.getKey());
+ return;
+ }
+
+ int[] old = null;
+
+ // make sure this only locks for one particular cache region
+ storageLock.writeLock().lock();
+
+ try
+ {
+ old = this.keyStore.get( element.getKey() );
+
+ if ( old != null )
+ {
+ this.dataFile.freeBlocks( old );
+ }
+
+ int[] blocks = this.dataFile.write( element );
+
+ this.keyStore.put( element.getKey(), blocks );
+
+ log.debug("{0}: Put to file [{1}] key [{2}]", () -> logCacheName,
+ () -> fileName, () -> element.getKey());
+ }
+ catch ( IOException e )
+ {
+ log.error("{0}: Failure updating element, key: {1} old: {2}",
+ logCacheName, element.getKey(), Arrays.toString(old), e);
+ }
+ finally
+ {
+ storageLock.writeLock().unlock();
+ }
+
+ log.debug("{0}: Storing element on disk, key: {1}", () -> logCacheName,
+ () -> element.getKey() );
+ }
+
+ /**
+ * Returns true if the removal was successful; or false if there is nothing to remove. Current
+ * implementation always result in a disk orphan.
+ * <p>
+ * @param key
+ * @return true if removed anything
+ * @see org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache#remove(Object)
+ */
+ @Override
+ protected boolean processRemove( K key )
+ {
+ if ( !isAlive() )
+ {
+ log.debug("{0}: No longer alive so returning false for key = {1}", logCacheName, key );
+ return false;
+ }
+
+ boolean reset = false;
+ boolean removed = false;
+
+ storageLock.writeLock().lock();
+
+ try
+ {
+ if (key instanceof String && key.toString().endsWith(NAME_COMPONENT_DELIMITER))
+ {
+ removed = performPartialKeyRemoval((String) key);
+ }
+ else if (key instanceof GroupAttrName && ((GroupAttrName<?>) key).attrName == null)
+ {
+ removed = performGroupRemoval(((GroupAttrName<?>) key).groupId);
+ }
+ else
+ {
+ removed = performSingleKeyRemoval(key);
+ }
+ }
+ catch ( Exception e )
+ {
+ log.error("{0}: Problem removing element.", logCacheName, e );
+ reset = true;
+ }
+ finally
+ {
+ storageLock.writeLock().unlock();
+ }
+
+ if ( reset )
+ {
+ reset();
+ }
+
+ return removed;
+ }
+
+ /**
+ * Remove all elements from the group. This does not use the iterator to remove. It builds a
+ * list of group elements and then removes them one by one.
+ * <p>
+ * This operates under a lock obtained in doRemove().
+ * <p>
+ *
+ * @param key
+ * @return true if an element was removed
+ */
+ private boolean performGroupRemoval(GroupId key)
+ {
+ // remove all keys of the same name group.
+ List<K> itemsToRemove = keyStore.keySet()
+ .stream()
+ .filter(k -> k instanceof GroupAttrName && ((GroupAttrName<?>) k).groupId.equals(key))
+ .collect(Collectors.toList());
+
+ // remove matches.
+ // Don't add to recycle bin here
+ // https://issues.apache.org/jira/browse/JCS-67
+ itemsToRemove.forEach(fullKey -> performSingleKeyRemoval(fullKey));
+ // TODO this needs to update the remove count separately
+
+ return !itemsToRemove.isEmpty();
+ }
+
+ /**
+ * Iterates over the keyset. Builds a list of matches. Removes all the keys in the list. Does
+ * not remove via the iterator, since the map impl may not support it.
+ * <p>
+ * This operates under a lock obtained in doRemove().
+ * <p>
+ *
+ * @param key
+ * @return true if there was a match
+ */
+ private boolean performPartialKeyRemoval(String key)
+ {
+ // remove all keys of the same name hierarchy.
+ List<K> itemsToRemove = keyStore.keySet()
+ .stream()
+ .filter(k -> k instanceof String && k.toString().startsWith(key))
+ .collect(Collectors.toList());
+
+ // remove matches.
+ // Don't add to recycle bin here
+ // https://issues.apache.org/jira/browse/JCS-67
+ itemsToRemove.forEach(fullKey -> performSingleKeyRemoval(fullKey));
+ // TODO this needs to update the remove count separately
+
+ return !itemsToRemove.isEmpty();
+ }
+
+
+ private boolean performSingleKeyRemoval(K key) {
+ boolean removed;
+ // remove single item.
+ int[] ded = this.keyStore.remove( key );
+ removed = ded != null;
+ if ( removed )
+ {
+ this.dataFile.freeBlocks( ded );
+ }
+
+ log.debug("{0}: Disk removal: Removed from key hash, key [{1}] removed = {2}",
+ logCacheName, key, removed);
+ return removed;
+ }
+
+ /**
+ * Resets the keyfile, the disk file, and the memory key map.
+ * <p>
+ * @see org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache#removeAll()
+ */
+ @Override
+ protected void processRemoveAll()
+ {
+ reset();
+ }
+
+ /**
+ * Dispose of the disk cache in a background thread. Joins against this thread to put a cap on
+ * the disposal time.
+ * <p>
+ * TODO make dispose window configurable.
+ */
+ @Override
+ public void processDispose()
+ {
+ Thread t = new Thread(this::disposeInternal, "BlockDiskCache-DisposalThread" );
+ t.start();
+ // wait up to 60 seconds for dispose and then quit if not done.
+ try
+ {
+ t.join( 60 * 1000 );
+ }
+ catch ( InterruptedException ex )
+ {
+ log.error("{0}: Interrupted while waiting for disposal thread to finish.",
+ logCacheName, ex );
+ }
+ }
+
+ /**
+ * Internal method that handles the disposal.
+ */
+ protected void disposeInternal()
+ {
+ if ( !isAlive() )
+ {
+ log.error("{0}: Not alive and dispose was called, filename: {1}", logCacheName, fileName);
+ return;
+ }
+ storageLock.writeLock().lock();
+ try
+ {
+ // Prevents any interaction with the cache while we're shutting down.
+ setAlive(false);
+ this.keyStore.saveKeys();
+
+ if (future != null)
+ {
+ future.cancel(true);
+ }
+
+ try
+ {
+ log.debug("{0}: Closing files, base filename: {1}", logCacheName, fileName );
+ dataFile.close();
+ // dataFile = null;
+
+ // TOD make a close
+ // keyFile.close();
+ // keyFile = null;
+ }
+ catch ( IOException e )
+ {
+ log.error("{0}: Failure closing files in dispose, filename: {1}",
+ logCacheName, fileName, e );
+ }
+ }
+ finally
+ {
+ storageLock.writeLock().unlock();
+ }
+
+ log.info("{0}: Shutdown complete.", logCacheName);
+ }
+
+ /**
+ * Returns the attributes.
+ * <p>
+ * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCache#getAuxiliaryCacheAttributes()
+ */
+ @Override
+ public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
+ {
+ return this.blockDiskCacheAttributes;
+ }
+
+ /**
+ * Reset effectively clears the disk cache, creating new files, recyclebins, and keymaps.
+ * <p>
+ * It can be used to handle errors by last resort, force content update, or removeall.
+ */
+ private void reset()
+ {
+ log.info("{0}: Resetting cache", logCacheName);
+
+ try
+ {
+ storageLock.writeLock().lock();
+
+ this.keyStore.reset();
+
+ if ( dataFile != null )
+ {
+ dataFile.reset();
+ }
+ }
+ catch ( IOException e )
+ {
+ log.error("{0}: Failure resetting state", logCacheName, e );
+ }
+ finally
+ {
+ storageLock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Add these blocks to the emptyBlock list.
+ * <p>
+ * @param blocksToFree
+ */
+ protected void freeBlocks( int[] blocksToFree )
+ {
+ this.dataFile.freeBlocks( blocksToFree );
+ }
+
+ /**
+ * Returns info about the disk cache.
+ * <p>
+ * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCache#getStatistics()
+ */
+ @Override
+ public IStats getStatistics()
+ {
+ IStats stats = new Stats();
+ stats.setTypeName( "Block Disk Cache" );
+
+ ArrayList<IStatElement<?>> elems = new ArrayList<>();
+
+ elems.add(new StatElement<>( "Is Alive", Boolean.valueOf(isAlive()) ) );
+ elems.add(new StatElement<>( "Key Map Size", Integer.valueOf(this.keyStore.size()) ) );
+
+ if (this.dataFile != null)
+ {
+ try
+ {
+ elems.add(new StatElement<>( "Data File Length", Long.valueOf(this.dataFile.length()) ) );
+ }
+ catch ( IOException e )
+ {
+ log.error( e );
+ }
+
+ elems.add(new StatElement<>( "Block Size Bytes",
+ Integer.valueOf(this.dataFile.getBlockSizeBytes()) ) );
+ elems.add(new StatElement<>( "Number Of Blocks",
+ Integer.valueOf(this.dataFile.getNumberOfBlocks()) ) );
+ elems.add(new StatElement<>( "Average Put Size Bytes",
+ Long.valueOf(this.dataFile.getAveragePutSizeBytes()) ) );
+ elems.add(new StatElement<>( "Empty Blocks",
+ Integer.valueOf(this.dataFile.getEmptyBlocks()) ) );
+ }
+
+ // get the stats from the super too
+ IStats sStats = super.getStatistics();
+ elems.addAll(sStats.getStatElements());
+
+ stats.setStatElements( elems );
+
+ return stats;
+ }
+
+ /**
+ * This is used by the event logging.
+ * <p>
+ * @return the location of the disk, either path or ip.
+ */
+ @Override
+ protected String getDiskLocation()
+ {
+ return dataFile.getFilePath();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheAttributes.java
new file mode 100644
index 0000000..6df7d40
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheAttributes.java
@@ -0,0 +1,118 @@
+package org.apache.commons.jcs3.auxiliary.disk.block;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCacheAttributes;
+
+/**
+ * This holds attributes for Block Disk Cache configuration.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class BlockDiskCacheAttributes
+ extends AbstractDiskCacheAttributes
+{
+ /** Don't change */
+ private static final long serialVersionUID = 6568840097657265989L;
+
+ /** The size per block in bytes. */
+ private int blockSizeBytes;
+
+ /** Maximum number of keys to be kept in memory */
+ private static final int DEFAULT_MAX_KEY_SIZE = 5000;
+
+ /** -1 means no limit. */
+ private int maxKeySize = DEFAULT_MAX_KEY_SIZE;
+
+ /** How often should we persist the keys. */
+ private static final long DEFAULT_KEY_PERSISTENCE_INTERVAL_SECONDS = 5 * 60;
+
+ /** The keys will be persisted at this interval. -1 mean never. */
+ private long keyPersistenceIntervalSeconds = DEFAULT_KEY_PERSISTENCE_INTERVAL_SECONDS;
+
+ /**
+ * The size of the blocks. All blocks are the same size.
+ * <p>
+ * @param blockSizeBytes The blockSizeBytes to set.
+ */
+ public void setBlockSizeBytes( int blockSizeBytes )
+ {
+ this.blockSizeBytes = blockSizeBytes;
+ }
+
+ /**
+ * @return Returns the blockSizeBytes.
+ */
+ public int getBlockSizeBytes()
+ {
+ return blockSizeBytes;
+ }
+
+ /**
+ * @param maxKeySize The maxKeySize to set.
+ */
+ public void setMaxKeySize( int maxKeySize )
+ {
+ this.maxKeySize = maxKeySize;
+ }
+
+ /**
+ * @return Returns the maxKeySize.
+ */
+ public int getMaxKeySize()
+ {
+ return maxKeySize;
+ }
+
+ /**
+ * @param keyPersistenceIntervalSeconds The keyPersistenceIntervalSeconds to set.
+ */
+ public void setKeyPersistenceIntervalSeconds( long keyPersistenceIntervalSeconds )
+ {
+ this.keyPersistenceIntervalSeconds = keyPersistenceIntervalSeconds;
+ }
+
+ /**
+ * @return Returns the keyPersistenceIntervalSeconds.
+ */
+ public long getKeyPersistenceIntervalSeconds()
+ {
+ return keyPersistenceIntervalSeconds;
+ }
+
+ /**
+ * Write out the values for debugging purposes.
+ * <p>
+ * @return String
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder str = new StringBuilder();
+ str.append( "\nBlockDiskAttributes " );
+ str.append( "\n DiskPath [" + this.getDiskPath() + "]" );
+ str.append( "\n MaxKeySize [" + this.getMaxKeySize() + "]" );
+ str.append( "\n MaxPurgatorySize [" + this.getMaxPurgatorySize() + "]" );
+ str.append( "\n BlockSizeBytes [" + this.getBlockSizeBytes() + "]" );
+ str.append( "\n KeyPersistenceIntervalSeconds [" + this.getKeyPersistenceIntervalSeconds() + "]" );
+ str.append( "\n DiskLimitType [" + this.getDiskLimitType() + "]" );
+ return str.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheFactory.java
new file mode 100644
index 0000000..8932375
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheFactory.java
@@ -0,0 +1,62 @@
+package org.apache.commons.jcs3.auxiliary.disk.block;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheFactory;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * Creates disk cache instances.
+ */
+public class BlockDiskCacheFactory
+ extends AbstractAuxiliaryCacheFactory
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( BlockDiskCacheFactory.class );
+
+ /**
+ * Create an instance of the BlockDiskCache.
+ * <p>
+ * @param iaca the cache attributes for this cache
+ * @param cacheMgr This allows auxiliaries to reference the manager without assuming that it is
+ * a singleton. This will allow JCS to be a non-singleton. Also, it makes it easier
+ * to test.
+ * @param cacheEventLogger
+ * @param elementSerializer
+ * @return BlockDiskCache
+ */
+ @Override
+ public <K, V> BlockDiskCache<K, V> createCache( AuxiliaryCacheAttributes iaca, ICompositeCacheManager cacheMgr,
+ ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
+ {
+ BlockDiskCacheAttributes idca = (BlockDiskCacheAttributes) iaca;
+ log.debug("Creating DiskCache for attributes = {0}", idca);
+
+ BlockDiskCache<K, V> cache = new BlockDiskCache<>( idca, elementSerializer );
+ cache.setCacheEventLogger( cacheEventLogger );
+
+ return cache;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskElementDescriptor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskElementDescriptor.java
new file mode 100644
index 0000000..3dedb97
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskElementDescriptor.java
@@ -0,0 +1,132 @@
+package org.apache.commons.jcs3.auxiliary.disk.block;
+
+/*
+ * 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.
+ */
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.Serializable;
+
+/**
+ * This represents an element on disk. This is used when we persist the keys. We only store the
+ * block addresses in memory. We don't need the length here, since all the blocks are the same size
+ * receyle bin.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class BlockDiskElementDescriptor<K>
+ implements Serializable, Externalizable
+{
+ /** Don't change */
+ private static final long serialVersionUID = -1400659301208101411L;
+
+ /** The key */
+ private K key;
+
+ /** The array of block numbers */
+ private int[] blocks;
+
+ /**
+ * @param key The key to set.
+ */
+ public void setKey( K key )
+ {
+ this.key = key;
+ }
+
+ /**
+ * @return Returns the key.
+ */
+ public K getKey()
+ {
+ return key;
+ }
+
+ /**
+ * @param blocks The blocks to set.
+ */
+ public void setBlocks( int[] blocks )
+ {
+ this.blocks = blocks;
+ }
+
+ /**
+ * This holds the block numbers. An item my be dispersed between multiple blocks.
+ * <p>
+ * @return Returns the blocks.
+ */
+ public int[] getBlocks()
+ {
+ return blocks;
+ }
+
+ /**
+ * For debugging.
+ * <p>
+ * @return Info on the descriptor.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\nBlockDiskElementDescriptor" );
+ buf.append( "\n key [" + this.getKey() + "]" );
+ buf.append( "\n blocks [" );
+ if ( this.getBlocks() != null )
+ {
+ for ( int i = 0; i < blocks.length; i++ )
+ {
+ buf.append( this.getBlocks()[i] );
+ }
+ }
+ buf.append( "]" );
+ return buf.toString();
+ }
+
+ /**
+ * Saves on reflection.
+ * <p>
+ * (non-Javadoc)
+ * @see java.io.Externalizable#readExternal(java.io.ObjectInput)
+ */
+ @Override
+ @SuppressWarnings("unchecked") // Need cast to K
+ public void readExternal( ObjectInput input )
+ throws IOException, ClassNotFoundException
+ {
+ this.key = (K) input.readObject();
+ this.blocks = (int[]) input.readObject();
+ }
+
+ /**
+ * Saves on reflection.
+ * <p>
+ * (non-Javadoc)
+ * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
+ */
+ @Override
+ public void writeExternal( ObjectOutput output )
+ throws IOException
+ {
+ output.writeObject( this.key );
+ output.writeObject( this.blocks );
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskKeyStore.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskKeyStore.java
new file mode 100644
index 0000000..f405eeb
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskKeyStore.java
@@ -0,0 +1,550 @@
+package org.apache.commons.jcs3.auxiliary.disk.block;
+
+/*
+ * 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.
+ */
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.commons.jcs3.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
+import org.apache.commons.jcs3.io.ObjectInputStreamClassLoaderAware;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.struct.AbstractLRUMap;
+import org.apache.commons.jcs3.utils.struct.LRUMap;
+import org.apache.commons.jcs3.utils.timing.ElapsedTimer;
+
+/**
+ * This is responsible for storing the keys.
+ * <p>
+ *
+ * @author Aaron Smuts
+ */
+public class BlockDiskKeyStore<K>
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog(BlockDiskKeyStore.class);
+
+ /** Attributes governing the behavior of the block disk cache. */
+ private final BlockDiskCacheAttributes blockDiskCacheAttributes;
+
+ /** The key to block map */
+ private Map<K, int[]> keyHash;
+
+ /** The file where we persist the keys */
+ private final File keyFile;
+
+ /** The name to prefix log messages with. */
+ protected final String logCacheName;
+
+ /** Name of the file where we persist the keys */
+ private final String fileName;
+
+ /** The maximum number of keys to store in memory */
+ private final int maxKeySize;
+
+ /**
+ * we need this so we can communicate free blocks to the data store when
+ * keys fall off the LRU
+ */
+ protected final BlockDiskCache<K, ?> blockDiskCache;
+
+ private DiskLimitType diskLimitType = DiskLimitType.COUNT;
+
+ private final int blockSize;
+
+ /**
+ * Set the configuration options.
+ * <p>
+ *
+ * @param cacheAttributes
+ * @param blockDiskCache
+ * used for freeing
+ */
+ public BlockDiskKeyStore(BlockDiskCacheAttributes cacheAttributes, BlockDiskCache<K, ?> blockDiskCache)
+ {
+ this.blockDiskCacheAttributes = cacheAttributes;
+ this.logCacheName = "Region [" + this.blockDiskCacheAttributes.getCacheName() + "] ";
+ this.fileName = this.blockDiskCacheAttributes.getCacheName();
+ this.maxKeySize = cacheAttributes.getMaxKeySize();
+ this.blockDiskCache = blockDiskCache;
+ this.diskLimitType = cacheAttributes.getDiskLimitType();
+ this.blockSize = cacheAttributes.getBlockSizeBytes();
+
+ File rootDirectory = cacheAttributes.getDiskPath();
+
+ log.info("{0}: Cache file root directory [{1}]", logCacheName, rootDirectory);
+
+ this.keyFile = new File(rootDirectory, fileName + ".key");
+
+ log.info("{0}: Key File [{1}]", logCacheName, this.keyFile.getAbsolutePath());
+
+ if (keyFile.length() > 0)
+ {
+ loadKeys();
+ if (!verify())
+ {
+ log.warn("{0}: Key File is invalid. Resetting file.", logCacheName);
+ initKeyMap();
+ reset();
+ }
+ }
+ else
+ {
+ initKeyMap();
+ }
+ }
+
+ /**
+ * Saves key file to disk. This gets the LRUMap entry set and write the
+ * entries out one by one after putting them in a wrapper.
+ */
+ protected void saveKeys()
+ {
+ try
+ {
+ ElapsedTimer timer = new ElapsedTimer();
+ int numKeys = keyHash.size();
+ log.info("{0}: Saving keys to [{1}], key count [{2}]", () -> logCacheName,
+ () -> this.keyFile.getAbsolutePath(), () -> numKeys);
+
+ synchronized (keyFile)
+ {
+ FileOutputStream fos = new FileOutputStream(keyFile);
+ BufferedOutputStream bos = new BufferedOutputStream(fos, 65536);
+
+ try (ObjectOutputStream oos = new ObjectOutputStream(bos))
+ {
+ if (!verify())
+ {
+ throw new IOException("Inconsistent key file");
+ }
+ // don't need to synchronize, since the underlying
+ // collection makes a copy
+ for (Map.Entry<K, int[]> entry : keyHash.entrySet())
+ {
+ BlockDiskElementDescriptor<K> descriptor = new BlockDiskElementDescriptor<>();
+ descriptor.setKey(entry.getKey());
+ descriptor.setBlocks(entry.getValue());
+ // stream these out in the loop.
+ oos.writeUnshared(descriptor);
+ }
+ }
+ }
+
+ log.info("{0}: Finished saving keys. It took {1} to store {2} keys. Key file length [{3}]",
+ () -> logCacheName, () -> timer.getElapsedTimeString(), () -> numKeys,
+ () -> keyFile.length());
+ }
+ catch (IOException e)
+ {
+ log.error("{0}: Problem storing keys.", logCacheName, e);
+ }
+ }
+
+ /**
+ * Resets the file and creates a new key map.
+ */
+ protected void reset()
+ {
+ synchronized (keyFile)
+ {
+ clearMemoryMap();
+ saveKeys();
+ }
+ }
+
+ /**
+ * This is mainly used for testing. It leave the disk in tact, and just
+ * clears memory.
+ */
+ protected void clearMemoryMap()
+ {
+ this.keyHash.clear();
+ }
+
+ /**
+ * Create the map for keys that contain the index position on disk.
+ */
+ private void initKeyMap()
+ {
+ keyHash = null;
+ if (maxKeySize >= 0)
+ {
+ if (this.diskLimitType == DiskLimitType.SIZE)
+ {
+ keyHash = new LRUMapSizeLimited(maxKeySize);
+ }
+ else
+ {
+ keyHash = new LRUMapCountLimited(maxKeySize);
+ }
+ log.info("{0}: Set maxKeySize to: \"{1}\"", logCacheName, maxKeySize);
+ }
+ else
+ {
+ // If no max size, use a plain map for memory and processing
+ // efficiency.
+ keyHash = new HashMap<>();
+ // keyHash = Collections.synchronizedMap( new HashMap() );
+ log.info("{0}: Set maxKeySize to unlimited", logCacheName);
+ }
+ }
+
+ /**
+ * Loads the keys from the .key file. The keys are stored individually on
+ * disk. They are added one by one to an LRUMap..
+ */
+ protected void loadKeys()
+ {
+ log.info("{0}: Loading keys for {1}", () -> logCacheName, () -> keyFile.toString());
+
+ try
+ {
+ // create a key map to use.
+ initKeyMap();
+
+ HashMap<K, int[]> keys = new HashMap<>();
+
+ synchronized (keyFile)
+ {
+ FileInputStream fis = new FileInputStream(keyFile);
+ BufferedInputStream bis = new BufferedInputStream(fis, 65536);
+
+ try (ObjectInputStream ois = new ObjectInputStreamClassLoaderAware(bis, null))
+ {
+ while (true)
+ {
+ @SuppressWarnings("unchecked")
+ // Need to cast from Object
+ BlockDiskElementDescriptor<K> descriptor = (BlockDiskElementDescriptor<K>) ois.readObject();
+ if (descriptor != null)
+ {
+ keys.put(descriptor.getKey(), descriptor.getBlocks());
+ }
+ }
+ }
+ catch (EOFException eof)
+ {
+ // nothing
+ }
+ }
+
+ if (!keys.isEmpty())
+ {
+ keyHash.putAll(keys);
+
+ log.debug("{0}: Found {1} in keys file.", logCacheName, keys.size());
+ log.info("{0}: Loaded keys from [{1}], key count: {2}; up to {3} will be available.",
+ () -> logCacheName, () -> fileName, () -> keyHash.size(),
+ () -> maxKeySize);
+ }
+ }
+ catch (Exception e)
+ {
+ log.error("{0}: Problem loading keys for file {1}", logCacheName, fileName, e);
+ }
+ }
+
+ /**
+ * Gets the entry set.
+ * <p>
+ *
+ * @return entry set.
+ */
+ public Set<Map.Entry<K, int[]>> entrySet()
+ {
+ return this.keyHash.entrySet();
+ }
+
+ /**
+ * Gets the key set.
+ * <p>
+ *
+ * @return key set.
+ */
+ public Set<K> keySet()
+ {
+ return this.keyHash.keySet();
+ }
+
+ /**
+ * Gets the size of the key hash.
+ * <p>
+ *
+ * @return the number of keys.
+ */
+ public int size()
+ {
+ return this.keyHash.size();
+ }
+
+ /**
+ * gets the object for the key.
+ * <p>
+ *
+ * @param key
+ * @return Object
+ */
+ public int[] get(K key)
+ {
+ return this.keyHash.get(key);
+ }
+
+ /**
+ * Puts a int[] in the keyStore.
+ * <p>
+ *
+ * @param key
+ * @param value
+ */
+ public void put(K key, int[] value)
+ {
+ this.keyHash.put(key, value);
+ }
+
+ /**
+ * Remove by key.
+ * <p>
+ *
+ * @param key
+ * @return BlockDiskElementDescriptor if it was present, else null
+ */
+ public int[] remove(K key)
+ {
+ return this.keyHash.remove(key);
+ }
+
+ /**
+ * Verify key store integrity
+ *
+ * @return true if key store is valid
+ */
+ private boolean verify()
+ {
+ Map<Integer, Set<K>> blockAllocationMap = new TreeMap<>();
+ for (Entry<K, int[]> e : keyHash.entrySet())
+ {
+ for (int block : e.getValue())
+ {
+ Set<K> keys = blockAllocationMap.get(block);
+ if (keys == null)
+ {
+ keys = new HashSet<>();
+ blockAllocationMap.put(block, keys);
+ }
+ else if (!log.isTraceEnabled())
+ {
+ // keys are not null, and no debug - fail fast
+ return false;
+ }
+ keys.add(e.getKey());
+ }
+ }
+ boolean ok = true;
+ if (log.isTraceEnabled())
+ {
+ for (Entry<Integer, Set<K>> e : blockAllocationMap.entrySet())
+ {
+ log.trace("Block {0}: {1}", e.getKey(), e.getValue());
+ if (e.getValue().size() > 1)
+ {
+ ok = false;
+ }
+ }
+ return ok;
+ }
+ else
+ {
+ return ok;
+ }
+ }
+
+ /**
+ * Class for recycling and lru. This implements the LRU size overflow
+ * callback, so we can mark the blocks as free.
+ */
+ public class LRUMapSizeLimited extends AbstractLRUMap<K, int[]>
+ {
+ /**
+ * <code>tag</code> tells us which map we are working on.
+ */
+ public final static String TAG = "orig-lru-size";
+
+ // size of the content in kB
+ private AtomicInteger contentSize;
+ private int maxSize;
+
+ /**
+ * Default
+ */
+ public LRUMapSizeLimited()
+ {
+ this(-1);
+ }
+
+ /**
+ * @param maxSize
+ * maximum cache size in kB
+ */
+ public LRUMapSizeLimited(int maxSize)
+ {
+ super();
+ this.maxSize = maxSize;
+ this.contentSize = new AtomicInteger(0);
+ }
+
+ // keep the content size in kB, so 2^31 kB is reasonable value
+ private void subLengthFromCacheSize(int[] value)
+ {
+ contentSize.addAndGet(value.length * blockSize / -1024 - 1);
+ }
+
+ // keep the content size in kB, so 2^31 kB is reasonable value
+ private void addLengthToCacheSize(int[] value)
+ {
+ contentSize.addAndGet(value.length * blockSize / 1024 + 1);
+ }
+
+ @Override
+ public int[] put(K key, int[] value)
+ {
+ int[] oldValue = null;
+
+ try
+ {
+ oldValue = super.put(key, value);
+ }
+ finally
+ {
+ if (value != null)
+ {
+ addLengthToCacheSize(value);
+ }
+ if (oldValue != null)
+ {
+ subLengthFromCacheSize(oldValue);
+ }
+ }
+
+ return oldValue;
+ }
+
+ @Override
+ public int[] remove(Object key)
+ {
+ int[] value = null;
+
+ try
+ {
+ value = super.remove(key);
+ return value;
+ }
+ finally
+ {
+ if (value != null)
+ {
+ subLengthFromCacheSize(value);
+ }
+ }
+ }
+
+ /**
+ * This is called when the may key size is reached. The least recently
+ * used item will be passed here. We will store the position and size of
+ * the spot on disk in the recycle bin.
+ * <p>
+ *
+ * @param key
+ * @param value
+ */
+ @Override
+ protected void processRemovedLRU(K key, int[] value)
+ {
+ blockDiskCache.freeBlocks(value);
+ if (log.isDebugEnabled())
+ {
+ log.debug("{0}: Removing key: [{1}] from key store.", logCacheName, key);
+ log.debug("{0}: Key store size: [{1}].", logCacheName, super.size());
+ }
+
+ if (value != null)
+ {
+ subLengthFromCacheSize(value);
+ }
+ }
+
+ @Override
+ protected boolean shouldRemove()
+ {
+ return maxSize > 0 && contentSize.get() > maxSize && this.size() > 1;
+ }
+ }
+
+ /**
+ * Class for recycling and lru. This implements the LRU overflow callback,
+ * so we can mark the blocks as free.
+ */
+ public class LRUMapCountLimited extends LRUMap<K, int[]>
+ {
+ /**
+ * <code>tag</code> tells us which map we are working on.
+ */
+ public final static String TAG = "orig-lru-count";
+
+ public LRUMapCountLimited(int maxKeySize)
+ {
+ super(maxKeySize);
+ }
+
+ /**
+ * This is called when the may key size is reached. The least recently
+ * used item will be passed here. We will store the position and size of
+ * the spot on disk in the recycle bin.
+ * <p>
+ *
+ * @param key
+ * @param value
+ */
+ @Override
+ protected void processRemovedLRU(K key, int[] value)
+ {
+ blockDiskCache.freeBlocks(value);
+ if (log.isDebugEnabled())
+ {
+ log.debug("{0}: Removing key: [{1}] from key store.", logCacheName, key);
+ log.debug("{0}: Key store size: [{1}].", logCacheName, super.size());
+ }
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDisk.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDisk.java
new file mode 100644
index 0000000..47df0fd
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDisk.java
@@ -0,0 +1,279 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.StandardOpenOption;
+
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/** Provides thread safe access to the underlying random access file. */
+public class IndexedDisk implements AutoCloseable
+{
+ /** The size of the header that indicates the amount of data stored in an occupied block. */
+ public static final byte HEADER_SIZE_BYTES = 4;
+
+ /** The serializer. */
+ private final IElementSerializer elementSerializer;
+
+ /** The logger */
+ private static final Log log = LogManager.getLog(IndexedDisk.class);
+
+ /** The path to the log directory. */
+ private final String filepath;
+
+ /** The data file. */
+ private final FileChannel fc;
+
+ /**
+ * Constructor for the Disk object
+ * <p>
+ * @param file
+ * @param elementSerializer
+ * @throws IOException
+ */
+ public IndexedDisk(File file, IElementSerializer elementSerializer)
+ throws IOException
+ {
+ this.filepath = file.getAbsolutePath();
+ this.elementSerializer = elementSerializer;
+ this.fc = FileChannel.open(file.toPath(),
+ StandardOpenOption.CREATE,
+ StandardOpenOption.READ,
+ StandardOpenOption.WRITE);
+ }
+
+ /**
+ * This reads an object from the given starting position on the file.
+ * <p>
+ * The first four bytes of the record should tell us how long it is. The data is read into a byte
+ * array and then an object is constructed from the byte array.
+ * <p>
+ * @return Serializable
+ * @param ded
+ * @throws IOException
+ * @throws ClassNotFoundException
+ */
+ protected <T> T readObject(IndexedDiskElementDescriptor ded)
+ throws IOException, ClassNotFoundException
+ {
+ String message = null;
+ boolean corrupted = false;
+ long fileLength = fc.size();
+ if (ded.pos > fileLength)
+ {
+ corrupted = true;
+ message = "Record " + ded + " starts past EOF.";
+ }
+ else
+ {
+ ByteBuffer datalength = ByteBuffer.allocate(HEADER_SIZE_BYTES);
+ fc.read(datalength, ded.pos);
+ datalength.flip();
+ int datalen = datalength.getInt();
+ if (ded.len != datalen)
+ {
+ corrupted = true;
+ message = "Record " + ded + " does not match data length on disk (" + datalen + ")";
+ }
+ else if (ded.pos + ded.len > fileLength)
+ {
+ corrupted = true;
+ message = "Record " + ded + " exceeds file length.";
+ }
+ }
+
+ if (corrupted)
+ {
+ log.warn("\n The file is corrupt: \n {0}", message);
+ throw new IOException("The File Is Corrupt, need to reset");
+ }
+
+ ByteBuffer data = ByteBuffer.allocate(ded.len);
+ fc.read(data, ded.pos + HEADER_SIZE_BYTES);
+ data.flip();
+
+ return elementSerializer.deSerialize(data.array(), null);
+ }
+
+ /**
+ * Moves the data stored from one position to another. The descriptor's position is updated.
+ * <p>
+ * @param ded
+ * @param newPosition
+ * @throws IOException
+ */
+ protected void move(final IndexedDiskElementDescriptor ded, final long newPosition)
+ throws IOException
+ {
+ ByteBuffer datalength = ByteBuffer.allocate(HEADER_SIZE_BYTES);
+ fc.read(datalength, ded.pos);
+ datalength.flip();
+ int length = datalength.getInt();
+
+ if (length != ded.len)
+ {
+ throw new IOException("Mismatched memory and disk length (" + length + ") for " + ded);
+ }
+
+ // TODO: more checks?
+
+ long readPos = ded.pos;
+ long writePos = newPosition;
+
+ // header len + data len
+ int remaining = HEADER_SIZE_BYTES + length;
+ ByteBuffer buffer = ByteBuffer.allocate(16384);
+
+ while (remaining > 0)
+ {
+ // chunk it
+ int chunkSize = Math.min(remaining, buffer.capacity());
+ buffer.limit(chunkSize);
+ fc.read(buffer, readPos);
+ buffer.flip();
+ fc.write(buffer, writePos);
+ buffer.clear();
+
+ writePos += chunkSize;
+ readPos += chunkSize;
+ remaining -= chunkSize;
+ }
+
+ ded.pos = newPosition;
+ }
+
+ /**
+ * Writes the given byte array to the Disk at the specified position.
+ * <p>
+ * @param data
+ * @param ded
+ * @return true if we wrote successfully
+ * @throws IOException
+ */
+ protected boolean write(IndexedDiskElementDescriptor ded, byte[] data)
+ throws IOException
+ {
+ long pos = ded.pos;
+ if (log.isTraceEnabled())
+ {
+ log.trace("write> pos={0}", pos);
+ log.trace("{0} -- data.length = {1}", fc, data.length);
+ }
+
+ if (data.length != ded.len)
+ {
+ throw new IOException("Mismatched descriptor and data lengths");
+ }
+
+ ByteBuffer headerBuffer = ByteBuffer.allocate(HEADER_SIZE_BYTES);
+ headerBuffer.putInt(data.length);
+ // write the header
+ headerBuffer.flip();
+ int written = fc.write(headerBuffer, pos);
+ assert written == HEADER_SIZE_BYTES;
+
+ //write the data
+ ByteBuffer dataBuffer = ByteBuffer.wrap(data);
+ written = fc.write(dataBuffer, pos + HEADER_SIZE_BYTES);
+
+ return written == data.length;
+ }
+
+ /**
+ * Serializes the object and write it out to the given position.
+ * <p>
+ * TODO: make this take a ded as well.
+ * @param obj
+ * @param pos
+ * @throws IOException
+ */
+ protected <T> void writeObject(T obj, long pos)
+ throws IOException
+ {
+ byte[] data = elementSerializer.serialize(obj);
+ write(new IndexedDiskElementDescriptor(pos, data.length), data);
+ }
+
+ /**
+ * Returns the raf length.
+ * <p>
+ * @return the length of the file.
+ * @throws IOException
+ */
+ protected long length()
+ throws IOException
+ {
+ return fc.size();
+ }
+
+ /**
+ * Closes the raf.
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ public void close()
+ throws IOException
+ {
+ fc.close();
+ }
+
+ /**
+ * Sets the raf to empty.
+ * <p>
+ * @throws IOException
+ */
+ protected synchronized void reset()
+ throws IOException
+ {
+ log.debug("Resetting Indexed File [{0}]", filepath);
+ fc.truncate(0);
+ fc.force(true);
+ }
+
+ /**
+ * Truncates the file to a given length.
+ * <p>
+ * @param length the new length of the file
+ * @throws IOException
+ */
+ protected void truncate(long length)
+ throws IOException
+ {
+ log.info("Truncating file [{0}] to {1}", filepath, length);
+ fc.truncate(length);
+ }
+
+ /**
+ * This is used for debugging.
+ * <p>
+ * @return the file path.
+ */
+ protected String getFilePath()
+ {
+ return filepath;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCache.java
new file mode 100644
index 0000000..66d5f2b
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCache.java
@@ -0,0 +1,1680 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache;
+import org.apache.commons.jcs3.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.control.group.GroupAttrName;
+import org.apache.commons.jcs3.engine.control.group.GroupId;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEvent;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.engine.stats.StatElement;
+import org.apache.commons.jcs3.engine.stats.Stats;
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.struct.AbstractLRUMap;
+import org.apache.commons.jcs3.utils.struct.LRUMap;
+import org.apache.commons.jcs3.utils.timing.ElapsedTimer;
+
+/**
+ * Disk cache that uses a RandomAccessFile with keys stored in memory. The maximum number of keys
+ * stored in memory is configurable. The disk cache tries to recycle spots on disk to limit file
+ * expansion.
+ */
+public class IndexedDiskCache<K, V> extends AbstractDiskCache<K, V>
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog(IndexedDiskCache.class);
+
+ /** Cache name used in log messages */
+ protected final String logCacheName;
+
+ /** The name of the file where the data is stored */
+ private final String fileName;
+
+ /** The IndexedDisk manages reads and writes to the data file. */
+ private IndexedDisk dataFile;
+
+ /** The IndexedDisk manages reads and writes to the key file. */
+ private IndexedDisk keyFile;
+
+ /** Map containing the keys and disk offsets. */
+ private final Map<K, IndexedDiskElementDescriptor> keyHash;
+
+ /** The maximum number of keys that we will keep in memory. */
+ private final int maxKeySize;
+
+ /** A handle on the data file. */
+ private File rafDir;
+
+ /** Should we keep adding to the recycle bin. False during optimization. */
+ private boolean doRecycle = true;
+
+ /** Should we optimize real time */
+ private boolean isRealTimeOptimizationEnabled = true;
+
+ /** Should we optimize on shutdown. */
+ private boolean isShutdownOptimizationEnabled = true;
+
+ /** are we currently optimizing the files */
+ private boolean isOptimizing = false;
+
+ /** The number of times the file has been optimized. */
+ private int timesOptimized = 0;
+
+ /** The thread optimizing the file. */
+ private volatile Thread currentOptimizationThread;
+
+ /** used for counting the number of requests */
+ private int removeCount = 0;
+
+ /** Should we queue puts. True when optimizing. We write the queue post optimization. */
+ private boolean queueInput = false;
+
+ /** list where puts made during optimization are made */
+ private final ConcurrentSkipListSet<IndexedDiskElementDescriptor> queuedPutList;
+
+ /** RECYLCE BIN -- array of empty spots */
+ private final ConcurrentSkipListSet<IndexedDiskElementDescriptor> recycle;
+
+ /** User configurable parameters */
+ private final IndexedDiskCacheAttributes cattr;
+
+ /** How many slots have we recycled. */
+ private int recycleCnt = 0;
+
+ /** How many items were there on startup. */
+ private int startupSize = 0;
+
+ /** the number of bytes free on disk. */
+ private final AtomicLong bytesFree = new AtomicLong(0);
+
+ /** mode we are working on (size or count limited **/
+ private DiskLimitType diskLimitType = DiskLimitType.COUNT;
+
+ /** simple stat */
+ private final AtomicInteger hitCount = new AtomicInteger(0);
+
+ /**
+ * Use this lock to synchronize reads and writes to the underlying storage mechanism.
+ */
+ protected ReentrantReadWriteLock storageLock = new ReentrantReadWriteLock();
+
+ /**
+ * Constructor for the DiskCache object.
+ * <p>
+ *
+ * @param cacheAttributes
+ */
+ public IndexedDiskCache(IndexedDiskCacheAttributes cacheAttributes)
+ {
+ this(cacheAttributes, null);
+ }
+
+ /**
+ * Constructor for the DiskCache object.
+ * <p>
+ *
+ * @param cattr
+ * @param elementSerializer
+ * used if supplied, the super's super will not set a null
+ */
+ public IndexedDiskCache(IndexedDiskCacheAttributes cattr, IElementSerializer elementSerializer)
+ {
+ super(cattr);
+
+ setElementSerializer(elementSerializer);
+
+ this.cattr = cattr;
+ this.maxKeySize = cattr.getMaxKeySize();
+ this.isRealTimeOptimizationEnabled = cattr.getOptimizeAtRemoveCount() > 0;
+ this.isShutdownOptimizationEnabled = cattr.isOptimizeOnShutdown();
+ this.logCacheName = "Region [" + getCacheName() + "] ";
+ this.diskLimitType = cattr.getDiskLimitType();
+ // Make a clean file name
+ this.fileName = getCacheName().replaceAll("[^a-zA-Z0-9-_\\.]", "_");
+ this.keyHash = createInitialKeyMap();
+ this.queuedPutList = new ConcurrentSkipListSet<>(new PositionComparator());
+ this.recycle = new ConcurrentSkipListSet<>();
+
+ try
+ {
+ initializeFileSystem(cattr);
+ initializeKeysAndData(cattr);
+
+ // Initialization finished successfully, so set alive to true.
+ setAlive(true);
+ log.info("{0}: Indexed Disk Cache is alive.", logCacheName);
+
+ // TODO: Should we improve detection of whether or not the file should be optimized.
+ if (isRealTimeOptimizationEnabled && keyHash.size() > 0)
+ {
+ // Kick off a real time optimization, in case we didn't do a final optimization.
+ doOptimizeRealTime();
+ }
+ }
+ catch (IOException e)
+ {
+ log.error("{0}: Failure initializing for fileName: {1} and directory: {2}",
+ logCacheName, fileName, this.rafDir.getAbsolutePath(), e);
+ }
+ }
+
+ /**
+ * Tries to create the root directory if it does not already exist.
+ * <p>
+ *
+ * @param cattr
+ */
+ private void initializeFileSystem(IndexedDiskCacheAttributes cattr)
+ {
+ this.rafDir = cattr.getDiskPath();
+ log.info("{0}: Cache file root directory: {1}", logCacheName, rafDir);
+ }
+
+ /**
+ * Creates the key and data disk caches.
+ * <p>
+ * Loads any keys if they are present and ClearDiskOnStartup is false.
+ * <p>
+ *
+ * @param cattr
+ * @throws IOException
+ */
+ private void initializeKeysAndData(IndexedDiskCacheAttributes cattr) throws IOException
+ {
+ this.dataFile = new IndexedDisk(new File(rafDir, fileName + ".data"), getElementSerializer());
+ this.keyFile = new IndexedDisk(new File(rafDir, fileName + ".key"), getElementSerializer());
+
+ if (cattr.isClearDiskOnStartup())
+ {
+ log.info("{0}: ClearDiskOnStartup is set to true. Ingnoring any persisted data.",
+ logCacheName);
+ initializeEmptyStore();
+ }
+ else if (keyFile.length() > 0)
+ {
+ // If the key file has contents, try to initialize the keys
+ // from it. In no keys are loaded reset the data file.
+ initializeStoreFromPersistedData();
+ }
+ else
+ {
+ // Otherwise start with a new empty map for the keys, and reset
+ // the data file if it has contents.
+ initializeEmptyStore();
+ }
+ }
+
+ /**
+ * Initializes an empty disk cache.
+ * <p>
+ *
+ * @throws IOException
+ */
+ private void initializeEmptyStore() throws IOException
+ {
+ this.keyHash.clear();
+
+ if (dataFile.length() > 0)
+ {
+ dataFile.reset();
+ }
+ }
+
+ /**
+ * Loads any persisted data and checks for consistency. If there is a consistency issue, the
+ * files are cleared.
+ * <p>
+ *
+ * @throws IOException
+ */
+ private void initializeStoreFromPersistedData() throws IOException
+ {
+ loadKeys();
+
+ if (keyHash.isEmpty())
+ {
+ dataFile.reset();
+ }
+ else
+ {
+ boolean isOk = checkKeyDataConsistency(false);
+ if (!isOk)
+ {
+ keyHash.clear();
+ keyFile.reset();
+ dataFile.reset();
+ log.warn("{0}: Corruption detected. Resetting data and keys files.", logCacheName);
+ }
+ else
+ {
+ synchronized (this)
+ {
+ startupSize = keyHash.size();
+ }
+ }
+ }
+ }
+
+ /**
+ * Loads the keys from the .key file. The keys are stored in a HashMap on disk. This is
+ * converted into a LRUMap.
+ */
+ protected void loadKeys()
+ {
+ log.debug("{0}: Loading keys for {1}", () -> logCacheName, () -> keyFile.toString());
+
+ storageLock.writeLock().lock();
+
+ try
+ {
+ // clear a key map to use.
+ keyHash.clear();
+
+ HashMap<K, IndexedDiskElementDescriptor> keys = keyFile.readObject(
+ new IndexedDiskElementDescriptor(0, (int) keyFile.length() - IndexedDisk.HEADER_SIZE_BYTES));
+
+ if (keys != null)
+ {
+ log.debug("{0}: Found {1} in keys file.", logCacheName, keys.size());
+
+ keyHash.putAll(keys);
+
+ log.info("{0}: Loaded keys from [{1}], key count: {2}; up to {3} will be available.",
+ () -> logCacheName, () -> fileName, () -> keyHash.size(), () -> maxKeySize);
+ }
+
+ if (log.isTraceEnabled())
+ {
+ dump(false);
+ }
+ }
+ catch (Exception e)
+ {
+ log.error("{0}: Problem loading keys for file {1}", logCacheName, fileName, e);
+ }
+ finally
+ {
+ storageLock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Check for minimal consistency between the keys and the datafile. Makes sure no starting
+ * positions in the keys exceed the file length.
+ * <p>
+ * The caller should take the appropriate action if the keys and data are not consistent.
+ *
+ * @param checkForDedOverlaps
+ * if <code>true</code>, do a more thorough check by checking for
+ * data overlap
+ * @return <code>true</code> if the test passes
+ */
+ private boolean checkKeyDataConsistency(boolean checkForDedOverlaps)
+ {
+ ElapsedTimer timer = new ElapsedTimer();
+ log.debug("{0}: Performing inital consistency check", logCacheName);
+
+ boolean isOk = true;
+ long fileLength = 0;
+ try
+ {
+ fileLength = dataFile.length();
+
+ for (Map.Entry<K, IndexedDiskElementDescriptor> e : keyHash.entrySet())
+ {
+ IndexedDiskElementDescriptor ded = e.getValue();
+
+ isOk = ded.pos + IndexedDisk.HEADER_SIZE_BYTES + ded.len <= fileLength;
+
+ if (!isOk)
+ {
+ log.warn("{0}: The dataFile is corrupted!\n raf.length() = {1}\n ded.pos = {2}",
+ logCacheName, fileLength, ded.pos);
+ break;
+ }
+ }
+
+ if (isOk && checkForDedOverlaps)
+ {
+ isOk = checkForDedOverlaps(createPositionSortedDescriptorList());
+ }
+ }
+ catch (IOException e)
+ {
+ log.error(e);
+ isOk = false;
+ }
+
+ log.info("{0}: Finished inital consistency check, isOk = {1} in {2}",
+ logCacheName, isOk, timer.getElapsedTimeString());
+
+ return isOk;
+ }
+
+ /**
+ * Detects any overlapping elements. This expects a sorted list.
+ * <p>
+ * The total length of an item is IndexedDisk.RECORD_HEADER + ded.len.
+ * <p>
+ *
+ * @param sortedDescriptors
+ * @return false if there are overlaps.
+ */
+ protected boolean checkForDedOverlaps(IndexedDiskElementDescriptor[] sortedDescriptors)
+ {
+ ElapsedTimer timer = new ElapsedTimer();
+ boolean isOk = true;
+ long expectedNextPos = 0;
+ for (int i = 0; i < sortedDescriptors.length; i++)
+ {
+ IndexedDiskElementDescriptor ded = sortedDescriptors[i];
+ if (expectedNextPos > ded.pos)
+ {
+ log.error("{0}: Corrupt file: overlapping deds {1}", logCacheName, ded);
+ isOk = false;
+ break;
+ }
+ else
+ {
+ expectedNextPos = ded.pos + IndexedDisk.HEADER_SIZE_BYTES + ded.len;
+ }
+ }
+ log.debug("{0}: Check for DED overlaps took {1} ms.", () -> logCacheName,
+ () -> timer.getElapsedTime());
+
+ return isOk;
+ }
+
+ /**
+ * Saves key file to disk. This converts the LRUMap to a HashMap for deserialization.
+ */
+ protected void saveKeys()
+ {
+ try
+ {
+ log.info("{0}: Saving keys to: {1}, key count: {2}",
+ () -> logCacheName, () -> fileName, () -> keyHash.size());
+
+ keyFile.reset();
+
+ HashMap<K, IndexedDiskElementDescriptor> keys = new HashMap<>();
+ keys.putAll(keyHash);
+
+ if (keys.size() > 0)
+ {
+ keyFile.writeObject(keys, 0);
+ }
+
+ log.info("{0}: Finished saving keys.", logCacheName);
+ }
+ catch (IOException e)
+ {
+ log.error("{0}: Problem storing keys.", logCacheName, e);
+ }
+ }
+
+ /**
+ * Update the disk cache. Called from the Queue. Makes sure the Item has not been retrieved from
+ * purgatory while in queue for disk. Remove items from purgatory when they go to disk.
+ * <p>
+ *
+ * @param ce
+ * The ICacheElement<K, V> to put to disk.
+ */
+ @Override
+ protected void processUpdate(ICacheElement<K, V> ce)
+ {
+ if (!isAlive())
+ {
+ log.error("{0}: No longer alive; aborting put of key = {1}",
+ () -> logCacheName, () -> ce.getKey());
+ return;
+ }
+
+ log.debug("{0}: Storing element on disk, key: {1}",
+ () -> logCacheName, () -> ce.getKey());
+
+ IndexedDiskElementDescriptor ded = null;
+
+ // old element with same key
+ IndexedDiskElementDescriptor old = null;
+
+ try
+ {
+ byte[] data = getElementSerializer().serialize(ce);
+
+ // make sure this only locks for one particular cache region
+ storageLock.writeLock().lock();
+ try
+ {
+ old = keyHash.get(ce.getKey());
+
+ // Item with the same key already exists in file.
+ // Try to reuse the location if possible.
+ if (old != null && data.length <= old.len)
+ {
+ // Reuse the old ded. The defrag relies on ded updates by reference, not
+ // replacement.
+ ded = old;
+ ded.len = data.length;
+ }
+ else
+ {
+ // we need this to compare in the recycle bin
+ ded = new IndexedDiskElementDescriptor(dataFile.length(), data.length);
+
+ if (doRecycle)
+ {
+ IndexedDiskElementDescriptor rep = recycle.ceiling(ded);
+ if (rep != null)
+ {
+ // remove element from recycle bin
+ recycle.remove(rep);
+ ded = rep;
+ ded.len = data.length;
+ recycleCnt++;
+ this.adjustBytesFree(ded, false);
+ log.debug("{0}: using recycled ded {1} rep.len = {2} ded.len = {3}",
+ logCacheName, ded.pos, rep.len, ded.len);
+ }
+ }
+
+ // Put it in the map
+ keyHash.put(ce.getKey(), ded);
+
+ if (queueInput)
+ {
+ queuedPutList.add(ded);
+ log.debug("{0}: added to queued put list. {1}",
+ () -> logCacheName, () -> queuedPutList.size());
+ }
+
+ // add the old slot to the recycle bin
+ if (old != null)
+ {
+ addToRecycleBin(old);
+ }
+ }
+
+ dataFile.write(ded, data);
+ }
+ finally
+ {
+ storageLock.writeLock().unlock();
+ }
+
+ log.debug("{0}: Put to file: {1}, key: {2}, position: {3}, size: {4}",
+ logCacheName, fileName, ce.getKey(), ded.pos, ded.len);
+ }
+ catch (IOException e)
+ {
+ log.error("{0}: Failure updating element, key: {1} old: {2}",
+ logCacheName, ce.getKey(), old, e);
+ }
+ }
+
+ /**
+ * Gets the key, then goes to disk to get the object.
+ * <p>
+ *
+ * @param key
+ * @return ICacheElement<K, V> or null
+ * @see AbstractDiskCache#doGet
+ */
+ @Override
+ protected ICacheElement<K, V> processGet(K key)
+ {
+ if (!isAlive())
+ {
+ log.error("{0}: No longer alive so returning null for key = {1}",
+ logCacheName, key);
+ return null;
+ }
+
+ log.debug("{0}: Trying to get from disk: {1}", logCacheName, key);
+
+ ICacheElement<K, V> object = null;
+ try
+ {
+ storageLock.readLock().lock();
+ try
+ {
+ object = readElement(key);
+ }
+ finally
+ {
+ storageLock.readLock().unlock();
+ }
+
+ if (object != null)
+ {
+ hitCount.incrementAndGet();
+ }
+ }
+ catch (IOException ioe)
+ {
+ log.error("{0}: Failure getting from disk, key = {1}", logCacheName, key, ioe);
+ reset();
+ }
+ return object;
+ }
+
+ /**
+ * Gets matching items from the cache.
+ * <p>
+ *
+ * @param pattern
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache matching keys
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> processGetMatching(String pattern)
+ {
+ Map<K, ICacheElement<K, V>> elements = new HashMap<>();
+ Set<K> keyArray = null;
+ storageLock.readLock().lock();
+ try
+ {
+ keyArray = new HashSet<>(keyHash.keySet());
+ }
+ finally
+ {
+ storageLock.readLock().unlock();
+ }
+
+ Set<K> matchingKeys = getKeyMatcher().getMatchingKeysFromArray(pattern, keyArray);
+
+ for (K key : matchingKeys)
+ {
+ ICacheElement<K, V> element = processGet(key);
+ if (element != null)
+ {
+ elements.put(key, element);
+ }
+ }
+ return elements;
+ }
+
+ /**
+ * Reads the item from disk.
+ * <p>
+ *
+ * @param key
+ * @return ICacheElement
+ * @throws IOException
+ */
+ private ICacheElement<K, V> readElement(K key) throws IOException
+ {
+ ICacheElement<K, V> object = null;
+
+ IndexedDiskElementDescriptor ded = keyHash.get(key);
+
+ if (ded != null)
+ {
+ log.debug("{0}: Found on disk, key: ", logCacheName, key);
+
+ try
+ {
+ ICacheElement<K, V> readObject = dataFile.readObject(ded);
+ object = readObject;
+ // TODO consider checking key equality and throwing if there is a failure
+ }
+ catch (IOException e)
+ {
+ log.error("{0}: IO Exception, Problem reading object from file", logCacheName, e);
+ throw e;
+ }
+ catch (Exception e)
+ {
+ log.error("{0}: Exception, Problem reading object from file", logCacheName, e);
+ throw new IOException(logCacheName + "Problem reading object from disk.", e);
+ }
+ }
+
+ return object;
+ }
+
+ /**
+ * Return the keys in this cache.
+ * <p>
+ *
+ * @see org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache#getKeySet()
+ */
+ @Override
+ public Set<K> getKeySet() throws IOException
+ {
+ HashSet<K> keys = new HashSet<>();
+
+ storageLock.readLock().lock();
+
+ try
+ {
+ keys.addAll(this.keyHash.keySet());
+ }
+ finally
+ {
+ storageLock.readLock().unlock();
+ }
+
+ return keys;
+ }
+
+ /**
+ * Returns true if the removal was successful; or false if there is nothing to remove. Current
+ * implementation always result in a disk orphan.
+ * <p>
+ *
+ * @return true if at least one item was removed.
+ * @param key
+ */
+ @Override
+ protected boolean processRemove(K key)
+ {
+ if (!isAlive())
+ {
+ log.error("{0}: No longer alive so returning false for key = {1}", logCacheName, key);
+ return false;
+ }
+
+ if (key == null)
+ {
+ return false;
+ }
+
+ boolean reset = false;
+ boolean removed = false;
+ try
+ {
+ storageLock.writeLock().lock();
+
+ if (key instanceof String && key.toString().endsWith(NAME_COMPONENT_DELIMITER))
+ {
+ removed = performPartialKeyRemoval((String) key);
+ }
+ else if (key instanceof GroupAttrName && ((GroupAttrName<?>) key).attrName == null)
+ {
+ removed = performGroupRemoval(((GroupAttrName<?>) key).groupId);
+ }
+ else
+ {
+ removed = performSingleKeyRemoval(key);
+ }
+ }
+ finally
+ {
+ storageLock.writeLock().unlock();
+ }
+
+ if (reset)
+ {
+ reset();
+ }
+
+ // this increments the remove count.
+ // there is no reason to call this if an item was not removed.
+ if (removed)
+ {
+ doOptimizeRealTime();
+ }
+
+ return removed;
+ }
+
+ /**
+ * Iterates over the keyset. Builds a list of matches. Removes all the keys in the list. Does
+ * not remove via the iterator, since the map impl may not support it.
+ * <p>
+ * This operates under a lock obtained in doRemove().
+ * <p>
+ *
+ * @param key
+ * @return true if there was a match
+ */
+ private boolean performPartialKeyRemoval(String key)
+ {
+ boolean removed = false;
+
+ // remove all keys of the same name hierarchy.
+ List<K> itemsToRemove = new LinkedList<>();
+
+ for (K k : keyHash.keySet())
+ {
+ if (k instanceof String && k.toString().startsWith(key))
+ {
+ itemsToRemove.add(k);
+ }
+ }
+
+ // remove matches.
+ for (K fullKey : itemsToRemove)
+ {
+ // Don't add to recycle bin here
+ // https://issues.apache.org/jira/browse/JCS-67
+ performSingleKeyRemoval(fullKey);
+ removed = true;
+ // TODO this needs to update the remove count separately
+ }
+
+ return removed;
+ }
+
+ /**
+ * Remove all elements from the group. This does not use the iterator to remove. It builds a
+ * list of group elements and then removes them one by one.
+ * <p>
+ * This operates under a lock obtained in doRemove().
+ * <p>
+ *
+ * @param key
+ * @return true if an element was removed
+ */
+ private boolean performGroupRemoval(GroupId key)
+ {
+ boolean removed = false;
+
+ // remove all keys of the same name group.
+ List<K> itemsToRemove = new LinkedList<>();
+
+ // remove all keys of the same name hierarchy.
+ for (K k : keyHash.keySet())
+ {
+ if (k instanceof GroupAttrName && ((GroupAttrName<?>) k).groupId.equals(key))
+ {
+ itemsToRemove.add(k);
+ }
+ }
+
+ // remove matches.
+ for (K fullKey : itemsToRemove)
+ {
+ // Don't add to recycle bin here
+ // https://issues.apache.org/jira/browse/JCS-67
+ performSingleKeyRemoval(fullKey);
+ removed = true;
+ // TODO this needs to update the remove count separately
+ }
+
+ return removed;
+ }
+
+ /**
+ * Removes an individual key from the cache.
+ * <p>
+ * This operates under a lock obtained in doRemove().
+ * <p>
+ *
+ * @param key
+ * @return true if an item was removed.
+ */
+ private boolean performSingleKeyRemoval(K key)
+ {
+ boolean removed;
+ // remove single item.
+ IndexedDiskElementDescriptor ded = keyHash.remove(key);
+ removed = ded != null;
+ addToRecycleBin(ded);
+
+ log.debug("{0}: Disk removal: Removed from key hash, key [{1}] removed = {2}",
+ logCacheName, key, removed);
+ return removed;
+ }
+
+ /**
+ * Remove all the items from the disk cache by reseting everything.
+ */
+ @Override
+ public void processRemoveAll()
+ {
+ ICacheEvent<String> cacheEvent =
+ createICacheEvent(getCacheName(), "all", ICacheEventLogger.REMOVEALL_EVENT);
+ try
+ {
+ reset();
+ }
+ finally
+ {
+ logICacheEvent(cacheEvent);
+ }
+ }
+
+ /**
+ * Reset effectively clears the disk cache, creating new files, recycle bins, and keymaps.
+ * <p>
+ * It can be used to handle errors by last resort, force content update, or removeall.
+ */
+ private void reset()
+ {
+ log.info("{0}: Resetting cache", logCacheName);
+
+ try
+ {
+ storageLock.writeLock().lock();
+
+ if (dataFile != null)
+ {
+ dataFile.close();
+ }
+
+ File dataFileTemp = new File(rafDir, fileName + ".data");
+ Files.delete(dataFileTemp.toPath());
+
+ if (keyFile != null)
+ {
+ keyFile.close();
+ }
+ File keyFileTemp = new File(rafDir, fileName + ".key");
+ Files.delete(keyFileTemp.toPath());
+
+ dataFile = new IndexedDisk(dataFileTemp, getElementSerializer());
+ keyFile = new IndexedDisk(keyFileTemp, getElementSerializer());
+
+ this.recycle.clear();
+ this.keyHash.clear();
+ }
+ catch (IOException e)
+ {
+ log.error("{0}: Failure resetting state", logCacheName, e);
+ }
+ finally
+ {
+ storageLock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Create the map for keys that contain the index position on disk.
+ *
+ * @return a new empty Map for keys and IndexedDiskElementDescriptors
+ */
+ private Map<K, IndexedDiskElementDescriptor> createInitialKeyMap()
+ {
+ Map<K, IndexedDiskElementDescriptor> keyMap = null;
+ if (maxKeySize >= 0)
+ {
+ if (this.diskLimitType == DiskLimitType.COUNT)
+ {
+ keyMap = new LRUMapCountLimited(maxKeySize);
+ }
+ else
+ {
+ keyMap = new LRUMapSizeLimited(maxKeySize);
+ }
+
+ log.info("{0}: Set maxKeySize to: \"{1}\"", logCacheName, maxKeySize);
+ }
+ else
+ {
+ // If no max size, use a plain map for memory and processing efficiency.
+ keyMap = new HashMap<>();
+ // keyHash = Collections.synchronizedMap( new HashMap() );
+ log.info("{0}: Set maxKeySize to unlimited", logCacheName);
+ }
+
+ return keyMap;
+ }
+
+ /**
+ * Dispose of the disk cache in a background thread. Joins against this thread to put a cap on
+ * the disposal time.
+ * <p>
+ * TODO make dispose window configurable.
+ */
+ @Override
+ public void processDispose()
+ {
+ ICacheEvent<String> cacheEvent = createICacheEvent(getCacheName(), "none", ICacheEventLogger.DISPOSE_EVENT);
+ try
+ {
+ Thread t = new Thread(this::disposeInternal, "IndexedDiskCache-DisposalThread");
+ t.start();
+ // wait up to 60 seconds for dispose and then quit if not done.
+ try
+ {
+ t.join(60 * 1000);
+ }
+ catch (InterruptedException ex)
+ {
+ log.error("{0}: Interrupted while waiting for disposal thread to finish.",
+ logCacheName, ex);
+ }
+ }
+ finally
+ {
+ logICacheEvent(cacheEvent);
+ }
+ }
+
+ /**
+ * Internal method that handles the disposal.
+ */
+ protected void disposeInternal()
+ {
+ if (!isAlive())
+ {
+ log.error("{0}: Not alive and dispose was called, filename: {1}",
+ logCacheName, fileName);
+ return;
+ }
+
+ // Prevents any interaction with the cache while we're shutting down.
+ setAlive(false);
+
+ Thread optimizationThread = currentOptimizationThread;
+ if (isRealTimeOptimizationEnabled && optimizationThread != null)
+ {
+ // Join with the current optimization thread.
+ log.debug("{0}: In dispose, optimization already in progress; waiting for completion.",
+ logCacheName);
+
+ try
+ {
+ optimizationThread.join();
+ }
+ catch (InterruptedException e)
+ {
+ log.error("{0}: Unable to join current optimization thread.",
+ logCacheName, e);
+ }
+ }
+ else if (isShutdownOptimizationEnabled && this.getBytesFree() > 0)
+ {
+ optimizeFile();
+ }
+
+ saveKeys();
+
+ try
+ {
+ log.debug("{0}: Closing files, base filename: {1}", logCacheName,
+ fileName);
+ dataFile.close();
+ dataFile = null;
+ keyFile.close();
+ keyFile = null;
+ }
+ catch (IOException e)
+ {
+ log.error("{0}: Failure closing files in dispose, filename: {1}",
+ logCacheName, fileName, e);
+ }
+
+ log.info("{0}: Shutdown complete.", logCacheName);
+ }
+
+ /**
+ * Add descriptor to recycle bin if it is not null. Adds the length of the item to the bytes
+ * free.
+ * <p>
+ * This is called in three places: (1) When an item is removed. All item removals funnel down to the removeSingleItem method.
+ * (2) When an item on disk is updated with a value that will not fit in the previous slot. (3) When the max key size is
+ * reached, the freed slot will be added.
+ * <p>
+ *
+ * @param ded
+ */
+ protected void addToRecycleBin(IndexedDiskElementDescriptor ded)
+ {
+ // reuse the spot
+ if (ded != null)
+ {
+ storageLock.readLock().lock();
+
+ try
+ {
+ adjustBytesFree(ded, true);
+
+ if (doRecycle)
+ {
+ recycle.add(ded);
+ log.debug("{0}: recycled ded {1}", logCacheName, ded);
+ }
+ }
+ finally
+ {
+ storageLock.readLock().unlock();
+ }
+ }
+ }
+
+ /**
+ * Performs the check for optimization, and if it is required, do it.
+ */
+ protected void doOptimizeRealTime()
+ {
+ if (isRealTimeOptimizationEnabled && !isOptimizing
+ && removeCount++ >= cattr.getOptimizeAtRemoveCount())
+ {
+ isOptimizing = true;
+
+ log.info("{0}: Optimizing file. removeCount [{1}] OptimizeAtRemoveCount [{2}]",
+ logCacheName, removeCount, cattr.getOptimizeAtRemoveCount());
+
+ if (currentOptimizationThread == null)
+ {
+ storageLock.writeLock().lock();
+
+ try
+ {
+ if (currentOptimizationThread == null)
+ {
+ currentOptimizationThread = new Thread(() -> {
+ optimizeFile();
+ currentOptimizationThread = null;
+ }, "IndexedDiskCache-OptimizationThread");
+ }
+ }
+ finally
+ {
+ storageLock.writeLock().unlock();
+ }
+
+ if (currentOptimizationThread != null)
+ {
+ currentOptimizationThread.start();
+ }
+ }
+ }
+ }
+
+ /**
+ * File optimization is handled by this method. It works as follows:
+ * <ol>
+ * <li>Shutdown recycling and turn on queuing of puts.</li>
+ * <li>Take a snapshot of the current descriptors. If there are any removes, ignore them, as they will be compacted during the
+ * next optimization.</li>
+ * <li>Optimize the snapshot. For each descriptor:
+ * <ol>
+ * <li>Obtain the write-lock.</li>
+ * <li>Shift the element on the disk, in order to compact out the free space.</li>
+ * <li>Release the write-lock. This allows elements to still be accessible during optimization.</li>
+ * </ol>
+ * </li>
+ * <li>Obtain the write-lock.</li>
+ * <li>All queued puts are made at the end of the file. Optimize these under a single write-lock.</li>
+ * <li>Truncate the file.</li>
+ * <li>Release the write-lock.</li>
+ * <li>Restore system to standard operation.</li>
+ * </ol>
+ */
+ protected void optimizeFile()
+ {
+ ElapsedTimer timer = new ElapsedTimer();
+ timesOptimized++;
+ log.info("{0}: Beginning Optimization #{1}", logCacheName, timesOptimized);
+
+ // CREATE SNAPSHOT
+ IndexedDiskElementDescriptor[] defragList = null;
+
+ storageLock.writeLock().lock();
+
+ try
+ {
+ queueInput = true;
+ // shut off recycle while we're optimizing,
+ doRecycle = false;
+ defragList = createPositionSortedDescriptorList();
+ }
+ finally
+ {
+ storageLock.writeLock().unlock();
+ }
+
+ // Defrag the file outside of the write lock. This allows a move to be made,
+ // and yet have the element still accessible for reading or writing.
+ long expectedNextPos = defragFile(defragList, 0);
+
+ // ADD THE QUEUED ITEMS to the end and then truncate
+ storageLock.writeLock().lock();
+
+ try
+ {
+ try
+ {
+ if (!queuedPutList.isEmpty())
+ {
+ defragList = queuedPutList.toArray(new IndexedDiskElementDescriptor[queuedPutList.size()]);
+
+ // pack them at the end
+ expectedNextPos = defragFile(defragList, expectedNextPos);
+ }
+ // TRUNCATE THE FILE
+ dataFile.truncate(expectedNextPos);
+ }
+ catch (IOException e)
+ {
+ log.error("{0}: Error optimizing queued puts.", logCacheName, e);
+ }
+
+ // RESTORE NORMAL OPERATION
+ removeCount = 0;
+ resetBytesFree();
+ this.recycle.clear();
+ queuedPutList.clear();
+ queueInput = false;
+ // turn recycle back on.
+ doRecycle = true;
+ isOptimizing = false;
+ }
+ finally
+ {
+ storageLock.writeLock().unlock();
+ }
+
+ log.info("{0}: Finished #{1}, Optimization took {2}",
+ logCacheName, timesOptimized, timer.getElapsedTimeString());
+ }
+
+ /**
+ * Defragments the file in place by compacting out the free space (i.e., moving records
+ * forward). If there were no gaps the resulting file would be the same size as the previous
+ * file. This must be supplied an ordered defragList.
+ * <p>
+ *
+ * @param defragList
+ * sorted list of descriptors for optimization
+ * @param startingPos
+ * the start position in the file
+ * @return this is the potential new file end
+ */
+ private long defragFile(IndexedDiskElementDescriptor[] defragList, long startingPos)
+ {
+ ElapsedTimer timer = new ElapsedTimer();
+ long preFileSize = 0;
+ long postFileSize = 0;
+ long expectedNextPos = 0;
+ try
+ {
+ preFileSize = this.dataFile.length();
+ // find the first gap in the disk and start defragging.
+ expectedNextPos = startingPos;
+ for (int i = 0; i < defragList.length; i++)
+ {
+ storageLock.writeLock().lock();
+ try
+ {
+ if (expectedNextPos != defragList[i].pos)
+ {
+ dataFile.move(defragList[i], expectedNextPos);
+ }
+ expectedNextPos = defragList[i].pos + IndexedDisk.HEADER_SIZE_BYTES + defragList[i].len;
+ }
+ finally
+ {
+ storageLock.writeLock().unlock();
+ }
+ }
+
+ postFileSize = this.dataFile.length();
+
+ // this is the potential new file end
+ return expectedNextPos;
+ }
+ catch (IOException e)
+ {
+ log.error("{0}: Error occurred during defragmentation.", logCacheName, e);
+ }
+ finally
+ {
+ log.info("{0}: Defragmentation took {1}. File Size (before={2}) (after={3}) (truncating to {4})",
+ logCacheName, timer.getElapsedTimeString(), preFileSize, postFileSize, expectedNextPos);
+ }
+
+ return 0;
+ }
+
+ /**
+ * Creates a snapshot of the IndexedDiskElementDescriptors in the keyHash and returns them
+ * sorted by position in the dataFile.
+ * <p>
+ *
+ * @return IndexedDiskElementDescriptor[]
+ */
+ private IndexedDiskElementDescriptor[] createPositionSortedDescriptorList()
+ {
+ List<IndexedDiskElementDescriptor> defragList = new ArrayList<>(keyHash.values());
+ Collections.sort(defragList, new PositionComparator());
+
+ return defragList.toArray(new IndexedDiskElementDescriptor[0]);
+ }
+
+ /**
+ * Returns the current cache size.
+ * <p>
+ *
+ * @return The size value
+ */
+ @Override
+ public int getSize()
+ {
+ return keyHash.size();
+ }
+
+ /**
+ * Returns the size of the recycle bin in number of elements.
+ * <p>
+ *
+ * @return The number of items in the bin.
+ */
+ protected int getRecyleBinSize()
+ {
+ return this.recycle.size();
+ }
+
+ /**
+ * Returns the number of times we have used spots from the recycle bin.
+ * <p>
+ *
+ * @return The number of spots used.
+ */
+ protected int getRecyleCount()
+ {
+ return this.recycleCnt;
+ }
+
+ /**
+ * Returns the number of bytes that are free. When an item is removed, its length is recorded.
+ * When a spot is used form the recycle bin, the length of the item stored is recorded.
+ * <p>
+ *
+ * @return The number bytes free on the disk file.
+ */
+ protected long getBytesFree()
+ {
+ return this.bytesFree.get();
+ }
+
+ /**
+ * Resets the number of bytes that are free.
+ */
+ private void resetBytesFree()
+ {
+ this.bytesFree.set(0);
+ }
+
+ /**
+ * To subtract you can pass in false for add..
+ * <p>
+ *
+ * @param ded
+ * @param add
+ */
+ private void adjustBytesFree(IndexedDiskElementDescriptor ded, boolean add)
+ {
+ if (ded != null)
+ {
+ int amount = ded.len + IndexedDisk.HEADER_SIZE_BYTES;
+
+ if (add)
+ {
+ this.bytesFree.addAndGet(amount);
+ }
+ else
+ {
+ this.bytesFree.addAndGet(-amount);
+ }
+ }
+ }
+
+ /**
+ * This is for debugging and testing.
+ * <p>
+ *
+ * @return the length of the data file.
+ * @throws IOException
+ */
+ protected long getDataFileSize() throws IOException
+ {
+ long size = 0;
+
+ storageLock.readLock().lock();
+
+ try
+ {
+ if (dataFile != null)
+ {
+ size = dataFile.length();
+ }
+ }
+ finally
+ {
+ storageLock.readLock().unlock();
+ }
+
+ return size;
+ }
+
+ /**
+ * For debugging. This dumps the values by default.
+ */
+ public void dump()
+ {
+ dump(true);
+ }
+
+ /**
+ * For debugging.
+ * <p>
+ *
+ * @param dumpValues
+ * A boolean indicating if values should be dumped.
+ */
+ public void dump(boolean dumpValues)
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("{0}: [dump] Number of keys: {1}", logCacheName, keyHash.size());
+
+ for (Map.Entry<K, IndexedDiskElementDescriptor> e : keyHash.entrySet())
+ {
+ K key = e.getKey();
+ IndexedDiskElementDescriptor ded = e.getValue();
+
+ log.trace("{0}: [dump] Disk element, key: {1}, pos: {2}, len: {3}" +
+ (dumpValues ? ", val: " + get(key) : ""),
+ logCacheName, key, ded.pos, ded.len);
+ }
+ }
+ }
+
+ /**
+ * @return Returns the AuxiliaryCacheAttributes.
+ */
+ @Override
+ public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
+ {
+ return this.cattr;
+ }
+
+ /**
+ * Returns info about the disk cache.
+ * <p>
+ *
+ * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCache#getStatistics()
+ */
+ @Override
+ public synchronized IStats getStatistics()
+ {
+ IStats stats = new Stats();
+ stats.setTypeName("Indexed Disk Cache");
+
+ ArrayList<IStatElement<?>> elems = new ArrayList<>();
+
+ elems.add(new StatElement<>("Is Alive", Boolean.valueOf(isAlive())));
+ elems.add(new StatElement<>("Key Map Size", Integer.valueOf(this.keyHash != null ? this.keyHash.size() : -1)));
+ try
+ {
+ elems.add(
+ new StatElement<>("Data File Length", Long.valueOf(this.dataFile != null ? this.dataFile.length() : -1L)));
+ }
+ catch (IOException e)
+ {
+ log.error(e);
+ }
+ elems.add(new StatElement<>("Max Key Size", this.maxKeySize));
+ elems.add(new StatElement<>("Hit Count", this.hitCount));
+ elems.add(new StatElement<>("Bytes Free", this.bytesFree));
+ elems.add(new StatElement<>("Optimize Operation Count", Integer.valueOf(this.removeCount)));
+ elems.add(new StatElement<>("Times Optimized", Integer.valueOf(this.timesOptimized)));
+ elems.add(new StatElement<>("Recycle Count", Integer.valueOf(this.recycleCnt)));
+ elems.add(new StatElement<>("Recycle Bin Size", Integer.valueOf(this.recycle.size())));
+ elems.add(new StatElement<>("Startup Size", Integer.valueOf(this.startupSize)));
+
+ // get the stats from the super too
+ IStats sStats = super.getStatistics();
+ elems.addAll(sStats.getStatElements());
+
+ stats.setStatElements(elems);
+
+ return stats;
+ }
+
+ /**
+ * This is exposed for testing.
+ * <p>
+ *
+ * @return Returns the timesOptimized.
+ */
+ protected int getTimesOptimized()
+ {
+ return timesOptimized;
+ }
+
+ /**
+ * This is used by the event logging.
+ * <p>
+ *
+ * @return the location of the disk, either path or ip.
+ */
+ @Override
+ protected String getDiskLocation()
+ {
+ return dataFile.getFilePath();
+ }
+
+ /**
+ * Compares IndexedDiskElementDescriptor based on their position.
+ * <p>
+ */
+ protected static final class PositionComparator implements Comparator<IndexedDiskElementDescriptor>, Serializable
+ {
+ /** serialVersionUID */
+ private static final long serialVersionUID = -8387365338590814113L;
+
+ /**
+ * Compares two descriptors based on position.
+ * <p>
+ *
+ * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+ */
+ @Override
+ public int compare(IndexedDiskElementDescriptor ded1, IndexedDiskElementDescriptor ded2)
+ {
+ if (ded1.pos < ded2.pos)
+ {
+ return -1;
+ }
+ else if (ded1.pos == ded2.pos)
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ }
+
+ /**
+ * Class for recycling and lru. This implements the LRU overflow callback, so we can add items
+ * to the recycle bin. This class counts the size element to decide, when to throw away an element
+ */
+ public class LRUMapSizeLimited extends AbstractLRUMap<K, IndexedDiskElementDescriptor>
+ {
+ /**
+ * <code>tag</code> tells us which map we are working on.
+ */
+ public static final String TAG = "orig";
+
+ // size of the content in kB
+ private AtomicInteger contentSize;
+ private int maxSize;
+
+ /**
+ * Default
+ */
+ public LRUMapSizeLimited()
+ {
+ this(-1);
+ }
+
+ /**
+ * @param maxKeySize
+ */
+ public LRUMapSizeLimited(int maxKeySize)
+ {
+ super();
+ this.maxSize = maxKeySize;
+ this.contentSize = new AtomicInteger(0);
+ }
+
+ // keep the content size in kB, so 2^31 kB is reasonable value
+ private void subLengthFromCacheSize(IndexedDiskElementDescriptor value)
+ {
+ contentSize.addAndGet((value.len + IndexedDisk.HEADER_SIZE_BYTES) / -1024 - 1);
+ }
+
+ // keep the content size in kB, so 2^31 kB is reasonable value
+ private void addLengthToCacheSize(IndexedDiskElementDescriptor value)
+ {
+ contentSize.addAndGet((value.len + IndexedDisk.HEADER_SIZE_BYTES) / 1024 + 1);
+ }
+
+ @Override
+ public IndexedDiskElementDescriptor put(K key, IndexedDiskElementDescriptor value)
+ {
+ IndexedDiskElementDescriptor oldValue = null;
+
+ try
+ {
+ oldValue = super.put(key, value);
+ }
+ finally
+ {
+ // keep the content size in kB, so 2^31 kB is reasonable value
+ if (value != null)
+ {
+ addLengthToCacheSize(value);
+ }
+ if (oldValue != null)
+ {
+ subLengthFromCacheSize(oldValue);
+ }
+ }
+
+ return oldValue;
+ }
+
+ @Override
+ public IndexedDiskElementDescriptor remove(Object key)
+ {
+ IndexedDiskElementDescriptor value = null;
+
+ try
+ {
+ value = super.remove(key);
+ return value;
+ }
+ finally
+ {
+ if (value != null)
+ {
+ subLengthFromCacheSize(value);
+ }
+ }
+ }
+
+ /**
+ * This is called when the may key size is reached. The least recently used item will be
+ * passed here. We will store the position and size of the spot on disk in the recycle bin.
+ * <p>
+ *
+ * @param key
+ * @param value
+ */
+ @Override
+ protected void processRemovedLRU(K key, IndexedDiskElementDescriptor value)
+ {
+ if (value != null)
+ {
+ subLengthFromCacheSize(value);
+ }
+
+ addToRecycleBin(value);
+
+ log.debug("{0}: Removing key: [{1}] from key store.", logCacheName, key);
+ log.debug("{0}: Key store size: [{1}].", logCacheName, this.size());
+
+ doOptimizeRealTime();
+ }
+
+ @Override
+ protected boolean shouldRemove()
+ {
+ return maxSize > 0 && contentSize.get() > maxSize && this.size() > 0;
+ }
+ }
+
+ /**
+ * Class for recycling and lru. This implements the LRU overflow callback, so we can add items
+ * to the recycle bin. This class counts the elements to decide, when to throw away an element
+ */
+
+ public class LRUMapCountLimited extends LRUMap<K, IndexedDiskElementDescriptor>
+ // implements Serializable
+ {
+ public LRUMapCountLimited(int maxKeySize)
+ {
+ super(maxKeySize);
+ }
+
+ /**
+ * This is called when the may key size is reached. The least recently used item will be
+ * passed here. We will store the position and size of the spot on disk in the recycle bin.
+ * <p>
+ *
+ * @param key
+ * @param value
+ */
+ @Override
+ protected void processRemovedLRU(K key, IndexedDiskElementDescriptor value)
+ {
+ addToRecycleBin(value);
+ log.debug("{0}: Removing key: [{1}] from key store.", logCacheName, key);
+ log.debug("{0}: Key store size: [{1}].", logCacheName, this.size());
+
+ doOptimizeRealTime();
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheAttributes.java
new file mode 100644
index 0000000..f90a72b
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheAttributes.java
@@ -0,0 +1,154 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCacheAttributes;
+
+/**
+ * Configuration class for the Indexed Disk Cache
+ */
+public class IndexedDiskCacheAttributes
+ extends AbstractDiskCacheAttributes
+{
+ /** Don't change. */
+ private static final long serialVersionUID = -2190863599358782950L;
+
+ /** default value */
+ private static final int DEFAULT_maxKeySize = 5000;
+
+ /** -1 means no limit. */
+ private int maxKeySize = DEFAULT_maxKeySize;
+
+ /** default to -1, i.e., don't optimize until shutdown */
+ private int optimizeAtRemoveCount = -1;
+
+ /** Should we optimize on shutdown. */
+ public static final boolean DEFAULT_OPTIMIZE_ON_SHUTDOWN = true;
+
+ /** Should we optimize on shutdown. */
+ private boolean optimizeOnShutdown = DEFAULT_OPTIMIZE_ON_SHUTDOWN;
+
+ /** Should we clear the disk on startup. */
+ public static final boolean DEFAULT_CLEAR_DISK_ON_STARTUP = false;
+
+ /** Should we clear the disk on startup. If true the contents of disk are cleared. */
+ private boolean clearDiskOnStartup = DEFAULT_CLEAR_DISK_ON_STARTUP;
+
+ /**
+ * Constructor for the DiskCacheAttributes object
+ */
+ public IndexedDiskCacheAttributes()
+ {
+ super();
+ }
+
+ /**
+ * Gets the maxKeySize attribute of the DiskCacheAttributes object
+ * <p>
+ * @return The maxKeySize value
+ */
+ public int getMaxKeySize()
+ {
+ return this.maxKeySize;
+ }
+
+ /**
+ * Sets the maxKeySize attribute of the DiskCacheAttributes object
+ * <p>
+ * @param maxKeySize The new maxKeySize value
+ */
+ public void setMaxKeySize( int maxKeySize )
+ {
+ this.maxKeySize = maxKeySize;
+ }
+
+ /**
+ * Gets the optimizeAtRemoveCount attribute of the DiskCacheAttributes object
+ * <p>
+ * @return The optimizeAtRemoveCount value
+ */
+ public int getOptimizeAtRemoveCount()
+ {
+ return this.optimizeAtRemoveCount;
+ }
+
+ /**
+ * Sets the optimizeAtRemoveCount attribute of the DiskCacheAttributes object This number
+ * determines how often the disk cache should run real time optimizations.
+ * <p>
+ * @param cnt The new optimizeAtRemoveCount value
+ */
+ public void setOptimizeAtRemoveCount( int cnt )
+ {
+ this.optimizeAtRemoveCount = cnt;
+ }
+
+ /**
+ * @param optimizeOnShutdown The optimizeOnShutdown to set.
+ */
+ public void setOptimizeOnShutdown( boolean optimizeOnShutdown )
+ {
+ this.optimizeOnShutdown = optimizeOnShutdown;
+ }
+
+ /**
+ * @return Returns the optimizeOnShutdown.
+ */
+ public boolean isOptimizeOnShutdown()
+ {
+ return optimizeOnShutdown;
+ }
+
+ /**
+ * @param clearDiskOnStartup the clearDiskOnStartup to set
+ */
+ public void setClearDiskOnStartup( boolean clearDiskOnStartup )
+ {
+ this.clearDiskOnStartup = clearDiskOnStartup;
+ }
+
+ /**
+ * @return the clearDiskOnStartup
+ */
+ public boolean isClearDiskOnStartup()
+ {
+ return clearDiskOnStartup;
+ }
+
+ /**
+ * Write out the values for debugging purposes.
+ * <p>
+ * @return String
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder str = new StringBuilder();
+ str.append( "IndexedDiskCacheAttributes " );
+ str.append( "\n diskPath = " + super.getDiskPath() );
+ str.append( "\n maxPurgatorySize = " + super.getMaxPurgatorySize() );
+ str.append( "\n maxKeySize = " + maxKeySize );
+ str.append( "\n optimizeAtRemoveCount = " + optimizeAtRemoveCount );
+ str.append( "\n shutdownSpoolTimeLimit = " + super.getShutdownSpoolTimeLimit() );
+ str.append( "\n optimizeOnShutdown = " + optimizeOnShutdown );
+ str.append( "\n clearDiskOnStartup = " + clearDiskOnStartup );
+ return str.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheFactory.java
new file mode 100644
index 0000000..cd5c660
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheFactory.java
@@ -0,0 +1,62 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheFactory;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * Creates disk cache instances.
+ */
+public class IndexedDiskCacheFactory
+ extends AbstractAuxiliaryCacheFactory
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog( IndexedDiskCacheFactory.class );
+
+ /**
+ * Create an instance of an IndexedDiskCache.
+ * <p>
+ * @param iaca cache attributes of this cache instance
+ * @param cacheMgr This allows auxiliaries to reference the manager without assuming that it is
+ * a singleton. This will allow JCS to be a non-singleton. Also, it makes it easier to
+ * test.
+ * @param cacheEventLogger
+ * @param elementSerializer
+ * @return IndexedDiskCache
+ */
+ @Override
+ public <K, V> IndexedDiskCache<K, V> createCache( AuxiliaryCacheAttributes iaca, ICompositeCacheManager cacheMgr,
+ ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
+ {
+ IndexedDiskCacheAttributes idca = (IndexedDiskCacheAttributes) iaca;
+ log.debug( "Creating DiskCache for attributes = {0}", idca );
+
+ IndexedDiskCache<K, V> cache = new IndexedDiskCache<>( idca, elementSerializer );
+ cache.setCacheEventLogger( cacheEventLogger );
+
+ return cache;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskDumper.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskDumper.java
new file mode 100644
index 0000000..ffb25d9
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskDumper.java
@@ -0,0 +1,57 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+
+
+/**
+ * Used to dump out a Disk cache from disk for debugging. This is meant to be
+ * run as a command line utility for
+ */
+public class IndexedDiskDumper
+{
+ /**
+ * The main program for the DiskDumper class
+ * <p>
+ * Creates a disk cache and then calls dump, which write out the contents to
+ * a debug log.
+ * <p>
+ * @param args
+ * The command line arguments
+ */
+ public static void main( String[] args )
+ {
+ if ( args.length != 1 )
+ {
+ System.out.println( "Usage: java org.apache.commons.jcs3.auxiliary.disk.DiskDump <cache_name>" );
+ System.exit( 0 );
+ }
+
+ IndexedDiskCacheAttributes attr = new IndexedDiskCacheAttributes();
+
+ attr.setCacheName( args[0] );
+ attr.setDiskPath( args[0] );
+
+ IndexedDiskCache<Serializable, Serializable> dc = new IndexedDiskCache<>( attr );
+ dc.dump( true );
+ System.exit( 0 );
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskElementDescriptor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskElementDescriptor.java
new file mode 100644
index 0000000..2158c46
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskElementDescriptor.java
@@ -0,0 +1,132 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+
+/**
+ * Disk objects are located by descriptor entries. These are saved on shutdown and loaded into
+ * memory on startup.
+ */
+public class IndexedDiskElementDescriptor
+ implements Serializable, Comparable<IndexedDiskElementDescriptor>
+{
+ /** Don't change */
+ private static final long serialVersionUID = -3029163572847659450L;
+
+ /** Position of the cache data entry on disk. */
+ long pos;
+
+ /** Number of bytes the serialized form of the cache data takes. */
+ int len;
+
+ /**
+ * Constructs a usable disk element descriptor.
+ * <p>
+ * @param pos
+ * @param len
+ */
+ public IndexedDiskElementDescriptor( long pos, int len )
+ {
+ this.pos = pos;
+ this.len = len;
+ }
+
+ /**
+ * @return debug string
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "[DED: " );
+ buf.append( " pos = " + pos );
+ buf.append( " len = " + len );
+ buf.append( "]" );
+ return buf.toString();
+ }
+
+ /**
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode()
+ {
+ return Long.valueOf(this.pos).hashCode() ^ Integer.valueOf(len).hashCode();
+ }
+
+ /**
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object o)
+ {
+ if (o == null)
+ {
+ return false;
+ }
+ else if (o instanceof IndexedDiskElementDescriptor)
+ {
+ IndexedDiskElementDescriptor ided = (IndexedDiskElementDescriptor)o;
+ return pos == ided.pos && len == ided.len;
+ }
+
+ return false;
+ }
+
+ /**
+ * Compares based on length, then on pos descending.
+ * <p>
+ * @param o Object
+ * @return int
+ */
+ @Override
+ public int compareTo( IndexedDiskElementDescriptor o )
+ {
+ if ( o == null )
+ {
+ return 1;
+ }
+
+ if ( o.len == len )
+ {
+ if ( o.pos == pos )
+ {
+ return 0;
+ }
+ else if ( o.pos < pos )
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ else if ( o.len > len )
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCache.java
new file mode 100644
index 0000000..720fdf2
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCache.java
@@ -0,0 +1,878 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.sql.DataSource;
+
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.DataSourceFactory;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEvent;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.engine.stats.StatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+
+/**
+ * This is the jdbc disk cache plugin.
+ * <p>
+ * It expects a table created by the following script. The table name is configurable.
+ * <p>
+ *
+ * <pre>
+ * drop TABLE JCS_STORE;
+ * CREATE TABLE JCS_STORE
+ * (
+ * CACHE_KEY VARCHAR(250) NOT NULL,
+ * REGION VARCHAR(250) NOT NULL,
+ * ELEMENT BLOB,
+ * CREATE_TIME TIMESTAMP,
+ * UPDATE_TIME_SECONDS BIGINT,
+ * MAX_LIFE_SECONDS BIGINT,
+ * SYSTEM_EXPIRE_TIME_SECONDS BIGINT,
+ * IS_ETERNAL CHAR(1),
+ * PRIMARY KEY (CACHE_KEY, REGION)
+ * );
+ * </pre>
+ * <p>
+ * The cleanup thread will delete non eternal items where (now - create time) > max life seconds *
+ * 1000
+ * <p>
+ * To speed up the deletion the SYSTEM_EXPIRE_TIME_SECONDS is used instead. It is recommended that
+ * an index be created on this column is you will have over a million records.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class JDBCDiskCache<K, V>
+ extends AbstractDiskCache<K, V>
+{
+ /** The local logger. */
+ private static final Log log = LogManager.getLog( JDBCDiskCache.class );
+
+ /** custom serialization */
+ private IElementSerializer elementSerializer = new StandardSerializer();
+
+ /** configuration */
+ private JDBCDiskCacheAttributes jdbcDiskCacheAttributes;
+
+ /** # of times update was called */
+ private final AtomicInteger updateCount = new AtomicInteger(0);
+
+ /** # of times get was called */
+ private final AtomicInteger getCount = new AtomicInteger(0);
+
+ /** # of times getMatching was called */
+ private final AtomicInteger getMatchingCount = new AtomicInteger(0);
+
+ /** if count % interval == 0 then log */
+ private static final int LOG_INTERVAL = 100;
+
+ /** db connection pool */
+ private DataSourceFactory dsFactory = null;
+
+ /** tracks optimization */
+ private TableState tableState;
+
+ /**
+ * Constructs a JDBC Disk Cache for the provided cache attributes. The table state object is
+ * used to mark deletions.
+ * <p>
+ * @param cattr the configuration object for this cache
+ * @param dsFactory the DataSourceFactory for this cache
+ * @param tableState an object to track table operations
+ * @param compositeCacheManager the global cache manager
+ */
+ public JDBCDiskCache( JDBCDiskCacheAttributes cattr, DataSourceFactory dsFactory, TableState tableState,
+ ICompositeCacheManager compositeCacheManager )
+ {
+ super( cattr );
+
+ setTableState( tableState );
+ setJdbcDiskCacheAttributes( cattr );
+
+ log.info( "jdbcDiskCacheAttributes = {0}", () -> getJdbcDiskCacheAttributes() );
+
+ // This initializes the pool access.
+ this.dsFactory = dsFactory;
+
+ // Initialization finished successfully, so set alive to true.
+ setAlive(true);
+ }
+
+ /**
+ * Inserts or updates. By default it will try to insert. If the item exists we will get an
+ * error. It will then update. This behavior is configurable. The cache can be configured to
+ * check before inserting.
+ * <p>
+ * @param ce
+ */
+ @Override
+ protected void processUpdate( ICacheElement<K, V> ce )
+ {
+ updateCount.incrementAndGet();
+
+ log.debug( "updating, ce = {0}", ce );
+
+ try (Connection con = getDataSource().getConnection())
+ {
+ log.debug( "Putting [{0}] on disk.", () -> ce.getKey());
+
+ byte[] element;
+
+ try
+ {
+ element = getElementSerializer().serialize( ce );
+ }
+ catch ( IOException e )
+ {
+ log.error( "Could not serialize element", e );
+ return;
+ }
+
+ insertOrUpdate( ce, con, element );
+ }
+ catch ( SQLException e )
+ {
+ log.error( "Problem getting connection.", e );
+ }
+
+ if ( log.isInfoEnabled() )
+ {
+ if ( updateCount.get() % LOG_INTERVAL == 0 )
+ {
+ // TODO make a log stats method
+ log.info( "Update Count [{0}]", updateCount);
+ }
+ }
+ }
+
+ /**
+ * If test before insert it true, we check to see if the element exists. If the element exists
+ * we will update. Otherwise, we try inserting. If this fails because the item exists, we will
+ * update.
+ * <p>
+ * @param ce
+ * @param con
+ * @param element
+ */
+ private void insertOrUpdate( ICacheElement<K, V> ce, Connection con, byte[] element )
+ {
+ boolean exists = false;
+
+ // First do a query to determine if the element already exists
+ if ( this.getJdbcDiskCacheAttributes().isTestBeforeInsert() )
+ {
+ exists = doesElementExist( ce, con );
+ }
+
+ // If it doesn't exist, insert it, otherwise update
+ if ( !exists )
+ {
+ exists = insertRow( ce, con, element );
+ }
+
+ // update if it exists.
+ if ( exists )
+ {
+ updateRow( ce, con, element );
+ }
+ }
+
+ /**
+ * This inserts a new row in the database.
+ * <p>
+ * @param ce
+ * @param con
+ * @param element
+ * @return true if the insertion fails because the record exists.
+ */
+ private boolean insertRow( ICacheElement<K, V> ce, Connection con, byte[] element )
+ {
+ boolean exists = false;
+ String sqlI = "insert into "
+ + getJdbcDiskCacheAttributes().getTableName()
+ + " (CACHE_KEY, REGION, ELEMENT, MAX_LIFE_SECONDS, IS_ETERNAL, CREATE_TIME, UPDATE_TIME_SECONDS, SYSTEM_EXPIRE_TIME_SECONDS) "
+ + " values (?, ?, ?, ?, ?, ?, ?, ?)";
+
+ try (PreparedStatement psInsert = con.prepareStatement( sqlI ))
+ {
+ psInsert.setString( 1, (String) ce.getKey() );
+ psInsert.setString( 2, this.getCacheName() );
+ psInsert.setBytes( 3, element );
+ psInsert.setLong( 4, ce.getElementAttributes().getMaxLife() );
+ if ( ce.getElementAttributes().getIsEternal() )
+ {
+ psInsert.setString( 5, "T" );
+ }
+ else
+ {
+ psInsert.setString( 5, "F" );
+ }
+ Timestamp createTime = new Timestamp( ce.getElementAttributes().getCreateTime() );
+ psInsert.setTimestamp( 6, createTime );
+
+ long now = System.currentTimeMillis() / 1000;
+ psInsert.setLong( 7, now );
+
+ long expireTime = now + ce.getElementAttributes().getMaxLife();
+ psInsert.setLong( 8, expireTime );
+
+ psInsert.execute();
+ }
+ catch ( SQLException e )
+ {
+ if ("23000".equals(e.getSQLState()))
+ {
+ exists = true;
+ }
+ else
+ {
+ log.error( "Could not insert element", e );
+ }
+
+ // see if it exists, if we didn't already
+ if ( !exists && !this.getJdbcDiskCacheAttributes().isTestBeforeInsert() )
+ {
+ exists = doesElementExist( ce, con );
+ }
+ }
+
+ return exists;
+ }
+
+ /**
+ * This updates a row in the database.
+ * <p>
+ * @param ce
+ * @param con
+ * @param element
+ */
+ private void updateRow( ICacheElement<K, V> ce, Connection con, byte[] element )
+ {
+ String sqlU = "update " + getJdbcDiskCacheAttributes().getTableName()
+ + " set ELEMENT = ?, CREATE_TIME = ?, UPDATE_TIME_SECONDS = ?, " + " SYSTEM_EXPIRE_TIME_SECONDS = ? "
+ + " where CACHE_KEY = ? and REGION = ?";
+
+ try (PreparedStatement psUpdate = con.prepareStatement( sqlU ))
+ {
+ psUpdate.setBytes( 1, element );
+
+ Timestamp createTime = new Timestamp( ce.getElementAttributes().getCreateTime() );
+ psUpdate.setTimestamp( 2, createTime );
+
+ long now = System.currentTimeMillis() / 1000;
+ psUpdate.setLong( 3, now );
+
+ long expireTime = now + ce.getElementAttributes().getMaxLife();
+ psUpdate.setLong( 4, expireTime );
+
+ psUpdate.setString( 5, (String) ce.getKey() );
+ psUpdate.setString( 6, this.getCacheName() );
+ psUpdate.execute();
+
+ log.debug( "ran update {0}", sqlU );
+ }
+ catch ( SQLException e )
+ {
+ log.error( "Error executing update sql [{0}]", sqlU, e );
+ }
+ }
+
+ /**
+ * Does an element exist for this key?
+ * <p>
+ * @param ce the cache element
+ * @param con a database connection
+ * @return boolean
+ */
+ protected boolean doesElementExist( ICacheElement<K, V> ce, Connection con )
+ {
+ boolean exists = false;
+ // don't select the element, since we want this to be fast.
+ String sqlS = "select CACHE_KEY from " + getJdbcDiskCacheAttributes().getTableName()
+ + " where REGION = ? and CACHE_KEY = ?";
+
+ try (PreparedStatement psSelect = con.prepareStatement( sqlS ))
+ {
+ psSelect.setString( 1, this.getCacheName() );
+ psSelect.setString( 2, (String) ce.getKey() );
+
+ try (ResultSet rs = psSelect.executeQuery())
+ {
+ exists = rs.next();
+ }
+
+ log.debug( "[{0}] existing status is {1}", ce.getKey(), exists );
+ }
+ catch ( SQLException e )
+ {
+ log.error( "Problem looking for item before insert.", e );
+ }
+
+ return exists;
+ }
+
+ /**
+ * Queries the database for the value. If it gets a result, the value is deserialized.
+ * <p>
+ * @param key
+ * @return ICacheElement
+ * @see org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache#get(Object)
+ */
+ @Override
+ protected ICacheElement<K, V> processGet( K key )
+ {
+ getCount.incrementAndGet();
+
+ log.debug( "Getting [{0}] from disk", key );
+
+ if ( !isAlive() )
+ {
+ return null;
+ }
+
+ ICacheElement<K, V> obj = null;
+
+ byte[] data = null;
+ try
+ {
+ // region, key
+ String selectString = "select ELEMENT from " + getJdbcDiskCacheAttributes().getTableName()
+ + " where REGION = ? and CACHE_KEY = ?";
+
+ try (Connection con = getDataSource().getConnection())
+ {
+ try (PreparedStatement psSelect = con.prepareStatement( selectString ))
+ {
+ psSelect.setString( 1, this.getCacheName() );
+ psSelect.setString( 2, key.toString() );
+
+ try (ResultSet rs = psSelect.executeQuery())
+ {
+ if ( rs.next() )
+ {
+ data = rs.getBytes( 1 );
+ }
+ if ( data != null )
+ {
+ try
+ {
+ // USE THE SERIALIZER
+ obj = getElementSerializer().deSerialize( data, null );
+ }
+ catch ( Exception e )
+ {
+ log.error( "Problem getting item for key [{0}]", key, e );
+ }
+ }
+ }
+ }
+ }
+ }
+ catch ( SQLException sqle )
+ {
+ log.error( "Caught a SQL exception trying to get the item for key [{0}]",
+ key, sqle );
+ }
+
+ if ( log.isInfoEnabled() )
+ {
+ if ( getCount.get() % LOG_INTERVAL == 0 )
+ {
+ // TODO make a log stats method
+ log.info( "Get Count [{0}]", getCount );
+ }
+ }
+ return obj;
+ }
+
+ /**
+ * This will run a like query. It will try to construct a usable query but different
+ * implementations will be needed to adjust the syntax.
+ * <p>
+ * @param pattern
+ * @return key,value map
+ */
+ @Override
+ protected Map<K, ICacheElement<K, V>> processGetMatching( String pattern )
+ {
+ getMatchingCount.incrementAndGet();
+
+ log.debug( "Getting [{0}] from disk", pattern);
+
+ if ( !isAlive() )
+ {
+ return null;
+ }
+
+ Map<K, ICacheElement<K, V>> results = new HashMap<>();
+
+ try
+ {
+ // region, key
+ String selectString = "select CACHE_KEY, ELEMENT from " + getJdbcDiskCacheAttributes().getTableName()
+ + " where REGION = ? and CACHE_KEY like ?";
+
+ try (Connection con = getDataSource().getConnection())
+ {
+ try (PreparedStatement psSelect = con.prepareStatement( selectString ))
+ {
+ psSelect.setString( 1, this.getCacheName() );
+ psSelect.setString( 2, constructLikeParameterFromPattern( pattern ) );
+
+ try (ResultSet rs = psSelect.executeQuery())
+ {
+ while ( rs.next() )
+ {
+ String key = rs.getString( 1 );
+ byte[] data = rs.getBytes( 2 );
+ if ( data != null )
+ {
+ try
+ {
+ // USE THE SERIALIZER
+ ICacheElement<K, V> value = getElementSerializer().deSerialize( data, null );
+ results.put( (K) key, value );
+ }
+ catch ( Exception e )
+ {
+ log.error( "Problem getting items for pattern [{0}]", pattern, e );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ catch ( SQLException sqle )
+ {
+ log.error( "Caught a SQL exception trying to get items for pattern [{0}]",
+ pattern, sqle );
+ }
+
+ if ( log.isInfoEnabled() )
+ {
+ if ( getMatchingCount.get() % LOG_INTERVAL == 0 )
+ {
+ // TODO make a log stats method
+ log.info( "Get Matching Count [{0}]", getMatchingCount);
+ }
+ }
+ return results;
+ }
+
+ /**
+ * @param pattern
+ * @return String to use in the like query.
+ */
+ public String constructLikeParameterFromPattern( String pattern )
+ {
+ String likePattern = pattern.replaceAll( "\\.\\+", "%" );
+ likePattern = likePattern.replaceAll( "\\.", "_" );
+
+ log.debug( "pattern = [{0}]", likePattern );
+
+ return likePattern;
+ }
+
+ /**
+ * Returns true if the removal was successful; or false if there is nothing to remove. Current
+ * implementation always results in a disk orphan.
+ * <p>
+ * @param key
+ * @return boolean
+ */
+ @Override
+ protected boolean processRemove( K key )
+ {
+ // remove single item.
+ String sql = "delete from " + getJdbcDiskCacheAttributes().getTableName()
+ + " where REGION = ? and CACHE_KEY = ?";
+
+ try (Connection con = getDataSource().getConnection())
+ {
+ boolean partial = false;
+ if ( key instanceof String && key.toString().endsWith( NAME_COMPONENT_DELIMITER ) )
+ {
+ // remove all keys of the same name group.
+ sql = "delete from " + getJdbcDiskCacheAttributes().getTableName()
+ + " where REGION = ? and CACHE_KEY like ?";
+ partial = true;
+ }
+
+ try (PreparedStatement psSelect = con.prepareStatement( sql ))
+ {
+ psSelect.setString( 1, this.getCacheName() );
+ if ( partial )
+ {
+ psSelect.setString( 2, key.toString() + "%" );
+ }
+ else
+ {
+ psSelect.setString( 2, key.toString() );
+ }
+
+ psSelect.executeUpdate();
+
+ setAlive(true);
+ }
+ catch ( SQLException e )
+ {
+ log.error( "Problem creating statement. sql [{0}]", sql, e );
+ setAlive(false);
+ }
+ }
+ catch ( SQLException e )
+ {
+ log.error( "Problem updating cache.", e );
+ reset();
+ }
+ return false;
+ }
+
+ /**
+ * This should remove all elements. The auxiliary can be configured to forbid this behavior. If
+ * remove all is not allowed, the method balks.
+ */
+ @Override
+ protected void processRemoveAll()
+ {
+ // it should never get here from the abstract disk cache.
+ if ( this.jdbcDiskCacheAttributes.isAllowRemoveAll() )
+ {
+ try (Connection con = getDataSource().getConnection())
+ {
+ String sql = "delete from " + getJdbcDiskCacheAttributes().getTableName() + " where REGION = ?";
+
+ try (PreparedStatement psDelete = con.prepareStatement( sql ))
+ {
+ psDelete.setString( 1, this.getCacheName() );
+ setAlive(true);
+ psDelete.executeUpdate();
+ }
+ catch ( SQLException e )
+ {
+ log.error( "Problem creating statement.", e );
+ setAlive(false);
+ }
+ }
+ catch ( SQLException e )
+ {
+ log.error( "Problem removing all.", e );
+ reset();
+ }
+ }
+ else
+ {
+ log.info( "RemoveAll was requested but the request was not fulfilled: "
+ + "allowRemoveAll is set to false." );
+ }
+ }
+
+ /**
+ * Removed the expired. (now - create time) > max life seconds * 1000
+ * <p>
+ * @return the number deleted
+ */
+ protected int deleteExpired()
+ {
+ int deleted = 0;
+
+ try (Connection con = getDataSource().getConnection())
+ {
+ // The shrinker thread might kick in before the table is created
+ // So check if the table exists first
+ DatabaseMetaData dmd = con.getMetaData();
+ ResultSet result = dmd.getTables(null, null,
+ getJdbcDiskCacheAttributes().getTableName(), null);
+
+ if (result.next())
+ {
+ getTableState().setState( TableState.DELETE_RUNNING );
+ long now = System.currentTimeMillis() / 1000;
+
+ String sql = "delete from " + getJdbcDiskCacheAttributes().getTableName()
+ + " where IS_ETERNAL = ? and REGION = ? and ? > SYSTEM_EXPIRE_TIME_SECONDS";
+
+ try (PreparedStatement psDelete = con.prepareStatement( sql ))
+ {
+ psDelete.setString( 1, "F" );
+ psDelete.setString( 2, this.getCacheName() );
+ psDelete.setLong( 3, now );
+
+ setAlive(true);
+
+ deleted = psDelete.executeUpdate();
+ }
+ catch ( SQLException e )
+ {
+ log.error( "Problem creating statement.", e );
+ setAlive(false);
+ }
+
+ logApplicationEvent( getAuxiliaryCacheAttributes().getName(), "deleteExpired",
+ "Deleted expired elements. URL: " + getDiskLocation() );
+ }
+ else
+ {
+ log.warn( "Trying to shrink non-existing table [{0}]",
+ getJdbcDiskCacheAttributes().getTableName() );
+ }
+ }
+ catch ( SQLException e )
+ {
+ logError( getAuxiliaryCacheAttributes().getName(), "deleteExpired",
+ e.getMessage() + " URL: " + getDiskLocation() );
+ log.error( "Problem removing expired elements from the table.", e );
+ reset();
+ }
+ finally
+ {
+ getTableState().setState( TableState.FREE );
+ }
+
+ return deleted;
+ }
+
+ /**
+ * Typically this is used to handle errors by last resort, force content update, or removeall
+ */
+ public void reset()
+ {
+ // nothing
+ }
+
+ /** Shuts down the pool */
+ @Override
+ public void processDispose()
+ {
+ ICacheEvent<K> cacheEvent = createICacheEvent( getCacheName(), (K)"none", ICacheEventLogger.DISPOSE_EVENT );
+
+ try
+ {
+ dsFactory.close();
+ }
+ catch ( SQLException e )
+ {
+ log.error( "Problem shutting down.", e );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Returns the current cache size. Just does a count(*) for the region.
+ * <p>
+ * @return The size value
+ */
+ @Override
+ public int getSize()
+ {
+ int size = 0;
+
+ // region, key
+ String selectString = "select count(*) from " + getJdbcDiskCacheAttributes().getTableName()
+ + " where REGION = ?";
+
+ try (Connection con = getDataSource().getConnection())
+ {
+ try (PreparedStatement psSelect = con.prepareStatement( selectString ))
+ {
+ psSelect.setString( 1, this.getCacheName() );
+
+ try (ResultSet rs = psSelect.executeQuery())
+ {
+ if ( rs.next() )
+ {
+ size = rs.getInt( 1 );
+ }
+ }
+ }
+ }
+ catch ( SQLException e )
+ {
+ log.error( "Problem getting size.", e );
+ }
+
+ return size;
+ }
+
+ /**
+ * Return the keys in this cache.
+ * <p>
+ * @see org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache#getKeySet()
+ */
+ @Override
+ public Set<K> getKeySet() throws IOException
+ {
+ throw new UnsupportedOperationException( "Groups not implemented." );
+ // return null;
+ }
+
+ /**
+ * @param elementSerializer The elementSerializer to set.
+ */
+ @Override
+ public void setElementSerializer( IElementSerializer elementSerializer )
+ {
+ this.elementSerializer = elementSerializer;
+ }
+
+ /**
+ * @return Returns the elementSerializer.
+ */
+ @Override
+ public IElementSerializer getElementSerializer()
+ {
+ return elementSerializer;
+ }
+
+ /**
+ * @param jdbcDiskCacheAttributes The jdbcDiskCacheAttributes to set.
+ */
+ protected void setJdbcDiskCacheAttributes( JDBCDiskCacheAttributes jdbcDiskCacheAttributes )
+ {
+ this.jdbcDiskCacheAttributes = jdbcDiskCacheAttributes;
+ }
+
+ /**
+ * @return Returns the jdbcDiskCacheAttributes.
+ */
+ protected JDBCDiskCacheAttributes getJdbcDiskCacheAttributes()
+ {
+ return jdbcDiskCacheAttributes;
+ }
+
+ /**
+ * @return Returns the AuxiliaryCacheAttributes.
+ */
+ @Override
+ public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
+ {
+ return this.getJdbcDiskCacheAttributes();
+ }
+
+ /**
+ * Extends the parent stats.
+ * <p>
+ * @return IStats
+ */
+ @Override
+ public IStats getStatistics()
+ {
+ IStats stats = super.getStatistics();
+ stats.setTypeName( "JDBC/Abstract Disk Cache" );
+
+ List<IStatElement<?>> elems = stats.getStatElements();
+
+ elems.add(new StatElement<>( "Update Count", updateCount ) );
+ elems.add(new StatElement<>( "Get Count", getCount ) );
+ elems.add(new StatElement<>( "Get Matching Count", getMatchingCount ) );
+ elems.add(new StatElement<>( "DB URL", getJdbcDiskCacheAttributes().getUrl()) );
+
+ stats.setStatElements( elems );
+
+ return stats;
+ }
+
+ /**
+ * Returns the name of the table.
+ * <p>
+ * @return the table name or UNDEFINED
+ */
+ protected String getTableName()
+ {
+ String name = "UNDEFINED";
+ if ( this.getJdbcDiskCacheAttributes() != null )
+ {
+ name = this.getJdbcDiskCacheAttributes().getTableName();
+ }
+ return name;
+ }
+
+ /**
+ * @param tableState The tableState to set.
+ */
+ public void setTableState( TableState tableState )
+ {
+ this.tableState = tableState;
+ }
+
+ /**
+ * @return Returns the tableState.
+ */
+ public TableState getTableState()
+ {
+ return tableState;
+ }
+
+ /**
+ * This is used by the event logging.
+ * <p>
+ * @return the location of the disk, either path or ip.
+ */
+ @Override
+ protected String getDiskLocation()
+ {
+ return this.jdbcDiskCacheAttributes.getUrl();
+ }
+
+ /**
+ * Public so managers can access it.
+ * @return the dsFactory
+ * @throws SQLException if getting a data source fails
+ */
+ public DataSource getDataSource() throws SQLException
+ {
+ return dsFactory.getDataSource();
+ }
+
+ /**
+ * For debugging.
+ * <p>
+ * @return this.getStats();
+ */
+ @Override
+ public String toString()
+ {
+ return this.getStats();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCacheAttributes.java
new file mode 100644
index 0000000..ffd50d6
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCacheAttributes.java
@@ -0,0 +1,331 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCacheAttributes;
+
+/**
+ * The configurator will set these values based on what is in the cache.ccf file.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class JDBCDiskCacheAttributes
+ extends AbstractDiskCacheAttributes
+{
+ /** Don't change */
+ private static final long serialVersionUID = -6535808344813320062L;
+
+ /** default */
+ private static final String DEFAULT_TABLE_NAME = "JCS_STORE";
+
+ /** DB username */
+ private String userName;
+
+ /** DB password */
+ private String password;
+
+ /** URL for the db */
+ private String url;
+
+ /** The name of the database. */
+ private String database = "";
+
+ /** The driver */
+ private String driverClassName;
+
+ /** The JNDI path. */
+ private String jndiPath;
+
+ /** The time between two JNDI lookups */
+ private long jndiTTL = 0L;
+
+ /** The table name */
+ private String tableName = DEFAULT_TABLE_NAME;
+
+ /** If false we will insert and if it fails we will update. */
+ private boolean testBeforeInsert = true;
+
+ /** This is the default limit on the maximum number of active connections. */
+ public static final int DEFAULT_MAX_TOTAL = 10;
+
+ /** Max connections allowed */
+ private int maxTotal = DEFAULT_MAX_TOTAL;
+
+ /** This is the default setting for the cleanup routine. */
+ public static final int DEFAULT_SHRINKER_INTERVAL_SECONDS = 300;
+
+ /** How often should we remove expired. */
+ private int shrinkerIntervalSeconds = DEFAULT_SHRINKER_INTERVAL_SECONDS;
+
+ /** Should we remove expired in the background. */
+ private boolean useDiskShrinker = true;
+
+ /** The default Pool Name to which the connection pool will be keyed. */
+ public static final String DEFAULT_POOL_NAME = "jcs";
+
+ /**
+ * If a pool name is supplied, the manager will attempt to load it. It should be configured in a
+ * separate section as follows. Assuming the name is "MyPool":
+ *
+ * <pre>
+ * jcs.jdbcconnectionpool.MyPool.attributes.userName=MyUserName
+ * jcs.jdbcconnectionpool.MyPool.attributes.password=MyPassword
+ * jcs.jdbcconnectionpool.MyPool.attributes.url=MyUrl
+ * jcs.jdbcconnectionpool.MyPool.attributes.maxActive=MyMaxActive
+ * jcs.jdbcconnectionpool.MyPool.attributes.driverClassName=MyDriverClassName
+ * </pre>
+ */
+ private String connectionPoolName;
+
+ /**
+ * @param userName The userName to set.
+ */
+ public void setUserName( String userName )
+ {
+ this.userName = userName;
+ }
+
+ /**
+ * @return Returns the userName.
+ */
+ public String getUserName()
+ {
+ return userName;
+ }
+
+ /**
+ * @param password The password to set.
+ */
+ public void setPassword( String password )
+ {
+ this.password = password;
+ }
+
+ /**
+ * @return Returns the password.
+ */
+ public String getPassword()
+ {
+ return password;
+ }
+
+ /**
+ * @param url The url to set.
+ */
+ public void setUrl( String url )
+ {
+ this.url = url;
+ }
+
+ /**
+ * @return Returns the url.
+ */
+ public String getUrl()
+ {
+ return url;
+ }
+
+ /**
+ * This is appended to the url.
+ * @param database The database to set.
+ */
+ public void setDatabase( String database )
+ {
+ this.database = database;
+ }
+
+ /**
+ * @return Returns the database.
+ */
+ public String getDatabase()
+ {
+ return database;
+ }
+
+ /**
+ * @param driverClassName The driverClassName to set.
+ */
+ public void setDriverClassName( String driverClassName )
+ {
+ this.driverClassName = driverClassName;
+ }
+
+ /**
+ * @return Returns the driverClassName.
+ */
+ public String getDriverClassName()
+ {
+ return driverClassName;
+ }
+
+ /**
+ * @return the jndiPath
+ */
+ public String getJndiPath()
+ {
+ return jndiPath;
+ }
+
+ /**
+ * @param jndiPath the jndiPath to set
+ */
+ public void setJndiPath(String jndiPath)
+ {
+ this.jndiPath = jndiPath;
+ }
+
+ /**
+ * @return the jndiTTL
+ */
+ public long getJndiTTL()
+ {
+ return jndiTTL;
+ }
+
+ /**
+ * @param jndiTTL the jndiTTL to set
+ */
+ public void setJndiTTL(long jndiTTL)
+ {
+ this.jndiTTL = jndiTTL;
+ }
+
+ /**
+ * @param tableName The tableName to set.
+ */
+ public void setTableName( String tableName )
+ {
+ this.tableName = tableName;
+ }
+
+ /**
+ * @return Returns the tableName.
+ */
+ public String getTableName()
+ {
+ return tableName;
+ }
+
+ /**
+ * If this is true then the disk cache will check to see if the item already exists in the
+ * database. If it is false, it will try to insert. If the insert fails it will try to update.
+ * <p>
+ * @param testBeforeInsert The testBeforeInsert to set.
+ */
+ public void setTestBeforeInsert( boolean testBeforeInsert )
+ {
+ this.testBeforeInsert = testBeforeInsert;
+ }
+
+ /**
+ * @return Returns the testBeforeInsert.
+ */
+ public boolean isTestBeforeInsert()
+ {
+ return testBeforeInsert;
+ }
+
+ /**
+ * @param maxTotal The maxTotal to set.
+ */
+ public void setMaxTotal( int maxActive )
+ {
+ this.maxTotal = maxActive;
+ }
+
+ /**
+ * @return Returns the maxTotal.
+ */
+ public int getMaxTotal()
+ {
+ return maxTotal;
+ }
+
+ /**
+ * @param shrinkerIntervalSecondsArg The shrinkerIntervalSeconds to set.
+ */
+ public void setShrinkerIntervalSeconds( int shrinkerIntervalSecondsArg )
+ {
+ this.shrinkerIntervalSeconds = shrinkerIntervalSecondsArg;
+ }
+
+ /**
+ * @return Returns the shrinkerIntervalSeconds.
+ */
+ public int getShrinkerIntervalSeconds()
+ {
+ return shrinkerIntervalSeconds;
+ }
+
+ /**
+ * @param useDiskShrinker The useDiskShrinker to set.
+ */
+ public void setUseDiskShrinker( boolean useDiskShrinker )
+ {
+ this.useDiskShrinker = useDiskShrinker;
+ }
+
+ /**
+ * @return Returns the useDiskShrinker.
+ */
+ public boolean isUseDiskShrinker()
+ {
+ return useDiskShrinker;
+ }
+
+ /**
+ * @param connectionPoolName the connectionPoolName to set
+ */
+ public void setConnectionPoolName( String connectionPoolName )
+ {
+ this.connectionPoolName = connectionPoolName;
+ }
+
+ /**
+ * @return the connectionPoolName
+ */
+ public String getConnectionPoolName()
+ {
+ return connectionPoolName;
+ }
+
+ /**
+ * For debugging.
+ * <p>
+ * @return debug string with most of the properties.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\nJDBCCacheAttributes" );
+ buf.append( "\n UserName [" + getUserName() + "]" );
+ buf.append( "\n Url [" + getUrl() + "]" );
+ buf.append( "\n Database [" + getDatabase() + "]" );
+ buf.append( "\n DriverClassName [" + getDriverClassName() + "]" );
+ buf.append( "\n TableName [" + getTableName() + "]" );
+ buf.append( "\n TestBeforeInsert [" + isTestBeforeInsert() + "]" );
+ buf.append( "\n MaxActive [" + getMaxTotal() + "]" );
+ buf.append( "\n AllowRemoveAll [" + isAllowRemoveAll() + "]" );
+ buf.append( "\n ShrinkerIntervalSeconds [" + getShrinkerIntervalSeconds() + "]" );
+ buf.append( "\n useDiskShrinker [" + isUseDiskShrinker() + "]" );
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCacheFactory.java
new file mode 100644
index 0000000..0e99d24
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCacheFactory.java
@@ -0,0 +1,266 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc;
+
+/*
+ * 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.
+ */
+
+import java.sql.SQLException;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheFactory;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.DataSourceFactory;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.JndiDataSourceFactory;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.SharedPoolDataSourceFactory;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.behavior.IRequireScheduler;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.config.PropertySetter;
+
+/**
+ * This factory should create JDBC auxiliary caches.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class JDBCDiskCacheFactory
+ extends AbstractAuxiliaryCacheFactory
+ implements IRequireScheduler
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( JDBCDiskCacheFactory.class );
+
+ /**
+ * A map of TableState objects to table names. Each cache has a table state object, which is
+ * used to determine if any long processes such as deletes or optimizations are running.
+ */
+ private ConcurrentMap<String, TableState> tableStates;
+
+ /** The background scheduler, one for all regions. Injected by the configurator */
+ protected ScheduledExecutorService scheduler;
+
+ /**
+ * A map of table name to shrinker threads. This allows each table to have a different setting.
+ * It assumes that there is only one jdbc disk cache auxiliary defined per table.
+ */
+ private ConcurrentMap<String, ShrinkerThread> shrinkerThreadMap;
+
+ /** Pool name to DataSourceFactories */
+ private ConcurrentMap<String, DataSourceFactory> dsFactories;
+
+ /** props prefix */
+ protected static final String POOL_CONFIGURATION_PREFIX = "jcs.jdbcconnectionpool.";
+
+ /** .attributes */
+ protected static final String ATTRIBUTE_PREFIX = ".attributes";
+
+ /**
+ * This factory method should create an instance of the jdbc cache.
+ * <p>
+ * @param rawAttr specific cache configuration attributes
+ * @param compositeCacheManager the global cache manager
+ * @param cacheEventLogger a specific logger for cache events
+ * @param elementSerializer a serializer for cache elements
+ * @return JDBCDiskCache the cache instance
+ * @throws SQLException if the cache instance could not be created
+ */
+ @Override
+ public <K, V> JDBCDiskCache<K, V> createCache( AuxiliaryCacheAttributes rawAttr,
+ ICompositeCacheManager compositeCacheManager,
+ ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
+ throws SQLException
+ {
+ JDBCDiskCacheAttributes cattr = (JDBCDiskCacheAttributes) rawAttr;
+ TableState tableState = getTableState( cattr.getTableName() );
+ DataSourceFactory dsFactory = getDataSourceFactory(cattr, compositeCacheManager.getConfigurationProperties());
+
+ JDBCDiskCache<K, V> cache = new JDBCDiskCache<>( cattr, dsFactory, tableState, compositeCacheManager );
+ cache.setCacheEventLogger( cacheEventLogger );
+ cache.setElementSerializer( elementSerializer );
+
+ // create a shrinker if we need it.
+ createShrinkerWhenNeeded( cattr, cache );
+
+ return cache;
+ }
+
+ /**
+ * Initialize this factory
+ */
+ @Override
+ public void initialize()
+ {
+ super.initialize();
+ this.tableStates = new ConcurrentHashMap<>();
+ this.shrinkerThreadMap = new ConcurrentHashMap<>();
+ this.dsFactories = new ConcurrentHashMap<>();
+ }
+
+ /**
+ * Dispose of this factory, clean up shared resources
+ */
+ @Override
+ public void dispose()
+ {
+ this.tableStates.clear();
+
+ for (DataSourceFactory dsFactory : this.dsFactories.values())
+ {
+ try
+ {
+ dsFactory.close();
+ }
+ catch (SQLException e)
+ {
+ log.error("Could not close data source factory {0}", dsFactory.getName(), e);
+ }
+ }
+
+ this.dsFactories.clear();
+ this.shrinkerThreadMap.clear();
+ super.dispose();
+ }
+
+ /**
+ * Get a table state for a given table name
+ *
+ * @param tableName
+ * @return a cached instance of the table state
+ */
+ protected TableState getTableState(String tableName)
+ {
+ return tableStates.computeIfAbsent(tableName, key -> new TableState(key));
+ }
+
+ /**
+ * @see org.apache.commons.jcs3.engine.behavior.IRequireScheduler#setScheduledExecutorService(java.util.concurrent.ScheduledExecutorService)
+ */
+ @Override
+ public void setScheduledExecutorService(ScheduledExecutorService scheduledExecutor)
+ {
+ this.scheduler = scheduledExecutor;
+ }
+
+ /**
+ * Get the scheduler service
+ *
+ * @return the scheduler
+ */
+ protected ScheduledExecutorService getScheduledExecutorService()
+ {
+ return scheduler;
+ }
+
+ /**
+ * If UseDiskShrinker is true then we will create a shrinker daemon if necessary.
+ * <p>
+ * @param cattr
+ * @param raf
+ */
+ protected void createShrinkerWhenNeeded( JDBCDiskCacheAttributes cattr, JDBCDiskCache<?, ?> raf )
+ {
+ // add cache to shrinker.
+ if ( cattr.isUseDiskShrinker() )
+ {
+ ScheduledExecutorService shrinkerService = getScheduledExecutorService();
+ ShrinkerThread shrinkerThread = shrinkerThreadMap.computeIfAbsent(cattr.getTableName(), key -> {
+ ShrinkerThread newShrinkerThread = new ShrinkerThread();
+
+ long intervalMillis = Math.max( 999, cattr.getShrinkerIntervalSeconds() * 1000 );
+ log.info( "Setting the shrinker to run every [{0}] ms. for table [{1}]",
+ intervalMillis, key );
+ shrinkerService.scheduleAtFixedRate(newShrinkerThread, 0, intervalMillis, TimeUnit.MILLISECONDS);
+
+ return newShrinkerThread;
+ });
+
+ shrinkerThread.addDiskCacheToShrinkList( raf );
+ }
+ }
+
+ /**
+ * manages the DataSourceFactories.
+ * <p>
+ * @param cattr the cache configuration
+ * @param configProps the configuration properties object
+ * @return a DataSourceFactory
+ * @throws SQLException if a database access error occurs
+ */
+ protected DataSourceFactory getDataSourceFactory( JDBCDiskCacheAttributes cattr,
+ Properties configProps ) throws SQLException
+ {
+ String poolName = null;
+
+ if (cattr.getConnectionPoolName() == null)
+ {
+ poolName = cattr.getCacheName() + "." + JDBCDiskCacheAttributes.DEFAULT_POOL_NAME;
+ }
+ else
+ {
+ poolName = cattr.getConnectionPoolName();
+ }
+
+
+ DataSourceFactory dsFactory = this.dsFactories.computeIfAbsent(poolName, key -> {
+ DataSourceFactory newDsFactory;
+ JDBCDiskCacheAttributes dsConfig = null;
+
+ if (cattr.getConnectionPoolName() == null)
+ {
+ dsConfig = cattr;
+ }
+ else
+ {
+ dsConfig = new JDBCDiskCacheAttributes();
+ String dsConfigAttributePrefix = POOL_CONFIGURATION_PREFIX + key + ATTRIBUTE_PREFIX;
+ PropertySetter.setProperties( dsConfig,
+ configProps,
+ dsConfigAttributePrefix + "." );
+
+ dsConfig.setConnectionPoolName(key);
+ }
+
+ if ( dsConfig.getJndiPath() != null )
+ {
+ newDsFactory = new JndiDataSourceFactory();
+ }
+ else
+ {
+ newDsFactory = new SharedPoolDataSourceFactory();
+ }
+
+ try
+ {
+ newDsFactory.initialize(dsConfig);
+ }
+ catch (SQLException e)
+ {
+ throw new RuntimeException(e);
+ }
+ return newDsFactory;
+ });
+
+ return dsFactory;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/ShrinkerThread.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/ShrinkerThread.java
new file mode 100644
index 0000000..fa9855a
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/ShrinkerThread.java
@@ -0,0 +1,149 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc;
+
+/*
+ * 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.
+ */
+
+import java.util.Iterator;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.timing.ElapsedTimer;
+
+/**
+ * Calls delete expired on the disk caches. The shrinker is run by a clock daemon. The shrinker
+ * calls delete on each region. It pauses between calls.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class ShrinkerThread
+ implements Runnable
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog( ShrinkerThread.class );
+
+ /** A set of JDBCDiskCache objects to call deleteExpired on. */
+ private final CopyOnWriteArraySet<JDBCDiskCache<?, ?>> shrinkSet =
+ new CopyOnWriteArraySet<>();
+
+ /** Default time period to use. */
+ private static final long DEFAULT_PAUSE_BETWEEN_REGION_CALLS_MILLIS = 5000;
+
+ /**
+ * How long should we wait between calls to deleteExpired when we are iterating through the list
+ * of regions. Delete can lock the table. We want to give clients a chance to get some work
+ * done.
+ */
+ private long pauseBetweenRegionCallsMillis = DEFAULT_PAUSE_BETWEEN_REGION_CALLS_MILLIS;
+
+ /**
+ * Does nothing special.
+ */
+ protected ShrinkerThread()
+ {
+ super();
+ }
+
+ /**
+ * Adds a JDBC disk cache to the set of disk cache to shrink.
+ * <p>
+ * @param diskCache
+ */
+ public void addDiskCacheToShrinkList( JDBCDiskCache<?, ?> diskCache )
+ {
+ // the set will prevent dupes.
+ // we could also just add these to a hashmap by region name
+ // but that might cause a problem if you wanted to use two different
+ // jbdc disk caches for the same region.
+ shrinkSet.add( diskCache );
+ }
+
+ /**
+ * Calls deleteExpired on each item in the set. It pauses between each call.
+ */
+ @Override
+ public void run()
+ {
+ try
+ {
+ deleteExpiredFromAllRegisteredRegions();
+ }
+ catch ( Throwable e )
+ {
+ log.error( "Caught an exception while trying to delete expired items.", e );
+ }
+ }
+
+ /**
+ * Deletes the expired items from all the registered regions.
+ */
+ private void deleteExpiredFromAllRegisteredRegions()
+ {
+ log.info( "Running JDBC disk cache shrinker. Number of regions [{0}]",
+ () -> shrinkSet.size() );
+
+ for (Iterator<JDBCDiskCache<?, ?>> i = shrinkSet.iterator(); i.hasNext();)
+ {
+ JDBCDiskCache<?, ?> cache = i.next();
+ ElapsedTimer timer = new ElapsedTimer();
+ int deleted = cache.deleteExpired();
+
+ log.info( "Deleted [{0}] expired for region [{1}] for table [{2}] in {3} ms.",
+ deleted, cache.getCacheName(), cache.getTableName(), timer.getElapsedTime() );
+
+ // don't pause after the last call to delete expired.
+ if ( i.hasNext() )
+ {
+ log.info( "Pausing for [{0}] ms before shrinking the next region.",
+ this.getPauseBetweenRegionCallsMillis() );
+
+ try
+ {
+ Thread.sleep( this.getPauseBetweenRegionCallsMillis() );
+ }
+ catch ( InterruptedException e )
+ {
+ log.warn( "Interrupted while waiting to delete expired for the next region." );
+ }
+ }
+ }
+ }
+
+ /**
+ * How long should we wait between calls to deleteExpired when we are iterating through the list
+ * of regions.
+ * <p>
+ * @param pauseBetweenRegionCallsMillis The pauseBetweenRegionCallsMillis to set.
+ */
+ public void setPauseBetweenRegionCallsMillis( long pauseBetweenRegionCallsMillis )
+ {
+ this.pauseBetweenRegionCallsMillis = pauseBetweenRegionCallsMillis;
+ }
+
+ /**
+ * How long should we wait between calls to deleteExpired when we are iterating through the list
+ * of regions.
+ * <p>
+ * @return Returns the pauseBetweenRegionCallsMillis.
+ */
+ public long getPauseBetweenRegionCallsMillis()
+ {
+ return pauseBetweenRegionCallsMillis;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/TableState.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/TableState.java
new file mode 100644
index 0000000..11dbad0
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/TableState.java
@@ -0,0 +1,114 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+
+/**
+ * This is used by various elements of the JDBC disk cache to indicate the
+ * status of a table. The MySQL disk cache, for instance, marks the status as
+ * optimizing when a scheduled optimization is taking place. This allows the
+ * cache to balk rather than block during long running optimizations.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class TableState
+ implements Serializable
+{
+ /** Don't change. */
+ private static final long serialVersionUID = -6625081552084964885L;
+
+ /** Name of the table whose state this reflects. */
+ private String tableName;
+
+ /**
+ * The table is free. It can be accessed and no potentially table locking
+ * jobs are running.
+ */
+ public static final int FREE = 0;
+
+ /** A potentially table locking deletion is running */
+ public static final int DELETE_RUNNING = 1;
+
+ /** A table locking optimization is running. */
+ public static final int OPTIMIZATION_RUNNING = 2;
+
+ /** we might want to add error */
+ private int state = FREE;
+
+ /**
+ * Construct a usable table state.
+ * <p>
+ * @param tableName
+ */
+ public TableState( String tableName )
+ {
+ this.setTableName( tableName );
+ }
+
+ /**
+ * @param tableName
+ * The tableName to set.
+ */
+ public void setTableName( String tableName )
+ {
+ this.tableName = tableName;
+ }
+
+ /**
+ * @return Returns the tableName.
+ */
+ public String getTableName()
+ {
+ return tableName;
+ }
+
+ /**
+ * @param state
+ * The state to set.
+ */
+ public void setState( int state )
+ {
+ this.state = state;
+ }
+
+ /**
+ * @return Returns the state.
+ */
+ public int getState()
+ {
+ return state;
+ }
+
+ /**
+ * Write out the values for debugging purposes.
+ * <p>
+ * @return String
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder str = new StringBuilder();
+ str.append( "TableState " );
+ str.append( "\n TableName = " + getTableName() );
+ str.append( "\n State = " + getState() );
+ return str.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/dsfactory/DataSourceFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/dsfactory/DataSourceFactory.java
new file mode 100644
index 0000000..fbb73ac
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/dsfactory/DataSourceFactory.java
@@ -0,0 +1,85 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory;
+
+/*
+ * 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.
+ */
+
+import java.sql.SQLException;
+
+import javax.sql.DataSource;
+
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes;
+
+
+/**
+ * A factory that returns a DataSource.
+ * Borrowed from Apache DB Torque
+ *
+ * @author <a href="mailto:jmcnally@apache.org">John McNally</a>
+ * @author <a href="mailto:fischer@seitenbau.de">Thomas Fischer</a>
+ * @version $Id: DataSourceFactory.java 1336091 2012-05-09 11:09:40Z tfischer $
+ */
+public interface DataSourceFactory
+{
+ /**
+ * Key for the configuration which contains DataSourceFactories
+ */
+ String DSFACTORY_KEY = "dsfactory";
+
+ /**
+ * Key for the configuration which contains the fully qualified name
+ * of the factory implementation class
+ */
+ String FACTORY_KEY = "factory";
+
+ /**
+ * @return the name of the factory.
+ */
+ String getName();
+
+ /**
+ * @return the <code>DataSource</code> configured by the factory.
+ * @throws SQLException if the source can't be returned
+ */
+ DataSource getDataSource() throws SQLException;
+
+ /**
+ * Initialize the factory.
+ *
+ * @param config the factory settings
+ * @throws SQLException Any exceptions caught during processing will be
+ * rethrown wrapped into a SQLException.
+ */
+ void initialize(JDBCDiskCacheAttributes config)
+ throws SQLException;
+
+ /**
+ * A hook which is called when the resources of the associated DataSource
+ * can be released.
+ * After close() is called, the other methods may not work any more
+ * (e.g. getDataSource() might return null).
+ * It is not guaranteed that this method does anything. For example,
+ * we do not want to close connections retrieved via JNDI, so the
+ * JndiDataSouurceFactory does not close these connections
+ *
+ * @throws SQLException Any exceptions caught during processing will be
+ * rethrown wrapped into a SQLException.
+ */
+ void close()
+ throws SQLException;
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/dsfactory/JndiDataSourceFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/dsfactory/JndiDataSourceFactory.java
new file mode 100644
index 0000000..7d33e01
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/dsfactory/JndiDataSourceFactory.java
@@ -0,0 +1,173 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory;
+
+/*
+ * 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.
+ */
+
+import java.sql.SQLException;
+import java.util.Hashtable;
+import java.util.Map;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.sql.DataSource;
+
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * A factory that looks up the DataSource from JNDI. It is also able
+ * to deploy the DataSource based on properties found in the
+ * configuration.
+ *
+ * This factory tries to avoid excessive context lookups to improve speed.
+ * The time between two lookups can be configured. The default is 0 (no cache).
+ *
+ * Borrowed and adapted from Apache DB Torque
+ *
+ * @author <a href="mailto:jmcnally@apache.org">John McNally</a>
+ * @author <a href="mailto:thomas@vandahl.org">Thomas Vandahl</a>
+ */
+public class JndiDataSourceFactory implements DataSourceFactory
+{
+ /** The log. */
+ private static Log log = LogManager.getLog(JndiDataSourceFactory.class);
+
+ /** The name of the factory. */
+ private String name;
+
+ /** The path to get the resource from. */
+ private String path;
+
+ /** The context to get the resource from. */
+ private Context ctx;
+
+ /** A locally cached copy of the DataSource */
+ private DataSource ds = null;
+
+ /** Time of last actual lookup action */
+ private long lastLookup = 0;
+
+ /** Time between two lookups */
+ private long ttl = 0; // ms
+
+ /**
+ * @return the name of the factory.
+ */
+ @Override
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * @see org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#getDataSource()
+ */
+ @Override
+ public DataSource getDataSource() throws SQLException
+ {
+ long time = System.currentTimeMillis();
+
+ if (ds == null || time - lastLookup > ttl)
+ {
+ try
+ {
+ synchronized (ctx)
+ {
+ ds = ((DataSource) ctx.lookup(path));
+ }
+ lastLookup = time;
+ }
+ catch (NamingException e)
+ {
+ throw new SQLException(e);
+ }
+ }
+
+ return ds;
+ }
+
+ /**
+ * @see org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#initialize(JDBCDiskCacheAttributes)
+ */
+ @Override
+ public void initialize(JDBCDiskCacheAttributes config) throws SQLException
+ {
+ this.name = config.getConnectionPoolName();
+ initJNDI(config);
+ }
+
+ /**
+ * Initializes JNDI.
+ *
+ * @param config where to read the settings from
+ * @throws SQLException if a property set fails
+ */
+ private void initJNDI(JDBCDiskCacheAttributes config) throws SQLException
+ {
+ log.debug("Starting initJNDI");
+
+ try
+ {
+ this.path = config.getJndiPath();
+ log.debug("JNDI path: {0}", path);
+
+ this.ttl = config.getJndiTTL();
+ log.debug("Time between context lookups: {0}", ttl);
+
+ Hashtable<String, Object> env = new Hashtable<>();
+ ctx = new InitialContext(env);
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("Created new InitialContext");
+ debugCtx(ctx);
+ }
+ }
+ catch (NamingException e)
+ {
+ throw new SQLException(e);
+ }
+ }
+
+ /**
+ * Does nothing. We do not want to close a dataSource retrieved from Jndi,
+ * because other applications might use it as well.
+ */
+ @Override
+ public void close()
+ {
+ // do nothing
+ }
+
+ /**
+ *
+ * @param ctx the context
+ * @throws NamingException
+ */
+ private void debugCtx(Context ctx) throws NamingException
+ {
+ log.trace("InitialContext -------------------------------");
+ Map<?, ?> env = ctx.getEnvironment();
+ log.trace("Environment properties: {0}", env.size());
+ env.forEach((key, value) -> log.trace(" {0}: {1}", key, value));
+ log.trace("----------------------------------------------");
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/dsfactory/SharedPoolDataSourceFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/dsfactory/SharedPoolDataSourceFactory.java
new file mode 100644
index 0000000..371ce16
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/dsfactory/SharedPoolDataSourceFactory.java
@@ -0,0 +1,152 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory;
+
+/*
+ * 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.
+ */
+
+import java.sql.SQLException;
+
+import javax.sql.ConnectionPoolDataSource;
+import javax.sql.DataSource;
+
+import org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS;
+import org.apache.commons.dbcp2.datasources.InstanceKeyDataSource;
+import org.apache.commons.dbcp2.datasources.SharedPoolDataSource;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * A factory that looks up the DataSource using the JDBC2 pool methods.
+ *
+ * Borrowed and adapted from Apache DB Torque
+ *
+ * @author <a href="mailto:jmcnally@apache.org">John McNally</a>
+ * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
+ */
+public class SharedPoolDataSourceFactory implements DataSourceFactory
+{
+ /** The log. */
+ private static Log log = LogManager.getLog(SharedPoolDataSourceFactory.class);
+
+ /** The name of the factory. */
+ private String name;
+
+ /** The wrapped <code>DataSource</code>. */
+ private SharedPoolDataSource ds = null;
+
+ /**
+ * @return the name of the factory.
+ */
+ @Override
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * @see org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#getDataSource()
+ */
+ @Override
+ public DataSource getDataSource()
+ {
+ return ds;
+ }
+
+ /**
+ * @see org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.DataSourceFactory#initialize(JDBCDiskCacheAttributes)
+ */
+ @Override
+ public void initialize(JDBCDiskCacheAttributes config) throws SQLException
+ {
+ this.name = config.getConnectionPoolName();
+ ConnectionPoolDataSource cpds = initCPDS(config);
+ SharedPoolDataSource dataSource = new SharedPoolDataSource();
+ initJdbc2Pool(dataSource, config);
+ dataSource.setConnectionPoolDataSource(cpds);
+ dataSource.setMaxTotal(config.getMaxTotal());
+ this.ds = dataSource;
+ }
+
+ /**
+ * Closes the pool associated with this factory and releases it.
+ * @throws SQLException if the pool cannot be closed properly
+ */
+ @Override
+ public void close() throws SQLException
+ {
+ try
+ {
+ if (ds != null)
+ {
+ ds.close();
+ }
+ }
+ catch (Exception e)
+ {
+ throw new SQLException("Exception caught closing data source", e);
+ }
+ ds = null;
+ }
+
+ /**
+ * Initializes the ConnectionPoolDataSource.
+ *
+ * @param config where to read the settings from
+ * @throws SQLException if a property set fails
+ * @return a configured <code>ConnectionPoolDataSource</code>
+ */
+ private ConnectionPoolDataSource initCPDS(final JDBCDiskCacheAttributes config)
+ throws SQLException
+ {
+ log.debug("Starting initCPDS");
+
+ DriverAdapterCPDS cpds = new DriverAdapterCPDS();
+
+ try
+ {
+ cpds.setDriver(config.getDriverClassName());
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new SQLException("Driver class not found " + config.getDriverClassName(), e);
+ }
+
+ cpds.setUrl(config.getUrl());
+ cpds.setUser(config.getUserName());
+ cpds.setPassword(config.getPassword());
+
+ return cpds;
+ }
+
+ /**
+ * Initializes the Jdbc2PoolDataSource.
+ *
+ * @param dataSource the dataSource to initialize, not null.
+ * @param config where to read the settings from, not null.
+ *
+ * @throws SQLException if a property set fails.
+ */
+ private void initJdbc2Pool(final InstanceKeyDataSource dataSource, final JDBCDiskCacheAttributes config)
+ throws SQLException
+ {
+ log.debug("Starting initJdbc2Pool");
+
+ dataSource.setDescription(config.getConnectionPoolName());
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/hsql/HSQLDiskCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/hsql/HSQLDiskCacheFactory.java
new file mode 100644
index 0000000..42fe5b5
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/hsql/HSQLDiskCacheFactory.java
@@ -0,0 +1,129 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc.hsql;
+
+/*
+ * 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.
+ */
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import javax.sql.DataSource;
+
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCache;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheFactory;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This factory should create hsql disk caches.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class HSQLDiskCacheFactory
+ extends JDBCDiskCacheFactory
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( HSQLDiskCacheFactory.class );
+
+ /**
+ * This factory method should create an instance of the hsqlcache.
+ * <p>
+ * @param rawAttr
+ * @param compositeCacheManager
+ * @param cacheEventLogger
+ * @param elementSerializer
+ * @return JDBCDiskCache
+ * @throws SQLException if the creation of the cache instance fails
+ */
+ @Override
+ public <K, V> JDBCDiskCache<K, V> createCache( AuxiliaryCacheAttributes rawAttr,
+ ICompositeCacheManager compositeCacheManager,
+ ICacheEventLogger cacheEventLogger,
+ IElementSerializer elementSerializer )
+ throws SQLException
+ {
+ // TODO get this from the attributes.
+ System.setProperty( "hsqldb.cache_scale", "8" );
+
+ JDBCDiskCache<K, V> cache = super.createCache(rawAttr, compositeCacheManager,
+ cacheEventLogger, elementSerializer);
+ setupDatabase( cache.getDataSource(), (JDBCDiskCacheAttributes) rawAttr );
+
+ return cache;
+ }
+
+ /**
+ * Creates the table if it doesn't exist
+ * <p>
+ * @param ds Data Source
+ * @param attributes Cache region configuration
+ * @throws SQLException
+ */
+ protected void setupDatabase( DataSource ds, JDBCDiskCacheAttributes attributes )
+ throws SQLException
+ {
+ try (Connection cConn = ds.getConnection())
+ {
+ setupTable( cConn, attributes.getTableName() );
+ log.info( "Finished setting up table [{0}]", attributes.getTableName());
+ }
+ }
+
+ /**
+ * SETUP TABLE FOR CACHE
+ * <p>
+ * @param cConn
+ * @param tableName
+ */
+ protected synchronized void setupTable( Connection cConn, String tableName ) throws SQLException
+ {
+ DatabaseMetaData dmd = cConn.getMetaData();
+ ResultSet result = dmd.getTables(null, null, tableName, null);
+
+ if (!result.next())
+ {
+ // TODO make the cached nature of the table configurable
+ StringBuilder createSql = new StringBuilder();
+ createSql.append( "CREATE CACHED TABLE ").append( tableName );
+ createSql.append( "( " );
+ createSql.append( "CACHE_KEY VARCHAR(250) NOT NULL, " );
+ createSql.append( "REGION VARCHAR(250) NOT NULL, " );
+ createSql.append( "ELEMENT BINARY, " );
+ createSql.append( "CREATE_TIME TIMESTAMP, " );
+ createSql.append( "UPDATE_TIME_SECONDS BIGINT, " );
+ createSql.append( "MAX_LIFE_SECONDS BIGINT, " );
+ createSql.append( "SYSTEM_EXPIRE_TIME_SECONDS BIGINT, " );
+ createSql.append( "IS_ETERNAL CHAR(1), " );
+ createSql.append( "PRIMARY KEY (CACHE_KEY, REGION) " );
+ createSql.append( ");" );
+
+ try (Statement sStatement = cConn.createStatement())
+ {
+ sStatement.execute( createSql.toString() );
+ }
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/MySQLDiskCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/MySQLDiskCache.java
new file mode 100644
index 0000000..59764dc
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/MySQLDiskCache.java
@@ -0,0 +1,165 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc.mysql;
+
+/*
+ * 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.
+ */
+
+import java.sql.SQLException;
+import java.util.Map;
+
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCache;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.TableState;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.DataSourceFactory;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * The MySQLDiskCache extends the core JDBCDiskCache.
+ * <p>
+ * Although the generic JDBC Disk Cache can be used for MySQL, the MySQL JDBC Disk Cache has
+ * additional features, such as table optimization that are particular to MySQL.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class MySQLDiskCache<K, V>
+ extends JDBCDiskCache<K, V>
+{
+ /** local logger */
+ private static final Log log = LogManager.getLog( MySQLDiskCache.class );
+
+ /** config attributes */
+ private final MySQLDiskCacheAttributes mySQLDiskCacheAttributes;
+
+ /**
+ * Delegates to the super and makes use of the MySQL specific parameters used for scheduled
+ * optimization.
+ * <p>
+ * @param attributes the configuration object for this cache
+ * @param dsFactory the DataSourceFactory for this cache
+ * @param tableState an object to track table operations
+ * @param compositeCacheManager the global cache manager
+ * @throws SQLException if the pool access could not be set up
+ */
+ public MySQLDiskCache( MySQLDiskCacheAttributes attributes, DataSourceFactory dsFactory,
+ TableState tableState, ICompositeCacheManager compositeCacheManager ) throws SQLException
+ {
+ super( attributes, dsFactory, tableState, compositeCacheManager );
+
+ mySQLDiskCacheAttributes = attributes;
+
+ log.debug( "MySQLDiskCacheAttributes = {0}", attributes );
+ }
+
+ /**
+ * This delegates to the generic JDBC disk cache. If we are currently optimizing, then this
+ * method will balk and return null.
+ * <p>
+ * @param key Key to locate value for.
+ * @return An object matching key, or null.
+ */
+ @Override
+ protected ICacheElement<K, V> processGet( K key )
+ {
+ if ( this.getTableState().getState() == TableState.OPTIMIZATION_RUNNING )
+ {
+ if ( this.mySQLDiskCacheAttributes.isBalkDuringOptimization() )
+ {
+ return null;
+ }
+ }
+ return super.processGet( key );
+ }
+
+ /**
+ * This delegates to the generic JDBC disk cache. If we are currently optimizing, then this
+ * method will balk and return null.
+ * <p>
+ * @param pattern used for like query.
+ * @return An object matching key, or null.
+ */
+ @Override
+ protected Map<K, ICacheElement<K, V>> processGetMatching( String pattern )
+ {
+ if ( this.getTableState().getState() == TableState.OPTIMIZATION_RUNNING )
+ {
+ if ( this.mySQLDiskCacheAttributes.isBalkDuringOptimization() )
+ {
+ return null;
+ }
+ }
+ return super.processGetMatching( pattern );
+ }
+
+ /**
+ * @param pattern
+ * @return String to use in the like query.
+ */
+ @Override
+ public String constructLikeParameterFromPattern( String pattern )
+ {
+ String likePattern = pattern.replaceAll( "\\.\\+", "%" );
+ likePattern = likePattern.replaceAll( "\\.", "_" );
+
+ log.debug( "pattern = [{0}]", likePattern );
+
+ return likePattern;
+ }
+
+ /**
+ * This delegates to the generic JDBC disk cache. If we are currently optimizing, then this
+ * method will balk and do nothing.
+ * <p>
+ * @param element
+ */
+ @Override
+ protected void processUpdate( ICacheElement<K, V> element )
+ {
+ if ( this.getTableState().getState() == TableState.OPTIMIZATION_RUNNING )
+ {
+ if ( this.mySQLDiskCacheAttributes.isBalkDuringOptimization() )
+ {
+ return;
+ }
+ }
+ super.processUpdate( element );
+ }
+
+ /**
+ * Removed the expired. (now - create time) > max life seconds * 1000
+ * <p>
+ * If we are currently optimizing, then this method will balk and do nothing.
+ * <p>
+ * TODO consider blocking and trying again.
+ * <p>
+ * @return the number deleted
+ */
+ @Override
+ protected int deleteExpired()
+ {
+ if ( this.getTableState().getState() == TableState.OPTIMIZATION_RUNNING )
+ {
+ if ( this.mySQLDiskCacheAttributes.isBalkDuringOptimization() )
+ {
+ return -1;
+ }
+ }
+ return super.deleteExpired();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/MySQLDiskCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/MySQLDiskCacheAttributes.java
new file mode 100644
index 0000000..854a932
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/MySQLDiskCacheAttributes.java
@@ -0,0 +1,107 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc.mysql;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes;
+
+/**
+ * This has additional attributes that are particular to the MySQL disk cache.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class MySQLDiskCacheAttributes
+ extends JDBCDiskCacheAttributes
+{
+ /** Don't change. */
+ private static final long serialVersionUID = -6535808344813320061L;
+
+ /**
+ * For now this is a simple comma delimited list of HH:MM:SS times to optimize
+ * the table. If none is supplied, then no optimizations will be performed.
+ * <p>
+ * In the future we can add a chron like scheduling system. This is to meet
+ * a pressing current need.
+ * <p>
+ * 03:01,15:00 will cause the optimizer to run at 3 am and at 3 pm.
+ */
+ private String optimizationSchedule = null;
+
+ /**
+ * If true, we will balk, that is return null during optimization rather than block.
+ */
+ public static final boolean DEFAULT_BALK_DURING_OPTIMIZATION = true;
+
+ /**
+ * If true, we will balk, that is return null during optimization rather than block.
+ * <p>
+ * <a href="http://en.wikipedia.org/wiki/Balking_pattern">Balking</a>
+ */
+ private boolean balkDuringOptimization = DEFAULT_BALK_DURING_OPTIMIZATION;
+
+ /**
+ * @param optimizationSchedule The optimizationSchedule to set.
+ */
+ public void setOptimizationSchedule( String optimizationSchedule )
+ {
+ this.optimizationSchedule = optimizationSchedule;
+ }
+
+ /**
+ * @return Returns the optimizationSchedule.
+ */
+ public String getOptimizationSchedule()
+ {
+ return optimizationSchedule;
+ }
+
+ /**
+ * @param balkDuringOptimization The balkDuringOptimization to set.
+ */
+ public void setBalkDuringOptimization( boolean balkDuringOptimization )
+ {
+ this.balkDuringOptimization = balkDuringOptimization;
+ }
+
+ /**
+ * Should we return null while optimizing the table.
+ * <p>
+ * @return Returns the balkDuringOptimization.
+ */
+ public boolean isBalkDuringOptimization()
+ {
+ return balkDuringOptimization;
+ }
+
+ /**
+ * For debugging.
+ * <p>
+ * @return debug string
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\nMySQLDiskCacheAttributes" );
+ buf.append( "\n OptimizationSchedule [" + getOptimizationSchedule() + "]" );
+ buf.append( "\n BalkDuringOptimization [" + isBalkDuringOptimization() + "]" );
+ buf.append( super.toString() );
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/MySQLDiskCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/MySQLDiskCacheFactory.java
new file mode 100644
index 0000000..da702ad
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/MySQLDiskCacheFactory.java
@@ -0,0 +1,162 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc.mysql;
+
+/*
+ * 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.
+ */
+
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+import javax.sql.DataSource;
+
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheFactory;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.TableState;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.DataSourceFactory;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.mysql.util.ScheduleParser;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This factory should create mysql disk caches.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class MySQLDiskCacheFactory
+ extends JDBCDiskCacheFactory
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( MySQLDiskCacheFactory.class );
+
+ /**
+ * This factory method should create an instance of the mysqlcache.
+ * <p>
+ * @param rawAttr specific cache configuration attributes
+ * @param compositeCacheManager the global cache manager
+ * @param cacheEventLogger a specific logger for cache events
+ * @param elementSerializer a serializer for cache elements
+ * @return MySQLDiskCache the cache instance
+ * @throws SQLException if the cache instance could not be created
+ */
+ @Override
+ public <K, V> MySQLDiskCache<K, V> createCache( AuxiliaryCacheAttributes rawAttr,
+ ICompositeCacheManager compositeCacheManager,
+ ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
+ throws SQLException
+ {
+ MySQLDiskCacheAttributes cattr = (MySQLDiskCacheAttributes) rawAttr;
+ TableState tableState = getTableState( cattr.getTableName() );
+ DataSourceFactory dsFactory = getDataSourceFactory(cattr, compositeCacheManager.getConfigurationProperties());
+
+ MySQLDiskCache<K, V> cache = new MySQLDiskCache<>( cattr, dsFactory, tableState, compositeCacheManager );
+ cache.setCacheEventLogger( cacheEventLogger );
+ cache.setElementSerializer( elementSerializer );
+
+ // create a shrinker if we need it.
+ createShrinkerWhenNeeded( cattr, cache );
+ scheduleOptimizations( cattr, tableState, cache.getDataSource() );
+
+ return cache;
+
+ }
+
+ /**
+ * For each time in the optimization schedule, this calls schedule Optimization.
+ * <p>
+ * @param attributes configuration properties.
+ * @param tableState for noting optimization in progress, etc.
+ * @param ds the DataSource
+ */
+ protected void scheduleOptimizations( MySQLDiskCacheAttributes attributes, TableState tableState, DataSource ds )
+ {
+ if ( attributes != null )
+ {
+ if ( attributes.getOptimizationSchedule() != null )
+ {
+ log.info( "Will try to configure optimization for table [{0}] on schedule [{1}]",
+ () -> attributes.getTableName(), () -> attributes.getOptimizationSchedule());
+
+ MySQLTableOptimizer optimizer = new MySQLTableOptimizer( attributes, tableState, ds );
+
+ // loop through the dates.
+ try
+ {
+ Date[] dates = ScheduleParser.createDatesForSchedule( attributes.getOptimizationSchedule() );
+ if ( dates != null )
+ {
+ for ( int i = 0; i < dates.length; i++ )
+ {
+ this.scheduleOptimization( dates[i], optimizer );
+ }
+ }
+ }
+ catch ( ParseException e )
+ {
+ log.warn( "Problem creating optimization schedule for table [{0}]",
+ attributes.getTableName(), e );
+ }
+ }
+ else
+ {
+ log.info( "Optimization is not configured for table [{0}]",
+ attributes.getTableName());
+ }
+ }
+ }
+
+ /**
+ * This takes in a single time and schedules the optimizer to be called at that time every day.
+ * <p>
+ * @param startTime -- HH:MM:SS format
+ * @param optimizer
+ */
+ protected void scheduleOptimization( Date startTime, MySQLTableOptimizer optimizer )
+ {
+ log.info( "startTime [{0}] for optimizer {1}", startTime, optimizer );
+
+ Date now = new Date();
+ long initialDelay = startTime.getTime() - now.getTime();
+
+ // have the daemon execute the optimization
+ getScheduledExecutorService().scheduleAtFixedRate(() -> optimizeTable(optimizer),
+ initialDelay, 86400L, TimeUnit.SECONDS );
+ }
+
+ /**
+ * This calls the optimizers' optimize table method. This is used by the timer.
+ * <p>
+ * @author Aaron Smuts
+ */
+ private void optimizeTable(MySQLTableOptimizer optimizer)
+ {
+ if ( optimizer != null )
+ {
+ boolean success = optimizer.optimizeTable();
+ log.info( "Optimization success status [{0}]", success );
+ }
+ else
+ {
+ log.warn( "OptimizerRunner: The optimizer is null. Could not optimize table." );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/MySQLTableOptimizer.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/MySQLTableOptimizer.java
new file mode 100644
index 0000000..dc83d54
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/MySQLTableOptimizer.java
@@ -0,0 +1,278 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc.mysql;
+
+/*
+ * 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.
+ */
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import javax.sql.DataSource;
+
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.TableState;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.timing.ElapsedTimer;
+
+/**
+ * The MySQL Table Optimizer can optimize MySQL tables. It knows how to optimize for MySQL databases
+ * in particular and how to repair the table if it is corrupted in the process.
+ * <p>
+ * We will probably be able to abstract out a generic optimizer interface from this class in the
+ * future.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class MySQLTableOptimizer
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( MySQLTableOptimizer.class );
+
+ /** The data source */
+ private DataSource dataSource = null;
+
+ /** The name of the table. */
+ private String tableName = null;
+
+ /** optimizing, etc. */
+ private final TableState tableState;
+
+ /**
+ * This constructs an optimizer with the disk cacn properties.
+ * <p>
+ * @param attributes
+ * @param tableState We mark the table status as optimizing when this is happening.
+ * @param dataSource access to the database
+ */
+ public MySQLTableOptimizer( MySQLDiskCacheAttributes attributes, TableState tableState, DataSource dataSource )
+ {
+ setTableName( attributes.getTableName() );
+
+ this.tableState = tableState;
+ this.dataSource = dataSource;
+ }
+
+ /**
+ * A scheduler will call this method. When it is called the table state is marked as optimizing.
+ * TODO we need to verify that no deletions are running before we call optimize. We should wait
+ * if a deletion is in progress.
+ * <p>
+ * This restores when there is an optimization error. The error output looks like this:
+ *
+ * <pre>
+ * mysql> optimize table JCS_STORE_FLIGHT_OPTION_ITINERARY;
+ * +---------------------------------------------+----------+----------+---------------------+
+ * | Table | Op | Msg_type | Msg_text |
+ * +---------------------------------------------+----------+----------+---------------------+
+ * | jcs_cache.JCS_STORE_FLIGHT_OPTION_ITINERARY | optimize | error | 2 when fixing table |
+ * | jcs_cache.JCS_STORE_FLIGHT_OPTION_ITINERARY | optimize | status | Operation failed |
+ * +---------------------------------------------+----------+----------+---------------------+
+ * 2 rows in set (51.78 sec)
+ * </pre>
+ *
+ * A successful repair response looks like this:
+ *
+ * <pre>
+ * mysql> REPAIR TABLE JCS_STORE_FLIGHT_OPTION_ITINERARY;
+ * +---------------------------------------------+--------+----------+----------------------------------------------+
+ * | Table | Op | Msg_type | Msg_text |
+ * +---------------------------------------------+--------+----------+----------------------------------------------+
+ * | jcs_cache.JCS_STORE_FLIGHT_OPTION_ITINERARY | repair | error | 2 when fixing table |
+ * | jcs_cache.JCS_STORE_FLIGHT_OPTION_ITINERARY | repair | warning | Number of rows changed from 131276 to 260461 |
+ * | jcs_cache.JCS_STORE_FLIGHT_OPTION_ITINERARY | repair | status | OK |
+ * +---------------------------------------------+--------+----------+----------------------------------------------+
+ * 3 rows in set (3 min 5.94 sec)
+ * </pre>
+ *
+ * A successful optimization looks like this:
+ *
+ * <pre>
+ * mysql> optimize table JCS_STORE_DEFAULT;
+ * +-----------------------------+----------+----------+----------+
+ * | Table | Op | Msg_type | Msg_text |
+ * +-----------------------------+----------+----------+----------+
+ * | jcs_cache.JCS_STORE_DEFAULT | optimize | status | OK |
+ * +-----------------------------+----------+----------+----------+
+ * 1 row in set (1.10 sec)
+ * </pre>
+ * @return true if it worked
+ */
+ public boolean optimizeTable()
+ {
+ ElapsedTimer timer = new ElapsedTimer();
+ boolean success = false;
+
+ if ( tableState.getState() == TableState.OPTIMIZATION_RUNNING )
+ {
+ log.warn( "Skipping optimization. Optimize was called, but the "
+ + "table state indicates that an optimization is currently running." );
+ return false;
+ }
+
+ try
+ {
+ tableState.setState( TableState.OPTIMIZATION_RUNNING );
+ log.info( "Optimizing table [{0}]", this.getTableName());
+
+ try (Connection con = dataSource.getConnection())
+ {
+ // TEST
+
+ try (Statement sStatement = con.createStatement())
+ {
+ ResultSet rs = sStatement.executeQuery( "optimize table " + this.getTableName() );
+
+ // first row is error, then status
+ // if there is only one row in the result set, everything
+ // should be fine.
+ // This may be mysql version specific.
+ if ( rs.next() )
+ {
+ String status = rs.getString( "Msg_type" );
+ String message = rs.getString( "Msg_text" );
+
+ log.info( "Message Type: {0}", status );
+ log.info( "Message: {0}", message );
+
+ if ( "error".equals( status ) )
+ {
+ log.warn( "Optimization was in error. Will attempt "
+ + "to repair the table. Message: {0}", message);
+
+ // try to repair the table.
+ success = repairTable( sStatement );
+ }
+ else
+ {
+ success = true;
+ }
+ }
+
+ // log the table status
+ String statusString = getTableStatus( sStatement );
+ log.info( "Table status after optimizing table [{0}]: {1}",
+ this.getTableName(), statusString );
+ }
+ catch ( SQLException e )
+ {
+ log.error( "Problem optimizing table [{0}]",
+ this.getTableName(), e );
+ return false;
+ }
+ }
+ catch ( SQLException e )
+ {
+ log.error( "Problem getting connection.", e );
+ }
+ }
+ finally
+ {
+ tableState.setState( TableState.FREE );
+
+ log.info( "Optimization of table [{0}] took {1} ms.",
+ () -> this.getTableName(), () -> timer.getElapsedTime() );
+ }
+
+ return success;
+ }
+
+ /**
+ * This calls show table status and returns the result as a String.
+ * <p>
+ * @param sStatement
+ * @return String
+ * @throws SQLException
+ */
+ protected String getTableStatus( Statement sStatement )
+ throws SQLException
+ {
+ ResultSet statusResultSet = sStatement.executeQuery( "show table status" );
+ StringBuilder statusString = new StringBuilder();
+ int numColumns = statusResultSet.getMetaData().getColumnCount();
+ while ( statusResultSet.next() )
+ {
+ statusString.append( "\n" );
+ for ( int i = 1; i <= numColumns; i++ )
+ {
+ statusString.append( statusResultSet.getMetaData().getColumnLabel( i ) + " ["
+ + statusResultSet.getString( i ) + "] | " );
+ }
+ }
+ return statusString.toString();
+ }
+
+ /**
+ * This is called if the optimization is in error.
+ * <p>
+ * It looks for "OK" in response. If it find "OK" as a message in any result set row, it returns
+ * true. Otherwise we assume that the repair failed.
+ * <p>
+ * @param sStatement
+ * @return true if successful
+ * @throws SQLException
+ */
+ protected boolean repairTable( Statement sStatement )
+ throws SQLException
+ {
+ boolean success = false;
+
+ // if( message != null && message.indexOf( ) )
+ ResultSet repairResult = sStatement.executeQuery( "repair table " + this.getTableName() );
+ StringBuilder repairString = new StringBuilder();
+ int numColumns = repairResult.getMetaData().getColumnCount();
+ while ( repairResult.next() )
+ {
+ for ( int i = 1; i <= numColumns; i++ )
+ {
+ repairString.append( repairResult.getMetaData().getColumnLabel( i ) + " [" + repairResult.getString( i )
+ + "] | " );
+ }
+
+ String message = repairResult.getString( "Msg_text" );
+ if ( "OK".equals( message ) )
+ {
+ success = true;
+ }
+ }
+ log.info("{0}", repairString);
+
+ if ( !success )
+ {
+ log.warn( "Failed to repair the table. {0}", repairString );
+ }
+ return success;
+ }
+
+ /**
+ * @param tableName The tableName to set.
+ */
+ public void setTableName( String tableName )
+ {
+ this.tableName = tableName;
+ }
+
+ /**
+ * @return Returns the tableName.
+ */
+ public String getTableName()
+ {
+ return tableName;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/util/ScheduleParser.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/util/ScheduleParser.java
new file mode 100644
index 0000000..11e87b9
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/util/ScheduleParser.java
@@ -0,0 +1,96 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc.mysql.util;
+
+/*
+ * 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.
+ */
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.StringTokenizer;
+
+/**
+ * Parses the very simple schedule format.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class ScheduleParser
+{
+ /**
+ * For each date time that is separated by a comma in the
+ * OptimizationSchedule, create a date and add it to an array of dates.
+ * <p>
+ * @param schedule
+ * @return Date[]
+ * @throws ParseException
+ */
+ public static Date[] createDatesForSchedule( String schedule )
+ throws ParseException
+ {
+ if ( schedule == null )
+ {
+ throw new ParseException( "Cannot create schedules for a null String.", 0 );
+ }
+
+ StringTokenizer toker = new StringTokenizer( schedule, "," );
+ Date[] dates = new Date[toker.countTokens()];
+ int cnt = 0;
+ while ( toker.hasMoreTokens() )
+ {
+ String time = toker.nextToken();
+ dates[cnt] = getDateForSchedule( time );
+ cnt++;
+ }
+ return dates;
+ }
+
+ /**
+ * For a single string it creates a date that is the next time this hh:mm:ss
+ * combo will be seen.
+ * <p>
+ * @param startTime
+ * @return Date
+ * @throws ParseException
+ */
+ public static Date getDateForSchedule( String startTime )
+ throws ParseException
+ {
+ if ( startTime == null )
+ {
+ throw new ParseException( "Cannot create date for a null String.", 0 );
+ }
+
+ SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
+ Date date = sdf.parse(startTime);
+ Calendar cal = Calendar.getInstance();
+ // This will result in a date of 1/1/1970
+ cal.setTime(date);
+
+ Calendar now = Calendar.getInstance();
+ cal.set(now.get(Calendar.YEAR), now.get(Calendar.MONTH), now.get(Calendar.DAY_OF_MONTH));
+
+ // if the date is less than now, add a day.
+ if ( cal.before( now ) )
+ {
+ cal.add( Calendar.DAY_OF_MONTH, 1 );
+ }
+
+ return cal.getTime();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/package.html b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/package.html
similarity index 100%
rename from commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/disk/package.html
rename to commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/disk/package.html
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCache.java
new file mode 100644
index 0000000..433ee5e
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCache.java
@@ -0,0 +1,417 @@
+package org.apache.commons.jcs3.auxiliary.lateral;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheEventLogging;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.lateral.behavior.ILateralCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheInfo;
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.ZombieCacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.behavior.IZombie;
+import org.apache.commons.jcs3.engine.stats.Stats;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * Lateral distributor. Returns null on get by default. Net search not implemented.
+ */
+public class LateralCache<K, V>
+ extends AbstractAuxiliaryCacheEventLogging<K, V>
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog( LateralCache.class );
+
+ /** generalize this, use another interface */
+ private final ILateralCacheAttributes lateralCacheAttributes;
+
+ /** The region name */
+ final String cacheName;
+
+ /** either http, socket.udp, or socket.tcp can set in config */
+ private ICacheServiceNonLocal<K, V> lateralCacheService;
+
+ /** Monitors the connection. */
+ private LateralCacheMonitor monitor;
+
+ /**
+ * Constructor for the LateralCache object
+ * <p>
+ * @param cattr
+ * @param lateral
+ * @param monitor
+ */
+ public LateralCache( ILateralCacheAttributes cattr, ICacheServiceNonLocal<K, V> lateral, LateralCacheMonitor monitor )
+ {
+ this.cacheName = cattr.getCacheName();
+ this.lateralCacheAttributes = cattr;
+ this.lateralCacheService = lateral;
+ this.monitor = monitor;
+ }
+
+ /**
+ * Constructor for the LateralCache object
+ * <p>
+ * @param cattr
+ */
+ public LateralCache( ILateralCacheAttributes cattr )
+ {
+ this.cacheName = cattr.getCacheName();
+ this.lateralCacheAttributes = cattr;
+ }
+
+ /**
+ * Update lateral.
+ * <p>
+ * @param ce
+ * @throws IOException
+ */
+ @Override
+ protected void processUpdate( ICacheElement<K, V> ce )
+ throws IOException
+ {
+ try
+ {
+ if (ce != null)
+ {
+ log.debug( "update: lateral = [{0}], CacheInfo.listenerId = {1}",
+ lateralCacheService, CacheInfo.listenerId );
+ lateralCacheService.update( ce, CacheInfo.listenerId );
+ }
+ }
+ catch ( IOException ex )
+ {
+ handleException( ex, "Failed to put [" + ce.getKey() + "] to " + ce.getCacheName() + "@" + lateralCacheAttributes );
+ }
+ }
+
+ /**
+ * The performance costs are too great. It is not recommended that you enable lateral gets.
+ * <p>
+ * @param key
+ * @return ICacheElement<K, V> or null
+ * @throws IOException
+ */
+ @Override
+ protected ICacheElement<K, V> processGet( K key )
+ throws IOException
+ {
+ ICacheElement<K, V> obj = null;
+
+ if ( this.lateralCacheAttributes.getPutOnlyMode() )
+ {
+ return null;
+ }
+ try
+ {
+ obj = lateralCacheService.get( cacheName, key );
+ }
+ catch ( Exception e )
+ {
+ log.error( e );
+ handleException( e, "Failed to get [" + key + "] from " + lateralCacheAttributes.getCacheName() + "@" + lateralCacheAttributes );
+ }
+ return obj;
+ }
+
+ /**
+ * @param pattern
+ * @return A map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ * @throws IOException
+ */
+ @Override
+ protected Map<K, ICacheElement<K, V>> processGetMatching( String pattern )
+ throws IOException
+ {
+ if ( this.lateralCacheAttributes.getPutOnlyMode() )
+ {
+ return Collections.emptyMap();
+ }
+ try
+ {
+ return lateralCacheService.getMatching( cacheName, pattern );
+ }
+ catch ( IOException e )
+ {
+ log.error( e );
+ handleException( e, "Failed to getMatching [" + pattern + "] from " + lateralCacheAttributes.getCacheName() + "@" + lateralCacheAttributes );
+ return Collections.emptyMap();
+ }
+ }
+
+ /**
+ * Return the keys in this cache.
+ * <p>
+ * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCache#getKeySet()
+ */
+ @Override
+ public Set<K> getKeySet() throws IOException
+ {
+ try
+ {
+ return lateralCacheService.getKeySet( cacheName );
+ }
+ catch ( IOException ex )
+ {
+ handleException( ex, "Failed to get key set from " + lateralCacheAttributes.getCacheName() + "@"
+ + lateralCacheAttributes );
+ }
+ return Collections.emptySet();
+ }
+
+ /**
+ * Synchronously remove from the remote cache; if failed, replace the remote handle with a
+ * zombie.
+ * <p>
+ * @param key
+ * @return false always
+ * @throws IOException
+ */
+ @Override
+ protected boolean processRemove( K key )
+ throws IOException
+ {
+ log.debug( "removing key: {0}", key );
+
+ try
+ {
+ lateralCacheService.remove( cacheName, key, CacheInfo.listenerId );
+ }
+ catch ( IOException ex )
+ {
+ handleException( ex, "Failed to remove " + key + " from " + lateralCacheAttributes.getCacheName() + "@" + lateralCacheAttributes );
+ }
+ return false;
+ }
+
+ /**
+ * Synchronously removeAll from the remote cache; if failed, replace the remote handle with a
+ * zombie.
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ protected void processRemoveAll()
+ throws IOException
+ {
+ try
+ {
+ lateralCacheService.removeAll( cacheName, CacheInfo.listenerId );
+ }
+ catch ( IOException ex )
+ {
+ handleException( ex, "Failed to remove all from " + lateralCacheAttributes.getCacheName() + "@" + lateralCacheAttributes );
+ }
+ }
+
+ /**
+ * Synchronously dispose the cache. Not sure we want this.
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ protected void processDispose()
+ throws IOException
+ {
+ log.debug( "Disposing of lateral cache" );
+
+ ///* HELP: This section did nothing but generate compilation warnings.
+ // TODO: may limit this functionality. It is dangerous.
+ // asmuts -- Added functionality to help with warnings. I'm not getting
+ // any.
+ try
+ {
+ lateralCacheService.dispose( this.lateralCacheAttributes.getCacheName() );
+ // Should remove connection
+ }
+ catch ( IOException ex )
+ {
+ log.error( "Couldn't dispose", ex );
+ handleException( ex, "Failed to dispose " + lateralCacheAttributes.getCacheName() );
+ }
+ }
+
+ /**
+ * Returns the cache status.
+ * <p>
+ * @return The status value
+ */
+ @Override
+ public CacheStatus getStatus()
+ {
+ return this.lateralCacheService instanceof IZombie ? CacheStatus.ERROR : CacheStatus.ALIVE;
+ }
+
+ /**
+ * Returns the current cache size.
+ * <p>
+ * @return The size value
+ */
+ @Override
+ public int getSize()
+ {
+ return 0;
+ }
+
+ /**
+ * Gets the cacheType attribute of the LateralCache object
+ * <p>
+ * @return The cacheType value
+ */
+ @Override
+ public CacheType getCacheType()
+ {
+ return CacheType.LATERAL_CACHE;
+ }
+
+ /**
+ * Gets the cacheName attribute of the LateralCache object
+ * <p>
+ * @return The cacheName value
+ */
+ @Override
+ public String getCacheName()
+ {
+ return cacheName;
+ }
+
+ /**
+ * Not yet sure what to do here.
+ * <p>
+ * @param ex
+ * @param msg
+ * @throws IOException
+ */
+ private void handleException( Exception ex, String msg )
+ throws IOException
+ {
+ log.error( "Disabling lateral cache due to error {0}", msg, ex );
+
+ lateralCacheService = new ZombieCacheServiceNonLocal<>( lateralCacheAttributes.getZombieQueueMaxSize() );
+ // may want to flush if region specifies
+ // Notify the cache monitor about the error, and kick off the recovery
+ // process.
+ monitor.notifyError();
+
+ // could stop the net search if it is built and try to reconnect?
+ if ( ex instanceof IOException )
+ {
+ throw (IOException) ex;
+ }
+ throw new IOException( ex.getMessage() );
+ }
+
+ /**
+ * Replaces the current remote cache service handle with the given handle.
+ * <p>
+ * @param restoredLateral
+ */
+ public void fixCache( ICacheServiceNonLocal<K, V> restoredLateral )
+ {
+ if ( this.lateralCacheService != null && this.lateralCacheService instanceof ZombieCacheServiceNonLocal )
+ {
+ ZombieCacheServiceNonLocal<K, V> zombie = (ZombieCacheServiceNonLocal<K, V>) this.lateralCacheService;
+ this.lateralCacheService = restoredLateral;
+ try
+ {
+ zombie.propagateEvents( restoredLateral );
+ }
+ catch ( Exception e )
+ {
+ try
+ {
+ handleException( e, "Problem propagating events from Zombie Queue to new Lateral Service." );
+ }
+ catch ( IOException e1 )
+ {
+ // swallow, since this is just expected kick back. Handle always throws
+ }
+ }
+ }
+ else
+ {
+ this.lateralCacheService = restoredLateral;
+ }
+ }
+
+ /**
+ * getStats
+ * <p>
+ * @return String
+ */
+ @Override
+ public String getStats()
+ {
+ return "";
+ }
+
+ /**
+ * @return Returns the AuxiliaryCacheAttributes.
+ */
+ @Override
+ public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
+ {
+ return lateralCacheAttributes;
+ }
+
+ /**
+ * @return debugging data.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\n LateralCache " );
+ buf.append( "\n Cache Name [" + lateralCacheAttributes.getCacheName() + "]" );
+ buf.append( "\n cattr = [" + lateralCacheAttributes + "]" );
+ return buf.toString();
+ }
+
+ /**
+ * @return extra data.
+ */
+ @Override
+ public String getEventLoggingExtraInfo()
+ {
+ return null;
+ }
+
+ /**
+ * The NoWait on top does not call out to here yet.
+ * <p>
+ * @return almost nothing
+ */
+ @Override
+ public IStats getStatistics()
+ {
+ IStats stats = new Stats();
+ stats.setTypeName( "LateralCache" );
+ return stats;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheAttributes.java
new file mode 100644
index 0000000..92e6a35
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheAttributes.java
@@ -0,0 +1,292 @@
+package org.apache.commons.jcs3.auxiliary.lateral;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.lateral.behavior.ILateralCacheAttributes;
+
+/**
+ * This class stores attributes for all of the available lateral cache auxiliaries.
+ */
+public class LateralCacheAttributes
+ extends AbstractAuxiliaryCacheAttributes
+ implements ILateralCacheAttributes
+{
+ /** Don't change */
+ private static final long serialVersionUID = -3408449508837393660L;
+
+ /** Default receive setting */
+ private static final boolean DEFAULT_RECEIVE = true;
+
+ /** THe type of lateral */
+ private String transmissionTypeName = "UDP";
+
+ /** indicates the lateral type, this needs to change */
+ private Type transmissionType = Type.UDP;
+
+ /** The http servers */
+ private String httpServers;
+
+ /** used to identify the service that this manager will be operating on */
+ private String httpServer = "";
+
+ /** this needs to change */
+ private String udpMulticastAddr = "228.5.6.7";
+
+ /** this needs to change */
+ private int udpMulticastPort = 6789;
+
+ /** this needs to change */
+ private int httpListenerPort = 8080;
+
+ /** disables gets from laterals */
+ private boolean putOnlyMode = true;
+
+ /**
+ * do we receive and broadcast or only broadcast this is useful when you don't want to get any
+ * notifications
+ */
+ private boolean receive = DEFAULT_RECEIVE;
+
+ /** If the primary fails, we will queue items before reconnect. This limits the number of items that can be queued. */
+ private int zombieQueueMaxSize = DEFAULT_ZOMBIE_QUEUE_MAX_SIZE;
+
+ /**
+ * Sets the httpServer attribute of the LateralCacheAttributes object
+ * <P>
+ * @param val The new httpServer value
+ */
+ @Override
+ public void setHttpServer( String val )
+ {
+ httpServer = val;
+ }
+
+ /**
+ * Gets the httpServer attribute of the LateralCacheAttributes object
+ * @return The httpServer value
+ */
+ @Override
+ public String getHttpServer()
+ {
+ return httpServer;
+ }
+
+ /**
+ * Sets the httpServers attribute of the LateralCacheAttributes object
+ * @param val The new httpServers value
+ */
+ @Override
+ public void setHttpServers( String val )
+ {
+ httpServers = val;
+ }
+
+ /**
+ * Gets the httpSrvers attribute of the LateralCacheAttributes object
+ * @return The httpServers value
+ */
+ @Override
+ public String getHttpServers()
+ {
+ return httpServers;
+ }
+
+ /**
+ * Sets the httpListenerPort attribute of the ILateralCacheAttributes object
+ * @param val The new tcpListenerPort value
+ */
+ @Override
+ public void setHttpListenerPort( int val )
+ {
+ this.httpListenerPort = val;
+ }
+
+ /**
+ * Gets the httpListenerPort attribute of the ILateralCacheAttributes object
+ * @return The httpListenerPort value
+ */
+ @Override
+ public int getHttpListenerPort()
+ {
+ return this.httpListenerPort;
+ }
+
+ /**
+ * Sets the udpMulticastAddr attribute of the LateralCacheAttributes object
+ * @param val The new udpMulticastAddr value
+ */
+ @Override
+ public void setUdpMulticastAddr( String val )
+ {
+ udpMulticastAddr = val;
+ }
+
+ /**
+ * Gets the udpMulticastAddr attribute of the LateralCacheAttributes object
+ * @return The udpMulticastAddr value
+ */
+ @Override
+ public String getUdpMulticastAddr()
+ {
+ return udpMulticastAddr;
+ }
+
+ /**
+ * Sets the udpMulticastPort attribute of the LateralCacheAttributes object
+ * @param val The new udpMulticastPort value
+ */
+ @Override
+ public void setUdpMulticastPort( int val )
+ {
+ udpMulticastPort = val;
+ }
+
+ /**
+ * Gets the udpMulticastPort attribute of the LateralCacheAttributes object
+ * @return The udpMulticastPort value
+ */
+ @Override
+ public int getUdpMulticastPort()
+ {
+ return udpMulticastPort;
+ }
+
+ /**
+ * Sets the transmissionType attribute of the LateralCacheAttributes object
+ * @param val The new transmissionType value
+ */
+ @Override
+ public void setTransmissionType( Type val )
+ {
+ this.transmissionType = val;
+ this.transmissionTypeName = val.toString();
+ }
+
+ /**
+ * Gets the transmissionType attribute of the LateralCacheAttributes object
+ * @return The transmissionType value
+ */
+ @Override
+ public Type getTransmissionType()
+ {
+ return this.transmissionType;
+ }
+
+ /**
+ * Sets the transmissionTypeName attribute of the LateralCacheAttributes object
+ * @param val The new transmissionTypeName value
+ */
+ @Override
+ public void setTransmissionTypeName( String val )
+ {
+ this.transmissionTypeName = val;
+ this.transmissionType = Type.valueOf(val);
+ }
+
+ /**
+ * Gets the transmissionTypeName attribute of the LateralCacheAttributes object
+ * @return The transmissionTypeName value
+ */
+ @Override
+ public String getTransmissionTypeName()
+ {
+ return this.transmissionTypeName;
+ }
+
+ /**
+ * Sets the outgoingOnlyMode attribute of the ILateralCacheAttributes. When this is true the
+ * lateral cache will only issue put and remove order and will not try to retrieve elements from
+ * other lateral caches.
+ * @param val The new transmissionTypeName value
+ */
+ @Override
+ public void setPutOnlyMode( boolean val )
+ {
+ this.putOnlyMode = val;
+ }
+
+ /**
+ * @return The outgoingOnlyMode value. Stops gets from going remote.
+ */
+ @Override
+ public boolean getPutOnlyMode()
+ {
+ return putOnlyMode;
+ }
+
+ /**
+ * @param receive The receive to set.
+ */
+ @Override
+ public void setReceive( boolean receive )
+ {
+ this.receive = receive;
+ }
+
+ /**
+ * @return Returns the receive.
+ */
+ @Override
+ public boolean isReceive()
+ {
+ return receive;
+ }
+
+ /**
+ * The number of elements the zombie queue will hold. This queue is used to store events if we
+ * loose our connection with the server.
+ * <p>
+ * @param zombieQueueMaxSize The zombieQueueMaxSize to set.
+ */
+ @Override
+ public void setZombieQueueMaxSize( int zombieQueueMaxSize )
+ {
+ this.zombieQueueMaxSize = zombieQueueMaxSize;
+ }
+
+ /**
+ * The number of elements the zombie queue will hold. This queue is used to store events if we
+ * loose our connection with the server.
+ * <p>
+ * @return Returns the zombieQueueMaxSize.
+ */
+ @Override
+ public int getZombieQueueMaxSize()
+ {
+ return zombieQueueMaxSize;
+ }
+
+ /**
+ * @return debug string.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ //buf.append( "cacheName=" + cacheName + "\n" );
+ //buf.append( "putOnlyMode=" + putOnlyMode + "\n" );
+ //buf.append( "transmissionTypeName=" + transmissionTypeName + "\n" );
+ //buf.append( "transmissionType=" + transmissionType + "\n" );
+ //buf.append( "tcpServer=" + tcpServer + "\n" );
+ buf.append( transmissionTypeName + httpServer + udpMulticastAddr + String.valueOf( udpMulticastPort ) );
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheMonitor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheMonitor.java
new file mode 100644
index 0000000..cb8f62a
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheMonitor.java
@@ -0,0 +1,136 @@
+package org.apache.commons.jcs3.auxiliary.lateral;
+
+/*
+ * 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.
+ */
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheMonitor;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.ZombieCacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+
+/**
+ * Used to monitor and repair any failed connection for the lateral cache service. By default the
+ * monitor operates in a failure driven mode. That is, it goes into a wait state until there is an
+ * error. Upon the notification of a connection error, the monitor changes to operate in a time
+ * driven mode. That is, it attempts to recover the connections on a periodic basis. When all failed
+ * connections are restored, it changes back to the failure driven mode.
+ */
+public class LateralCacheMonitor extends AbstractAuxiliaryCacheMonitor
+{
+ /**
+ * Map of caches to monitor
+ */
+ private final ConcurrentHashMap<String, LateralCacheNoWait<?, ?>> caches;
+
+ /**
+ * Reference to the factory
+ */
+ private final LateralTCPCacheFactory factory;
+
+ /**
+ * Allows close classes, ie testers to set the idle period to something testable.
+ * <p>
+ * @param idlePeriod
+ */
+ protected static void forceShortIdlePeriod( long idlePeriod )
+ {
+ LateralCacheMonitor.idlePeriod = idlePeriod;
+ }
+
+ /**
+ * Constructor for the LateralCacheMonitor object
+ * <p>
+ * It's the clients responsibility to decide how many of these there will be.
+ *
+ * @param factory a reference to the factory that manages the service instances
+ */
+ public LateralCacheMonitor(LateralTCPCacheFactory factory)
+ {
+ super("JCS-LateralCacheMonitor");
+ this.factory = factory;
+ this.caches = new ConcurrentHashMap<>();
+ setIdlePeriod(20000L);
+ }
+
+ /**
+ * Add a cache to be monitored
+ *
+ * @param cache the cache
+ */
+ public void addCache(LateralCacheNoWait<?, ?> cache)
+ {
+ this.caches.put(cache.getCacheName(), cache);
+
+ // if not yet started, go ahead
+ if (this.getState() == Thread.State.NEW)
+ {
+ this.start();
+ }
+ }
+
+ /**
+ * Clean up all resources before shutdown
+ */
+ @Override
+ public void dispose()
+ {
+ this.caches.clear();
+ }
+
+ /**
+ * Main processing method for the LateralCacheMonitor object
+ */
+ @Override
+ public void doWork()
+ {
+ // Monitor each cache instance one after the other.
+ log.info( "Number of caches to monitor = " + caches.size() );
+ //for
+ for (Map.Entry<String, LateralCacheNoWait<?, ?>> entry : caches.entrySet())
+ {
+ String cacheName = entry.getKey();
+
+ @SuppressWarnings("unchecked") // Downcast to match service
+ LateralCacheNoWait<Object, Object> c = (LateralCacheNoWait<Object, Object>) entry.getValue();
+ if ( c.getStatus() == CacheStatus.ERROR )
+ {
+ log.info( "Found LateralCacheNoWait in error, " + cacheName );
+
+ ITCPLateralCacheAttributes lca = (ITCPLateralCacheAttributes)c.getAuxiliaryCacheAttributes();
+
+ // Get service instance
+ ICacheServiceNonLocal<Object, Object> cacheService = factory.getCSNLInstance(lca);
+
+ // If we can't fix them, just skip and re-try in the
+ // next round.
+ if (cacheService instanceof ZombieCacheServiceNonLocal)
+ {
+ continue;
+ }
+
+ c.fixCache(cacheService);
+ }
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheNoWait.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheNoWait.java
new file mode 100644
index 0000000..b85616b
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheNoWait.java
@@ -0,0 +1,433 @@
+package org.apache.commons.jcs3.auxiliary.lateral;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.rmi.UnmarshalException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheAdaptor;
+import org.apache.commons.jcs3.engine.CacheEventQueueFactory;
+import org.apache.commons.jcs3.engine.CacheInfo;
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheEventQueue;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.stats.StatElement;
+import org.apache.commons.jcs3.engine.stats.Stats;
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * Used to queue up update requests to the underlying cache. These requests will be processed in
+ * their order of arrival via the cache event queue processor.
+ */
+public class LateralCacheNoWait<K, V>
+ extends AbstractAuxiliaryCache<K, V>
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog( LateralCacheNoWait.class );
+
+ /** The cache */
+ private final LateralCache<K, V> cache;
+
+ /** The event queue */
+ private ICacheEventQueue<K, V> eventQueue;
+
+ /** times get called */
+ private int getCount = 0;
+
+ /** times remove called */
+ private int removeCount = 0;
+
+ /** times put called */
+ private int putCount = 0;
+
+ /**
+ * Constructs with the given lateral cache, and fires up an event queue for asynchronous
+ * processing.
+ * <p>
+ * @param cache
+ */
+ public LateralCacheNoWait( LateralCache<K, V> cache )
+ {
+ this.cache = cache;
+
+ log.debug( "Constructing LateralCacheNoWait, LateralCache = [{0}]", cache );
+
+ CacheEventQueueFactory<K, V> fact = new CacheEventQueueFactory<>();
+ this.eventQueue = fact.createCacheEventQueue( new CacheAdaptor<>( cache ), CacheInfo.listenerId, cache
+ .getCacheName(), cache.getAuxiliaryCacheAttributes().getEventQueuePoolName(), cache
+ .getAuxiliaryCacheAttributes().getEventQueueType() );
+
+ // need each no wait to handle each of its real updates and removes,
+ // since there may
+ // be more than one per cache? alternative is to have the cache
+ // perform updates using a different method that specifies the listener
+ // this.q = new CacheEventQueue(new CacheAdaptor(this),
+ // LateralCacheInfo.listenerId, cache.getCacheName());
+ if ( cache.getStatus() == CacheStatus.ERROR )
+ {
+ eventQueue.destroy();
+ }
+ }
+
+ /**
+ * @param ce
+ * @throws IOException
+ */
+ @Override
+ public void update( ICacheElement<K, V> ce )
+ throws IOException
+ {
+ putCount++;
+ try
+ {
+ eventQueue.addPutEvent( ce );
+ }
+ catch ( IOException ex )
+ {
+ log.error( ex );
+ eventQueue.destroy();
+ }
+ }
+
+ /**
+ * Synchronously reads from the lateral cache.
+ * <p>
+ * @param key
+ * @return ICacheElement<K, V> if found, else null
+ */
+ @Override
+ public ICacheElement<K, V> get( K key )
+ {
+ getCount++;
+ if ( this.getStatus() != CacheStatus.ERROR )
+ {
+ try
+ {
+ return cache.get( key );
+ }
+ catch ( UnmarshalException ue )
+ {
+ log.debug( "Retrying the get owing to UnmarshalException..." );
+ try
+ {
+ return cache.get( key );
+ }
+ catch ( IOException ex )
+ {
+ log.error( "Failed in retrying the get for the second time." );
+ eventQueue.destroy();
+ }
+ }
+ catch ( IOException ex )
+ {
+ eventQueue.destroy();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
+ {
+ if ( keys != null && !keys.isEmpty() )
+ {
+ Map<K, ICacheElement<K, V>> elements = keys.stream()
+ .collect(Collectors.toMap(
+ key -> key,
+ key -> get(key))).entrySet().stream()
+ .filter(entry -> entry.getValue() != null)
+ .collect(Collectors.toMap(
+ entry -> entry.getKey(),
+ entry -> entry.getValue()));
+
+ return elements;
+ }
+
+ return new HashMap<>();
+ }
+
+ /**
+ * Synchronously reads from the lateral cache.
+ * <p>
+ * @param pattern
+ * @return ICacheElement<K, V> if found, else empty
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching(String pattern)
+ {
+ getCount++;
+ if ( this.getStatus() != CacheStatus.ERROR )
+ {
+ try
+ {
+ return cache.getMatching( pattern );
+ }
+ catch ( UnmarshalException ue )
+ {
+ log.debug( "Retrying the get owing to UnmarshalException." );
+ try
+ {
+ return cache.getMatching( pattern );
+ }
+ catch ( IOException ex )
+ {
+ log.error( "Failed in retrying the get for the second time." );
+ eventQueue.destroy();
+ }
+ }
+ catch ( IOException ex )
+ {
+ eventQueue.destroy();
+ }
+ }
+ return Collections.emptyMap();
+ }
+
+ /**
+ * Return the keys in this cache.
+ * <p>
+ * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCache#getKeySet()
+ */
+ @Override
+ public Set<K> getKeySet() throws IOException
+ {
+ try
+ {
+ return cache.getKeySet();
+ }
+ catch ( IOException ex )
+ {
+ log.error( ex );
+ eventQueue.destroy();
+ }
+ return Collections.emptySet();
+ }
+
+ /**
+ * Adds a remove request to the lateral cache.
+ * <p>
+ * @param key
+ * @return always false
+ */
+ @Override
+ public boolean remove( K key )
+ {
+ removeCount++;
+ try
+ {
+ eventQueue.addRemoveEvent( key );
+ }
+ catch ( IOException ex )
+ {
+ log.error( ex );
+ eventQueue.destroy();
+ }
+ return false;
+ }
+
+ /** Adds a removeAll request to the lateral cache. */
+ @Override
+ public void removeAll()
+ {
+ try
+ {
+ eventQueue.addRemoveAllEvent();
+ }
+ catch ( IOException ex )
+ {
+ log.error( ex );
+ eventQueue.destroy();
+ }
+ }
+
+ /** Adds a dispose request to the lateral cache. */
+ @Override
+ public void dispose()
+ {
+ try
+ {
+ eventQueue.addDisposeEvent();
+ }
+ catch ( IOException ex )
+ {
+ log.error( ex );
+ eventQueue.destroy();
+ }
+ }
+
+ /**
+ * No lateral invocation.
+ * <p>
+ * @return The size value
+ */
+ @Override
+ public int getSize()
+ {
+ return cache.getSize();
+ }
+
+ /**
+ * No lateral invocation.
+ * <p>
+ * @return The cacheType value
+ */
+ @Override
+ public CacheType getCacheType()
+ {
+ return cache.getCacheType();
+ }
+
+ /**
+ * Returns the asyn cache status. An error status indicates either the lateral connection is not
+ * available, or the asyn queue has been unexpectedly destroyed. No lateral invocation.
+ * <p>
+ * @return The status value
+ */
+ @Override
+ public CacheStatus getStatus()
+ {
+ return eventQueue.isWorking() ? cache.getStatus() : CacheStatus.ERROR;
+ }
+
+ /**
+ * Gets the cacheName attribute of the LateralCacheNoWait object
+ * <p>
+ * @return The cacheName value
+ */
+ @Override
+ public String getCacheName()
+ {
+ return cache.getCacheName();
+ }
+
+ /**
+ * Replaces the lateral cache service handle with the given handle and reset the queue by
+ * starting up a new instance.
+ * <p>
+ * @param lateral
+ */
+ public void fixCache( ICacheServiceNonLocal<K, V> lateral )
+ {
+ cache.fixCache( lateral );
+ resetEventQ();
+ }
+
+ /**
+ * Resets the event q by first destroying the existing one and starting up new one.
+ */
+ public void resetEventQ()
+ {
+ if ( eventQueue.isWorking() )
+ {
+ eventQueue.destroy();
+ }
+ CacheEventQueueFactory<K, V> fact = new CacheEventQueueFactory<>();
+ this.eventQueue = fact.createCacheEventQueue( new CacheAdaptor<>( cache ), CacheInfo.listenerId, cache
+ .getCacheName(), cache.getAuxiliaryCacheAttributes().getEventQueuePoolName(), cache
+ .getAuxiliaryCacheAttributes().getEventQueueType() );
+ }
+
+ /**
+ * @return Returns the AuxiliaryCacheAttributes.
+ */
+ @Override
+ public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
+ {
+ return cache.getAuxiliaryCacheAttributes();
+ }
+
+ /**
+ * getStats
+ * @return String
+ */
+ @Override
+ public String getStats()
+ {
+ return getStatistics().toString();
+ }
+
+ /**
+ * this won't be called since we don't do ICache logging here.
+ * <p>
+ * @return String
+ */
+ @Override
+ public String getEventLoggingExtraInfo()
+ {
+ return "Lateral Cache No Wait";
+ }
+
+ /**
+ * @return statistics about this communication
+ */
+ @Override
+ public IStats getStatistics()
+ {
+ IStats stats = new Stats();
+ stats.setTypeName( "Lateral Cache No Wait" );
+
+ ArrayList<IStatElement<?>> elems = new ArrayList<>();
+
+ // get the stats from the event queue too
+ IStats eqStats = this.eventQueue.getStatistics();
+ elems.addAll(eqStats.getStatElements());
+
+ elems.add(new StatElement<>( "Get Count", Integer.valueOf(this.getCount) ) );
+ elems.add(new StatElement<>( "Remove Count", Integer.valueOf(this.removeCount) ) );
+ elems.add(new StatElement<>( "Put Count", Integer.valueOf(this.putCount) ) );
+ elems.add(new StatElement<>( "Attributes", cache.getAuxiliaryCacheAttributes() ) );
+
+ stats.setStatElements( elems );
+
+ return stats;
+ }
+
+ /**
+ * @return debugging info.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( " LateralCacheNoWait " );
+ buf.append( " Status = " + this.getStatus() );
+ buf.append( " cache = [" + cache.toString() + "]" );
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheNoWaitFacade.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheNoWaitFacade.java
new file mode 100644
index 0000000..18e4c22
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheNoWaitFacade.java
@@ -0,0 +1,467 @@
+package org.apache.commons.jcs3.auxiliary.lateral;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.lateral.behavior.ILateralCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.lateral.behavior.ILateralCacheListener;
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.stats.StatElement;
+import org.apache.commons.jcs3.engine.stats.Stats;
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * Used to provide access to multiple services under nowait protection. Composite factory should
+ * construct LateralCacheNoWaitFacade to give to the composite cache out of caches it constructs
+ * from the varies manager to lateral services. Perhaps the lateralcache factory should be able to
+ * do this.
+ */
+public class LateralCacheNoWaitFacade<K, V>
+ extends AbstractAuxiliaryCache<K, V>
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( LateralCacheNoWaitFacade.class );
+
+ /** The queuing facade to the client. */
+ public LateralCacheNoWait<K, V>[] noWaits;
+
+ /** The region name */
+ private final String cacheName;
+
+ /** A cache listener */
+ private ILateralCacheListener<K, V> listener;
+
+ /** User configurable attributes. */
+ private final ILateralCacheAttributes lateralCacheAttributes;
+
+ /** Disposed state of this facade */
+ private boolean disposed = false;
+
+ /**
+ * Constructs with the given lateral cache, and fires events to any listeners.
+ * <p>
+ * @param noWaits
+ * @param cattr
+ */
+ public LateralCacheNoWaitFacade(ILateralCacheListener<K, V> listener, LateralCacheNoWait<K, V>[] noWaits, ILateralCacheAttributes cattr )
+ {
+ log.debug( "CONSTRUCTING NO WAIT FACADE" );
+ this.listener = listener;
+ this.noWaits = noWaits;
+ this.cacheName = cattr.getCacheName();
+ this.lateralCacheAttributes = cattr;
+ }
+
+ /**
+ * Tells you if the no wait is in the list or not.
+ * <p>
+ * @param noWait
+ * @return true if the noWait is in the list.
+ */
+ public boolean containsNoWait( LateralCacheNoWait<K, V> noWait )
+ {
+ Optional<LateralCacheNoWait<K, V>> optional = Arrays.stream(noWaits)
+ // we know noWait isn't null
+ .filter(nw -> noWait.equals( nw ))
+ .findFirst();
+
+ return optional.isPresent();
+ }
+
+ /**
+ * Adds a no wait to the list if it isn't already in the list.
+ * <p>
+ * @param noWait
+ * @return true if it wasn't already contained
+ */
+ public synchronized boolean addNoWait( LateralCacheNoWait<K, V> noWait )
+ {
+ if ( noWait == null )
+ {
+ return false;
+ }
+
+ if ( containsNoWait( noWait ) )
+ {
+ log.debug( "No Wait already contained, [{0}]", noWait );
+ return false;
+ }
+
+ @SuppressWarnings("unchecked") // No generic arrays in java
+ LateralCacheNoWait<K, V>[] newArray = new LateralCacheNoWait[noWaits.length + 1];
+
+ System.arraycopy( noWaits, 0, newArray, 0, noWaits.length );
+
+ // set the last position to the new noWait
+ newArray[noWaits.length] = noWait;
+
+ noWaits = newArray;
+
+ return true;
+ }
+
+ /**
+ * Removes a no wait from the list if it is already there.
+ * <p>
+ * @param noWait
+ * @return true if it was already in the array
+ */
+ public synchronized boolean removeNoWait( LateralCacheNoWait<K, V> noWait )
+ {
+ if ( noWait == null )
+ {
+ return false;
+ }
+
+ int position = -1;
+ for ( int i = 0; i < noWaits.length; i++ )
+ {
+ // we know noWait isn't null
+ if ( noWait.equals( noWaits[i] ) )
+ {
+ position = i;
+ break;
+ }
+ }
+
+ if ( position == -1 )
+ {
+ return false;
+ }
+
+ @SuppressWarnings("unchecked") // No generic arrays in java
+ LateralCacheNoWait<K, V>[] newArray = new LateralCacheNoWait[noWaits.length - 1];
+
+ System.arraycopy( noWaits, 0, newArray, 0, position );
+ if ( noWaits.length != position )
+ {
+ System.arraycopy( noWaits, position + 1, newArray, position, noWaits.length - position - 1 );
+ }
+ noWaits = newArray;
+
+ return true;
+ }
+
+ /**
+ * @param ce
+ * @throws IOException
+ */
+ @Override
+ public void update( ICacheElement<K, V> ce )
+ throws IOException
+ {
+ log.debug( "updating through lateral cache facade, noWaits.length = {0}",
+ noWaits.length );
+
+ for (LateralCacheNoWait<K, V> nw : noWaits)
+ {
+ nw.update( ce );
+ }
+ }
+
+ /**
+ * Synchronously reads from the lateral cache.
+ * <p>
+ * @param key
+ * @return ICacheElement
+ */
+ @Override
+ public ICacheElement<K, V> get( K key )
+ {
+ Optional<ICacheElement<K, V>> optional = Arrays.stream(noWaits)
+ .map(nw -> nw.get( key ))
+ .filter(obj -> obj != null)
+ .findFirst();
+
+ if (optional.isPresent())
+ {
+ return optional.get();
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
+ {
+ if ( keys != null && !keys.isEmpty() )
+ {
+ Map<K, ICacheElement<K, V>> elements = keys.stream()
+ .collect(Collectors.toMap(
+ key -> key,
+ key -> get(key))).entrySet().stream()
+ .filter(entry -> entry.getValue() != null)
+ .collect(Collectors.toMap(
+ entry -> entry.getKey(),
+ entry -> entry.getValue()));
+
+ return elements;
+ }
+
+ return new HashMap<>();
+ }
+
+ /**
+ * Synchronously reads from the lateral cache. Get a response from each! This will be slow.
+ * Merge them.
+ * <p>
+ * @param pattern
+ * @return ICacheElement
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching(String pattern)
+ {
+ Map<K, ICacheElement<K, V>> elements = new HashMap<>();
+ for (LateralCacheNoWait<K, V> nw : noWaits)
+ {
+ elements.putAll( nw.getMatching( pattern ) );
+ }
+ return elements;
+ }
+
+ /**
+ * Return the keys in this cache.
+ * <p>
+ * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCache#getKeySet()
+ */
+ @Override
+ public Set<K> getKeySet() throws IOException
+ {
+ HashSet<K> allKeys = new HashSet<>();
+ for (LateralCacheNoWait<K, V> nw : noWaits)
+ {
+ if ( nw != null )
+ {
+ Set<K> keys = nw.getKeySet();
+ if (keys != null)
+ {
+ allKeys.addAll( keys );
+ }
+ }
+ }
+ return allKeys;
+ }
+
+ /**
+ * Adds a remove request to the lateral cache.
+ * <p>
+ * @param key
+ * @return always false.
+ */
+ @Override
+ public boolean remove( K key )
+ {
+ Arrays.stream(noWaits).forEach(nw -> nw.remove( key ));
+ return false;
+ }
+
+ /**
+ * Adds a removeAll request to the lateral cache.
+ */
+ @Override
+ public void removeAll()
+ {
+ Arrays.stream(noWaits).forEach(nw -> nw.removeAll());
+ }
+
+ /** Adds a dispose request to the lateral cache. */
+ @Override
+ public void dispose()
+ {
+ try
+ {
+ if ( listener != null )
+ {
+ listener.dispose();
+ listener = null;
+ }
+
+ Arrays.stream(noWaits).forEach(nw -> nw.dispose());
+ }
+ finally
+ {
+ disposed = true;
+ }
+ }
+
+ /**
+ * No lateral invocation.
+ * @return The size value
+ */
+ @Override
+ public int getSize()
+ {
+ return 0;
+ //cache.getSize();
+ }
+
+ /**
+ * Gets the cacheType attribute of the LateralCacheNoWaitFacade object.
+ * <p>
+ * @return The cacheType value
+ */
+ @Override
+ public CacheType getCacheType()
+ {
+ return CacheType.LATERAL_CACHE;
+ }
+
+ /**
+ * Gets the cacheName attribute of the LateralCacheNoWaitFacade object.
+ * <p>
+ * @return The cacheName value
+ */
+ @Override
+ public String getCacheName()
+ {
+ return "";
+ //cache.getCacheName();
+ }
+
+ /**
+ * Gets the status attribute of the LateralCacheNoWaitFacade object
+ * @return The status value
+ */
+ @Override
+ public CacheStatus getStatus()
+ {
+ if (disposed)
+ {
+ return CacheStatus.DISPOSED;
+ }
+
+ if (noWaits.length == 0 || listener != null)
+ {
+ return CacheStatus.ALIVE;
+ }
+
+ List<CacheStatus> statii = Arrays.stream(noWaits)
+ .map(nw -> nw.getStatus())
+ .collect(Collectors.toList());
+
+ // It's alive if ANY of its nowaits is alive
+ if (statii.contains(CacheStatus.ALIVE))
+ {
+ return CacheStatus.ALIVE;
+ }
+ // It's alive if ANY of its nowaits is in error, but
+ // none are alive, then it's in error
+ if (statii.contains(CacheStatus.ERROR))
+ {
+ return CacheStatus.ERROR;
+ }
+
+ // Otherwise, it's been disposed, since it's the only status left
+ return CacheStatus.DISPOSED;
+ }
+
+ /**
+ * @return Returns the AuxiliaryCacheAttributes.
+ */
+ @Override
+ public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
+ {
+ return this.lateralCacheAttributes;
+ }
+
+ /**
+ * @return "LateralCacheNoWaitFacade: " + cacheName;
+ */
+ @Override
+ public String toString()
+ {
+ return "LateralCacheNoWaitFacade: " + cacheName;
+ }
+
+ /**
+ * this won't be called since we don't do ICache logging here.
+ * <p>
+ * @return String
+ */
+ @Override
+ public String getEventLoggingExtraInfo()
+ {
+ return "Lateral Cache No Wait";
+ }
+
+ /**
+ * getStats
+ * @return String
+ */
+ @Override
+ public String getStats()
+ {
+ return getStatistics().toString();
+ }
+
+ /**
+ * @return IStats
+ */
+ @Override
+ public IStats getStatistics()
+ {
+ IStats stats = new Stats();
+ stats.setTypeName( "Lateral Cache No Wait Facade" );
+
+ ArrayList<IStatElement<?>> elems = new ArrayList<>();
+
+ if ( noWaits != null )
+ {
+ elems.add(new StatElement<>( "Number of No Waits", Integer.valueOf(noWaits.length) ) );
+
+ for ( LateralCacheNoWait<K, V> lcnw : noWaits )
+ {
+ if ( lcnw != null )
+ {
+ // get the stats from the super too
+ IStats sStats = lcnw.getStatistics();
+ elems.addAll(sStats.getStatElements());
+ }
+ }
+ }
+
+ stats.setStatElements( elems );
+
+ return stats;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCommand.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCommand.java
new file mode 100644
index 0000000..410f023
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCommand.java
@@ -0,0 +1,47 @@
+package org.apache.commons.jcs3.auxiliary.lateral;
+
+/*
+ * 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.
+ */
+
+/**
+ * Enumeration of the available lateral commands
+ */
+public enum LateralCommand
+{
+ /** The command for updates */
+ UPDATE,
+
+ /** The command for removes */
+ REMOVE,
+
+ /** The command instructing us to remove all */
+ REMOVEALL,
+
+ /** The command for disposing the cache. */
+ DISPOSE,
+
+ /** Command to return an object. */
+ GET,
+
+ /** Command to return an object. */
+ GET_MATCHING,
+
+ /** Command to get all keys */
+ GET_KEYSET
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralElementDescriptor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralElementDescriptor.java
new file mode 100644
index 0000000..f2d3b82
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/LateralElementDescriptor.java
@@ -0,0 +1,83 @@
+package org.apache.commons.jcs3.auxiliary.lateral;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/**
+ * This class wraps command to other laterals. It is essentially a
+ * JCS-TCP-Lateral packet. The headers specify the action the receiver should
+ * take.
+ */
+public class LateralElementDescriptor<K, V>
+ implements Serializable
+{
+ /** Don't change */
+ private static final long serialVersionUID = 5268222498076063575L;
+
+ /** The Cache Element that we are distributing. */
+ public ICacheElement<K, V> ce;
+
+ /**
+ * The id of the the source of the request. This is used to prevent infinite
+ * loops.
+ */
+ public long requesterId;
+
+ /** The operation has been requested by the client. */
+ public LateralCommand command = LateralCommand.UPDATE;
+
+ /**
+ * The hashcode value for this element.
+ */
+ public int valHashCode = -1;
+
+ /** Constructor for the LateralElementDescriptor object */
+ public LateralElementDescriptor()
+ {
+ super();
+ }
+
+ /**
+ * Constructor for the LateralElementDescriptor object
+ * <p>
+ * @param ce ICacheElement<K, V> payload
+ */
+ public LateralElementDescriptor( ICacheElement<K, V> ce )
+ {
+ this.ce = ce;
+ }
+
+ /**
+ * @return String, all the important values that can be configured
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\n LateralElementDescriptor " );
+ buf.append( "\n command = [" + this.command + "]" );
+ buf.append( "\n valHashCode = [" + this.valHashCode + "]" );
+ buf.append( "\n ICacheElement = [" + this.ce + "]" );
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/behavior/ILateralCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/behavior/ILateralCacheAttributes.java
new file mode 100644
index 0000000..6cec965
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/behavior/ILateralCacheAttributes.java
@@ -0,0 +1,200 @@
+package org.apache.commons.jcs3.auxiliary.lateral.behavior;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+
+/**
+ * This interface defines configuration options common to lateral cache plugins.
+ * <p>
+ * TODO it needs to be trimmed down. The old version had features for every lateral. Now, the
+ * individual laterals have their own specific attributes interfaces.
+ */
+public interface ILateralCacheAttributes
+ extends AuxiliaryCacheAttributes
+{
+ enum Type
+ {
+ /** HTTP type */
+ HTTP, // 1
+
+ /** UDP type */
+ UDP, // 2
+
+ /** TCP type */
+ TCP, // 3
+
+ /** XMLRPC type */
+ XMLRPC // 4
+ }
+
+ /**
+ * The number of elements the zombie queue will hold. This queue is used to store events if we
+ * loose our connection with the server.
+ */
+ int DEFAULT_ZOMBIE_QUEUE_MAX_SIZE = 1000;
+
+ /**
+ * Sets the httpServer attribute of the ILateralCacheAttributes object
+ * <p>
+ * @param val The new httpServer value
+ */
+ void setHttpServer( String val );
+
+ /**
+ * Gets the httpServer attribute of the ILateralCacheAttributes object
+ * <p>
+ * @return The httpServer value
+ */
+ String getHttpServer();
+
+ /**
+ * Sets the httpListenerPort attribute of the ILateralCacheAttributes object
+ * <p>
+ * @param val The new tcpListenerPort value
+ */
+ void setHttpListenerPort( int val );
+
+ /**
+ * Gets the httpListenerPort attribute of the ILateralCacheAttributes object
+ * <p>
+ * @return The httpListenerPort value
+ */
+ int getHttpListenerPort();
+
+ /**
+ * Sets the httpServers attribute of the LateralCacheAttributes object
+ * <p>
+ * @param val The new httpServers value
+ */
+ void setHttpServers( String val );
+
+ /**
+ * Gets the httpSrvers attribute of the LateralCacheAttributes object
+ * <p>
+ * @return The httpServers value
+ */
+ String getHttpServers();
+
+ /**
+ * Sets the udpMulticastAddr attribute of the ILateralCacheAttributes object
+ * <p>
+ * @param val The new udpMulticastAddr value
+ */
+ void setUdpMulticastAddr( String val );
+
+ /**
+ * Gets the udpMulticastAddr attribute of the ILateralCacheAttributes object
+ * <p>
+ * @return The udpMulticastAddr value
+ */
+ String getUdpMulticastAddr();
+
+ /**
+ * Sets the udpMulticastPort attribute of the ILateralCacheAttributes object
+ * <p>
+ * @param val The new udpMulticastPort value
+ */
+ void setUdpMulticastPort( int val );
+
+ /**
+ * Gets the udpMulticastPort attribute of the ILateralCacheAttributes object
+ * <p>
+ * @return The udpMulticastPort value
+ */
+ int getUdpMulticastPort();
+
+ /**
+ * Sets the transmissionType attribute of the ILateralCacheAttributes object
+ * <p>
+ * @param val The new transmissionType value
+ */
+ void setTransmissionType( Type val );
+
+ /**
+ * Gets the transmissionType attribute of the ILateralCacheAttributes object
+ * <p>
+ * @return The transmissionType value
+ */
+ Type getTransmissionType();
+
+ /**
+ * Sets the transmissionTypeName attribute of the ILateralCacheAttributes object
+ * <p>
+ * @param val The new transmissionTypeName value
+ */
+ void setTransmissionTypeName( String val );
+
+ /**
+ * Gets the transmissionTypeName attribute of the ILateralCacheAttributes object
+ * <p>
+ * @return The transmissionTypeName value
+ */
+ String getTransmissionTypeName();
+
+ /**
+ * Sets the putOnlyMode attribute of the ILateralCacheAttributes. When this is true the lateral
+ * cache will only issue put and remove order and will not try to retrieve elements from other
+ * lateral caches.
+ * <p>
+ * @param val The new transmissionTypeName value
+ */
+ void setPutOnlyMode( boolean val );
+
+ /**
+ * @return The outgoingOnlyMode value. Stops gets from going remote.
+ */
+ boolean getPutOnlyMode();
+
+ /**
+ * @param receive The receive to set.
+ */
+ void setReceive( boolean receive );
+
+ /**
+ * Should a listener be created. By default this is true.
+ * <p>
+ * If this is false the lateral will connect to others but it will not create a listener to
+ * receive.
+ * <p>
+ * It is possible if two laterals are misconfigured that lateral A may have a region R1 that is
+ * not configured for the lateral but another is. And if cache B has region R1 configured for
+ * lateral distribution, A will get messages for R1 but not send them.
+ * <p>
+ * @return true if we should have a listener connection
+ */
+ boolean isReceive();
+
+ /**
+ * The number of elements the zombie queue will hold. This queue is used to store events if we
+ * loose our connection with the server.
+ * <p>
+ * @param zombieQueueMaxSize The zombieQueueMaxSize to set.
+ */
+ void setZombieQueueMaxSize( int zombieQueueMaxSize );
+
+ /**
+ * The number of elements the zombie queue will hold. This queue is used to store events if we
+ * loose our connection with the server.
+ * <p>
+ * @return Returns the zombieQueueMaxSize.
+ */
+ int getZombieQueueMaxSize();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/behavior/ILateralCacheListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/behavior/ILateralCacheListener.java
new file mode 100644
index 0000000..006a3f5
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/behavior/ILateralCacheListener.java
@@ -0,0 +1,51 @@
+package org.apache.commons.jcs3.auxiliary.lateral.behavior;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.engine.behavior.ICacheListener;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+
+/**
+ * Listens for lateral cache event notification.
+ */
+public interface ILateralCacheListener<K, V>
+ extends ICacheListener<K, V>
+{
+ /**
+ * Initialize this listener
+ */
+ void init();
+
+ /**
+ * @param cacheMgr
+ * The cacheMgr to set.
+ */
+ void setCacheManager( ICompositeCacheManager cacheMgr );
+
+ /**
+ * @return Returns the cacheMgr.
+ */
+ ICompositeCacheManager getCacheManager();
+
+ /**
+ * Dispose this listener
+ */
+ void dispose();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/package.html b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/package.html
similarity index 100%
rename from commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/lateral/package.html
rename to commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/package.html
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPCacheFactory.java
new file mode 100644
index 0000000..ce7d98d
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPCacheFactory.java
@@ -0,0 +1,404 @@
+package org.apache.commons.jcs3.auxiliary.lateral.socket.tcp;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheFactory;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCache;
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCacheMonitor;
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCacheNoWait;
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCacheNoWaitFacade;
+import org.apache.commons.jcs3.auxiliary.lateral.behavior.ILateralCacheListener;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheWatchRepairable;
+import org.apache.commons.jcs3.engine.ZombieCacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.ZombieCacheWatch;
+import org.apache.commons.jcs3.engine.behavior.ICache;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.behavior.IShutdownObserver;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.discovery.UDPDiscoveryManager;
+import org.apache.commons.jcs3.utils.discovery.UDPDiscoveryService;
+
+/**
+ * Constructs a LateralCacheNoWaitFacade for the given configuration. Each lateral service / local
+ * relationship is managed by one manager. This manager can have multiple caches. The remote
+ * relationships are consolidated and restored via these managers.
+ * <p>
+ * The facade provides a front to the composite cache so the implementation is transparent.
+ */
+public class LateralTCPCacheFactory
+ extends AbstractAuxiliaryCacheFactory
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( LateralTCPCacheFactory.class );
+
+ /** Address to service map. */
+ private ConcurrentHashMap<String, ICacheServiceNonLocal<?, ?>> csnlInstances;
+
+ /** Map of available discovery listener instances, keyed by port. */
+ private ConcurrentHashMap<String, LateralTCPDiscoveryListener> lTCPDLInstances;
+
+ /** Monitor thread */
+ private LateralCacheMonitor monitor;
+
+ /**
+ * Wrapper of the lateral cache watch service; or wrapper of a zombie
+ * service if failed to connect.
+ */
+ private CacheWatchRepairable lateralWatch;
+
+ /**
+ * Creates a TCP lateral.
+ * <p>
+ * @param iaca
+ * @param cacheMgr
+ * @param cacheEventLogger
+ * @param elementSerializer
+ * @return LateralCacheNoWaitFacade
+ */
+ @Override
+ public <K, V> LateralCacheNoWaitFacade<K, V> createCache(
+ AuxiliaryCacheAttributes iaca, ICompositeCacheManager cacheMgr,
+ ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
+ {
+ ITCPLateralCacheAttributes lac = (ITCPLateralCacheAttributes) iaca;
+ ArrayList<ICache<K, V>> noWaits = new ArrayList<>();
+
+ // pairs up the tcp servers and set the tcpServer value and
+ // get the manager and then get the cache
+ // no servers are required.
+ if ( lac.getTcpServers() != null )
+ {
+ StringTokenizer it = new StringTokenizer( lac.getTcpServers(), "," );
+ log.debug( "Configured for [{0}] servers.", () -> it.countTokens() );
+
+ while ( it.hasMoreElements() )
+ {
+ String server = (String) it.nextElement();
+ log.debug( "tcp server = {0}", server );
+ ITCPLateralCacheAttributes lacC = (ITCPLateralCacheAttributes) lac.clone();
+ lacC.setTcpServer( server );
+
+ LateralCacheNoWait<K, V> lateralNoWait = createCacheNoWait(lacC, cacheEventLogger, elementSerializer);
+
+ addListenerIfNeeded( lacC, cacheMgr );
+ monitor.addCache(lateralNoWait);
+ noWaits.add( lateralNoWait );
+ }
+ }
+
+ ILateralCacheListener<K, V> listener = createListener( lac, cacheMgr );
+
+ // create the no wait facade.
+ @SuppressWarnings("unchecked") // No generic arrays in java
+ LateralCacheNoWait<K, V>[] lcnwArray = noWaits.toArray( new LateralCacheNoWait[0] );
+ LateralCacheNoWaitFacade<K, V> lcnwf =
+ new LateralCacheNoWaitFacade<>(listener, lcnwArray, lac );
+
+ // create udp discovery if available.
+ createDiscoveryService( lac, lcnwf, cacheMgr, cacheEventLogger, elementSerializer );
+
+ return lcnwf;
+ }
+
+ protected <K, V> LateralCacheNoWait<K, V> createCacheNoWait( ITCPLateralCacheAttributes lca,
+ ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
+ {
+ ICacheServiceNonLocal<K, V> lateralService = getCSNLInstance(lca);
+
+ LateralCache<K, V> cache = new LateralCache<>( lca, lateralService, this.monitor );
+ cache.setCacheEventLogger( cacheEventLogger );
+ cache.setElementSerializer( elementSerializer );
+
+ log.debug( "Created cache for noWait, cache [{0}]", cache );
+
+ LateralCacheNoWait<K, V> lateralNoWait = new LateralCacheNoWait<>( cache );
+ lateralNoWait.setCacheEventLogger( cacheEventLogger );
+ lateralNoWait.setElementSerializer( elementSerializer );
+
+ log.info( "Created LateralCacheNoWait for [{0}] LateralCacheNoWait = [{1}]",
+ lca, lateralNoWait );
+
+ return lateralNoWait;
+ }
+
+ /**
+ * Initialize this factory
+ */
+ @Override
+ public void initialize()
+ {
+ this.csnlInstances = new ConcurrentHashMap<>();
+ this.lTCPDLInstances = new ConcurrentHashMap<>();
+
+ // Create the monitoring daemon thread
+ this.monitor = new LateralCacheMonitor(this);
+ this.monitor.setDaemon( true );
+ this.monitor.start();
+
+ this.lateralWatch = new CacheWatchRepairable();
+ this.lateralWatch.setCacheWatch( new ZombieCacheWatch() );
+ }
+
+ /**
+ * Dispose of this factory, clean up shared resources
+ */
+ @Override
+ public void dispose()
+ {
+ for (ICacheServiceNonLocal<?, ?> service : this.csnlInstances.values())
+ {
+ try
+ {
+ service.dispose("");
+ }
+ catch (IOException e)
+ {
+ log.error("Could not dispose service " + service, e);
+ }
+ }
+
+ this.csnlInstances.clear();
+
+ // TODO: shut down discovery listeners
+ this.lTCPDLInstances.clear();
+
+ if (this.monitor != null)
+ {
+ this.monitor.notifyShutdown();
+ try
+ {
+ this.monitor.join(5000);
+ }
+ catch (InterruptedException e)
+ {
+ // swallow
+ }
+ this.monitor = null;
+ }
+ }
+
+ /**
+ * Returns an instance of the cache service.
+ * <p>
+ * @param lca configuration for the creation of a new service instance
+ *
+ * @return ICacheServiceNonLocal<K, V>
+ */
+ // Need to cast because of common map for all cache services
+ @SuppressWarnings("unchecked")
+ public <K, V> ICacheServiceNonLocal<K, V> getCSNLInstance( ITCPLateralCacheAttributes lca )
+ {
+ String key = lca.getTcpServer();
+
+ csnlInstances.computeIfPresent(key, (name, service) -> {
+ // If service creation did not succeed last time, force retry
+ if (service instanceof ZombieCacheServiceNonLocal)
+ {
+ log.info("Disposing of zombie service instance for [{0}]", name);
+ return null;
+ }
+
+ return service;
+ });
+
+ ICacheServiceNonLocal<K, V> service =
+ (ICacheServiceNonLocal<K, V>) csnlInstances.computeIfAbsent(key, name -> {
+
+ log.info( "Instance for [{0}] is null, creating", name );
+
+ // Create the service
+ try
+ {
+ log.info( "Creating TCP service, lca = {0}", lca );
+
+ return new LateralTCPService<>( lca );
+ }
+ catch ( IOException ex )
+ {
+ // Failed to connect to the lateral server.
+ // Configure this LateralCacheManager instance to use the
+ // "zombie" services.
+ log.error( "Failure, lateral instance will use zombie service", ex );
+
+ ICacheServiceNonLocal<K, V> zombieService =
+ new ZombieCacheServiceNonLocal<>( lca.getZombieQueueMaxSize() );
+
+ // Notify the cache monitor about the error, and kick off
+ // the recovery process.
+ monitor.notifyError();
+
+ return zombieService;
+ }
+ });
+
+ return service;
+ }
+
+ /**
+ * Gets the instance attribute of the LateralCacheTCPListener class.
+ * <p>
+ * @param ilca ITCPLateralCacheAttributes
+ * @param cacheManager a reference to the global cache manager
+ *
+ * @return The instance value
+ */
+ private LateralTCPDiscoveryListener getDiscoveryListener(ITCPLateralCacheAttributes ilca, ICompositeCacheManager cacheManager)
+ {
+ String key = ilca.getUdpDiscoveryAddr() + ":" + ilca.getUdpDiscoveryPort();
+
+ LateralTCPDiscoveryListener ins = lTCPDLInstances.computeIfAbsent(key, key1 -> {
+ log.info("Created new discovery listener for cacheName {0} for request {1}",
+ key1, ilca.getCacheName());
+ return new LateralTCPDiscoveryListener( this.getName(), cacheManager);
+ });
+
+ return ins;
+ }
+
+ /**
+ * Add listener for receivers
+ * <p>
+ * @param iaca cache configuration attributes
+ * @param cacheMgr the composite cache manager
+ */
+ private void addListenerIfNeeded( ITCPLateralCacheAttributes iaca, ICompositeCacheManager cacheMgr )
+ {
+ // don't create a listener if we are not receiving.
+ if ( iaca.isReceive() )
+ {
+ try
+ {
+ addLateralCacheListener( iaca.getCacheName(),
+ LateralTCPListener.getInstance( iaca, cacheMgr ) );
+ }
+ catch ( IOException ioe )
+ {
+ log.error("Problem creating lateral listener", ioe);
+ }
+ }
+ else
+ {
+ log.debug( "Not creating a listener since we are not receiving." );
+ }
+ }
+
+ /**
+ * Adds the lateral cache listener to the underlying cache-watch service.
+ * <p>
+ * @param cacheName The feature to be added to the LateralCacheListener attribute
+ * @param listener The feature to be added to the LateralCacheListener attribute
+ * @throws IOException
+ */
+ private <K, V> void addLateralCacheListener( String cacheName, ILateralCacheListener<K, V> listener )
+ throws IOException
+ {
+ synchronized ( this.lateralWatch )
+ {
+ lateralWatch.addCacheListener( cacheName, listener );
+ }
+ }
+
+ /**
+ * Makes sure a listener gets created. It will get monitored as soon as it
+ * is used.
+ * <p>
+ * This should be called by create cache.
+ * <p>
+ * @param attr ITCPLateralCacheAttributes
+ * @param cacheMgr
+ *
+ * @return the listener if created, else null
+ */
+ private <K, V> ILateralCacheListener<K, V> createListener( ITCPLateralCacheAttributes attr,
+ ICompositeCacheManager cacheMgr )
+ {
+ ILateralCacheListener<K, V> listener = null;
+
+ // don't create a listener if we are not receiving.
+ if ( attr.isReceive() )
+ {
+ log.info( "Getting listener for {0}", attr );
+
+ // make a listener. if one doesn't exist
+ listener = LateralTCPListener.getInstance( attr, cacheMgr );
+
+ // register for shutdown notification
+ cacheMgr.registerShutdownObserver( (IShutdownObserver) listener );
+ }
+ else
+ {
+ log.debug( "Not creating a listener since we are not receiving." );
+ }
+
+ return listener;
+ }
+
+ /**
+ * Creates the discovery service. Only creates this for tcp laterals right now.
+ * <p>
+ * @param lac ITCPLateralCacheAttributes
+ * @param lcnwf
+ * @param cacheMgr
+ * @param cacheEventLogger
+ * @param elementSerializer
+ * @return null if none is created.
+ */
+ private synchronized <K, V> UDPDiscoveryService createDiscoveryService(
+ ITCPLateralCacheAttributes lac,
+ LateralCacheNoWaitFacade<K, V> lcnwf,
+ ICompositeCacheManager cacheMgr,
+ ICacheEventLogger cacheEventLogger,
+ IElementSerializer elementSerializer )
+ {
+ UDPDiscoveryService discovery = null;
+
+ // create the UDP discovery for the TCP lateral
+ if ( lac.isUdpDiscoveryEnabled() )
+ {
+ // One can be used for all regions
+ LateralTCPDiscoveryListener discoveryListener = getDiscoveryListener( lac, cacheMgr );
+ discoveryListener.addNoWaitFacade( lac.getCacheName(), lcnwf );
+
+ // need a factory for this so it doesn't
+ // get dereferenced, also we don't want one for every region.
+ discovery = UDPDiscoveryManager.getInstance().getService( lac.getUdpDiscoveryAddr(),
+ lac.getUdpDiscoveryPort(),
+ lac.getTcpListenerPort(), cacheMgr);
+
+ discovery.addParticipatingCacheName( lac.getCacheName() );
+ discovery.addDiscoveryListener( discoveryListener );
+
+ log.info( "Registered TCP lateral cache [{0}] with UDPDiscoveryService.",
+ () -> lac.getCacheName() );
+ }
+ return discovery;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPDiscoveryListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPDiscoveryListener.java
new file mode 100644
index 0000000..a1f953f
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPDiscoveryListener.java
@@ -0,0 +1,315 @@
+package org.apache.commons.jcs3.auxiliary.lateral.socket.tcp;
+
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCacheNoWait;
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCacheNoWaitFacade;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.discovery.DiscoveredService;
+import org.apache.commons.jcs3.utils.discovery.behavior.IDiscoveryListener;
+
+/**
+ * This knows how to add and remove discovered services. It observes UDP discovery events.
+ * <p>
+ * We can have one listener per region, or one shared by all regions.
+ */
+public class LateralTCPDiscoveryListener
+ implements IDiscoveryListener
+{
+ /** The log factory */
+ private static final Log log = LogManager.getLog( LateralTCPDiscoveryListener.class );
+
+ /**
+ * Map of no wait facades. these are used to determine which regions are locally configured to
+ * use laterals.
+ */
+ private final ConcurrentMap<String, LateralCacheNoWaitFacade<?, ?>> facades =
+ new ConcurrentHashMap<>();
+
+ /**
+ * List of regions that are configured differently here than on another server. We keep track of
+ * this to limit the amount of info logging.
+ */
+ private final CopyOnWriteArrayList<String> knownDifferentlyConfiguredRegions =
+ new CopyOnWriteArrayList<>();
+
+ /** The name of the cache factory */
+ private final String factoryName;
+
+ /** Reference to the cache manager for auxiliary cache access */
+ private final ICompositeCacheManager cacheManager;
+
+ /**
+ * This plugs into the udp discovery system. It will receive add and remove events.
+ * <p>
+ * @param factoryName the name of the related cache factory
+ * @param cacheManager the global cache manager
+ */
+ protected LateralTCPDiscoveryListener( String factoryName, ICompositeCacheManager cacheManager )
+ {
+ this.factoryName = factoryName;
+ this.cacheManager = cacheManager;
+ }
+
+ /**
+ * Adds a nowait facade under this cachename. If one already existed, it will be overridden.
+ * <p>
+ * This adds nowaits to a facade for the region name. If the region has no facade, then it is
+ * not configured to use the lateral cache, and no facade will be created.
+ * <p>
+ * @param cacheName - the region name
+ * @param facade - facade (for region) => multiple lateral clients.
+ * @return true if the facade was not already registered.
+ */
+ public boolean addNoWaitFacade( String cacheName, LateralCacheNoWaitFacade<?, ?> facade )
+ {
+ boolean isNew = !containsNoWaitFacade( cacheName );
+
+ // override or put anew, it doesn't matter
+ facades.put( cacheName, facade );
+ knownDifferentlyConfiguredRegions.remove( cacheName );
+
+ return isNew;
+ }
+
+ /**
+ * Allows us to see if the facade is present.
+ * <p>
+ * @param cacheName - facades are for a region
+ * @return do we contain the no wait. true if so
+ */
+ public boolean containsNoWaitFacade( String cacheName )
+ {
+ return facades.containsKey( cacheName );
+ }
+
+ /**
+ * Allows us to see if the facade is present and if it has the no wait.
+ * <p>
+ * @param cacheName - facades are for a region
+ * @param noWait - is this no wait in the facade
+ * @return do we contain the no wait. true if so
+ */
+ public <K, V> boolean containsNoWait( String cacheName, LateralCacheNoWait<K, V> noWait )
+ {
+ @SuppressWarnings("unchecked") // Need to cast because of common map for all facades
+ LateralCacheNoWaitFacade<K, V> facade =
+ (LateralCacheNoWaitFacade<K, V>)facades.get( noWait.getCacheName() );
+
+ if ( facade == null )
+ {
+ return false;
+ }
+
+ return facade.containsNoWait( noWait );
+ }
+
+ /**
+ * When a broadcast is received from the UDP Discovery receiver, for each cacheName in the
+ * message, the add no wait will be called here. To add a no wait, the facade is looked up for
+ * this cache name.
+ * <p>
+ * Each region has a facade. The facade contains a list of end points--the other tcp lateral
+ * services.
+ * <p>
+ * @param noWait
+ * @return true if we found the no wait and added it. False if the no wait was not present or if
+ * we already had it.
+ */
+ protected <K, V> boolean addNoWait( LateralCacheNoWait<K, V> noWait )
+ {
+ @SuppressWarnings("unchecked") // Need to cast because of common map for all facades
+ LateralCacheNoWaitFacade<K, V> facade =
+ (LateralCacheNoWaitFacade<K, V>)facades.get( noWait.getCacheName() );
+ log.debug( "addNoWait > Got facade for {0} = {1}", noWait.getCacheName(), facade );
+
+ if ( facade != null )
+ {
+ boolean isNew = facade.addNoWait( noWait );
+ log.debug( "Called addNoWait, isNew = {0}", isNew );
+ return isNew;
+ }
+ else
+ {
+ if ( knownDifferentlyConfiguredRegions.addIfAbsent( noWait.getCacheName() ) )
+ {
+ log.info( "addNoWait > Different nodes are configured differently "
+ + "or region [{0}] is not yet used on this side.",
+ () -> noWait.getCacheName() );
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Look up the facade for the name. If it doesn't exist, then the region is not configured for
+ * use with the lateral cache. If it is present, remove the item from the no wait list.
+ * <p>
+ * @param noWait
+ * @return true if we found the no wait and removed it. False if the no wait was not present.
+ */
+ protected <K, V> boolean removeNoWait( LateralCacheNoWait<K, V> noWait )
+ {
+ @SuppressWarnings("unchecked") // Need to cast because of common map for all facades
+ LateralCacheNoWaitFacade<K, V> facade =
+ (LateralCacheNoWaitFacade<K, V>)facades.get( noWait.getCacheName() );
+ log.debug( "removeNoWait > Got facade for {0} = {1}", noWait.getCacheName(), facade);
+
+ if ( facade != null )
+ {
+ boolean removed = facade.removeNoWait( noWait );
+ log.debug( "Called removeNoWait, removed {0}", removed );
+ return removed;
+ }
+ else
+ {
+ if ( knownDifferentlyConfiguredRegions.addIfAbsent( noWait.getCacheName() ) )
+ {
+ log.info( "addNoWait > Different nodes are configured differently "
+ + "or region [{0}] is not yet used on this side.",
+ () -> noWait.getCacheName() );
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Creates the lateral cache if needed.
+ * <p>
+ * We could go to the composite cache manager and get the the cache for the region. This would
+ * force a full configuration of the region. One advantage of this would be that the creation of
+ * the later would go through the factory, which would add the item to the no wait list. But we
+ * don't want to do this. This would force this client to have all the regions as the other.
+ * This might not be desired. We don't want to send or receive for a region here that is either
+ * not used or not configured to use the lateral.
+ * <p>
+ * Right now, I'm afraid that the region will get puts if another instance has the region
+ * configured to use the lateral and our address is configured. This might be a bug, but it
+ * shouldn't happen with discovery.
+ * <p>
+ * @param service
+ */
+ @Override
+ public void addDiscoveredService( DiscoveredService service )
+ {
+ // get a cache and add it to the no waits
+ // the add method should not add the same.
+ // we need the listener port from the original config.
+ ArrayList<String> regions = service.getCacheNames();
+ String serverAndPort = service.getServiceAddress() + ":" + service.getServicePort();
+
+ if ( regions != null )
+ {
+ // for each region get the cache
+ for (String cacheName : regions)
+ {
+ AuxiliaryCache<?, ?> ic = cacheManager.getAuxiliaryCache(factoryName, cacheName);
+
+ log.debug( "Got cache, ic = {0}", ic );
+
+ // add this to the nowaits for this cachename
+ if ( ic != null )
+ {
+ AuxiliaryCacheAttributes aca = ic.getAuxiliaryCacheAttributes();
+ if (aca instanceof ITCPLateralCacheAttributes)
+ {
+ ITCPLateralCacheAttributes lca = (ITCPLateralCacheAttributes)aca;
+ if (lca.getTransmissionType() != LateralCacheAttributes.Type.TCP
+ || !serverAndPort.equals(lca.getTcpServer()) )
+ {
+ // skip caches not belonging to this service
+ continue;
+ }
+ }
+
+ addNoWait( (LateralCacheNoWait<?, ?>) ic );
+ log.debug( "Called addNoWait for cacheName [{0}]", cacheName );
+ }
+ }
+ }
+ else
+ {
+ log.warn( "No cache names found in message {0}", service );
+ }
+ }
+
+ /**
+ * Removes the lateral cache.
+ * <p>
+ * We need to tell the manager that this instance is bad, so it will reconnect the sender if it
+ * comes back.
+ * <p>
+ * @param service
+ */
+ @Override
+ public void removeDiscoveredService( DiscoveredService service )
+ {
+ // get a cache and add it to the no waits
+ // the add method should not add the same.
+ // we need the listener port from the original config.
+ ArrayList<String> regions = service.getCacheNames();
+ String serverAndPort = service.getServiceAddress() + ":" + service.getServicePort();
+
+ if ( regions != null )
+ {
+ // for each region get the cache
+ for (String cacheName : regions)
+ {
+ AuxiliaryCache<?, ?> ic = cacheManager.getAuxiliaryCache(factoryName, cacheName);
+
+ log.debug( "Got cache, ic = {0}", ic );
+
+ // remove this to the nowaits for this cachename
+ if ( ic != null )
+ {
+ AuxiliaryCacheAttributes aca = ic.getAuxiliaryCacheAttributes();
+ if (aca instanceof ITCPLateralCacheAttributes)
+ {
+ ITCPLateralCacheAttributes lca = (ITCPLateralCacheAttributes)aca;
+ if (lca.getTransmissionType() != LateralCacheAttributes.Type.TCP
+ || !serverAndPort.equals(lca.getTcpServer()) )
+ {
+ // skip caches not belonging to this service
+ continue;
+ }
+ }
+
+ removeNoWait( (LateralCacheNoWait<?, ?>) ic );
+ log.debug( "Called removeNoWait for cacheName [{0}]", cacheName );
+ }
+ }
+ }
+ else
+ {
+ log.warn( "No cache names found in message {0}", service );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPListener.java
new file mode 100644
index 0000000..16d5c5e
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPListener.java
@@ -0,0 +1,677 @@
+package org.apache.commons.jcs3.auxiliary.lateral.socket.tcp;
+
+/*
+ * 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.
+ */
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.commons.jcs3.auxiliary.lateral.LateralElementDescriptor;
+import org.apache.commons.jcs3.auxiliary.lateral.behavior.ILateralCacheListener;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheInfo;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IShutdownObserver;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.io.ObjectInputStreamClassLoaderAware;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.threadpool.DaemonThreadFactory;
+
+/**
+ * Listens for connections from other TCP lateral caches and handles them. The initialization method
+ * starts a listening thread, which creates a socket server. When messages are received they are
+ * passed to a pooled executor which then calls the appropriate handle method.
+ */
+public class LateralTCPListener<K, V>
+ implements ILateralCacheListener<K, V>, IShutdownObserver
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( LateralTCPListener.class );
+
+ /** How long the server will block on an accept(). 0 is infinite. */
+ private static final int acceptTimeOut = 1000;
+
+ /** The CacheHub this listener is associated with */
+ private transient ICompositeCacheManager cacheManager;
+
+ /** Map of available instances, keyed by port */
+ private static final ConcurrentHashMap<String, ILateralCacheListener<?, ?>> instances =
+ new ConcurrentHashMap<>();
+
+ /** The socket listener */
+ private ListenerThread receiver;
+
+ /** Configuration attributes */
+ private ITCPLateralCacheAttributes tcpLateralCacheAttributes;
+
+ /** The processor. We should probably use an event queue here. */
+ private ExecutorService pooledExecutor;
+
+ /** put count */
+ private int putCnt = 0;
+
+ /** remove count */
+ private int removeCnt = 0;
+
+ /** get count */
+ private int getCnt = 0;
+
+ /**
+ * Use the vmid by default. This can be set for testing. If we ever need to run more than one
+ * per vm, then we need a new technique.
+ */
+ private long listenerId = CacheInfo.listenerId;
+
+ /** is this shut down? */
+ private AtomicBoolean shutdown;
+
+ /** is this terminated? */
+ private AtomicBoolean terminated;
+
+ /**
+ * Gets the instance attribute of the LateralCacheTCPListener class.
+ * <p>
+ * @param ilca ITCPLateralCacheAttributes
+ * @param cacheMgr
+ * @return The instance value
+ */
+ public static <K, V> LateralTCPListener<K, V>
+ getInstance( ITCPLateralCacheAttributes ilca, ICompositeCacheManager cacheMgr )
+ {
+ @SuppressWarnings("unchecked") // Need to cast because of common map for all instances
+ LateralTCPListener<K, V> ins = (LateralTCPListener<K, V>) instances.computeIfAbsent(
+ String.valueOf( ilca.getTcpListenerPort() ),
+ k -> {
+ LateralTCPListener<K, V> newIns = new LateralTCPListener<>( ilca );
+
+ newIns.init();
+ newIns.setCacheManager( cacheMgr );
+
+ log.info( "Created new listener {0}",
+ () -> ilca.getTcpListenerPort() );
+
+ return newIns;
+ });
+
+ return ins;
+ }
+
+ /**
+ * Only need one since it does work for all regions, just reference by multiple region names.
+ * <p>
+ * @param ilca
+ */
+ protected LateralTCPListener( ITCPLateralCacheAttributes ilca )
+ {
+ this.setTcpLateralCacheAttributes( ilca );
+ }
+
+ /**
+ * This starts the ListenerThread on the specified port.
+ */
+ @Override
+ public synchronized void init()
+ {
+ try
+ {
+ int port = getTcpLateralCacheAttributes().getTcpListenerPort();
+ String host = getTcpLateralCacheAttributes().getTcpListenerHost();
+
+ pooledExecutor = Executors.newCachedThreadPool(
+ new DaemonThreadFactory("JCS-LateralTCPListener-"));
+ terminated = new AtomicBoolean(false);
+ shutdown = new AtomicBoolean(false);
+
+ ServerSocket serverSocket;
+ if (host != null && host.length() > 0)
+ {
+ log.info( "Listening on {0}:{1}", host, port );
+ // Resolve host name
+ InetAddress inetAddress = InetAddress.getByName(host);
+ //Bind the SocketAddress with inetAddress and port
+ SocketAddress endPoint = new InetSocketAddress(inetAddress, port);
+
+ serverSocket = new ServerSocket();
+ serverSocket.bind(endPoint);
+ }
+ else
+ {
+ log.info( "Listening on port {0}", port );
+ serverSocket = new ServerSocket( port );
+ }
+ serverSocket.setSoTimeout( acceptTimeOut );
+
+ receiver = new ListenerThread(serverSocket);
+ receiver.setDaemon( true );
+ receiver.start();
+ }
+ catch ( IOException ex )
+ {
+ throw new IllegalStateException( ex );
+ }
+ }
+
+ /**
+ * Let the lateral cache set a listener_id. Since there is only one listener for all the
+ * regions and every region gets registered? the id shouldn't be set if it isn't zero. If it is
+ * we assume that it is a reconnect.
+ * <p>
+ * By default, the listener id is the vmid.
+ * <p>
+ * The service should set this value. This value will never be changed by a server we connect
+ * to. It needs to be non static, for unit tests.
+ * <p>
+ * The service will use the value it sets in all send requests to the sender.
+ * <p>
+ * @param id The new listenerId value
+ * @throws IOException
+ */
+ @Override
+ public void setListenerId( long id )
+ throws IOException
+ {
+ this.listenerId = id;
+ log.debug( "set listenerId = {0}", id );
+ }
+
+ /**
+ * Gets the listenerId attribute of the LateralCacheTCPListener object
+ * <p>
+ * @return The listenerId value
+ * @throws IOException
+ */
+ @Override
+ public long getListenerId()
+ throws IOException
+ {
+ return this.listenerId;
+ }
+
+ /**
+ * Increments the put count. Gets the cache that was injected by the lateral factory. Calls put
+ * on the cache.
+ * <p>
+ * @see org.apache.commons.jcs3.engine.behavior.ICacheListener#handlePut(org.apache.commons.jcs3.engine.behavior.ICacheElement)
+ */
+ @Override
+ public void handlePut( ICacheElement<K, V> element )
+ throws IOException
+ {
+ putCnt++;
+ if ( log.isInfoEnabled() && getPutCnt() % 100 == 0 )
+ {
+ log.info( "Put Count (port {0}) = {1}",
+ () -> getTcpLateralCacheAttributes().getTcpListenerPort(),
+ () -> getPutCnt() );
+ }
+
+ log.debug( "handlePut> cacheName={0}, key={1}",
+ () -> element.getCacheName(), () -> element.getKey() );
+
+ getCache( element.getCacheName() ).localUpdate( element );
+ }
+
+ /**
+ * Increments the remove count. Gets the cache that was injected by the lateral factory. Calls
+ * remove on the cache.
+ * <p>
+ * @see org.apache.commons.jcs3.engine.behavior.ICacheListener#handleRemove(java.lang.String,
+ * Object)
+ */
+ @Override
+ public void handleRemove( String cacheName, K key )
+ throws IOException
+ {
+ removeCnt++;
+ if ( log.isInfoEnabled() && getRemoveCnt() % 100 == 0 )
+ {
+ log.info( "Remove Count = {0}", () -> getRemoveCnt() );
+ }
+
+ log.debug( "handleRemove> cacheName={0}, key={1}", cacheName, key );
+
+ getCache( cacheName ).localRemove( key );
+ }
+
+ /**
+ * Gets the cache that was injected by the lateral factory. Calls removeAll on the cache.
+ * <p>
+ * @see org.apache.commons.jcs3.engine.behavior.ICacheListener#handleRemoveAll(java.lang.String)
+ */
+ @Override
+ public void handleRemoveAll( String cacheName )
+ throws IOException
+ {
+ log.debug( "handleRemoveAll> cacheName={0}", cacheName );
+
+ getCache( cacheName ).localRemoveAll();
+ }
+
+ /**
+ * Gets the cache that was injected by the lateral factory. Calls get on the cache.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @return a ICacheElement
+ * @throws IOException
+ */
+ public ICacheElement<K, V> handleGet( String cacheName, K key )
+ throws IOException
+ {
+ getCnt++;
+ if ( log.isInfoEnabled() && getGetCnt() % 100 == 0 )
+ {
+ log.info( "Get Count (port {0}) = {1}",
+ () -> getTcpLateralCacheAttributes().getTcpListenerPort(),
+ () -> getGetCnt() );
+ }
+
+ log.debug( "handleGet> cacheName={0}, key={1}", cacheName, key );
+
+ return getCache( cacheName ).localGet( key );
+ }
+
+ /**
+ * Gets the cache that was injected by the lateral factory. Calls get on the cache.
+ * <p>
+ * @param cacheName the name of the cache
+ * @param pattern the matching pattern
+ * @return Map
+ * @throws IOException
+ */
+ public Map<K, ICacheElement<K, V>> handleGetMatching( String cacheName, String pattern )
+ throws IOException
+ {
+ getCnt++;
+ if ( log.isInfoEnabled() && getGetCnt() % 100 == 0 )
+ {
+ log.info( "GetMatching Count (port {0}) = {1}",
+ () -> getTcpLateralCacheAttributes().getTcpListenerPort(),
+ () -> getGetCnt() );
+ }
+
+ log.debug( "handleGetMatching> cacheName={0}, pattern={1}", cacheName, pattern );
+
+ return getCache( cacheName ).localGetMatching( pattern );
+ }
+
+ /**
+ * Gets the cache that was injected by the lateral factory. Calls getKeySet on the cache.
+ * <p>
+ * @param cacheName the name of the cache
+ * @return a set of keys
+ * @throws IOException
+ */
+ public Set<K> handleGetKeySet( String cacheName ) throws IOException
+ {
+ return getCache( cacheName ).getKeySet(true);
+ }
+
+ /**
+ * This marks this instance as terminated.
+ * <p>
+ * @see org.apache.commons.jcs3.engine.behavior.ICacheListener#handleDispose(java.lang.String)
+ */
+ @Override
+ public void handleDispose( String cacheName )
+ throws IOException
+ {
+ log.info( "handleDispose > cacheName={0} | Ignoring message. "
+ + "Do not dispose from remote.", cacheName );
+
+ // TODO handle active deregistration, rather than passive detection
+ terminated.set(true);
+ }
+
+ @Override
+ public synchronized void dispose()
+ {
+ terminated.set(true);
+ notify();
+
+ pooledExecutor.shutdownNow();
+ }
+
+ /**
+ * Gets the cacheManager attribute of the LateralCacheTCPListener object.
+ * <p>
+ * Normally this is set by the factory. If it wasn't set the listener defaults to the expected
+ * singleton behavior of the cache manager.
+ * <p>
+ * @param name
+ * @return CompositeCache
+ */
+ protected CompositeCache<K, V> getCache( String name )
+ {
+ return getCacheManager().getCache( name );
+ }
+
+ /**
+ * This is roughly the number of updates the lateral has received.
+ * <p>
+ * @return Returns the putCnt.
+ */
+ public int getPutCnt()
+ {
+ return putCnt;
+ }
+
+ /**
+ * @return Returns the getCnt.
+ */
+ public int getGetCnt()
+ {
+ return getCnt;
+ }
+
+ /**
+ * @return Returns the removeCnt.
+ */
+ public int getRemoveCnt()
+ {
+ return removeCnt;
+ }
+
+ /**
+ * @param cacheMgr The cacheMgr to set.
+ */
+ @Override
+ public void setCacheManager( ICompositeCacheManager cacheMgr )
+ {
+ this.cacheManager = cacheMgr;
+ }
+
+ /**
+ * @return Returns the cacheMgr.
+ */
+ @Override
+ public ICompositeCacheManager getCacheManager()
+ {
+ return cacheManager;
+ }
+
+ /**
+ * @param tcpLateralCacheAttributes The tcpLateralCacheAttributes to set.
+ */
+ public void setTcpLateralCacheAttributes( ITCPLateralCacheAttributes tcpLateralCacheAttributes )
+ {
+ this.tcpLateralCacheAttributes = tcpLateralCacheAttributes;
+ }
+
+ /**
+ * @return Returns the tcpLateralCacheAttributes.
+ */
+ public ITCPLateralCacheAttributes getTcpLateralCacheAttributes()
+ {
+ return tcpLateralCacheAttributes;
+ }
+
+ /**
+ * Processes commands from the server socket. There should be one listener for each configured
+ * TCP lateral.
+ */
+ public class ListenerThread
+ extends Thread
+ {
+ /** The socket listener */
+ private final ServerSocket serverSocket;
+
+ /**
+ * Constructor
+ *
+ * @param serverSocket
+ */
+ public ListenerThread(ServerSocket serverSocket)
+ {
+ super();
+ this.serverSocket = serverSocket;
+ }
+
+ /** Main processing method for the ListenerThread object */
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public void run()
+ {
+ try (ServerSocket ssck = serverSocket)
+ {
+ ConnectionHandler handler;
+
+ outer: while ( true )
+ {
+ log.debug( "Waiting for clients to connect " );
+
+ Socket socket = null;
+ inner: while (true)
+ {
+ // Check to see if we've been asked to exit, and exit
+ if (terminated.get())
+ {
+ log.debug("Thread terminated, exiting gracefully");
+ break outer;
+ }
+
+ try
+ {
+ socket = ssck.accept();
+ break inner;
+ }
+ catch (SocketTimeoutException e)
+ {
+ // No problem! We loop back up!
+ continue inner;
+ }
+ }
+
+ if ( socket != null && log.isDebugEnabled() )
+ {
+ InetAddress inetAddress = socket.getInetAddress();
+ log.debug( "Connected to client at {0}", inetAddress );
+ }
+
+ handler = new ConnectionHandler( socket );
+ pooledExecutor.execute( handler );
+ }
+ }
+ catch ( IOException e )
+ {
+ log.error( "Exception caught in TCP listener", e );
+ }
+ }
+ }
+
+ /**
+ * A Separate thread that runs when a command comes into the LateralTCPReceiver.
+ */
+ public class ConnectionHandler
+ implements Runnable
+ {
+ /** The socket connection, passed in via constructor */
+ private final Socket socket;
+
+ /**
+ * Construct for a given socket
+ * @param socket
+ */
+ public ConnectionHandler( Socket socket )
+ {
+ this.socket = socket;
+ }
+
+ /**
+ * Main processing method for the LateralTCPReceiverConnection object
+ */
+ @Override
+ @SuppressWarnings({"unchecked", // Need to cast from Object
+ "synthetic-access" })
+ public void run()
+ {
+ try (ObjectInputStream ois =
+ new ObjectInputStreamClassLoaderAware( socket.getInputStream(), null ))
+ {
+ while ( true )
+ {
+ LateralElementDescriptor<K, V> led =
+ (LateralElementDescriptor<K, V>) ois.readObject();
+
+ if ( led == null )
+ {
+ log.debug( "LateralElementDescriptor is null" );
+ continue;
+ }
+ if ( led.requesterId == getListenerId() )
+ {
+ log.debug( "from self" );
+ }
+ else
+ {
+ log.debug( "receiving LateralElementDescriptor from another led = {0}",
+ led );
+
+ handle( led );
+ }
+ }
+ }
+ catch ( EOFException e )
+ {
+ log.info( "Caught EOFException, closing connection.", e );
+ }
+ catch ( SocketException e )
+ {
+ log.info( "Caught SocketException, closing connection.", e );
+ }
+ catch ( Exception e )
+ {
+ log.error( "Unexpected exception.", e );
+ }
+ }
+
+ /**
+ * This calls the appropriate method, based on the command sent in the Lateral element
+ * descriptor.
+ * <p>
+ * @param led
+ * @throws IOException
+ */
+ @SuppressWarnings("synthetic-access")
+ private void handle( LateralElementDescriptor<K, V> led )
+ throws IOException
+ {
+ String cacheName = led.ce.getCacheName();
+ K key = led.ce.getKey();
+ Serializable obj = null;
+
+ switch (led.command)
+ {
+ case UPDATE:
+ handlePut( led.ce );
+ break;
+
+ case REMOVE:
+ // if a hashcode was given and filtering is on
+ // check to see if they are the same
+ // if so, then don't remove, otherwise issue a remove
+ if ( led.valHashCode != -1 )
+ {
+ if ( getTcpLateralCacheAttributes().isFilterRemoveByHashCode() )
+ {
+ ICacheElement<K, V> test = getCache( cacheName ).localGet( key );
+ if ( test != null )
+ {
+ if ( test.getVal().hashCode() == led.valHashCode )
+ {
+ log.debug( "Filtering detected identical hashCode [{0}], "
+ + "not issuing a remove for led {1}",
+ led.valHashCode, led );
+ return;
+ }
+ else
+ {
+ log.debug( "Different hashcodes, in cache [{0}] sent [{1}]",
+ test.getVal().hashCode(), led.valHashCode );
+ }
+ }
+ }
+ }
+ handleRemove( cacheName, key );
+ break;
+
+ case REMOVEALL:
+ handleRemoveAll( cacheName );
+ break;
+
+ case GET:
+ obj = handleGet( cacheName, key );
+ break;
+
+ case GET_MATCHING:
+ obj = (Serializable) handleGetMatching( cacheName, (String) key );
+ break;
+
+ case GET_KEYSET:
+ obj = (Serializable) handleGetKeySet(cacheName);
+ break;
+
+ default: break;
+ }
+
+ if (obj != null)
+ {
+ ObjectOutputStream oos = new ObjectOutputStream( socket.getOutputStream() );
+ oos.writeObject( obj );
+ oos.flush();
+ }
+ }
+ }
+
+ /**
+ * Shuts down the receiver.
+ */
+ @Override
+ public void shutdown()
+ {
+ if ( shutdown.compareAndSet(false, true) )
+ {
+ log.info( "Shutting down TCP Lateral receiver." );
+
+ receiver.interrupt();
+ }
+ else
+ {
+ log.debug( "Shutdown already called." );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPSender.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPSender.java
new file mode 100644
index 0000000..3f42065
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPSender.java
@@ -0,0 +1,259 @@
+package org.apache.commons.jcs3.auxiliary.lateral.socket.tcp;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+
+import org.apache.commons.jcs3.auxiliary.lateral.LateralElementDescriptor;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes;
+import org.apache.commons.jcs3.io.ObjectInputStreamClassLoaderAware;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This class is based on the log4j SocketAppender class. I'm using a different repair structure, so
+ * it is significantly different.
+ */
+public class LateralTCPSender
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( LateralTCPSender.class );
+
+ /** Config */
+ private final int socketOpenTimeOut;
+ private final int socketSoTimeOut;
+
+ /** The stream from the server connection. */
+ private ObjectOutputStream oos;
+
+ /** The socket connection with the server. */
+ private Socket socket;
+
+ /** how many messages sent */
+ private int sendCnt = 0;
+
+ /** Use to synchronize multiple threads that may be trying to get. */
+ private final Object getLock = new int[0];
+
+ /**
+ * Constructor for the LateralTCPSender object.
+ * <p>
+ * @param lca
+ * @throws IOException
+ */
+ public LateralTCPSender( ITCPLateralCacheAttributes lca )
+ throws IOException
+ {
+ this.socketOpenTimeOut = lca.getOpenTimeOut();
+ this.socketSoTimeOut = lca.getSocketTimeOut();
+
+ String p1 = lca.getTcpServer();
+ if ( p1 == null )
+ {
+ throw new IOException( "Invalid server (null)" );
+ }
+
+ String h2 = p1.substring( 0, p1.indexOf( ":" ) );
+ int po = Integer.parseInt( p1.substring( p1.indexOf( ":" ) + 1 ) );
+ log.debug( "h2 = {0}, po = {1}", h2, po );
+
+ if ( h2.length() == 0 )
+ {
+ throw new IOException( "Cannot connect to invalid address [" + h2 + ":" + po + "]" );
+ }
+
+ init( h2, po );
+ }
+
+ /**
+ * Creates a connection to a TCP server.
+ * <p>
+ * @param host
+ * @param port
+ * @throws IOException
+ */
+ protected void init( String host, int port )
+ throws IOException
+ {
+ try
+ {
+ log.info( "Attempting connection to [{0}]", host );
+
+ // have time out socket open do this for us
+ try
+ {
+ socket = new Socket();
+ socket.connect( new InetSocketAddress( host, port ), this.socketOpenTimeOut );
+ }
+ catch ( IOException ioe )
+ {
+ if (socket != null)
+ {
+ socket.close();
+ }
+
+ throw new IOException( "Cannot connect to " + host + ":" + port, ioe );
+ }
+
+ socket.setSoTimeout( socketSoTimeOut );
+ synchronized ( this )
+ {
+ oos = new ObjectOutputStream( socket.getOutputStream() );
+ }
+ }
+ catch ( java.net.ConnectException e )
+ {
+ log.debug( "Remote host [{0}] refused connection.", host );
+ throw e;
+ }
+ catch ( IOException e )
+ {
+ log.debug( "Could not connect to [{0}]", host, e );
+ throw e;
+ }
+ }
+
+ /**
+ * Sends commands to the lateral cache listener.
+ * <p>
+ * @param led
+ * @throws IOException
+ */
+ public <K, V> void send( LateralElementDescriptor<K, V> led )
+ throws IOException
+ {
+ sendCnt++;
+ if ( log.isInfoEnabled() && sendCnt % 100 == 0 )
+ {
+ log.info( "Send Count (port {0}) = {1}", socket.getPort(), sendCnt );
+ }
+
+ log.debug( "sending LateralElementDescriptor" );
+
+ if ( led == null )
+ {
+ return;
+ }
+
+ if ( oos == null )
+ {
+ throw new IOException( "No remote connection is available for LateralTCPSender." );
+ }
+
+ synchronized ( this.getLock )
+ {
+ oos.writeUnshared( led );
+ oos.flush();
+ }
+ }
+
+ /**
+ * Sends commands to the lateral cache listener and gets a response. I'm afraid that we could
+ * get into a pretty bad blocking situation here. This needs work. I just wanted to get some
+ * form of get working. However, get is not recommended for performance reasons. If you have 10
+ * laterals, then you have to make 10 failed gets to find out none of the caches have the item.
+ * <p>
+ * @param led
+ * @return ICacheElement
+ * @throws IOException
+ */
+ public <K, V> Object sendAndReceive( LateralElementDescriptor<K, V> led )
+ throws IOException
+ {
+ if ( led == null )
+ {
+ return null;
+ }
+
+ if ( oos == null )
+ {
+ throw new IOException( "No remote connection is available for LateralTCPSender." );
+ }
+
+ Object response = null;
+
+ // Synchronized to insure that the get requests to server from this
+ // sender and the responses are processed in order, else you could
+ // return the wrong item from the cache.
+ // This is a big block of code. May need to re-think this strategy.
+ // This may not be necessary.
+ // Normal puts, etc to laterals do not have to be synchronized.
+ synchronized ( this.getLock )
+ {
+ try
+ {
+ // clean up input stream, nothing should be there yet.
+ if ( socket.getInputStream().available() > 0 )
+ {
+ socket.getInputStream().read( new byte[socket.getInputStream().available()] );
+ }
+ }
+ catch ( IOException ioe )
+ {
+ log.error( "Problem cleaning socket before send {0}", socket, ioe );
+ throw ioe;
+ }
+
+ // write object to listener
+ oos.writeUnshared( led );
+ oos.flush();
+
+ try (ObjectInputStream ois = new ObjectInputStreamClassLoaderAware( socket.getInputStream(), null ))
+ {
+ socket.setSoTimeout( socketSoTimeOut );
+ response = ois.readObject();
+ }
+ catch ( IOException ioe )
+ {
+ String message = "Could not open ObjectInputStream to " + socket +
+ " SoTimeout [" + socket.getSoTimeout() +
+ "] Connected [" + socket.isConnected() + "]";
+ log.error( message, ioe );
+ throw ioe;
+ }
+ catch ( Exception e )
+ {
+ log.error( e );
+ }
+ }
+
+ return response;
+ }
+
+ /**
+ * Closes connection used by all LateralTCPSenders for this lateral connection. Dispose request
+ * should come into the facade and be sent to all lateral cache services. The lateral cache
+ * service will then call this method.
+ * <p>
+ * @throws IOException
+ */
+ public void dispose()
+ throws IOException
+ {
+ log.info( "Dispose called" );
+ // WILL CLOSE CONNECTION USED BY ALL
+ oos.close();
+ socket.close();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPService.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPService.java
new file mode 100644
index 0000000..81f4eb2
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPService.java
@@ -0,0 +1,451 @@
+package org.apache.commons.jcs3.auxiliary.lateral.socket.tcp;
+
+/*
+ * 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.
+ */
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCommand;
+import org.apache.commons.jcs3.auxiliary.lateral.LateralElementDescriptor;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.CacheInfo;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * A lateral cache service implementation. Does not implement getGroupKey
+ * TODO: Remove generics
+ */
+public class LateralTCPService<K, V>
+ implements ICacheServiceNonLocal<K, V>
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog( LateralTCPService.class );
+
+ /** special configuration */
+ private final boolean allowPut;
+ private final boolean allowGet;
+ private final boolean issueRemoveOnPut;
+
+ /** Sends to another lateral. */
+ private LateralTCPSender sender;
+
+ /** use the vmid by default */
+ private long listenerId = CacheInfo.listenerId;
+
+ /**
+ * Constructor for the LateralTCPService object
+ * <p>
+ * @param lca ITCPLateralCacheAttributes
+ * @throws IOException
+ */
+ public LateralTCPService( ITCPLateralCacheAttributes lca )
+ throws IOException
+ {
+ this.allowGet = lca.isAllowGet();
+ this.allowPut = lca.isAllowPut();
+ this.issueRemoveOnPut = lca.isIssueRemoveOnPut();
+
+ try
+ {
+ sender = new LateralTCPSender( lca );
+
+ log.debug( "Created sender to [{0}]", () -> lca.getTcpServer() );
+ }
+ catch ( IOException e )
+ {
+ // log.error( "Could not create sender", e );
+ // This gets thrown over and over in recovery mode.
+ // The stack trace isn't useful here.
+ log.error( "Could not create sender to [{0}] -- {1}", lca.getTcpServer(), e.getMessage());
+ throw e;
+ }
+ }
+
+ /**
+ * @param item
+ * @throws IOException
+ */
+ @Override
+ public void update( ICacheElement<K, V> item )
+ throws IOException
+ {
+ update( item, getListenerId() );
+ }
+
+ /**
+ * If put is allowed, we will issue a put. If issue put on remove is configured, we will issue a
+ * remove. Either way, we create a lateral element descriptor, which is essentially a JCS TCP
+ * packet. It describes what operation the receiver should take when it gets the packet.
+ * <p>
+ * @see org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal#update(org.apache.commons.jcs3.engine.behavior.ICacheElement,
+ * long)
+ */
+ @Override
+ public void update( ICacheElement<K, V> item, long requesterId )
+ throws IOException
+ {
+ // if we don't allow put, see if we should remove on put
+ if ( !this.allowPut &&
+ // if we can't remove on put, and we can't put then return
+ !this.issueRemoveOnPut )
+ {
+ return;
+ }
+
+ // if we shouldn't remove on put, then put
+ if ( !this.issueRemoveOnPut )
+ {
+ LateralElementDescriptor<K, V> led = new LateralElementDescriptor<>( item );
+ led.requesterId = requesterId;
+ led.command = LateralCommand.UPDATE;
+ sender.send( led );
+ }
+ // else issue a remove with the hashcode for remove check on
+ // on the other end, this will be a server config option
+ else
+ {
+ log.debug( "Issuing a remove for a put" );
+
+ // set the value to null so we don't send the item
+ CacheElement<K, V> ce = new CacheElement<>( item.getCacheName(), item.getKey(), null );
+ LateralElementDescriptor<K, V> led = new LateralElementDescriptor<>( ce );
+ led.requesterId = requesterId;
+ led.command = LateralCommand.REMOVE;
+ led.valHashCode = item.getVal().hashCode();
+ sender.send( led );
+ }
+ }
+
+ /**
+ * Uses the default listener id and calls the next remove method.
+ * <p>
+ * @see org.apache.commons.jcs3.engine.behavior.ICacheService#remove(String, Object)
+ */
+ @Override
+ public void remove( String cacheName, K key )
+ throws IOException
+ {
+ remove( cacheName, key, getListenerId() );
+ }
+
+ /**
+ * Wraps the key in a LateralElementDescriptor.
+ * <p>
+ * @see org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal#remove(String, Object, long)
+ */
+ @Override
+ public void remove( String cacheName, K key, long requesterId )
+ throws IOException
+ {
+ CacheElement<K, V> ce = new CacheElement<>( cacheName, key, null );
+ LateralElementDescriptor<K, V> led = new LateralElementDescriptor<>( ce );
+ led.requesterId = requesterId;
+ led.command = LateralCommand.REMOVE;
+ sender.send( led );
+ }
+
+ /**
+ * Does nothing.
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ public void release()
+ throws IOException
+ {
+ // nothing needs to be done
+ }
+
+ /**
+ * Will close the connection.
+ * <p>
+ * @param cacheName
+ * @throws IOException
+ */
+ @Override
+ public void dispose( String cacheName )
+ throws IOException
+ {
+ sender.dispose();
+ }
+
+ /**
+ * @param cacheName
+ * @param key
+ * @return ICacheElement<K, V> if found.
+ * @throws IOException
+ */
+ @Override
+ public ICacheElement<K, V> get( String cacheName, K key )
+ throws IOException
+ {
+ return get( cacheName, key, getListenerId() );
+ }
+
+ /**
+ * If get is allowed, we will issues a get request.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @return ICacheElement<K, V> if found.
+ * @throws IOException
+ */
+ @Override
+ public ICacheElement<K, V> get( String cacheName, K key, long requesterId )
+ throws IOException
+ {
+ // if get is not allowed return
+ if ( this.allowGet )
+ {
+ CacheElement<K, V> ce = new CacheElement<>( cacheName, key, null );
+ LateralElementDescriptor<K, V> led = new LateralElementDescriptor<>( ce );
+ // led.requesterId = requesterId; // later
+ led.command = LateralCommand.GET;
+ @SuppressWarnings("unchecked") // Need to cast from Object
+ ICacheElement<K, V> response = (ICacheElement<K, V>)sender.sendAndReceive( led );
+ if ( response != null )
+ {
+ return response;
+ }
+ return null;
+ }
+ else
+ {
+ // nothing needs to be done
+ return null;
+ }
+ }
+
+ /**
+ * If allow get is true, we will issue a getmatching query.
+ * <p>
+ * @param cacheName
+ * @param pattern
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache matching the pattern.
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern )
+ throws IOException
+ {
+ return getMatching( cacheName, pattern, getListenerId() );
+ }
+
+ /**
+ * If allow get is true, we will issue a getmatching query.
+ * <p>
+ * @param cacheName
+ * @param pattern
+ * @param requesterId - our identity
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache matching the pattern.
+ * @throws IOException
+ */
+ @Override
+ @SuppressWarnings("unchecked") // Need to cast from Object
+ public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern, long requesterId )
+ throws IOException
+ {
+ // if get is not allowed return
+ if ( this.allowGet )
+ {
+ CacheElement<String, String> ce = new CacheElement<>( cacheName, pattern, null );
+ LateralElementDescriptor<String, String> led = new LateralElementDescriptor<>( ce );
+ // led.requesterId = requesterId; // later
+ led.command = LateralCommand.GET_MATCHING;
+
+ Object response = sender.sendAndReceive( led );
+ if ( response != null )
+ {
+ return (Map<K, ICacheElement<K, V>>) response;
+ }
+ return Collections.emptyMap();
+ }
+ else
+ {
+ // nothing needs to be done
+ return null;
+ }
+ }
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * @param cacheName
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys )
+ throws IOException
+ {
+ return getMultiple( cacheName, keys, getListenerId() );
+ }
+
+ /**
+ * This issues a separate get for each item.
+ * <p>
+ * TODO We should change this. It should issue one request.
+ * <p>
+ * @param cacheName
+ * @param keys
+ * @param requesterId
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys, long requesterId )
+ throws IOException
+ {
+ Map<K, ICacheElement<K, V>> elements = new HashMap<>();
+
+ if ( keys != null && !keys.isEmpty() )
+ {
+ for (K key : keys)
+ {
+ ICacheElement<K, V> element = get( cacheName, key );
+
+ if ( element != null )
+ {
+ elements.put( key, element );
+ }
+ }
+ }
+ return elements;
+ }
+
+ /**
+ * Return the keys in this cache.
+ * <p>
+ * @param cacheName the name of the cache region
+ * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCache#getKeySet()
+ */
+ @Override
+ @SuppressWarnings("unchecked") // Need cast from Object
+ public Set<K> getKeySet(String cacheName) throws IOException
+ {
+ CacheElement<String, String> ce = new CacheElement<>(cacheName, null, null);
+ LateralElementDescriptor<String, String> led = new LateralElementDescriptor<>(ce);
+ // led.requesterId = requesterId; // later
+ led.command = LateralCommand.GET_KEYSET;
+ Object response = sender.sendAndReceive(led);
+ if (response != null)
+ {
+ return (Set<K>) response;
+ }
+
+ return null;
+ }
+
+ /**
+ * @param cacheName
+ * @throws IOException
+ */
+ @Override
+ public void removeAll( String cacheName )
+ throws IOException
+ {
+ removeAll( cacheName, getListenerId() );
+ }
+
+ /**
+ * @param cacheName
+ * @param requesterId
+ * @throws IOException
+ */
+ @Override
+ public void removeAll( String cacheName, long requesterId )
+ throws IOException
+ {
+ CacheElement<String, String> ce = new CacheElement<>( cacheName, "ALL", null );
+ LateralElementDescriptor<String, String> led = new LateralElementDescriptor<>( ce );
+ led.requesterId = requesterId;
+ led.command = LateralCommand.REMOVEALL;
+ sender.send( led );
+ }
+
+ /**
+ * @param args
+ */
+ public static void main( String args[] )
+ {
+ try
+ {
+ LateralTCPSender sender = new LateralTCPSender( new TCPLateralCacheAttributes() );
+
+ // process user input till done
+ boolean notDone = true;
+ String message = null;
+ // wait to dispose
+ BufferedReader br = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
+
+ while ( notDone )
+ {
+ System.out.println( "enter message:" );
+ message = br.readLine();
+
+ if (message == null)
+ {
+ notDone = false;
+ continue;
+ }
+
+ CacheElement<String, String> ce = new CacheElement<>( "test", "test", message );
+ LateralElementDescriptor<String, String> led = new LateralElementDescriptor<>( ce );
+ sender.send( led );
+ }
+ }
+ catch ( IOException e )
+ {
+ System.out.println( e.toString() );
+ }
+ }
+
+ /**
+ * @param listernId The listernId to set.
+ */
+ protected void setListenerId( long listernId )
+ {
+ this.listenerId = listernId;
+ }
+
+ /**
+ * @return Returns the listernId.
+ */
+ protected long getListenerId()
+ {
+ return listenerId;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/TCPLateralCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/TCPLateralCacheAttributes.java
new file mode 100644
index 0000000..9fcb5c6
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/TCPLateralCacheAttributes.java
@@ -0,0 +1,407 @@
+package org.apache.commons.jcs3.auxiliary.lateral.socket.tcp;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes;
+
+/**
+ * This interface defines functions that are particular to the TCP Lateral Cache plugin. It extends
+ * the generic LateralCacheAttributes interface which in turn extends the AuxiliaryCache interface.
+ */
+public class TCPLateralCacheAttributes
+ extends LateralCacheAttributes
+ implements ITCPLateralCacheAttributes
+{
+ /** Don't change. */
+ private static final long serialVersionUID = 1077889204513905220L;
+
+ /** default */
+ private static final String DEFAULT_UDP_DISCOVERY_ADDRESS = "228.5.6.7";
+
+ /** default */
+ private static final int DEFAULT_UDP_DISCOVERY_PORT = 6789;
+
+ /** default */
+ private static final boolean DEFAULT_UDP_DISCOVERY_ENABLED = true;
+
+ /** default */
+ private static final boolean DEFAULT_ALLOW_GET = true;
+
+ /** default */
+ private static final boolean DEFAULT_ALLOW_PUT = true;
+
+ /** default */
+ private static final boolean DEFAULT_ISSUE_REMOVE_FOR_PUT = false;
+
+ /** default */
+ private static final boolean DEFAULT_FILTER_REMOVE_BY_HASH_CODE = true;
+
+ /** default - Only block for 1 second before timing out on a read.*/
+ private static final int DEFAULT_SOCKET_TIME_OUT = 1000;
+
+ /** default - Only block for 2 seconds before timing out on startup.*/
+ private static final int DEFAULT_OPEN_TIMEOUT = 2000;
+
+ /** TCP -------------------------------------------- */
+ private String tcpServers = "";
+
+ /** used to identify the service that this manager will be operating on */
+ private String tcpServer = "";
+
+ /** The port */
+ private int tcpListenerPort = 0;
+
+ /** The host */
+ private String tcpListenerHost = "";
+
+ /** udp discovery for tcp server */
+ private String udpDiscoveryAddr = DEFAULT_UDP_DISCOVERY_ADDRESS;
+
+ /** discovery port */
+ private int udpDiscoveryPort = DEFAULT_UDP_DISCOVERY_PORT;
+
+ /** discovery switch */
+ private boolean udpDiscoveryEnabled = DEFAULT_UDP_DISCOVERY_ENABLED;
+
+ /** can we put */
+ private boolean allowPut = DEFAULT_ALLOW_GET;
+
+ /** can we go laterally for a get */
+ private boolean allowGet = DEFAULT_ALLOW_PUT;
+
+ /** call remove when there is a put */
+ private boolean issueRemoveOnPut = DEFAULT_ISSUE_REMOVE_FOR_PUT;
+
+ /** don't remove it the hashcode is the same */
+ private boolean filterRemoveByHashCode = DEFAULT_FILTER_REMOVE_BY_HASH_CODE;
+
+ /** Only block for socketTimeOut seconds before timing out on a read. */
+ private int socketTimeOut = DEFAULT_SOCKET_TIME_OUT;
+
+ /** Only block for openTimeOut seconds before timing out on startup. */
+ private int openTimeOut = DEFAULT_OPEN_TIMEOUT;
+
+ /**
+ * Sets the tcpServer attribute of the ILateralCacheAttributes object
+ * <p>
+ * @param val The new tcpServer value
+ */
+ @Override
+ public void setTcpServer( String val )
+ {
+ this.tcpServer = val;
+ }
+
+ /**
+ * Gets the tcpServer attribute of the ILateralCacheAttributes object
+ * <p>
+ * @return The tcpServer value
+ */
+ @Override
+ public String getTcpServer()
+ {
+ return this.tcpServer;
+ }
+
+ /**
+ * Sets the tcpServers attribute of the ILateralCacheAttributes object
+ * <p>
+ * @param val The new tcpServers value
+ */
+ @Override
+ public void setTcpServers( String val )
+ {
+ this.tcpServers = val;
+ }
+
+ /**
+ * Gets the tcpServers attribute of the ILateralCacheAttributes object
+ * <p>
+ * @return The tcpServers value
+ */
+ @Override
+ public String getTcpServers()
+ {
+ return this.tcpServers;
+ }
+
+ /**
+ * Sets the tcpListenerPort attribute of the ILateralCacheAttributes object
+ * <p>
+ * @param val The new tcpListenerPort value
+ */
+ @Override
+ public void setTcpListenerPort( int val )
+ {
+ this.tcpListenerPort = val;
+ }
+
+ /**
+ * Gets the tcpListenerPort attribute of the ILateralCacheAttributes object
+ * <p>
+ * @return The tcpListenerPort value
+ */
+ @Override
+ public int getTcpListenerPort()
+ {
+ return this.tcpListenerPort;
+ }
+
+ /**
+ * Sets the tcpListenerHost attribute of the ILateralCacheAttributes object
+ * <p>
+ * @param val
+ * The new tcpListenerHost value
+ */
+ @Override
+ public void setTcpListenerHost( String val )
+ {
+ this.tcpListenerHost = val;
+ }
+
+ /**
+ * Gets the tcpListenerHost attribute of the ILateralCacheAttributes object
+ * <p>
+ * @return The tcpListenerHost value
+ */
+ @Override
+ public String getTcpListenerHost()
+ {
+ return this.tcpListenerHost;
+ }
+
+ /**
+ * Can setup UDP Discovery. This only works for TCp laterals right now. It allows TCP laterals
+ * to find each other by broadcasting to a multicast port.
+ * <p>
+ * @param udpDiscoveryEnabled The udpDiscoveryEnabled to set.
+ */
+ @Override
+ public void setUdpDiscoveryEnabled( boolean udpDiscoveryEnabled )
+ {
+ this.udpDiscoveryEnabled = udpDiscoveryEnabled;
+ }
+
+ /**
+ * Whether or not TCP laterals can try to find each other by multicast communication.
+ * <p>
+ * @return Returns the udpDiscoveryEnabled.
+ */
+ @Override
+ public boolean isUdpDiscoveryEnabled()
+ {
+ return this.udpDiscoveryEnabled;
+ }
+
+ /**
+ * The port to use if UDPDiscovery is enabled.
+ * <p>
+ * @return Returns the udpDiscoveryPort.
+ */
+ @Override
+ public int getUdpDiscoveryPort()
+ {
+ return this.udpDiscoveryPort;
+ }
+
+ /**
+ * Sets the port to use if UDPDiscovery is enabled.
+ * <p>
+ * @param udpDiscoveryPort The udpDiscoveryPort to set.
+ */
+ @Override
+ public void setUdpDiscoveryPort( int udpDiscoveryPort )
+ {
+ this.udpDiscoveryPort = udpDiscoveryPort;
+ }
+
+ /**
+ * The address to broadcast to if UDPDiscovery is enabled.
+ * <p>
+ * @return Returns the udpDiscoveryAddr.
+ */
+ @Override
+ public String getUdpDiscoveryAddr()
+ {
+ return this.udpDiscoveryAddr;
+ }
+
+ /**
+ * Sets the address to broadcast to if UDPDiscovery is enabled.
+ * <p>
+ * @param udpDiscoveryAddr The udpDiscoveryAddr to set.
+ */
+ @Override
+ public void setUdpDiscoveryAddr( String udpDiscoveryAddr )
+ {
+ this.udpDiscoveryAddr = udpDiscoveryAddr;
+ }
+
+ /**
+ * Is the lateral allowed to try and get from other laterals.
+ * <p>
+ * This replaces the old putOnlyMode
+ * <p>
+ * @param allowGet
+ */
+ @Override
+ public void setAllowGet( boolean allowGet )
+ {
+ this.allowGet = allowGet;
+ }
+
+ /**
+ * Is the lateral allowed to try and get from other laterals.
+ * <p>
+ * @return true if the lateral will try to get
+ */
+ @Override
+ public boolean isAllowGet()
+ {
+ return this.allowGet;
+ }
+
+ /**
+ * Is the lateral allowed to put objects to other laterals.
+ * <p>
+ * @param allowPut
+ */
+ @Override
+ public void setAllowPut( boolean allowPut )
+ {
+ this.allowPut = allowPut;
+ }
+
+ /**
+ * Is the lateral allowed to put objects to other laterals.
+ * <p>
+ * @return true if puts are allowed
+ */
+ @Override
+ public boolean isAllowPut()
+ {
+ return this.allowPut;
+ }
+
+ /**
+ * Should the client send a remove command rather than a put when update is called. This is a
+ * client option, not a receiver option. This allows you to prevent the lateral from serializing
+ * objects.
+ * <p>
+ * @param issueRemoveOnPut
+ */
+ @Override
+ public void setIssueRemoveOnPut( boolean issueRemoveOnPut )
+ {
+ this.issueRemoveOnPut = issueRemoveOnPut;
+ }
+
+ /**
+ * Should the client send a remove command rather than a put when update is called. This is a
+ * client option, not a receiver option. This allows you to prevent the lateral from serializing
+ * objects.
+ * <p>
+ * @return true if updates will result in a remove command being sent.
+ */
+ @Override
+ public boolean isIssueRemoveOnPut()
+ {
+ return this.issueRemoveOnPut;
+ }
+
+ /**
+ * Should the receiver try to match hashcodes. If true, the receiver will see if the client
+ * supplied a hashcode. If it did, then it will try to get the item locally. If the item exists,
+ * then it will compare the hashcode. if they are the same, it will not remove. This isn't
+ * perfect since different objects can have the same hashcode, but it is unlikely of objects of
+ * the same type.
+ * <p>
+ * @return boolean
+ */
+ @Override
+ public boolean isFilterRemoveByHashCode()
+ {
+ return this.filterRemoveByHashCode;
+ }
+
+ /**
+ * Should the receiver try to match hashcodes. If true, the receiver will see if the client
+ * supplied a hashcode. If it did, then it will try to get the item locally. If the item exists,
+ * then it will compare the hashcode. if they are the same, it will not remove. This isn't
+ * perfect since different objects can have the same hashcode, but it is unlikely of objects of
+ * the same type.
+ * <p>
+ * @param filter
+ */
+ @Override
+ public void setFilterRemoveByHashCode( boolean filter )
+ {
+ this.filterRemoveByHashCode = filter;
+ }
+
+ /**
+ * @param socketTimeOut the socketTimeOut to set
+ */
+ @Override
+ public void setSocketTimeOut( int socketTimeOut )
+ {
+ this.socketTimeOut = socketTimeOut;
+ }
+
+ /**
+ * @return the socketTimeOut
+ */
+ @Override
+ public int getSocketTimeOut()
+ {
+ return socketTimeOut;
+ }
+
+ /**
+ * @param openTimeOut the openTimeOut to set
+ */
+ @Override
+ public void setOpenTimeOut( int openTimeOut )
+ {
+ this.openTimeOut = openTimeOut;
+ }
+
+ /**
+ * @return the openTimeOut
+ */
+ @Override
+ public int getOpenTimeOut()
+ {
+ return openTimeOut;
+ }
+
+ /**
+ * Used to key the instance TODO create another method for this and use toString for debugging
+ * only.
+ * <p>
+ * @return String
+ */
+ @Override
+ public String toString()
+ {
+ return this.getTcpServer() + ":" + this.getTcpListenerPort();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/behavior/ITCPLateralCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/behavior/ITCPLateralCacheAttributes.java
new file mode 100644
index 0000000..ce4569f
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/behavior/ITCPLateralCacheAttributes.java
@@ -0,0 +1,233 @@
+package org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.behavior;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.lateral.behavior.ILateralCacheAttributes;
+
+/**
+ * This interface defines functions that are particular to the TCP Lateral Cache
+ * plugin. It extends the generic LateralCacheAttributes interface which in turn
+ * extends the AuxiliaryCache interface.
+ * <p>
+ * @author Aaron Smuts
+ */
+public interface ITCPLateralCacheAttributes
+ extends ILateralCacheAttributes
+{
+ /**
+ * Sets the tcpServer attribute of the ILateralCacheAttributes object
+ * <p>
+ * @param val
+ * The new tcpServer value
+ */
+ void setTcpServer( String val );
+
+ /**
+ * Gets the tcpServer attribute of the ILateralCacheAttributes object
+ * <p>
+ * @return The tcpServer value
+ */
+ String getTcpServer();
+
+ /**
+ * Sets the tcpServers attribute of the ILateralCacheAttributes object
+ * <p>
+ * @param val
+ * The new tcpServers value
+ */
+ void setTcpServers( String val );
+
+ /**
+ * Gets the tcpServers attribute of the ILateralCacheAttributes object
+ * <p>
+ * @return The tcpServers value
+ */
+ String getTcpServers();
+
+ /**
+ * Sets the tcpListenerPort attribute of the ILateralCacheAttributes object
+ * <p>
+ * @param val
+ * The new tcpListenerPort value
+ */
+ void setTcpListenerPort( int val );
+
+ /**
+ * Gets the tcpListenerPort attribute of the ILateralCacheAttributes object
+ * <p>
+ * @return The tcpListenerPort value
+ */
+ int getTcpListenerPort();
+
+ /**
+ * Sets the tcpListenerHost attribute of the ILateralCacheAttributes object
+ * <p>
+ * @param val
+ * The new tcpListenerHost value
+ */
+ void setTcpListenerHost( String val );
+
+ /**
+ * Gets the tcpListenerHost attribute of the ILateralCacheAttributes object
+ * <p>
+ * @return The tcpListenerHost value
+ */
+ String getTcpListenerHost();
+
+ /**
+ * Can setup UDP Discovery. This only works for TCp laterals right now. It
+ * allows TCP laterals to find each other by broadcasting to a multicast
+ * port.
+ * <p>
+ * @param udpDiscoveryEnabled
+ * The udpDiscoveryEnabled to set.
+ */
+ void setUdpDiscoveryEnabled( boolean udpDiscoveryEnabled );
+
+ /**
+ * Whether or not TCP laterals can try to find each other by multicast
+ * communication.
+ * <p>
+ * @return Returns the udpDiscoveryEnabled.
+ */
+ boolean isUdpDiscoveryEnabled();
+
+ /**
+ * The port to use if UDPDiscovery is enabled.
+ * <p>
+ * @return Returns the udpDiscoveryPort.
+ */
+ int getUdpDiscoveryPort();
+
+ /**
+ * Sets the port to use if UDPDiscovery is enabled.
+ * <p>
+ * @param udpDiscoveryPort
+ * The udpDiscoveryPort to set.
+ */
+ void setUdpDiscoveryPort( int udpDiscoveryPort );
+
+ /**
+ * The address to broadcast to if UDPDiscovery is enabled.
+ * <p>
+ * @return Returns the udpDiscoveryAddr.
+ */
+ String getUdpDiscoveryAddr();
+
+ /**
+ * Sets the address to broadcast to if UDPDiscovery is enabled.
+ * <p>
+ * @param udpDiscoveryAddr
+ * The udpDiscoveryAddr to set.
+ */
+ void setUdpDiscoveryAddr( String udpDiscoveryAddr );
+
+ /**
+ * Is the lateral allowed to try and get from other laterals.
+ * <p>
+ * This replaces the old putOnlyMode
+ * <p>
+ * @param allowGet
+ */
+ void setAllowGet( boolean allowGet );
+
+ /**
+ * Is the lateral allowed to try and get from other laterals.
+ * <p>
+ * @return true if the lateral will try to get
+ */
+ boolean isAllowGet();
+
+ /**
+ * Is the lateral allowed to put objects to other laterals.
+ * <p>
+ * @param allowPut
+ */
+ void setAllowPut( boolean allowPut );
+
+ /**
+ * Is the lateral allowed to put objects to other laterals.
+ * <p>
+ * @return true if puts are allowed
+ */
+ boolean isAllowPut();
+
+ /**
+ * Should the client send a remove command rather than a put when update is
+ * called. This is a client option, not a receiver option. This allows you
+ * to prevent the lateral from serializing objects.
+ * <p>
+ * @param issueRemoveOnPut
+ */
+ void setIssueRemoveOnPut( boolean issueRemoveOnPut );
+
+ /**
+ * Should the client send a remove command rather than a put when update is
+ * called. This is a client option, not a receiver option. This allows you
+ * to prevent the lateral from serializing objects.
+ * <p>
+ * @return true if updates will result in a remove command being sent.
+ */
+ boolean isIssueRemoveOnPut();
+
+ /**
+ * Should the receiver try to match hashcodes. If true, the receiver will
+ * see if the client supplied a hashcode. If it did, then it will try to get
+ * the item locally. If the item exists, then it will compare the hashcode.
+ * if they are the same, it will not remove. This isn't perfect since
+ * different objects can have the same hashcode, but it is unlikely of
+ * objects of the same type.
+ * <p>
+ * @return boolean
+ */
+ boolean isFilterRemoveByHashCode();
+
+ /**
+ * Should the receiver try to match hashcodes. If true, the receiver will
+ * see if the client supplied a hashcode. If it did, then it will try to get
+ * the item locally. If the item exists, then it will compare the hashcode.
+ * if they are the same, it will not remove. This isn't perfect since
+ * different objects can have the same hashcode, but it is unlikely of
+ * objects of the same type.
+ * <p>
+ * @param filter
+ */
+ void setFilterRemoveByHashCode( boolean filter );
+
+ /**
+ * @param socketTimeOut the socketTimeOut to set
+ */
+ void setSocketTimeOut( int socketTimeOut );
+
+ /**
+ * @return the socketTimeOut
+ */
+ int getSocketTimeOut();
+
+ /**
+ * @param openTimeOut the openTimeOut to set
+ */
+ void setOpenTimeOut( int openTimeOut );
+
+ /**
+ * @return the openTimeOut
+ */
+ int getOpenTimeOut();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/package.html b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/package.html
similarity index 100%
rename from commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/package.html
rename to commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/package.html
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/AbstractRemoteAuxiliaryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/AbstractRemoteAuxiliaryCache.java
new file mode 100644
index 0000000..66009a6
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/AbstractRemoteAuxiliaryCache.java
@@ -0,0 +1,653 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheEventLogging;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheClient;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheListener;
+import org.apache.commons.jcs3.auxiliary.remote.server.behavior.RemoteType;
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.ZombieCacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElementSerialized;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.behavior.IZombie;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.engine.stats.StatElement;
+import org.apache.commons.jcs3.engine.stats.Stats;
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.serialization.SerializationConversionUtil;
+import org.apache.commons.jcs3.utils.threadpool.ThreadPoolManager;
+
+/** Abstract base for remote caches. I'm trying to break out and reuse common functionality. */
+public abstract class AbstractRemoteAuxiliaryCache<K, V>
+ extends AbstractAuxiliaryCacheEventLogging<K, V>
+ implements IRemoteCacheClient<K, V>
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog( AbstractRemoteAuxiliaryCache.class );
+
+ /**
+ * This does the work. In an RMI instances, it will be a remote reference. In an http remote
+ * cache it will be an http client. In zombie mode it is replaced with a balking facade.
+ */
+ private ICacheServiceNonLocal<K, V> remoteCacheService;
+
+ /** The cacheName */
+ protected final String cacheName;
+
+ /** The listener. This can be null. */
+ private IRemoteCacheListener<K, V> remoteCacheListener;
+
+ /** The configuration values. TODO, we'll need a base here. */
+ private IRemoteCacheAttributes remoteCacheAttributes;
+
+ /** A thread pool for gets if configured. */
+ private ExecutorService pool = null;
+
+ /** Should we get asynchronously using a pool. */
+ private boolean usePoolForGet = false;
+
+ /**
+ * Creates the base.
+ * <p>
+ * @param cattr
+ * @param remote
+ * @param listener
+ */
+ public AbstractRemoteAuxiliaryCache( IRemoteCacheAttributes cattr, ICacheServiceNonLocal<K, V> remote,
+ IRemoteCacheListener<K, V> listener )
+ {
+ this.setRemoteCacheAttributes( cattr );
+ this.cacheName = cattr.getCacheName();
+ this.setRemoteCacheService( remote );
+ this.setRemoteCacheListener( listener );
+
+ if ( log.isDebugEnabled() )
+ {
+ log.debug( "Construct> cacheName={0}", () -> cattr.getCacheName() );
+ log.debug( "irca = {0}", () -> getRemoteCacheAttributes() );
+ log.debug( "remote = {0}", remote );
+ log.debug( "listener = {0}", listener );
+ }
+
+ // use a pool if it is greater than 0
+ log.debug( "GetTimeoutMillis() = {0}",
+ () -> getRemoteCacheAttributes().getGetTimeoutMillis() );
+
+ if ( getRemoteCacheAttributes().getGetTimeoutMillis() > 0 )
+ {
+ pool = ThreadPoolManager.getInstance().getExecutorService( getRemoteCacheAttributes().getThreadPoolName() );
+ log.debug( "Thread Pool = {0}", pool );
+ usePoolForGet = true;
+ }
+ }
+
+ /**
+ * Synchronously dispose the remote cache; if failed, replace the remote handle with a zombie.
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ protected void processDispose()
+ throws IOException
+ {
+ log.info( "Disposing of remote cache." );
+ try
+ {
+ if ( getRemoteCacheListener() != null )
+ {
+ getRemoteCacheListener().dispose();
+ }
+ }
+ catch ( IOException ex )
+ {
+ log.error( "Couldn't dispose", ex );
+ handleException( ex, "Failed to dispose [" + cacheName + "]", ICacheEventLogger.DISPOSE_EVENT );
+ }
+ }
+
+ /**
+ * Synchronously get from the remote cache; if failed, replace the remote handle with a zombie.
+ * <p>
+ * Use threadpool to timeout if a value is set for GetTimeoutMillis
+ * <p>
+ * If we are a cluster client, we need to leave the Element in its serialized form. Cluster
+ * clients cannot deserialize objects. Cluster clients get ICacheElementSerialized objects from
+ * other remote servers.
+ * <p>
+ * @param key
+ * @return ICacheElement, a wrapper around the key, value, and attributes
+ * @throws IOException
+ */
+ @Override
+ protected ICacheElement<K, V> processGet( K key )
+ throws IOException
+ {
+ ICacheElement<K, V> retVal = null;
+ try
+ {
+ if ( usePoolForGet )
+ {
+ retVal = getUsingPool( key );
+ }
+ else
+ {
+ retVal = getRemoteCacheService().get( cacheName, key, getListenerId() );
+ }
+
+ // Eventually the instance of will not be necessary.
+ if ( retVal instanceof ICacheElementSerialized )
+ {
+ // Never try to deserialize if you are a cluster client. Cluster
+ // clients are merely intra-remote cache communicators. Remote caches are assumed
+ // to have no ability to deserialize the objects.
+ if ( this.getRemoteCacheAttributes().getRemoteType() != RemoteType.CLUSTER )
+ {
+ retVal = SerializationConversionUtil.getDeSerializedCacheElement( (ICacheElementSerialized<K, V>) retVal,
+ super.getElementSerializer() );
+ }
+ }
+ }
+ catch ( Exception ex )
+ {
+ handleException( ex, "Failed to get [" + key + "] from [" + cacheName + "]", ICacheEventLogger.GET_EVENT );
+ }
+ return retVal;
+ }
+
+ /**
+ * This allows gets to timeout in case of remote server machine shutdown.
+ * <p>
+ * @param key
+ * @return ICacheElement
+ * @throws IOException
+ */
+ public ICacheElement<K, V> getUsingPool( final K key )
+ throws IOException
+ {
+ int timeout = getRemoteCacheAttributes().getGetTimeoutMillis();
+
+ try
+ {
+ Callable<ICacheElement<K, V>> command = () -> getRemoteCacheService().get( cacheName, key, getListenerId() );
+
+ // execute using the pool
+ Future<ICacheElement<K, V>> future = pool.submit(command);
+
+ // used timed get in order to timeout
+ ICacheElement<K, V> ice = future.get(timeout, TimeUnit.MILLISECONDS);
+
+ if ( ice == null )
+ {
+ log.debug( "nothing found in remote cache" );
+ }
+ else
+ {
+ log.debug( "found item in remote cache" );
+ }
+ return ice;
+ }
+ catch ( TimeoutException te )
+ {
+ log.warn( "TimeoutException, Get Request timed out after {0}", timeout );
+ throw new IOException( "Get Request timed out after " + timeout );
+ }
+ catch ( InterruptedException ex )
+ {
+ log.warn( "InterruptedException, Get Request timed out after {0}", timeout );
+ throw new IOException( "Get Request timed out after " + timeout );
+ }
+ catch (ExecutionException ex)
+ {
+ // assume that this is an IOException thrown by the callable.
+ log.error( "ExecutionException, Assuming an IO exception thrown in the background.", ex );
+ throw new IOException( "Get Request timed out after " + timeout );
+ }
+ }
+
+ /**
+ * Calls get matching on the server. Each entry in the result is unwrapped.
+ * <p>
+ * @param pattern
+ * @return Map
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> processGetMatching( String pattern )
+ throws IOException
+ {
+ Map<K, ICacheElement<K, V>> results = new HashMap<>();
+ try
+ {
+ Map<K, ICacheElement<K, V>> rawResults = getRemoteCacheService().getMatching( cacheName, pattern, getListenerId() );
+
+ // Eventually the instance of will not be necessary.
+ if ( rawResults != null )
+ {
+ for (Map.Entry<K, ICacheElement<K, V>> entry : rawResults.entrySet())
+ {
+ ICacheElement<K, V> unwrappedResult = null;
+ if ( entry.getValue() instanceof ICacheElementSerialized )
+ {
+ // Never try to deserialize if you are a cluster client. Cluster
+ // clients are merely intra-remote cache communicators. Remote caches are assumed
+ // to have no ability to deserialize the objects.
+ if ( this.getRemoteCacheAttributes().getRemoteType() != RemoteType.CLUSTER )
+ {
+ unwrappedResult = SerializationConversionUtil
+ .getDeSerializedCacheElement( (ICacheElementSerialized<K, V>) entry.getValue(),
+ super.getElementSerializer() );
+ }
+ }
+ else
+ {
+ unwrappedResult = entry.getValue();
+ }
+ results.put( entry.getKey(), unwrappedResult );
+ }
+ }
+ }
+ catch ( Exception ex )
+ {
+ handleException( ex, "Failed to getMatching [" + pattern + "] from [" + cacheName + "]",
+ ICacheEventLogger.GET_EVENT );
+ }
+ return results;
+ }
+
+ /**
+ * Synchronously remove from the remote cache; if failed, replace the remote handle with a
+ * zombie.
+ * <p>
+ * @param key
+ * @return boolean, whether or not the item was removed
+ * @throws IOException
+ */
+ @Override
+ protected boolean processRemove( K key )
+ throws IOException
+ {
+ if ( !this.getRemoteCacheAttributes().getGetOnly() )
+ {
+ log.debug( "remove> key={0}", key );
+ try
+ {
+ getRemoteCacheService().remove( cacheName, key, getListenerId() );
+ }
+ catch ( Exception ex )
+ {
+ handleException( ex, "Failed to remove " + key + " from " + cacheName, ICacheEventLogger.REMOVE_EVENT );
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Synchronously removeAll from the remote cache; if failed, replace the remote handle with a
+ * zombie.
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ protected void processRemoveAll()
+ throws IOException
+ {
+ if ( !this.getRemoteCacheAttributes().getGetOnly() )
+ {
+ try
+ {
+ getRemoteCacheService().removeAll( cacheName, getListenerId() );
+ }
+ catch ( Exception ex )
+ {
+ handleException( ex, "Failed to remove all from " + cacheName, ICacheEventLogger.REMOVEALL_EVENT );
+ }
+ }
+ }
+
+ /**
+ * Serializes the object and then calls update on the remote server with the byte array. The
+ * byte array is wrapped in a ICacheElementSerialized. This allows the remote server to operate
+ * without any knowledge of caches classes.
+ * <p>
+ * @param ce
+ * @throws IOException
+ */
+ @Override
+ protected void processUpdate( ICacheElement<K, V> ce )
+ throws IOException
+ {
+ if ( !getRemoteCacheAttributes().getGetOnly() )
+ {
+ ICacheElementSerialized<K, V> serialized = null;
+ try
+ {
+ log.debug( "sending item to remote server" );
+
+ // convert so we don't have to know about the object on the
+ // other end.
+ serialized = SerializationConversionUtil.getSerializedCacheElement( ce, super.getElementSerializer() );
+
+ remoteCacheService.update( serialized, getListenerId() );
+ }
+ catch ( NullPointerException npe )
+ {
+ log.error( "npe for ce = {0} ce.attr = {1}", ce, ce.getElementAttributes(), npe );
+ }
+ catch ( Exception ex )
+ {
+ // event queue will wait and retry
+ handleException( ex, "Failed to put [" + ce.getKey() + "] to " + ce.getCacheName(),
+ ICacheEventLogger.UPDATE_EVENT );
+ }
+ }
+ else
+ {
+ log.debug( "get only mode, not sending to remote server" );
+ }
+ }
+
+ /**
+ * Return the keys in this cache.
+ * <p>
+ * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCache#getKeySet()
+ */
+ @Override
+ public Set<K> getKeySet()
+ throws IOException
+ {
+ return getRemoteCacheService().getKeySet(cacheName);
+ }
+
+ /**
+ * Allows other member of this package to access the listener. This is mainly needed for
+ * deregistering a listener.
+ * <p>
+ * @return IRemoteCacheListener, the listener for this remote server
+ */
+ @Override
+ public IRemoteCacheListener<K, V> getListener()
+ {
+ return getRemoteCacheListener();
+ }
+
+ /**
+ * let the remote cache set a listener_id. Since there is only one listener for all the regions
+ * and every region gets registered? the id shouldn't be set if it isn't zero. If it is we
+ * assume that it is a reconnect.
+ * <p>
+ * @param id The new listenerId value
+ */
+ public void setListenerId( long id )
+ {
+ if ( getRemoteCacheListener() != null )
+ {
+ try
+ {
+ getRemoteCacheListener().setListenerId( id );
+
+ log.debug( "set listenerId = {0}", id );
+ }
+ catch ( Exception e )
+ {
+ log.error( "Problem setting listenerId", e );
+ }
+ }
+ }
+
+ /**
+ * Gets the listenerId attribute of the RemoteCacheListener object
+ * <p>
+ * @return The listenerId value
+ */
+ @Override
+ public long getListenerId()
+ {
+ if ( getRemoteCacheListener() != null )
+ {
+ try
+ {
+ log.debug( "get listenerId = {0}", getRemoteCacheListener().getListenerId() );
+ return getRemoteCacheListener().getListenerId();
+ }
+ catch ( IOException e )
+ {
+ log.error( "Problem getting listenerId", e );
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the current cache size.
+ * @return The size value
+ */
+ @Override
+ public int getSize()
+ {
+ return 0;
+ }
+
+ /**
+ * Custom exception handling some children. This should be used to initiate failover.
+ * <p>
+ * @param ex
+ * @param msg
+ * @param eventName
+ * @throws IOException
+ */
+ protected abstract void handleException( Exception ex, String msg, String eventName )
+ throws IOException;
+
+ /**
+ * Gets the stats attribute of the RemoteCache object.
+ * <p>
+ * @return The stats value
+ */
+ @Override
+ public String getStats()
+ {
+ return getStatistics().toString();
+ }
+
+ /**
+ * @return IStats object
+ */
+ @Override
+ public IStats getStatistics()
+ {
+ IStats stats = new Stats();
+ stats.setTypeName( "AbstractRemoteAuxiliaryCache" );
+
+ ArrayList<IStatElement<?>> elems = new ArrayList<>();
+
+ elems.add(new StatElement<>( "Remote Type", this.getRemoteCacheAttributes().getRemoteTypeName() ) );
+
+// if ( this.getRemoteCacheAttributes().getRemoteType() == RemoteType.CLUSTER )
+// {
+// // something cluster specific
+// }
+
+ elems.add(new StatElement<>( "UsePoolForGet", Boolean.valueOf(usePoolForGet) ) );
+
+ if ( pool != null )
+ {
+ elems.add(new StatElement<>( "Pool", pool ) );
+ }
+
+ if ( getRemoteCacheService() instanceof ZombieCacheServiceNonLocal )
+ {
+ elems.add(new StatElement<>( "Zombie Queue Size",
+ Integer.valueOf(( (ZombieCacheServiceNonLocal<K, V>) getRemoteCacheService() ).getQueueSize()) ) );
+ }
+
+ stats.setStatElements( elems );
+
+ return stats;
+ }
+
+ /**
+ * Returns the cache status. An error status indicates the remote connection is not available.
+ * <p>
+ * @return The status value
+ */
+ @Override
+ public CacheStatus getStatus()
+ {
+ return getRemoteCacheService() instanceof IZombie ? CacheStatus.ERROR : CacheStatus.ALIVE;
+ }
+
+ /**
+ * Replaces the current remote cache service handle with the given handle. If the current remote
+ * is a Zombie, then it propagates any events that are queued to the restored service.
+ * <p>
+ * @param restoredRemote ICacheServiceNonLocal -- the remote server or proxy to the remote server
+ */
+ @Override
+ public void fixCache( ICacheServiceNonLocal<?, ?> restoredRemote )
+ {
+ @SuppressWarnings("unchecked") // Don't know how to do this properly
+ ICacheServiceNonLocal<K, V> remote = (ICacheServiceNonLocal<K, V>)restoredRemote;
+ ICacheServiceNonLocal<K, V> prevRemote = getRemoteCacheService();
+ if ( prevRemote instanceof ZombieCacheServiceNonLocal )
+ {
+ ZombieCacheServiceNonLocal<K, V> zombie = (ZombieCacheServiceNonLocal<K, V>) prevRemote;
+ setRemoteCacheService( remote );
+ try
+ {
+ zombie.propagateEvents( remote );
+ }
+ catch ( Exception e )
+ {
+ try
+ {
+ handleException( e, "Problem propagating events from Zombie Queue to new Remote Service.",
+ "fixCache" );
+ }
+ catch ( IOException e1 )
+ {
+ // swallow, since this is just expected kick back. Handle always throws
+ }
+ }
+ }
+ else
+ {
+ setRemoteCacheService( remote );
+ }
+ }
+
+
+ /**
+ * Gets the cacheType attribute of the RemoteCache object
+ * @return The cacheType value
+ */
+ @Override
+ public CacheType getCacheType()
+ {
+ return CacheType.REMOTE_CACHE;
+ }
+
+ /**
+ * Gets the cacheName attribute of the RemoteCache object.
+ * <p>
+ * @return The cacheName value
+ */
+ @Override
+ public String getCacheName()
+ {
+ return cacheName;
+ }
+
+ /**
+ * @param remote the remote to set
+ */
+ protected void setRemoteCacheService( ICacheServiceNonLocal<K, V> remote )
+ {
+ this.remoteCacheService = remote;
+ }
+
+ /**
+ * @return the remote
+ */
+ protected ICacheServiceNonLocal<K, V> getRemoteCacheService()
+ {
+ return remoteCacheService;
+ }
+
+ /**
+ * @return Returns the AuxiliaryCacheAttributes.
+ */
+ @Override
+ public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
+ {
+ return getRemoteCacheAttributes();
+ }
+
+ /**
+ * @param remoteCacheAttributes the remoteCacheAttributes to set
+ */
+ protected void setRemoteCacheAttributes( IRemoteCacheAttributes remoteCacheAttributes )
+ {
+ this.remoteCacheAttributes = remoteCacheAttributes;
+ }
+
+ /**
+ * @return the remoteCacheAttributes
+ */
+ protected IRemoteCacheAttributes getRemoteCacheAttributes()
+ {
+ return remoteCacheAttributes;
+ }
+
+ /**
+ * @param remoteCacheListener the remoteCacheListener to set
+ */
+ protected void setRemoteCacheListener( IRemoteCacheListener<K, V> remoteCacheListener )
+ {
+ this.remoteCacheListener = remoteCacheListener;
+ }
+
+ /**
+ * @return the remoteCacheListener
+ */
+ protected IRemoteCacheListener<K, V> getRemoteCacheListener()
+ {
+ return remoteCacheListener;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/AbstractRemoteCacheListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/AbstractRemoteCacheListener.java
new file mode 100644
index 0000000..451c71b
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/AbstractRemoteCacheListener.java
@@ -0,0 +1,266 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.net.UnknownHostException;
+
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheListener;
+import org.apache.commons.jcs3.auxiliary.remote.server.behavior.RemoteType;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElementSerialized;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.net.HostNameUtil;
+import org.apache.commons.jcs3.utils.serialization.SerializationConversionUtil;
+
+/** Shared listener base. */
+public abstract class AbstractRemoteCacheListener<K, V>
+ implements IRemoteCacheListener<K, V>
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( AbstractRemoteCacheListener.class );
+
+ /** The cached name of the local host. The remote server gets this for logging purposes. */
+ private static String localHostName = null;
+
+ /**
+ * The cache manager used to put items in different regions. This is set lazily and should not
+ * be sent to the remote server.
+ */
+ private final ICompositeCacheManager cacheMgr;
+
+ /** The remote cache configuration object. */
+ private final IRemoteCacheAttributes irca;
+
+ /** This is set by the remote cache server. */
+ private long listenerId = 0;
+
+ /** Custom serializer. */
+ private final IElementSerializer elementSerializer;
+
+ /**
+ * Only need one since it does work for all regions, just reference by multiple region names.
+ * <p>
+ * The constructor exports this object, making it available to receive incoming calls. The
+ * callback port is anonymous unless a local port value was specified in the configuration.
+ * <p>
+ * @param irca cache configuration
+ * @param cacheMgr the cache hub
+ * @param elementSerializer a custom serializer
+ */
+ public AbstractRemoteCacheListener( IRemoteCacheAttributes irca, ICompositeCacheManager cacheMgr, IElementSerializer elementSerializer )
+ {
+ this.irca = irca;
+ this.cacheMgr = cacheMgr;
+ this.elementSerializer = elementSerializer;
+ }
+
+ /**
+ * Let the remote cache set a listener_id. Since there is only one listener for all the regions
+ * and every region gets registered? the id shouldn't be set if it isn't zero. If it is we
+ * assume that it is a reconnect.
+ * <p>
+ * @param id The new listenerId value
+ * @throws IOException
+ */
+ @Override
+ public void setListenerId( long id )
+ throws IOException
+ {
+ listenerId = id;
+ log.info( "set listenerId = [{0}]", id );
+ }
+
+ /**
+ * Gets the listenerId attribute of the RemoteCacheListener object. This is stored in the
+ * object. The RemoteCache object contains a reference to the listener and get the id this way.
+ * <p>
+ * @return The listenerId value
+ * @throws IOException
+ */
+ @Override
+ public long getListenerId()
+ throws IOException
+ {
+ log.debug( "get listenerId = [{0}]", listenerId );
+ return listenerId;
+
+ }
+
+ /**
+ * Gets the remoteType attribute of the RemoteCacheListener object
+ * <p>
+ * @return The remoteType value
+ * @throws IOException
+ */
+ @Override
+ public RemoteType getRemoteType()
+ throws IOException
+ {
+ log.debug( "getRemoteType = [{0}]", () -> irca.getRemoteType() );
+ return irca.getRemoteType();
+ }
+
+ /**
+ * If this is configured to remove on put, then remove the element since it has been updated
+ * elsewhere. cd should be incomplete for faster transmission. We don't want to pass data only
+ * invalidation. The next time it is used the local cache will get the new version from the
+ * remote store.
+ * <p>
+ * If remove on put is not configured, then update the item.
+ * @param cb
+ * @throws IOException
+ */
+ @Override
+ public void handlePut( ICacheElement<K, V> cb )
+ throws IOException
+ {
+ if ( irca.getRemoveUponRemotePut() )
+ {
+ log.debug( "PUTTING ELEMENT FROM REMOTE, ( invalidating ) " );
+ handleRemove( cb.getCacheName(), cb.getKey() );
+ }
+ else
+ {
+ log.debug( "PUTTING ELEMENT FROM REMOTE, ( updating ) " );
+ log.debug( "cb = {0}", cb );
+
+ // Eventually the instance of will not be necessary.
+ if ( cb instanceof ICacheElementSerialized )
+ {
+ log.debug( "Object needs to be deserialized." );
+ try
+ {
+ cb = SerializationConversionUtil.getDeSerializedCacheElement(
+ (ICacheElementSerialized<K, V>) cb, this.elementSerializer );
+ log.debug( "Deserialized result = {0}", cb );
+ }
+ catch ( IOException e )
+ {
+ throw e;
+ }
+ catch ( ClassNotFoundException e )
+ {
+ log.error( "Received a serialized version of a class that we don't know about.", e );
+ }
+ }
+
+ getCacheManager().<K, V>getCache( cb.getCacheName() ).localUpdate( cb );
+ }
+ }
+
+ /**
+ * Calls localRemove on the CompositeCache.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @throws IOException
+ */
+ @Override
+ public void handleRemove( String cacheName, K key )
+ throws IOException
+ {
+ log.debug( "handleRemove> cacheName={0}, key={1}", cacheName, key );
+
+ getCacheManager().<K, V>getCache( cacheName ).localRemove( key );
+ }
+
+ /**
+ * Calls localRemoveAll on the CompositeCache.
+ * <p>
+ * @param cacheName
+ * @throws IOException
+ */
+ @Override
+ public void handleRemoveAll( String cacheName )
+ throws IOException
+ {
+ log.debug( "handleRemoveAll> cacheName={0}", cacheName );
+
+ getCacheManager().<K, V>getCache( cacheName ).localRemoveAll();
+ }
+
+ /**
+ * @param cacheName
+ * @throws IOException
+ */
+ @Override
+ public void handleDispose( String cacheName )
+ throws IOException
+ {
+ log.debug( "handleDispose> cacheName={0}", cacheName );
+ // TODO consider what to do here, we really don't want to
+ // dispose, we just want to disconnect.
+ // just allow the cache to go into error recovery mode.
+ // getCacheManager().freeCache( cacheName, true );
+ }
+
+ /**
+ * Gets the cacheManager attribute of the RemoteCacheListener object. This is one of the few
+ * places that force the cache to be a singleton.
+ */
+ protected ICompositeCacheManager getCacheManager()
+ {
+ return cacheMgr;
+ }
+
+ /**
+ * This is for debugging. It allows the remote server to log the address of clients.
+ * <p>
+ * @return String
+ * @throws IOException
+ */
+ @Override
+ public synchronized String getLocalHostAddress()
+ throws IOException
+ {
+ if ( localHostName == null )
+ {
+ try
+ {
+ localHostName = HostNameUtil.getLocalHostAddress();
+ }
+ catch ( UnknownHostException uhe )
+ {
+ localHostName = "unknown";
+ }
+ }
+ return localHostName;
+ }
+
+ /**
+ * For easier debugging.
+ * <p>
+ * @return Basic info on this listener.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\n AbstractRemoteCacheListener: " )
+ .append( "\n RemoteHost = ").append(irca.getRemoteLocation())
+ .append( "\n ListenerId = ").append(listenerId);
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/AbstractRemoteCacheNoWaitFacade.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/AbstractRemoteCacheNoWaitFacade.java
new file mode 100644
index 0000000..cdc2baf
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/AbstractRemoteCacheNoWaitFacade.java
@@ -0,0 +1,434 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.engine.stats.StatElement;
+import org.apache.commons.jcs3.engine.stats.Stats;
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/** An abstract base for the No Wait Facade. Different implementations will failover differently. */
+public abstract class AbstractRemoteCacheNoWaitFacade<K, V>
+ extends AbstractAuxiliaryCache<K, V>
+{
+ /** log instance */
+ private static final Log log = LogManager.getLog( AbstractRemoteCacheNoWaitFacade.class );
+
+ /** The connection to a remote server, or a zombie. */
+ protected List<RemoteCacheNoWait<K, V>> noWaits;
+
+ /** holds failover and cluster information */
+ private final IRemoteCacheAttributes remoteCacheAttributes;
+
+ /**
+ * Constructs with the given remote cache, and fires events to any listeners.
+ * <p>
+ * @param noWaits
+ * @param rca
+ * @param cacheEventLogger
+ * @param elementSerializer
+ */
+ public AbstractRemoteCacheNoWaitFacade( List<RemoteCacheNoWait<K,V>> noWaits, IRemoteCacheAttributes rca,
+ ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
+ {
+ log.debug( "CONSTRUCTING NO WAIT FACADE" );
+ this.remoteCacheAttributes = rca;
+ setCacheEventLogger( cacheEventLogger );
+ setElementSerializer( elementSerializer );
+ this.noWaits = new ArrayList<>(noWaits);
+ for (RemoteCacheNoWait<K,V> nw : this.noWaits)
+ {
+ // FIXME: This cast is very brave. Remove this.
+ ((RemoteCache<K, V>)nw.getRemoteCache()).setFacade(this);
+ }
+ }
+
+ /**
+ * Put an element in the cache.
+ * <p>
+ * @param ce
+ * @throws IOException
+ */
+ @Override
+ public void update( ICacheElement<K, V> ce )
+ throws IOException
+ {
+ log.debug( "updating through cache facade, noWaits.length = {0}",
+ () -> noWaits.size() );
+
+ for (RemoteCacheNoWait<K, V> nw : noWaits)
+ {
+ try
+ {
+ nw.update( ce );
+ // an initial move into a zombie will lock this to primary
+ // recovery. will not discover other servers until primary
+ // reconnect
+ // and subsequent error
+ }
+ catch ( IOException ex )
+ {
+ String message = "Problem updating no wait. Will initiate failover if the noWait is in error.";
+ log.error( message, ex );
+
+ if ( getCacheEventLogger() != null )
+ {
+ getCacheEventLogger().logError( "RemoteCacheNoWaitFacade",
+ ICacheEventLogger.UPDATE_EVENT,
+ message + ":" + ex.getMessage() + " REGION: " + ce.getCacheName()
+ + " ELEMENT: " + ce );
+ }
+
+ // can handle failover here? Is it safe to try the others?
+ // check to see it the noWait is now a zombie
+ // if it is a zombie, then move to the next in the failover list
+ // will need to keep them in order or a count
+ failover( nw );
+ // should start a failover thread
+ // should probably only failover if there is only one in the noWait
+ // list
+ // Should start a background thread to restore the original primary if we are in failover state.
+ }
+ }
+ }
+
+ /**
+ * Synchronously reads from the remote cache.
+ * <p>
+ * @param key
+ * @return Either an ICacheElement<K, V> or null if it is not found.
+ */
+ @Override
+ public ICacheElement<K, V> get( K key )
+ {
+ for (RemoteCacheNoWait<K, V> nw : noWaits)
+ {
+ try
+ {
+ ICacheElement<K, V> obj = nw.get( key );
+ if ( obj != null )
+ {
+ return obj;
+ }
+ }
+ catch ( IOException ex )
+ {
+ log.debug( "Failed to get." );
+ return null;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Synchronously read from the remote cache.
+ * <p>
+ * @param pattern
+ * @return map
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching( String pattern )
+ throws IOException
+ {
+ for (RemoteCacheNoWait<K, V> nw : noWaits)
+ {
+ try
+ {
+ return nw.getMatching( pattern );
+ }
+ catch ( IOException ex )
+ {
+ log.debug( "Failed to getMatching." );
+ }
+ }
+ return Collections.emptyMap();
+ }
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple( Set<K> keys )
+ {
+ if ( keys != null && !keys.isEmpty() )
+ {
+ for (RemoteCacheNoWait<K, V> nw : noWaits)
+ {
+ try
+ {
+ return nw.getMultiple( keys );
+ }
+ catch ( IOException ex )
+ {
+ log.debug( "Failed to get." );
+ }
+ }
+ }
+
+ return Collections.emptyMap();
+ }
+
+ /**
+ * Return the keys in this cache.
+ * <p>
+ * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCache#getKeySet()
+ */
+ @Override
+ public Set<K> getKeySet() throws IOException
+ {
+ HashSet<K> allKeys = new HashSet<>();
+ for (RemoteCacheNoWait<K, V> nw : noWaits)
+ {
+ if ( nw != null )
+ {
+ Set<K> keys = nw.getKeySet();
+ if(keys != null)
+ {
+ allKeys.addAll( keys );
+ }
+ }
+ }
+ return allKeys;
+ }
+
+ /**
+ * Adds a remove request to the remote cache.
+ * <p>
+ * @param key
+ * @return whether or not it was removed, right now it return false.
+ */
+ @Override
+ public boolean remove( K key )
+ {
+ try
+ {
+ for (RemoteCacheNoWait<K, V> nw : noWaits)
+ {
+ nw.remove( key );
+ }
+ }
+ catch ( IOException ex )
+ {
+ log.error( ex );
+ }
+ return false;
+ }
+
+ /**
+ * Adds a removeAll request to the remote cache.
+ */
+ @Override
+ public void removeAll()
+ {
+ try
+ {
+ for (RemoteCacheNoWait<K, V> nw : noWaits)
+ {
+ nw.removeAll();
+ }
+ }
+ catch ( IOException ex )
+ {
+ log.error( ex );
+ }
+ }
+
+ /** Adds a dispose request to the remote cache. */
+ @Override
+ public void dispose()
+ {
+ for (RemoteCacheNoWait<K, V> nw : noWaits)
+ {
+ nw.dispose();
+ }
+ }
+
+ /**
+ * No remote invocation.
+ * <p>
+ * @return The size value
+ */
+ @Override
+ public int getSize()
+ {
+ return 0;
+ // cache.getSize();
+ }
+
+ /**
+ * Gets the cacheType attribute of the RemoteCacheNoWaitFacade object.
+ * <p>
+ * @return The cacheType value
+ */
+ @Override
+ public CacheType getCacheType()
+ {
+ return CacheType.REMOTE_CACHE;
+ }
+
+ /**
+ * Gets the cacheName attribute of the RemoteCacheNoWaitFacade object.
+ * <p>
+ * @return The cacheName value
+ */
+ @Override
+ public String getCacheName()
+ {
+ return remoteCacheAttributes.getCacheName();
+ }
+
+ /**
+ * Gets the status attribute of the RemoteCacheNoWaitFacade object
+ * <p>
+ * Return ALIVE if any are alive.
+ * <p>
+ * @return The status value
+ */
+ @Override
+ public CacheStatus getStatus()
+ {
+ for (RemoteCacheNoWait<K, V> nw : noWaits)
+ {
+ if ( nw.getStatus() == CacheStatus.ALIVE )
+ {
+ return CacheStatus.ALIVE;
+ }
+ }
+
+ return CacheStatus.DISPOSED;
+ }
+
+ /**
+ * String form of some of the configuration information for the remote cache.
+ * <p>
+ * @return Some info for logging.
+ */
+ @Override
+ public String toString()
+ {
+ return "RemoteCacheNoWaitFacade: " + remoteCacheAttributes.getCacheName() + ", rca = " + remoteCacheAttributes;
+ }
+
+ /**
+ * Begin the failover process if this is a local cache. Clustered remote caches do not failover.
+ * <p>
+ * @param rcnw The no wait in error.
+ */
+ protected abstract void failover( RemoteCacheNoWait<K, V> rcnw );
+
+ /**
+ * Get the primary server from the list of failovers
+ *
+ * @return a no wait
+ */
+ public RemoteCacheNoWait<K, V> getPrimaryServer()
+ {
+ return noWaits.get(0);
+ }
+
+ /**
+ * restore the primary server in the list of failovers
+ *
+ */
+ public void restorePrimaryServer(RemoteCacheNoWait<K, V> rcnw)
+ {
+ noWaits.clear();
+ noWaits.add(rcnw);
+ }
+
+ /**
+ * @return Returns the AuxiliaryCacheAttributes.
+ */
+ @Override
+ public IRemoteCacheAttributes getAuxiliaryCacheAttributes()
+ {
+ return this.remoteCacheAttributes;
+ }
+
+ /**
+ * getStats
+ * @return String
+ */
+ @Override
+ public String getStats()
+ {
+ return getStatistics().toString();
+ }
+
+ /**
+ * @return statistics about the cache region
+ */
+ @Override
+ public IStats getStatistics()
+ {
+ IStats stats = new Stats();
+ stats.setTypeName( "Remote Cache No Wait Facade" );
+
+ ArrayList<IStatElement<?>> elems = new ArrayList<>();
+
+ if ( noWaits != null )
+ {
+ elems.add(new StatElement<>( "Number of No Waits", Integer.valueOf(noWaits.size()) ) );
+
+ for ( RemoteCacheNoWait<K, V> rcnw : noWaits )
+ {
+ // get the stats from the super too
+ IStats sStats = rcnw.getStatistics();
+ elems.addAll(sStats.getStatElements());
+ }
+ }
+
+ stats.setStatElements( elems );
+
+ return stats;
+ }
+
+ /**
+ * This typically returns end point info .
+ * <p>
+ * @return the name
+ */
+ @Override
+ public String getEventLoggingExtraInfo()
+ {
+ return "Remote Cache No Wait Facade";
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/CommonRemoteCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/CommonRemoteCacheAttributes.java
new file mode 100644
index 0000000..39d9de1
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/CommonRemoteCacheAttributes.java
@@ -0,0 +1,295 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.ICommonRemoteCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheConstants;
+import org.apache.commons.jcs3.auxiliary.remote.server.behavior.RemoteType;
+
+/**
+ * Attributes common to remote cache client and server.
+ */
+public class CommonRemoteCacheAttributes
+ extends AbstractAuxiliaryCacheAttributes
+ implements ICommonRemoteCacheAttributes
+{
+ /** Don't change */
+ private static final long serialVersionUID = -1555143736942374000L;
+
+ /** The service name */
+ private String remoteServiceName = IRemoteCacheConstants.REMOTE_CACHE_SERVICE_VAL;
+
+ /** server host and port */
+ private RemoteLocation location;
+
+ /** Cluster chain */
+ private String clusterServers = "";
+
+ /** THe type of remote cache, local or cluster */
+ private RemoteType remoteType = RemoteType.LOCAL;
+
+ /** Should we issue a local remove if we get a put from a remote server */
+ private boolean removeUponRemotePut = true;
+
+ /** Can we receive from or put to the remote. this probably shouldn't be used. Use receive. */
+ private boolean getOnly = false;
+
+ /** Should we put and get from the clusters. */
+ private boolean localClusterConsistency = false;
+
+ /** read and connect timeout */
+ private int rmiSocketFactoryTimeoutMillis = DEFAULT_RMI_SOCKET_FACTORY_TIMEOUT_MILLIS;
+
+ /** Default constructor for the RemoteCacheAttributes object */
+ public CommonRemoteCacheAttributes()
+ {
+ super();
+ }
+
+ /**
+ * Gets the remoteTypeName attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @return The remoteTypeName value
+ */
+ @Override
+ public String getRemoteTypeName()
+ {
+ return remoteType != null ? remoteType.toString() : RemoteType.LOCAL.toString();
+ }
+
+ /**
+ * Sets the remoteTypeName attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @param s The new remoteTypeName value
+ */
+ @Override
+ public void setRemoteTypeName( String s )
+ {
+ RemoteType rt = RemoteType.valueOf(s);
+ if (rt != null)
+ {
+ this.remoteType = rt;
+ }
+ }
+
+ /**
+ * Gets the remoteType attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @return The remoteType value
+ */
+ @Override
+ public RemoteType getRemoteType()
+ {
+ return remoteType;
+ }
+
+ /**
+ * Sets the remoteType attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @param p The new remoteType value
+ */
+ @Override
+ public void setRemoteType( RemoteType p )
+ {
+ this.remoteType = p;
+ }
+
+ /**
+ * Gets the remoteServiceName attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @return The remoteServiceName value
+ */
+ @Override
+ public String getRemoteServiceName()
+ {
+ return this.remoteServiceName;
+ }
+
+ /**
+ * Sets the remoteServiceName attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @param s The new remoteServiceName value
+ */
+ @Override
+ public void setRemoteServiceName( String s )
+ {
+ this.remoteServiceName = s;
+ }
+
+ /**
+ * Sets the location attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @param location The new location value
+ */
+ @Override
+ public void setRemoteLocation( RemoteLocation location )
+ {
+ this.location = location;
+ }
+
+ /**
+ * Sets the location attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @param host The new remoteHost value
+ * @param port The new remotePort value
+ */
+ @Override
+ public void setRemoteLocation( String host, int port )
+ {
+ this.location = new RemoteLocation(host, port);
+ }
+
+ /**
+ * Gets the location attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @return The remote location value
+ */
+ @Override
+ public RemoteLocation getRemoteLocation()
+ {
+ return this.location;
+ }
+
+ /**
+ * Gets the clusterServers attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @return The clusterServers value
+ */
+ @Override
+ public String getClusterServers()
+ {
+ return this.clusterServers;
+ }
+
+ /**
+ * Sets the clusterServers attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @param s The new clusterServers value
+ */
+ @Override
+ public void setClusterServers( String s )
+ {
+ this.clusterServers = s;
+ }
+
+ /**
+ * Gets the removeUponRemotePut attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @return The removeUponRemotePut value
+ */
+ @Override
+ public boolean getRemoveUponRemotePut()
+ {
+ return this.removeUponRemotePut;
+ }
+
+ /**
+ * Sets the removeUponRemotePut attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @param r The new removeUponRemotePut value
+ */
+ @Override
+ public void setRemoveUponRemotePut( boolean r )
+ {
+ this.removeUponRemotePut = r;
+ }
+
+ /**
+ * Gets the getOnly attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @return The getOnly value
+ */
+ @Override
+ public boolean getGetOnly()
+ {
+ return this.getOnly;
+ }
+
+ /**
+ * Sets the getOnly attribute of the RemoteCacheAttributes object
+ * @param r The new getOnly value
+ */
+ @Override
+ public void setGetOnly( boolean r )
+ {
+ this.getOnly = r;
+ }
+
+ /**
+ * Should cluster updates be propagated to the locals.
+ * <p>
+ * @return The localClusterConsistency value
+ */
+ @Override
+ public boolean isLocalClusterConsistency()
+ {
+ return localClusterConsistency;
+ }
+
+ /**
+ * Should cluster updates be propagated to the locals.
+ * <p>
+ * @param r The new localClusterConsistency value
+ */
+ @Override
+ public void setLocalClusterConsistency( boolean r )
+ {
+ this.localClusterConsistency = r;
+ }
+
+ /**
+ * @param rmiSocketFactoryTimeoutMillis The rmiSocketFactoryTimeoutMillis to set.
+ */
+ @Override
+ public void setRmiSocketFactoryTimeoutMillis( int rmiSocketFactoryTimeoutMillis )
+ {
+ this.rmiSocketFactoryTimeoutMillis = rmiSocketFactoryTimeoutMillis;
+ }
+
+ /**
+ * @return Returns the rmiSocketFactoryTimeoutMillis.
+ */
+ @Override
+ public int getRmiSocketFactoryTimeoutMillis()
+ {
+ return rmiSocketFactoryTimeoutMillis;
+ }
+
+ /**
+ * @return String, all the important values that can be configured
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\n RemoteCacheAttributes " );
+ if (this.location != null)
+ {
+ buf.append( "\n remoteHost = [" + this.location.getHost() + "]" );
+ buf.append( "\n remotePort = [" + this.location.getPort() + "]" );
+ }
+ buf.append( "\n cacheName = [" + getCacheName() + "]" );
+ buf.append( "\n remoteType = [" + remoteType + "]" );
+ buf.append( "\n removeUponRemotePut = [" + this.removeUponRemotePut + "]" );
+ buf.append( "\n getOnly = [" + getOnly + "]" );
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCache.java
new file mode 100644
index 0000000..6a62adb
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCache.java
@@ -0,0 +1,209 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheListener;
+import org.apache.commons.jcs3.auxiliary.remote.server.behavior.RemoteType;
+import org.apache.commons.jcs3.engine.ZombieCacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.stats.StatElement;
+import org.apache.commons.jcs3.engine.stats.Stats;
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * Client proxy for an RMI remote cache.
+ * <p>
+ * This handles gets, updates, and removes. It also initiates failover recovery when an error is
+ * encountered.
+ */
+public class RemoteCache<K, V>
+ extends AbstractRemoteAuxiliaryCache<K, V>
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog( RemoteCache.class );
+
+ /** for error notifications */
+ private final RemoteCacheMonitor monitor;
+
+ /** back link for failover initiation */
+ private AbstractRemoteCacheNoWaitFacade<K, V> facade;
+
+ /**
+ * Constructor for the RemoteCache object. This object communicates with a remote cache server.
+ * One of these exists for each region. This also holds a reference to a listener. The same
+ * listener is used for all regions for one remote server. Holding a reference to the listener
+ * allows this object to know the listener id assigned by the remote cache.
+ * <p>
+ * @param cattr the cache configuration
+ * @param remote the remote cache server handle
+ * @param listener a listener
+ * @param monitor the cache monitor
+ */
+ public RemoteCache( IRemoteCacheAttributes cattr,
+ ICacheServiceNonLocal<K, V> remote,
+ IRemoteCacheListener<K, V> listener,
+ RemoteCacheMonitor monitor )
+ {
+ super( cattr, remote, listener );
+ this.monitor = monitor;
+
+ RemoteUtils.configureGlobalCustomSocketFactory( getRemoteCacheAttributes().getRmiSocketFactoryTimeoutMillis() );
+ }
+
+ /**
+ * @return IStats object
+ */
+ @Override
+ public IStats getStatistics()
+ {
+ IStats stats = new Stats();
+ stats.setTypeName( "Remote Cache" );
+
+ ArrayList<IStatElement<?>> elems = new ArrayList<>();
+
+ elems.add(new StatElement<>( "Remote Host:Port", getIPAddressForService() ) );
+ elems.add(new StatElement<>( "Remote Type", this.getRemoteCacheAttributes().getRemoteTypeName() ) );
+
+// if ( this.getRemoteCacheAttributes().getRemoteType() == RemoteType.CLUSTER )
+// {
+// // something cluster specific
+// }
+
+ // get the stats from the super too
+ IStats sStats = super.getStatistics();
+ elems.addAll(sStats.getStatElements());
+
+ stats.setStatElements( elems );
+
+ return stats;
+ }
+
+ /**
+ * Set facade
+ *
+ * @param facade the facade to set
+ */
+ protected void setFacade(AbstractRemoteCacheNoWaitFacade<K, V> facade)
+ {
+ this.facade = facade;
+ }
+
+ /**
+ * Get facade
+ *
+ * @return the facade
+ */
+ protected AbstractRemoteCacheNoWaitFacade<K, V> getFacade()
+ {
+ return facade;
+ }
+
+ /**
+ * Handles exception by disabling the remote cache service before re-throwing the exception in
+ * the form of an IOException.
+ * <p>
+ * @param ex
+ * @param msg
+ * @param eventName
+ * @throws IOException
+ */
+ @Override
+ protected void handleException( Exception ex, String msg, String eventName )
+ throws IOException
+ {
+ String message = "Disabling remote cache due to error: " + msg;
+
+ logError( cacheName, "", message );
+ log.error( message, ex );
+
+ // we should not switch if the existing is a zombie.
+ if ( getRemoteCacheService() == null || !( getRemoteCacheService() instanceof ZombieCacheServiceNonLocal ) )
+ {
+ // TODO make configurable
+ setRemoteCacheService( new ZombieCacheServiceNonLocal<>( getRemoteCacheAttributes().getZombieQueueMaxSize() ) );
+ }
+ // may want to flush if region specifies
+ // Notify the cache monitor about the error, and kick off the recovery
+ // process.
+ monitor.notifyError();
+
+ log.debug( "Initiating failover, rcnwf = {0}", facade );
+
+ if ( facade != null && facade.getAuxiliaryCacheAttributes().getRemoteType() == RemoteType.LOCAL )
+ {
+ log.debug( "Found facade, calling failover" );
+ // may need to remove the noWait index here. It will be 0 if it is
+ // local since there is only 1 possible listener.
+ facade.failover( facade.getPrimaryServer() );
+ }
+
+ if ( ex instanceof IOException )
+ {
+ throw (IOException) ex;
+ }
+ throw new IOException( ex );
+ }
+
+ /**
+ * Debugging info.
+ * <p>
+ * @return basic info about the RemoteCache
+ */
+ @Override
+ public String toString()
+ {
+ return "RemoteCache: " + cacheName + " attributes = " + getRemoteCacheAttributes();
+ }
+
+ /**
+ * Gets the extra info for the event log.
+ * <p>
+ * @return disk location
+ */
+ @Override
+ public String getEventLoggingExtraInfo()
+ {
+ return getIPAddressForService();
+ }
+
+ /**
+ * IP address for the service, if one is stored.
+ * <p>
+ * Protected for testing.
+ * <p>
+ * @return String
+ */
+ protected String getIPAddressForService()
+ {
+ String ipAddress = "(null)";
+ if (this.getRemoteCacheAttributes().getRemoteLocation() != null)
+ {
+ ipAddress = this.getRemoteCacheAttributes().getRemoteLocation().toString();
+ }
+ return ipAddress;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheAttributes.java
new file mode 100644
index 0000000..ed5de40
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheAttributes.java
@@ -0,0 +1,263 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.util.List;
+
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheAttributes;
+
+/**
+ * These objects are used to configure the remote cache client.
+ */
+public class RemoteCacheAttributes
+ extends CommonRemoteCacheAttributes
+ implements IRemoteCacheAttributes
+{
+ /** Don't change */
+ private static final long serialVersionUID = -1555143736942374000L;
+
+ /**
+ * Failover servers will be used by local caches one at a time. Listeners will be registered
+ * with all cluster servers. If we add a get from cluster attribute we will have the ability to
+ * chain clusters and have them get from each other.
+ */
+ private String failoverServers = "";
+
+ /** callback */
+ private int localPort = 0;
+
+ /** what failover server we are connected to. */
+ private int failoverIndex = 0;
+
+ /** List of failover server addresses */
+ private List<RemoteLocation> failovers;
+
+ /** default name is remote_cache_client */
+ private String threadPoolName = "remote_cache_client";
+
+ /** must be greater than 0 for a pool to be used. */
+ private int getTimeoutMillis = -1;
+
+ /**
+ * Can we receive from the server. You might have a 0 local store and keep everything on the
+ * remote. If so, you don't want to be notified of updates.
+ */
+ private boolean receive = DEFAULT_RECEIVE;
+
+ /** If the primary fails, we will queue items before reconnect. This limits the number of items that can be queued. */
+ private int zombieQueueMaxSize = DEFAULT_ZOMBIE_QUEUE_MAX_SIZE;
+
+ /** Default constructor for the RemoteCacheAttributes object */
+ public RemoteCacheAttributes()
+ {
+ super();
+ }
+
+ /**
+ * Gets the failoverIndex attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @return The failoverIndex value
+ */
+ @Override
+ public int getFailoverIndex()
+ {
+ return failoverIndex;
+ }
+
+ /**
+ * Sets the failoverIndex attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @param p The new failoverIndex value
+ */
+ @Override
+ public void setFailoverIndex( int p )
+ {
+ this.failoverIndex = p;
+ }
+
+ /**
+ * Gets the failovers attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @return The failovers value
+ */
+ @Override
+ public List<RemoteLocation> getFailovers()
+ {
+ return this.failovers;
+ }
+
+ /**
+ * Sets the failovers attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @param failovers The new failovers value
+ */
+ @Override
+ public void setFailovers( List<RemoteLocation> failovers )
+ {
+ this.failovers = failovers;
+ }
+
+ /**
+ * Gets the failoverServers attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @return The failoverServers value
+ */
+ @Override
+ public String getFailoverServers()
+ {
+ return this.failoverServers;
+ }
+
+ /**
+ * Sets the failoverServers attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @param s The new failoverServers value
+ */
+ @Override
+ public void setFailoverServers( String s )
+ {
+ this.failoverServers = s;
+ }
+
+ /**
+ * Gets the localPort attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @return The localPort value
+ */
+ @Override
+ public int getLocalPort()
+ {
+ return this.localPort;
+ }
+
+ /**
+ * Sets the localPort attribute of the RemoteCacheAttributes object
+ * @param p The new localPort value
+ */
+ @Override
+ public void setLocalPort( int p )
+ {
+ this.localPort = p;
+ }
+
+ /**
+ * @return the name of the pool
+ */
+ @Override
+ public String getThreadPoolName()
+ {
+ return threadPoolName;
+ }
+
+ /**
+ * @param name
+ */
+ @Override
+ public void setThreadPoolName( String name )
+ {
+ threadPoolName = name;
+ }
+
+ /**
+ * @return getTimeoutMillis
+ */
+ @Override
+ public int getGetTimeoutMillis()
+ {
+ return getTimeoutMillis;
+ }
+
+ /**
+ * @param millis
+ */
+ @Override
+ public void setGetTimeoutMillis( int millis )
+ {
+ getTimeoutMillis = millis;
+ }
+
+ /**
+ * By default this option is true. If you set it to false, you will not receive updates or
+ * removes from the remote server.
+ * <p>
+ * @param receive
+ */
+ @Override
+ public void setReceive( boolean receive )
+ {
+ this.receive = receive;
+ }
+
+ /**
+ * If RECEIVE is false then the remote cache will not register a listener with the remote
+ * server. This allows you to configure a remote server as a repository from which you can get
+ * and to which you put, but from which you do not receive any notifications. That is, you will
+ * not receive updates or removes.
+ * <p>
+ * If you set this option to false, you should set your local memory size to 0.
+ * <p>
+ * The remote cache manager uses this value to decide whether or not to register a listener.
+ * @return the receive value.
+ */
+ @Override
+ public boolean isReceive()
+ {
+ return this.receive;
+ }
+
+ /**
+ * The number of elements the zombie queue will hold. This queue is used to store events if we
+ * loose our connection with the server.
+ * <p>
+ * @param zombieQueueMaxSize The zombieQueueMaxSize to set.
+ */
+ @Override
+ public void setZombieQueueMaxSize( int zombieQueueMaxSize )
+ {
+ this.zombieQueueMaxSize = zombieQueueMaxSize;
+ }
+
+ /**
+ * The number of elements the zombie queue will hold. This queue is used to store events if we
+ * loose our connection with the server.
+ * <p>
+ * @return Returns the zombieQueueMaxSize.
+ */
+ @Override
+ public int getZombieQueueMaxSize()
+ {
+ return zombieQueueMaxSize;
+ }
+
+ /**
+ * @return String, all the important values that can be configured
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder(super.toString());
+ buf.append( "\n receive = [" + isReceive() + "]" );
+ buf.append( "\n getTimeoutMillis = [" + getGetTimeoutMillis() + "]" );
+ buf.append( "\n threadPoolName = [" + getThreadPoolName() + "]" );
+ buf.append( "\n localClusterConsistency = [" + isLocalClusterConsistency() + "]" );
+ buf.append( "\n zombieQueueMaxSize = [" + getZombieQueueMaxSize() + "]" );
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheFactory.java
new file mode 100644
index 0000000..cbf76d9
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheFactory.java
@@ -0,0 +1,272 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.rmi.registry.Registry;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheFactory;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.server.behavior.RemoteType;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+
+/**
+ * The RemoteCacheFactory creates remote caches for the cache hub. It returns a no wait facade which
+ * is a wrapper around a no wait. The no wait object is either an active connection to a remote
+ * cache or a balking zombie if the remote cache is not accessible. It should be transparent to the
+ * clients.
+ */
+public class RemoteCacheFactory
+ extends AbstractAuxiliaryCacheFactory
+{
+ /** Monitor thread */
+ private RemoteCacheMonitor monitor;
+
+ /** Contains mappings of RemoteLocation instance to RemoteCacheManager instance. */
+ private ConcurrentMap<RemoteLocation, RemoteCacheManager> managers;
+
+ /** Lock for initialization of manager instances */
+ private Lock managerLock;
+
+ /**
+ * For LOCAL clients we get a handle to all the failovers, but we do not register a listener
+ * with them. We create the RemoteCacheManager, but we do not get a cache.
+ * <p>
+ * The failover runner will get a cache from the manager. When the primary is restored it will
+ * tell the manager for the failover to deregister the listener.
+ * <p>
+ * @param iaca
+ * @param cacheMgr
+ * @param cacheEventLogger
+ * @param elementSerializer
+ * @return AuxiliaryCache
+ */
+ @Override
+ public <K, V> AuxiliaryCache<K, V> createCache(
+ AuxiliaryCacheAttributes iaca, ICompositeCacheManager cacheMgr,
+ ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
+ {
+ RemoteCacheAttributes rca = (RemoteCacheAttributes) iaca;
+
+ ArrayList<RemoteCacheNoWait<K,V>> noWaits = new ArrayList<>();
+
+ switch (rca.getRemoteType())
+ {
+ case LOCAL:
+ // a list to be turned into an array of failover server information
+ ArrayList<RemoteLocation> failovers = new ArrayList<>();
+
+ // not necessary if a failover list is defined
+ // REGISTER PRIMARY LISTENER
+ // if it is a primary
+ boolean primaryDefined = false;
+ if ( rca.getRemoteLocation() != null )
+ {
+ primaryDefined = true;
+
+ failovers.add( rca.getRemoteLocation() );
+ RemoteCacheManager rcm = getManager( rca, cacheMgr, cacheEventLogger, elementSerializer );
+ RemoteCacheNoWait<K,V> ic = rcm.getCache( rca );
+ noWaits.add( ic );
+ }
+
+ // GET HANDLE BUT DONT REGISTER A LISTENER FOR FAILOVERS
+ String failoverList = rca.getFailoverServers();
+ if ( failoverList != null )
+ {
+ StringTokenizer fit = new StringTokenizer( failoverList, "," );
+ int fCnt = 0;
+ while ( fit.hasMoreTokens() )
+ {
+ fCnt++;
+
+ String server = fit.nextToken();
+ RemoteLocation location = RemoteLocation.parseServerAndPort(server);
+
+ if (location != null)
+ {
+ failovers.add( location );
+ rca.setRemoteLocation(location);
+ RemoteCacheManager rcm = getManager( rca, cacheMgr, cacheEventLogger, elementSerializer );
+
+ // add a listener if there are none, need to tell rca what
+ // number it is at
+ if ( ( !primaryDefined && fCnt == 1 ) || noWaits.size() <= 0 )
+ {
+ RemoteCacheNoWait<K,V> ic = rcm.getCache( rca );
+ noWaits.add( ic );
+ }
+ }
+ }
+ // end while
+ }
+ // end if failoverList != null
+
+ rca.setFailovers( failovers );
+ break;
+
+ case CLUSTER:
+ // REGISTER LISTENERS FOR EACH SYSTEM CLUSTERED CACHEs
+ StringTokenizer it = new StringTokenizer( rca.getClusterServers(), "," );
+ while ( it.hasMoreElements() )
+ {
+ String server = (String) it.nextElement();
+ RemoteLocation location = RemoteLocation.parseServerAndPort(server);
+
+ if (location != null)
+ {
+ rca.setRemoteLocation(location);
+ RemoteCacheManager rcm = getManager( rca, cacheMgr, cacheEventLogger, elementSerializer );
+ rca.setRemoteType( RemoteType.CLUSTER );
+ RemoteCacheNoWait<K,V> ic = rcm.getCache( rca );
+ noWaits.add( ic );
+ }
+ }
+ break;
+ }
+
+ RemoteCacheNoWaitFacade<K, V> rcnwf =
+ new RemoteCacheNoWaitFacade<>(noWaits, rca, cacheEventLogger, elementSerializer, this );
+
+ return rcnwf;
+ }
+
+ // end createCache
+
+ /**
+ * Returns an instance of RemoteCacheManager for the given connection parameters.
+ * <p>
+ * Host and Port uniquely identify a manager instance.
+ * <p>
+ * @param cattr
+ *
+ * @return The instance value or null if no such manager exists
+ */
+ public RemoteCacheManager getManager( IRemoteCacheAttributes cattr )
+ {
+ if ( cattr.getRemoteLocation() == null )
+ {
+ cattr.setRemoteLocation("", Registry.REGISTRY_PORT);
+ }
+
+ RemoteLocation loc = cattr.getRemoteLocation();
+ RemoteCacheManager ins = managers.get( loc );
+
+ return ins;
+ }
+
+ /**
+ * Returns an instance of RemoteCacheManager for the given connection parameters.
+ * <p>
+ * Host and Port uniquely identify a manager instance.
+ * <p>
+ * If the connection cannot be established, zombie objects will be used for future recovery
+ * purposes.
+ * <p>
+ * @param cattr
+ * @param cacheMgr
+ * @param cacheEventLogger
+ * @param elementSerializer
+ * @return The instance value, never null
+ */
+ public RemoteCacheManager getManager( IRemoteCacheAttributes cattr, ICompositeCacheManager cacheMgr,
+ ICacheEventLogger cacheEventLogger,
+ IElementSerializer elementSerializer )
+ {
+ RemoteCacheManager ins = getManager( cattr );
+
+ if ( ins == null )
+ {
+ managerLock.lock();
+
+ try
+ {
+ ins = managers.get( cattr.getRemoteLocation() );
+
+ if (ins == null)
+ {
+ ins = new RemoteCacheManager( cattr, cacheMgr, monitor, cacheEventLogger, elementSerializer);
+ managers.put( cattr.getRemoteLocation(), ins );
+ monitor.addManager(ins);
+ }
+ }
+ finally
+ {
+ managerLock.unlock();
+ }
+ }
+
+ return ins;
+ }
+
+ /**
+ * @see org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheFactory#initialize()
+ */
+ @Override
+ public void initialize()
+ {
+ super.initialize();
+
+ managers = new ConcurrentHashMap<>();
+ managerLock = new ReentrantLock();
+
+ monitor = new RemoteCacheMonitor();
+ monitor.setDaemon(true);
+ }
+
+ /**
+ * @see org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheFactory#dispose()
+ */
+ @Override
+ public void dispose()
+ {
+ for (RemoteCacheManager manager : managers.values())
+ {
+ manager.release();
+ }
+
+ managers.clear();
+
+ if (monitor != null)
+ {
+ monitor.notifyShutdown();
+ try
+ {
+ monitor.join(5000);
+ }
+ catch (InterruptedException e)
+ {
+ // swallow
+ }
+ monitor = null;
+ }
+
+ super.dispose();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheFailoverRunner.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheFailoverRunner.java
new file mode 100644
index 0000000..909bf6b
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheFailoverRunner.java
@@ -0,0 +1,389 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheMonitor;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.behavior.ICache;
+
+/**
+ * The RemoteCacheFailoverRunner tries to establish a connection with a failover
+ * server, if any are defined. Once a failover connection is made, it will
+ * attempt to replace the failover with the primary remote server.
+ * <p>
+ * It works by switching out the RemoteCacheNoWait inside the Facade.
+ * <p>
+ * Client (i.e.) the CompositeCache has reference to a RemoteCacheNoWaitFacade.
+ * This facade is created by the RemoteCacheFactory. The factory maintains a set
+ * of managers, one for each remote server. Typically, there will only be one
+ * manager.
+ * <p>
+ * If you use multiple remote servers, you may want to set one or more as
+ * failovers. If a local cache cannot connect to the primary server, or looses
+ * its connection to the primary server, it will attempt to restore that
+ * Connection in the background. If failovers are defined, the Failover runner
+ * will try to connect to a failover until the primary is restored.
+ *
+ */
+public class RemoteCacheFailoverRunner<K, V> extends AbstractAuxiliaryCacheMonitor
+{
+ /** The facade returned to the composite cache. */
+ private final RemoteCacheNoWaitFacade<K, V> facade;
+
+ /** Factory instance */
+ private final RemoteCacheFactory cacheFactory;
+
+ /**
+ * Constructor for the RemoteCacheFailoverRunner object. This allows the
+ * FailoverRunner to modify the facade that the CompositeCache references.
+ *
+ * @param facade the facade the CompositeCache talks to.
+ * @param cacheFactory the cache factory instance
+ */
+ public RemoteCacheFailoverRunner( RemoteCacheNoWaitFacade<K, V> facade, RemoteCacheFactory cacheFactory )
+ {
+ super("JCS-RemoteCacheFailoverRunner");
+ this.facade = facade;
+ this.cacheFactory = cacheFactory;
+ setIdlePeriod(20000L);
+ }
+
+ /**
+ * Clean up all resources before shutdown
+ */
+ @Override
+ protected void dispose()
+ {
+ // empty
+ }
+
+ /**
+ * do actual work
+ */
+ @Override
+ protected void doWork()
+ {
+ // empty
+ }
+
+
+ /**
+ * Main processing method for the RemoteCacheFailoverRunner object.
+ * <p>
+ * If we do not have a connection with any failover server, this will try to
+ * connect one at a time. If no connection can be made, it goes to sleep for
+ * a while (20 seconds).
+ * <p>
+ * Once a connection with a failover is made, we will try to reconnect to
+ * the primary server.
+ * <p>
+ * The primary server is the first server defines in the FailoverServers
+ * list.
+ */
+ @Override
+ public void run()
+ {
+ // start the main work of connecting to a failover and then restoring
+ // the primary.
+ connectAndRestore();
+
+ if ( log.isInfoEnabled() )
+ {
+ int failoverIndex = facade.getAuxiliaryCacheAttributes().getFailoverIndex();
+ log.info( "Exiting failover runner. Failover index = {0}", failoverIndex);
+
+ if ( failoverIndex <= 0 )
+ {
+ log.info( "Failover index is <= 0, meaning we are not connected to a failover server." );
+ }
+ else if ( failoverIndex > 0 )
+ {
+ log.info( "Failover index is > 0, meaning we are connected to a failover server." );
+ }
+ // log if we are allright or not.
+ }
+ }
+
+ /**
+ * This is the main loop. If there are failovers defined, then this will
+ * continue until the primary is re-connected. If no failovers are defined,
+ * this will exit automatically.
+ */
+ private void connectAndRestore()
+ {
+ IRemoteCacheAttributes rca0 = facade.getAuxiliaryCacheAttributes();
+
+ do
+ {
+ log.info( "Remote cache FAILOVER RUNNING." );
+
+ // there is no active listener
+ if ( !allright.get() )
+ {
+ // Monitor each RemoteCacheManager instance one after the other.
+ // Each RemoteCacheManager corresponds to one remote connection.
+ List<RemoteLocation> failovers = rca0.getFailovers();
+ // we should probably check to see if there are any failovers,
+ // even though the caller
+ // should have already.
+
+ if ( failovers == null )
+ {
+ log.warn( "Remote is misconfigured, failovers was null." );
+ return;
+ }
+ else if ( failovers.size() == 1 )
+ {
+ // if there is only the primary, return out of this
+ log.info( "No failovers defined, exiting failover runner." );
+ return;
+ }
+
+ int fidx = rca0.getFailoverIndex();
+ log.debug( "fidx = {0} failovers.size = {1}", () -> fidx,
+ () -> failovers.size() );
+
+ // shouldn't we see if the primary is backup?
+ // If we don't check the primary, if it gets connected in the
+ // background,
+ // we will disconnect it only to put it right back
+ ListIterator<RemoteLocation> i = failovers.listIterator(fidx); // + 1; // +1 skips the primary
+ log.debug( "starting at failover i = {0}", i );
+
+ // try them one at a time until successful
+ for ( ; i.hasNext() && !allright.get();)
+ {
+ RemoteLocation server = i.next();
+ log.debug( "Trying server [{1}] at failover index i = {1}",
+ server, i );
+
+ RemoteCacheAttributes rca = (RemoteCacheAttributes) rca0.clone();
+ rca.setRemoteLocation(server);
+ RemoteCacheManager rcm = cacheFactory.getManager( rca );
+
+ log.debug( "RemoteCacheAttributes for failover = {0}", rca );
+
+ if (rcm != null)
+ {
+ // add a listener if there are none, need to tell rca
+ // what number it is at
+ ICache<K, V> ic = rcm.getCache( rca );
+ if ( ic.getStatus() == CacheStatus.ALIVE )
+ {
+ // may need to do this more gracefully
+ log.debug( "resetting no wait" );
+ facade.restorePrimaryServer((RemoteCacheNoWait<K, V>) ic);
+ rca0.setFailoverIndex( i.nextIndex() );
+
+ log.debug( "setting ALLRIGHT to true" );
+ if ( i.hasPrevious() )
+ {
+ log.debug( "Moving to Primary Recovery Mode, failover index = {0}", i );
+ }
+ else
+ {
+ log.debug( "No need to connect to failover, the primary server is back up." );
+ }
+
+ allright.set(true);
+
+ log.info( "CONNECTED to host = [{0}]",
+ () -> rca.getRemoteLocation() );
+ }
+ }
+ }
+ }
+ // end if !allright
+ // get here if while index >0 and allright, meaning that we are
+ // connected to some backup server.
+ else
+ {
+ log.debug( "ALLRIGHT is true " );
+ log.info( "Failover runner is in primary recovery mode. "
+ + "Failover index = {0} Will now try to reconnect to "
+ + "primary server.", () -> rca0.getFailoverIndex() );
+ }
+
+ boolean primaryRestoredSuccessfully = false;
+ // if we are not connected to the primary, try.
+ if ( rca0.getFailoverIndex() > 0 )
+ {
+ primaryRestoredSuccessfully = restorePrimary();
+ log.debug( "Primary recovery success state = {0}",
+ primaryRestoredSuccessfully );
+ }
+
+ if ( !primaryRestoredSuccessfully )
+ {
+ // Time driven mode: sleep between each round of recovery
+ // attempt.
+ try
+ {
+ log.warn( "Failed to reconnect to primary server. "
+ + "Cache failover runner is going to sleep for "
+ + "{0} milliseconds.", idlePeriod );
+ Thread.sleep( idlePeriod );
+ }
+ catch ( InterruptedException ex )
+ {
+ // ignore;
+ }
+ }
+
+ // try to bring the listener back to the primary
+ }
+ while ( rca0.getFailoverIndex() > 0 || !allright.get() );
+ // continue if the primary is not restored or if things are not allright.
+ }
+
+ /**
+ * Try to restore the primary server.
+ * <p>
+ * Once primary is restored the failover listener must be deregistered.
+ * <p>
+ * The primary server is the first server defines in the FailoverServers
+ * list.
+ *
+ * @return boolean value indicating whether the restoration was successful
+ */
+ private boolean restorePrimary()
+ {
+ IRemoteCacheAttributes rca0 = facade.getAuxiliaryCacheAttributes();
+ // try to move back to the primary
+ RemoteLocation server = rca0.getFailovers().get(0);
+
+ log.info( "Trying to restore connection to primary remote server "
+ + "[{0}]", server );
+
+ RemoteCacheAttributes rca = (RemoteCacheAttributes) rca0.clone();
+ rca.setRemoteLocation(server);
+ RemoteCacheManager rcm = cacheFactory.getManager( rca );
+
+ if (rcm != null)
+ {
+ // add a listener if there are none, need to tell rca what number it
+ // is at
+ ICache<K, V> ic = rcm.getCache( rca );
+ // by default the listener id should be 0, else it will be the
+ // listener
+ // Originally associated with the remote cache. either way is fine.
+ // We just don't want the listener id from a failover being used.
+ // If the remote server was rebooted this could be a problem if new
+ // locals were also added.
+
+ if ( ic.getStatus() == CacheStatus.ALIVE )
+ {
+ try
+ {
+ // we could have more than one listener registered right
+ // now.
+ // this will not result in a loop, only duplication
+ // stop duplicate listening.
+ if ( facade.getPrimaryServer() != null && facade.getPrimaryServer().getStatus() == CacheStatus.ALIVE )
+ {
+ int fidx = rca0.getFailoverIndex();
+
+ if ( fidx > 0 )
+ {
+ RemoteLocation serverOld = rca0.getFailovers().get(fidx);
+
+ log.debug( "Failover Index = {0} the server at that "
+ + "index is [{1}]", fidx, serverOld );
+
+ if ( serverOld != null )
+ {
+ // create attributes that reflect the
+ // previous failed over configuration.
+ RemoteCacheAttributes rcaOld = (RemoteCacheAttributes) rca0.clone();
+ rcaOld.setRemoteLocation(serverOld);
+ RemoteCacheManager rcmOld = cacheFactory.getManager( rcaOld );
+
+ if ( rcmOld != null )
+ {
+ // manager can remove by name if
+ // necessary
+ rcmOld.removeRemoteCacheListener( rcaOld );
+ }
+ log.info( "Successfully deregistered from "
+ + "FAILOVER remote server = {0}", serverOld );
+ }
+ }
+ else if ( fidx == 0 )
+ {
+ // this should never happen. If there are no
+ // failovers this shouldn't get called.
+ if ( log.isDebugEnabled() )
+ {
+ log.debug( "No need to restore primary, it is already restored." );
+ return true;
+ }
+ }
+ else if ( fidx < 0 )
+ {
+ // this should never happen
+ log.warn( "Failover index is less than 0, this shouldn't happen" );
+ }
+ }
+ }
+ catch ( IOException e )
+ {
+ // TODO, should try again, or somehow stop the listener
+ log.error("Trouble trying to deregister old failover "
+ + "listener prior to restoring the primary = {0}",
+ server, e );
+ }
+
+ // Restore primary
+ // may need to do this more gracefully, letting the failover finish in the background
+ RemoteCacheNoWait<K, V> failoverNoWait = facade.getPrimaryServer();
+
+ // swap in a new one
+ facade.restorePrimaryServer((RemoteCacheNoWait<K, V>) ic);
+ rca0.setFailoverIndex( 0 );
+
+ String message = "Successfully reconnected to PRIMARY "
+ + "remote server. Substituted primary for "
+ + "failoverNoWait [" + failoverNoWait + "]";
+ log.info( message );
+
+ if ( facade.getCacheEventLogger() != null )
+ {
+ facade.getCacheEventLogger().logApplicationEvent(
+ "RemoteCacheFailoverRunner", "RestoredPrimary",
+ message );
+ }
+ return true;
+ }
+ }
+
+ // else all right
+ // if the failover index was at 0 here, we would be in a bad
+ // situation, unless there were just
+ // no failovers configured.
+ log.debug( "Primary server status in error, not connected." );
+
+ return false;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheListener.java
new file mode 100644
index 0000000..4b5a93b
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheListener.java
@@ -0,0 +1,115 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheConstants;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * Registered with RemoteCache server. The server updates the local caches via this listener. Each
+ * server assigns a unique listener id for a listener.
+ * <p>
+ * One listener is used per remote cache server. The same listener is used for all the regions that
+ * talk to a particular server.
+ */
+public class RemoteCacheListener<K, V>
+ extends AbstractRemoteCacheListener<K, V>
+ implements IRemoteCacheConstants
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( RemoteCacheListener.class );
+
+ /** Has this client been shutdown. */
+ private boolean disposed = false;
+
+ /**
+ * Only need one since it does work for all regions, just reference by multiple region names.
+ * <p>
+ * The constructor exports this object, making it available to receive incoming calls. The
+ * callback port is anonymous unless a local port value was specified in the configuration.
+ * <p>
+ * @param irca cache configuration
+ * @param cacheMgr the cache hub
+ * @param elementSerializer a custom serializer
+ */
+ public RemoteCacheListener( IRemoteCacheAttributes irca, ICompositeCacheManager cacheMgr, IElementSerializer elementSerializer )
+ {
+ super( irca, cacheMgr, elementSerializer );
+
+ // Export this remote object to make it available to receive incoming
+ // calls.
+ try
+ {
+ UnicastRemoteObject.exportObject( this, irca.getLocalPort() );
+ }
+ catch ( RemoteException ex )
+ {
+ log.error( "Problem exporting object.", ex );
+ throw new IllegalStateException( ex.getMessage() );
+ }
+ }
+
+ /**
+ * Deregister itself.
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ public synchronized void dispose()
+ throws IOException
+ {
+ if ( !disposed )
+ {
+ log.info( "Unexporting listener." );
+ try
+ {
+ UnicastRemoteObject.unexportObject( this, true );
+ }
+ catch ( RemoteException ex )
+ {
+ log.error( "Problem unexporting the listener.", ex );
+ throw new IllegalStateException( ex.getMessage() );
+ }
+ disposed = true;
+ }
+ }
+
+ /**
+ * For easier debugging.
+ * <p>
+ * @return Basic info on this listener.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\n RemoteCacheListener: " );
+ buf.append( super.toString() );
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheManager.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheManager.java
new file mode 100644
index 0000000..84119e2
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheManager.java
@@ -0,0 +1,348 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.rmi.Naming;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheClient;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheListener;
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.CacheWatchRepairable;
+import org.apache.commons.jcs3.engine.ZombieCacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.ZombieCacheWatch;
+import org.apache.commons.jcs3.engine.behavior.ICacheObserver;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * An instance of RemoteCacheManager corresponds to one remote connection of a specific host and
+ * port. All RemoteCacheManager instances are monitored by the singleton RemoteCacheMonitor
+ * monitoring daemon for error detection and recovery.
+ * <p>
+ * Getting an instance of the remote cache has the effect of getting a handle on the remote server.
+ * Listeners are not registered with the server until a cache is requested from the manager.
+ */
+public class RemoteCacheManager
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( RemoteCacheManager.class );
+
+ /** Contains instances of RemoteCacheNoWait managed by a RemoteCacheManager instance. */
+ private final ConcurrentMap<String, RemoteCacheNoWait<?, ?>> caches =
+ new ConcurrentHashMap<>();
+
+ /** The event logger. */
+ private final ICacheEventLogger cacheEventLogger;
+
+ /** The serializer. */
+ private final IElementSerializer elementSerializer;
+
+ /** Handle to the remote cache service; or a zombie handle if failed to connect. */
+ private ICacheServiceNonLocal<?, ?> remoteService;
+
+ /**
+ * Wrapper of the remote cache watch service; or wrapper of a zombie service if failed to
+ * connect.
+ */
+ private final CacheWatchRepairable remoteWatch;
+
+ /** The cache manager listeners will need to use to get a cache. */
+ private final ICompositeCacheManager cacheMgr;
+
+ /** For error notification */
+ private final RemoteCacheMonitor monitor;
+
+ /** The service found through lookup */
+ private final String registry;
+
+ /** can it be restored */
+ private boolean canFix = true;
+
+ /**
+ * Constructs an instance to with the given remote connection parameters. If the connection
+ * cannot be made, "zombie" services will be temporarily used until a successful re-connection
+ * is made by the monitoring daemon.
+ * <p>
+ * @param cattr cache attributes
+ * @param cacheMgr the cache hub
+ * @param monitor the cache monitor thread for error notifications
+ * @param cacheEventLogger
+ * @param elementSerializer
+ */
+ protected RemoteCacheManager( IRemoteCacheAttributes cattr, ICompositeCacheManager cacheMgr,
+ RemoteCacheMonitor monitor,
+ ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer)
+ {
+ this.cacheMgr = cacheMgr;
+ this.monitor = monitor;
+ this.cacheEventLogger = cacheEventLogger;
+ this.elementSerializer = elementSerializer;
+ this.remoteWatch = new CacheWatchRepairable();
+
+ this.registry = RemoteUtils.getNamingURL(cattr.getRemoteLocation(), cattr.getRemoteServiceName());
+
+ try
+ {
+ lookupRemoteService();
+ }
+ catch (IOException e)
+ {
+ log.error("Could not find server", e);
+ // Notify the cache monitor about the error, and kick off the
+ // recovery process.
+ monitor.notifyError();
+ }
+ }
+
+ /**
+ * Lookup remote service from registry
+ * @throws IOException if the remote service could not be found
+ *
+ */
+ protected void lookupRemoteService() throws IOException
+ {
+ log.info( "Looking up server [{0}]", registry );
+ try
+ {
+ Object obj = Naming.lookup( registry );
+ log.info( "Server found: {0}", obj );
+
+ // Successful connection to the remote server.
+ this.remoteService = (ICacheServiceNonLocal<?, ?>) obj;
+ log.debug( "Remote Service = {0}", remoteService );
+ remoteWatch.setCacheWatch( (ICacheObserver) remoteService );
+ }
+ catch ( Exception ex )
+ {
+ // Failed to connect to the remote server.
+ // Configure this RemoteCacheManager instance to use the "zombie"
+ // services.
+ this.remoteService = new ZombieCacheServiceNonLocal<>();
+ remoteWatch.setCacheWatch( new ZombieCacheWatch() );
+ throw new IOException( "Problem finding server at [" + registry + "]", ex );
+ }
+ }
+
+ /**
+ * Adds the remote cache listener to the underlying cache-watch service.
+ * <p>
+ * @param cattr The feature to be added to the RemoteCacheListener attribute
+ * @param listener The feature to be added to the RemoteCacheListener attribute
+ * @throws IOException
+ */
+ public <K, V> void addRemoteCacheListener( IRemoteCacheAttributes cattr, IRemoteCacheListener<K, V> listener )
+ throws IOException
+ {
+ if ( cattr.isReceive() )
+ {
+ log.info( "The remote cache is configured to receive events from the remote server. "
+ + "We will register a listener. remoteWatch = {0} | IRemoteCacheListener = {1}"
+ + " | cacheName ", remoteWatch, listener, cattr.getCacheName() );
+
+ remoteWatch.addCacheListener( cattr.getCacheName(), listener );
+ }
+ else
+ {
+ log.info( "The remote cache is configured to NOT receive events from the remote server. "
+ + "We will NOT register a listener." );
+ }
+ }
+
+ /**
+ * Removes a listener. When the primary recovers the failover must deregister itself for a
+ * region. The failover runner will call this method to de-register. We do not want to deregister
+ * all listeners to a remote server, in case a failover is a primary of another region. Having
+ * one regions failover act as another servers primary is not currently supported.
+ * <p>
+ * @param cattr
+ * @throws IOException
+ */
+ public void removeRemoteCacheListener( IRemoteCacheAttributes cattr )
+ throws IOException
+ {
+ RemoteCacheNoWait<?, ?> cache = caches.get( cattr.getCacheName() );
+ if ( cache != null )
+ {
+ removeListenerFromCache(cache);
+ }
+ else
+ {
+ if ( cattr.isReceive() )
+ {
+ log.warn( "Trying to deregister Cache Listener that was never registered." );
+ }
+ else
+ {
+ log.debug( "Since the remote cache is configured to not receive, "
+ + "there is no listener to deregister." );
+ }
+ }
+ }
+
+ // common helper method
+ private void removeListenerFromCache(RemoteCacheNoWait<?, ?> cache) throws IOException
+ {
+ IRemoteCacheClient<?, ?> rc = cache.getRemoteCache();
+ log.debug( "Found cache for [{0}], deregistering listener.",
+ () -> cache.getCacheName() );
+ // could also store the listener for a server in the manager.
+ IRemoteCacheListener<?, ?> listener = rc.getListener();
+ remoteWatch.removeCacheListener( cache.getCacheName(), listener );
+ }
+
+ /**
+ * Gets a RemoteCacheNoWait from the RemoteCacheManager. The RemoteCacheNoWait objects are
+ * identified by the cache name value of the RemoteCacheAttributes object.
+ * <p>
+ * If the client is configured to register a listener, this call results on a listener being
+ * created if one isn't already registered with the remote cache for this region.
+ * <p>
+ * @param cattr
+ * @return The cache value
+ */
+ @SuppressWarnings("unchecked") // Need to cast because of common map for all caches
+ public <K, V> RemoteCacheNoWait<K, V> getCache( IRemoteCacheAttributes cattr )
+ {
+ RemoteCacheNoWait<K, V> remoteCacheNoWait =
+ (RemoteCacheNoWait<K, V>) caches.computeIfAbsent(cattr.getCacheName(), key -> {
+ return newRemoteCacheNoWait(cattr);
+ });
+
+ // might want to do some listener sanity checking here.
+ return remoteCacheNoWait;
+ }
+
+ /**
+ * Create new RemoteCacheNoWait instance
+ *
+ * @param cattr the cache configuration
+ * @return the instance
+ */
+ protected <K, V> RemoteCacheNoWait<K, V> newRemoteCacheNoWait(IRemoteCacheAttributes cattr)
+ {
+ RemoteCacheNoWait<K, V> remoteCacheNoWait;
+ // create a listener first and pass it to the remotecache
+ // sender.
+ RemoteCacheListener<K, V> listener = null;
+ try
+ {
+ listener = new RemoteCacheListener<>( cattr, cacheMgr, elementSerializer );
+ addRemoteCacheListener( cattr, listener );
+ }
+ catch ( Exception e )
+ {
+ log.error( "Problem adding listener. RemoteCacheListener = {0}",
+ listener, e );
+ }
+
+ IRemoteCacheClient<K, V> remoteCacheClient =
+ new RemoteCache<>( cattr, (ICacheServiceNonLocal<K, V>) remoteService, listener, monitor );
+ remoteCacheClient.setCacheEventLogger( cacheEventLogger );
+ remoteCacheClient.setElementSerializer( elementSerializer );
+
+ remoteCacheNoWait = new RemoteCacheNoWait<>( remoteCacheClient );
+ remoteCacheNoWait.setCacheEventLogger( cacheEventLogger );
+ remoteCacheNoWait.setElementSerializer( elementSerializer );
+
+ return remoteCacheNoWait;
+ }
+
+ /** Shutdown all. */
+ public void release()
+ {
+ for (RemoteCacheNoWait<?, ?> c : caches.values())
+ {
+ try
+ {
+ log.info( "freeCache [{0}]", () -> c.getCacheName() );
+
+ removeListenerFromCache(c);
+ c.dispose();
+ }
+ catch ( IOException ex )
+ {
+ log.error( "Problem releasing {0}", c.getCacheName(), ex );
+ }
+ }
+
+ caches.clear();
+ }
+
+ /**
+ * Fixes up all the caches managed by this cache manager.
+ */
+ public void fixCaches()
+ {
+ if ( !canFix )
+ {
+ return;
+ }
+
+ log.info( "Fixing caches. ICacheServiceNonLocal {0} | IRemoteCacheObserver {1}",
+ remoteService, remoteWatch );
+
+ for (RemoteCacheNoWait<?, ?> c : caches.values())
+ {
+ if (c.getStatus() == CacheStatus.ERROR)
+ {
+ c.fixCache( remoteService );
+ }
+ }
+
+ if ( log.isInfoEnabled() )
+ {
+ String msg = "Remote connection to " + registry + " resumed.";
+ if ( cacheEventLogger != null )
+ {
+ cacheEventLogger.logApplicationEvent( "RemoteCacheManager", "fix", msg );
+ }
+ log.info( msg );
+ }
+ }
+
+ /**
+ * Returns true if the connection to the remote host can be
+ * successfully re-established.
+ * <p>
+ * @return true if we found a failover server
+ */
+ public boolean canFixCaches()
+ {
+ try
+ {
+ lookupRemoteService();
+ }
+ catch (IOException e)
+ {
+ log.error("Could not find server", e);
+ canFix = false;
+ }
+
+ return canFix;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheMonitor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheMonitor.java
new file mode 100644
index 0000000..8ef72ef
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheMonitor.java
@@ -0,0 +1,100 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheMonitor;
+
+/**
+ * Used to monitor and repair any failed connection for the remote cache service. By default the
+ * monitor operates in a failure driven mode. That is, it goes into a wait state until there is an
+ * error.
+ *
+ * TODO consider moving this into an active monitoring mode. Upon the notification of a
+ * connection error, the monitor changes to operate in a time driven mode. That is, it attempts to
+ * recover the connections on a periodic basis. When all failed connections are restored, it changes
+ * back to the failure driven mode.
+ */
+public class RemoteCacheMonitor extends AbstractAuxiliaryCacheMonitor
+{
+ /**
+ * Map of managers to monitor
+ */
+ private final ConcurrentHashMap<RemoteCacheManager, RemoteCacheManager> managers;
+
+ /** Constructor for the RemoteCacheMonitor object */
+ public RemoteCacheMonitor()
+ {
+ super("JCS-RemoteCacheMonitor");
+ this.managers = new ConcurrentHashMap<>();
+ setIdlePeriod(30000L);
+ }
+
+ /**
+ * Add a manager to be monitored
+ *
+ * @param manager the remote cache manager
+ */
+ public void addManager(RemoteCacheManager manager)
+ {
+ this.managers.put(manager, manager);
+
+ // if not yet started, go ahead
+ if (this.getState() == Thread.State.NEW)
+ {
+ this.start();
+ }
+ }
+
+ /**
+ * Clean up all resources before shutdown
+ */
+ @Override
+ public void dispose()
+ {
+ this.managers.clear();
+ }
+
+ // Avoid the use of any synchronization in the process of monitoring for
+ // performance reason.
+ // If exception is thrown owing to synchronization,
+ // just skip the monitoring until the next round.
+ /** Main processing method for the RemoteCacheMonitor object */
+ @Override
+ public void doWork()
+ {
+ // Monitor each RemoteCacheManager instance one after the other.
+ // Each RemoteCacheManager corresponds to one remote connection.
+ for (RemoteCacheManager mgr : managers.values())
+ {
+ // If we can't fix them, just skip and re-try in
+ // the next round.
+ if ( mgr.canFixCaches() )
+ {
+ mgr.fixCaches();
+ }
+ else
+ {
+ allright.set(false);
+ }
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheNoWait.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheNoWait.java
new file mode 100644
index 0000000..bf683a9
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheNoWait.java
@@ -0,0 +1,517 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.rmi.UnmarshalException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheClient;
+import org.apache.commons.jcs3.engine.CacheAdaptor;
+import org.apache.commons.jcs3.engine.CacheEventQueueFactory;
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheEventQueue;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.stats.StatElement;
+import org.apache.commons.jcs3.engine.stats.Stats;
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * The RemoteCacheNoWait wraps the RemoteCacheClient. The client holds a handle on the
+ * RemoteCacheService.
+ * <p>
+ * Used to queue up update requests to the underlying cache. These requests will be processed in
+ * their order of arrival via the cache event queue processor.
+ * <p>
+ * Typically errors will be handled down stream. We only need to kill the queue if an error makes it
+ * to this level from the queue. That can only happen if the queue is damaged, since the events are
+ * Processed asynchronously.
+ * <p>
+ * There is no reason to create a queue on startup if the remote is not healthy.
+ * <p>
+ * If the remote cache encounters an error it will zombie--create a balking facade for the service.
+ * The Zombie will queue up items until the connection is restored. An alternative way to accomplish
+ * the same thing would be to stop, not destroy the queue at this level. That way items would be
+ * added to the queue and then when the connection is restored, we could start the worker threads
+ * again. This is a better long term solution, but it requires some significant changes to the
+ * complicated worker queues.
+ */
+public class RemoteCacheNoWait<K, V>
+ extends AbstractAuxiliaryCache<K, V>
+{
+ /** log instance */
+ private static final Log log = LogManager.getLog( RemoteCacheNoWait.class );
+
+ /** The remote cache client */
+ private final IRemoteCacheClient<K, V> remoteCacheClient;
+
+ /** Event queue for queuing up calls like put and remove. */
+ private ICacheEventQueue<K, V> cacheEventQueue;
+
+ /** how many times get has been called. */
+ private int getCount = 0;
+
+ /** how many times getMatching has been called. */
+ private int getMatchingCount = 0;
+
+ /** how many times getMultiple has been called. */
+ private int getMultipleCount = 0;
+
+ /** how many times remove has been called. */
+ private int removeCount = 0;
+
+ /** how many times put has been called. */
+ private int putCount = 0;
+
+ /**
+ * Constructs with the given remote cache, and fires up an event queue for asynchronous
+ * processing.
+ * <p>
+ * @param cache
+ */
+ public RemoteCacheNoWait( IRemoteCacheClient<K, V> cache )
+ {
+ remoteCacheClient = cache;
+ this.cacheEventQueue = createCacheEventQueue(cache);
+
+ if ( remoteCacheClient.getStatus() == CacheStatus.ERROR )
+ {
+ cacheEventQueue.destroy();
+ }
+ }
+
+ /**
+ * Create a cache event queue from the parameters of the remote client
+ * @param client the remote client
+ */
+ private ICacheEventQueue<K, V> createCacheEventQueue( IRemoteCacheClient<K, V> client )
+ {
+ CacheEventQueueFactory<K, V> factory = new CacheEventQueueFactory<>();
+ ICacheEventQueue<K, V> ceq = factory.createCacheEventQueue(
+ new CacheAdaptor<>( client ),
+ client.getListenerId(),
+ client.getCacheName(),
+ client.getAuxiliaryCacheAttributes().getEventQueuePoolName(),
+ client.getAuxiliaryCacheAttributes().getEventQueueType() );
+ return ceq;
+ }
+
+ /**
+ * Adds a put event to the queue.
+ * <p>
+ * @param element
+ * @throws IOException
+ */
+ @Override
+ public void update( ICacheElement<K, V> element )
+ throws IOException
+ {
+ putCount++;
+ try
+ {
+ cacheEventQueue.addPutEvent( element );
+ }
+ catch ( IOException e )
+ {
+ log.error( "Problem adding putEvent to queue.", e );
+ cacheEventQueue.destroy();
+ throw e;
+ }
+ }
+
+ /**
+ * Synchronously reads from the remote cache.
+ * <p>
+ * @param key
+ * @return element from the remote cache, or null if not present
+ * @throws IOException
+ */
+ @Override
+ public ICacheElement<K, V> get( K key )
+ throws IOException
+ {
+ getCount++;
+ try
+ {
+ return remoteCacheClient.get( key );
+ }
+ catch ( UnmarshalException ue )
+ {
+ log.debug( "Retrying the get owing to UnmarshalException." );
+
+ try
+ {
+ return remoteCacheClient.get( key );
+ }
+ catch ( IOException ex )
+ {
+ log.info( "Failed in retrying the get for the second time. ", ex );
+ }
+ }
+ catch ( IOException ex )
+ {
+ // We don't want to destroy the queue on a get failure.
+ // The RemoteCache will Zombie and queue.
+ // Since get does not use the queue, I don't want to kill the queue.
+ throw ex;
+ }
+
+ return null;
+ }
+
+ /**
+ * @param pattern
+ * @return Map
+ * @throws IOException
+ *
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching( String pattern )
+ throws IOException
+ {
+ getMatchingCount++;
+ try
+ {
+ return remoteCacheClient.getMatching( pattern );
+ }
+ catch ( UnmarshalException ue )
+ {
+ log.debug( "Retrying the getMatching owing to UnmarshalException." );
+
+ try
+ {
+ return remoteCacheClient.getMatching( pattern );
+ }
+ catch ( IOException ex )
+ {
+ log.info( "Failed in retrying the getMatching for the second time.", ex );
+ }
+ }
+ catch ( IOException ex )
+ {
+ // We don't want to destroy the queue on a get failure.
+ // The RemoteCache will Zombie and queue.
+ // Since get does not use the queue, I don't want to kill the queue.
+ throw ex;
+ }
+
+ return Collections.emptyMap();
+ }
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys. Sends the getMultiple
+ * request on to the server rather than looping through the requested keys.
+ * <p>
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple( Set<K> keys )
+ throws IOException
+ {
+ getMultipleCount++;
+ try
+ {
+ return remoteCacheClient.getMultiple( keys );
+ }
+ catch ( UnmarshalException ue )
+ {
+ log.debug( "Retrying the getMultiple owing to UnmarshalException..." );
+
+ try
+ {
+ return remoteCacheClient.getMultiple( keys );
+ }
+ catch ( IOException ex )
+ {
+ log.info( "Failed in retrying the getMultiple for the second time.", ex );
+ }
+ }
+ catch ( IOException ex )
+ {
+ // We don't want to destroy the queue on a get failure.
+ // The RemoteCache will Zombie and queue.
+ // Since get does not use the queue, I don't want to kill the queue.
+ throw ex;
+ }
+
+ return new HashMap<>();
+ }
+
+ /**
+ * Return the keys in this cache.
+ * <p>
+ * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCache#getKeySet()
+ */
+ @Override
+ public Set<K> getKeySet() throws IOException
+ {
+ return remoteCacheClient.getKeySet();
+ }
+
+ /**
+ * Adds a remove request to the remote cache.
+ * <p>
+ * @param key
+ * @return if this was successful
+ * @throws IOException
+ */
+ @Override
+ public boolean remove( K key )
+ throws IOException
+ {
+ removeCount++;
+ try
+ {
+ cacheEventQueue.addRemoveEvent( key );
+ }
+ catch ( IOException e )
+ {
+ log.error( "Problem adding RemoveEvent to queue.", e );
+ cacheEventQueue.destroy();
+ throw e;
+ }
+ return false;
+ }
+
+ /**
+ * Adds a removeAll request to the remote cache.
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ public void removeAll()
+ throws IOException
+ {
+ try
+ {
+ cacheEventQueue.addRemoveAllEvent();
+ }
+ catch ( IOException e )
+ {
+ log.error( "Problem adding RemoveAllEvent to queue.", e );
+ cacheEventQueue.destroy();
+ throw e;
+ }
+ }
+
+ /** Adds a dispose request to the remote cache. */
+ @Override
+ public void dispose()
+ {
+ try
+ {
+ cacheEventQueue.addDisposeEvent();
+ }
+ catch ( IOException e )
+ {
+ log.error( "Problem adding DisposeEvent to queue.", e );
+ cacheEventQueue.destroy();
+ }
+ }
+
+ /**
+ * No remote invocation.
+ * <p>
+ * @return The size value
+ */
+ @Override
+ public int getSize()
+ {
+ return remoteCacheClient.getSize();
+ }
+
+ /**
+ * No remote invocation.
+ * <p>
+ * @return The cacheType value
+ */
+ @Override
+ public CacheType getCacheType()
+ {
+ return CacheType.REMOTE_CACHE;
+ }
+
+ /**
+ * Returns the asyn cache status. An error status indicates either the remote connection is not
+ * available, or the asyn queue has been unexpectedly destroyed. No remote invocation.
+ * <p>
+ * @return The status value
+ */
+ @Override
+ public CacheStatus getStatus()
+ {
+ return cacheEventQueue.isWorking() ? remoteCacheClient.getStatus() : CacheStatus.ERROR;
+ }
+
+ /**
+ * Gets the cacheName attribute of the RemoteCacheNoWait object
+ * <p>
+ * @return The cacheName value
+ */
+ @Override
+ public String getCacheName()
+ {
+ return remoteCacheClient.getCacheName();
+ }
+
+ /**
+ * Replaces the remote cache service handle with the given handle and reset the event queue by
+ * starting up a new instance.
+ * <p>
+ * @param remote
+ */
+ public void fixCache( ICacheServiceNonLocal<?, ?> remote )
+ {
+ remoteCacheClient.fixCache( remote );
+ resetEventQ();
+ }
+
+ /**
+ * Resets the event q by first destroying the existing one and starting up new one.
+ * <p>
+ * There may be no good reason to kill the existing queue. We will sometimes need to set a new
+ * listener id, so we should create a new queue. We should let the old queue drain. If we were
+ * Connected to the failover, it would be best to finish sending items.
+ */
+ public void resetEventQ()
+ {
+ ICacheEventQueue<K, V> previousQueue = cacheEventQueue;
+
+ this.cacheEventQueue = createCacheEventQueue(this.remoteCacheClient);
+
+ if ( previousQueue.isWorking() )
+ {
+ // we don't expect anything, it would have all gone to the zombie
+ log.info( "resetEventQ, previous queue has [{0}] items queued up.",
+ () -> previousQueue.size() );
+ previousQueue.destroy();
+ }
+ }
+
+ /**
+ * This is temporary. It allows the manager to get the lister.
+ * <p>
+ * @return the instance of the remote cache client used by this object
+ */
+ protected IRemoteCacheClient<K, V> getRemoteCache()
+ {
+ return remoteCacheClient;
+ }
+
+ /**
+ * @return Returns the AuxiliaryCacheAttributes.
+ */
+ @Override
+ public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
+ {
+ return remoteCacheClient.getAuxiliaryCacheAttributes();
+ }
+
+ /**
+ * This is for testing only. It allows you to take a look at the event queue.
+ * <p>
+ * @return ICacheEventQueue
+ */
+ protected ICacheEventQueue<K, V> getCacheEventQueue()
+ {
+ return this.cacheEventQueue;
+ }
+
+ /**
+ * Returns the stats and the cache.toString().
+ * <p>
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString()
+ {
+ return getStats() + "\n" + remoteCacheClient.toString();
+ }
+
+ /**
+ * Returns the statistics in String form.
+ * <p>
+ * @return String
+ */
+ @Override
+ public String getStats()
+ {
+ return getStatistics().toString();
+ }
+
+ /**
+ * @return statistics about this communication
+ */
+ @Override
+ public IStats getStatistics()
+ {
+ IStats stats = new Stats();
+ stats.setTypeName( "Remote Cache No Wait" );
+
+ ArrayList<IStatElement<?>> elems = new ArrayList<>();
+
+ elems.add(new StatElement<>( "Status", getStatus() ) );
+
+ // get the stats from the cache queue too
+ IStats cStats = this.remoteCacheClient.getStatistics();
+ if ( cStats != null )
+ {
+ elems.addAll(cStats.getStatElements());
+ }
+
+ // get the stats from the event queue too
+ IStats eqStats = this.cacheEventQueue.getStatistics();
+ elems.addAll(eqStats.getStatElements());
+
+ elems.add(new StatElement<>( "Get Count", Integer.valueOf(this.getCount) ) );
+ elems.add(new StatElement<>( "GetMatching Count", Integer.valueOf(this.getMatchingCount) ) );
+ elems.add(new StatElement<>( "GetMultiple Count", Integer.valueOf(this.getMultipleCount) ) );
+ elems.add(new StatElement<>( "Remove Count", Integer.valueOf(this.removeCount) ) );
+ elems.add(new StatElement<>( "Put Count", Integer.valueOf(this.putCount) ) );
+
+ stats.setStatElements( elems );
+
+ return stats;
+ }
+
+ /**
+ * this won't be called since we don't do ICache logging here.
+ * <p>
+ * @return String
+ */
+ @Override
+ public String getEventLoggingExtraInfo()
+ {
+ return "Remote Cache No Wait";
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheNoWaitFacade.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheNoWaitFacade.java
new file mode 100644
index 0000000..0ec1615
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheNoWaitFacade.java
@@ -0,0 +1,101 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.util.List;
+
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.server.behavior.RemoteType;
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * Used to provide access to multiple services under nowait protection. Factory should construct
+ * NoWaitFacade to give to the composite cache out of caches it constructs from the varies manager
+ * to lateral services.
+ * <p>
+ * Typically, we only connect to one remote server per facade. We use a list of one
+ * RemoteCacheNoWait.
+ */
+public class RemoteCacheNoWaitFacade<K, V>
+ extends AbstractRemoteCacheNoWaitFacade<K, V>
+{
+ /** log instance */
+ private static final Log log = LogManager.getLog( RemoteCacheNoWaitFacade.class );
+
+ /** Provide factory instance to RemoteCacheFailoverRunner */
+ private final RemoteCacheFactory cacheFactory;
+
+ /**
+ * Constructs with the given remote cache, and fires events to any listeners.
+ * <p>
+ * @param noWaits
+ * @param rca
+ * @param cacheEventLogger
+ * @param elementSerializer
+ * @param cacheFactory
+ */
+ public RemoteCacheNoWaitFacade( List<RemoteCacheNoWait<K,V>> noWaits,
+ IRemoteCacheAttributes rca,
+ ICacheEventLogger cacheEventLogger,
+ IElementSerializer elementSerializer,
+ RemoteCacheFactory cacheFactory)
+ {
+ super( noWaits, rca, cacheEventLogger, elementSerializer );
+ this.cacheFactory = cacheFactory;
+ }
+
+ /**
+ * Begin the failover process if this is a local cache. Clustered remote caches do not failover.
+ * <p>
+ * @param rcnw The no wait in error.
+ */
+ @Override
+ protected void failover( RemoteCacheNoWait<K, V> rcnw )
+ {
+ log.debug( "in failover for {0}", rcnw );
+
+ if ( getAuxiliaryCacheAttributes().getRemoteType() == RemoteType.LOCAL )
+ {
+ if ( rcnw.getStatus() == CacheStatus.ERROR )
+ {
+ // start failover, primary recovery process
+ RemoteCacheFailoverRunner<K, V> runner = new RemoteCacheFailoverRunner<>( this, this.cacheFactory );
+ runner.setDaemon( true );
+ runner.start();
+ runner.notifyError();
+
+ if ( getCacheEventLogger() != null )
+ {
+ getCacheEventLogger().logApplicationEvent( "RemoteCacheNoWaitFacade", "InitiatedFailover",
+ rcnw + " was in error." );
+ }
+ }
+ else
+ {
+ log.info( "The noWait is not in error" );
+ }
+ }
+ }
+
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteLocation.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteLocation.java
new file mode 100644
index 0000000..ec2e19e
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteLocation.java
@@ -0,0 +1,144 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/*
+ * 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.
+ */
+
+/**
+ * Location of the RMI registry.
+ */
+public final class RemoteLocation
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog( RemoteLocation.class );
+
+ /** Pattern for parsing server:port */
+ private static final Pattern SERVER_COLON_PORT = Pattern.compile("(\\S+)\\s*:\\s*(\\d+)");
+
+ /** Host name */
+ private final String host;
+
+ /** Port */
+ private final int port;
+
+ /**
+ * Constructor for the Location object
+ * <p>
+ * @param host
+ * @param port
+ */
+ public RemoteLocation( String host, int port )
+ {
+ this.host = host;
+ this.port = port;
+ }
+
+ /**
+ * @return the host
+ */
+ public String getHost()
+ {
+ return host;
+ }
+
+ /**
+ * @return the port
+ */
+ public int getPort()
+ {
+ return port;
+ }
+
+ /**
+ * @param obj
+ * @return true if the host and port are equal
+ */
+ @Override
+ public boolean equals( Object obj )
+ {
+ if ( obj == this )
+ {
+ return true;
+ }
+ if ( obj == null || !( obj instanceof RemoteLocation ) )
+ {
+ return false;
+ }
+ RemoteLocation l = (RemoteLocation) obj;
+ if ( this.host == null )
+ {
+ return l.host == null && port == l.port;
+ }
+ return host.equals( l.host ) && port == l.port;
+ }
+
+ /**
+ * @return int
+ */
+ @Override
+ public int hashCode()
+ {
+ return host == null ? port : host.hashCode() ^ port;
+ }
+
+ /**
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+ if (this.host != null)
+ {
+ sb.append(this.host);
+ }
+ sb.append(':').append(this.port);
+
+ return sb.toString();
+ }
+
+ /**
+ * Parse remote server and port from the string representation server:port and store them in
+ * a RemoteLocation object
+ *
+ * @param server the input string
+ * @return the remote location object
+ */
+ public static RemoteLocation parseServerAndPort(final String server)
+ {
+ Matcher match = SERVER_COLON_PORT.matcher(server);
+
+ if (match.find() && match.groupCount() == 2)
+ {
+ RemoteLocation location = new RemoteLocation( match.group(1), Integer.parseInt( match.group(2) ) );
+ return location;
+ }
+ else
+ {
+ log.error("Invalid server descriptor: {0}", server);
+ }
+
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteUtils.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteUtils.java
new file mode 100644
index 0000000..427992d
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/RemoteUtils.java
@@ -0,0 +1,264 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URL;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.RMISocketFactory;
+import java.util.Properties;
+
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This class provides some basic utilities for doing things such as starting
+ * the registry properly.
+ */
+public class RemoteUtils
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog(RemoteUtils.class);
+
+ /** No instances please. */
+ private RemoteUtils()
+ {
+ super();
+ }
+
+ /**
+ * Creates and exports a registry on the specified port of the local host.
+ * <p>
+ *
+ * @param port
+ * @return the registry
+ */
+ public static Registry createRegistry(int port)
+ {
+ Registry registry = null;
+
+ // if ( log.isInfoEnabled() )
+ // {
+ // log.info( "createRegistry> Setting security manager" );
+ // }
+ //
+ // System.setSecurityManager( new RMISecurityManager() );
+
+ if (port < 1024)
+ {
+ log.warn("createRegistry> Port chosen was less than 1024, will use default [{0}] instead.",
+ Registry.REGISTRY_PORT);
+ port = Registry.REGISTRY_PORT;
+ }
+
+ try
+ {
+ registry = LocateRegistry.createRegistry(port);
+ log.info("createRegistry> Created the registry on port {0}", port);
+ }
+ catch (RemoteException e)
+ {
+ log.warn("createRegistry> Problem creating registry. It may already be started.",
+ e);
+ }
+ catch (Throwable t)
+ {
+ log.error("createRegistry> Problem creating registry.", t);
+ }
+
+ if (registry == null)
+ {
+ try
+ {
+ registry = LocateRegistry.getRegistry(port);
+ }
+ catch (RemoteException e)
+ {
+ log.error("createRegistry> Problem getting a registry reference.", e);
+ }
+ }
+
+ return registry;
+ }
+
+ /**
+ * Loads properties for the named props file.
+ * First tries class path, then file, then URL
+ * <p>
+ *
+ * @param propFile
+ * @return The properties object for the file
+ * @throws IOException
+ */
+ public static Properties loadProps(String propFile)
+ throws IOException
+ {
+ InputStream is = RemoteUtils.class.getResourceAsStream(propFile);
+
+ if (null == is) // not found in class path
+ {
+ // Try root of class path
+ if (propFile != null && !propFile.startsWith("/"))
+ {
+ is = RemoteUtils.class.getResourceAsStream("/" + propFile);
+ }
+ }
+
+ if (null == is) // not found in class path
+ {
+ if (new File(propFile).exists())
+ {
+ // file found
+ is = new FileInputStream(propFile);
+ }
+ else
+ {
+ // try URL
+ is = new URL(propFile).openStream();
+ }
+ }
+
+ Properties props = new Properties();
+ try
+ {
+ props.load(is);
+ log.debug("props.size={0}", () -> props.size());
+
+ if (log.isTraceEnabled())
+ {
+ StringBuilder buf = new StringBuilder();
+ props.forEach((key, value)
+ -> buf.append('\n').append(key).append(" = ").append(value));
+ log.trace(buf.toString());
+ }
+
+ }
+ catch (IOException ex)
+ {
+ log.error("Error loading remote properties, for file name "
+ + "[{0}]", propFile, ex);
+ }
+ finally
+ {
+ if (is != null)
+ {
+ is.close();
+ }
+ }
+ return props;
+ }
+
+ /**
+ * Configure a custom socket factory to set the timeout value. This sets the
+ * global socket factory. It's used only if a custom factory is not
+ * configured for the specific object.
+ * <p>
+ *
+ * @param timeoutMillis
+ */
+ public static void configureGlobalCustomSocketFactory(final int timeoutMillis)
+ {
+ try
+ {
+ // Don't set a socket factory if the setting is -1
+ if (timeoutMillis > 0)
+ {
+ log.info("RmiSocketFactoryTimeoutMillis [{0}]. "
+ + " Configuring a custom socket factory.", timeoutMillis);
+
+ // use this socket factory to add a timeout.
+ RMISocketFactory.setSocketFactory(new RMISocketFactory()
+ {
+ @Override
+ public Socket createSocket(String host, int port)
+ throws IOException
+ {
+ Socket socket = new Socket();
+ socket.setSoTimeout(timeoutMillis);
+ socket.setSoLinger(false, 0);
+ socket.connect(new InetSocketAddress(host, port), timeoutMillis);
+ return socket;
+ }
+
+ @Override
+ public ServerSocket createServerSocket(int port)
+ throws IOException
+ {
+ return new ServerSocket(port);
+ }
+ });
+ }
+ }
+ catch (IOException e)
+ {
+ // Only try to do it once. Otherwise we
+ // Generate errors for each region on construction.
+ RMISocketFactory factoryInUse = RMISocketFactory.getSocketFactory();
+ if (factoryInUse != null && !factoryInUse.getClass().getName().startsWith("org.apache.commons.jcs3"))
+ {
+ log.info("Could not create new custom socket factory. {0} Factory in use = {1}",
+ () -> e.getMessage(), () -> RMISocketFactory.getSocketFactory());
+ }
+ }
+ }
+
+ /**
+ * Get the naming url used for RMI registration
+ *
+ * @param location
+ * the remote location
+ * @param serviceName
+ * the remote service name
+ * @return the URL for RMI lookup
+ */
+ public static String getNamingURL(final RemoteLocation location, final String serviceName)
+ {
+ return getNamingURL(location.getHost(), location.getPort(), serviceName);
+ }
+
+ /**
+ * Get the naming url used for RMI registration
+ *
+ * @param registryHost
+ * the remote host
+ * @param registryPort
+ * the remote port
+ * @param serviceName
+ * the remote service name
+ * @return the URL for RMI lookup
+ */
+ public static String getNamingURL(final String registryHost, final int registryPort, final String serviceName)
+ {
+ if (registryHost.contains(":"))
+ { // TODO improve this check? See also JCS-133
+ return "//[" + registryHost.replaceFirst("%", "%25") + "]:" + registryPort + "/" + serviceName;
+ }
+ final String registryURL = "//" + registryHost + ":" + registryPort + "/" + serviceName;
+ return registryURL;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/behavior/ICommonRemoteCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/behavior/ICommonRemoteCacheAttributes.java
new file mode 100644
index 0000000..be29370
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/behavior/ICommonRemoteCacheAttributes.java
@@ -0,0 +1,172 @@
+package org.apache.commons.jcs3.auxiliary.remote.behavior;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteLocation;
+import org.apache.commons.jcs3.auxiliary.remote.server.behavior.RemoteType;
+
+/**
+ * This specifies what a remote cache configuration object should look like.
+ */
+public interface ICommonRemoteCacheAttributes
+ extends AuxiliaryCacheAttributes
+{
+ /** The default timeout for the custom RMI socket factory */
+ int DEFAULT_RMI_SOCKET_FACTORY_TIMEOUT_MILLIS = 10000;
+
+ /**
+ * Gets the remoteTypeName attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @return The remoteTypeName value
+ */
+ String getRemoteTypeName();
+
+ /**
+ * Sets the remoteTypeName attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @param s The new remoteTypeName value
+ */
+ void setRemoteTypeName( String s );
+
+ /**
+ * Gets the remoteType attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @return The remoteType value
+ */
+ RemoteType getRemoteType();
+
+ /**
+ * Sets the remoteType attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @param p The new remoteType value
+ */
+ void setRemoteType( RemoteType p );
+
+ /**
+ * Gets the remoteServiceName attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @return The remoteServiceName value
+ */
+ String getRemoteServiceName();
+
+ /**
+ * Sets the remoteServiceName attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @param s The new remoteServiceName value
+ */
+ void setRemoteServiceName( String s );
+
+ /**
+ * Sets the location attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @param location The new location value
+ */
+ void setRemoteLocation( RemoteLocation location );
+
+ /**
+ * Sets the location attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @param host The new remoteHost value
+ * @param port The new remotePort value
+ */
+ void setRemoteLocation( String host, int port );
+
+ /**
+ * Gets the location attribute of the RemoteCacheAttributes object.
+ * <p>
+ * @return The remote location value
+ */
+ public RemoteLocation getRemoteLocation();
+
+ /**
+ * Gets the clusterServers attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @return The clusterServers value
+ */
+ String getClusterServers();
+
+ /**
+ * Sets the clusterServers attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @param s The new clusterServers value
+ */
+ void setClusterServers( String s );
+
+ /**
+ * Gets the removeUponRemotePut attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @return The removeUponRemotePut value
+ */
+ boolean getRemoveUponRemotePut();
+
+ /**
+ * Sets the removeUponRemotePut attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @param r The new removeUponRemotePut value
+ */
+ void setRemoveUponRemotePut( boolean r );
+
+ /**
+ * Gets the getOnly attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @return The getOnly value
+ */
+ boolean getGetOnly();
+
+ /**
+ * Sets the getOnly attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @param r The new getOnly value
+ */
+ void setGetOnly( boolean r );
+
+ /**
+ * Should cluster updates be propagated to the locals
+ * <p>
+ * @return The localClusterConsistency value
+ */
+ boolean isLocalClusterConsistency();
+
+ /**
+ * Should cluster updates be propagated to the locals
+ * <p>
+ * @param r The new localClusterConsistency value
+ */
+ void setLocalClusterConsistency( boolean r );
+
+ /**
+ * This sets a general timeout on the rmi socket factory. By default the socket factory will
+ * block forever.
+ * <p>
+ * We have a default setting. The default rmi behavior should never be used.
+ * <p>
+ * @return int milliseconds
+ */
+ int getRmiSocketFactoryTimeoutMillis();
+
+ /**
+ * This sets a general timeout on the RMI socket factory. By default the socket factory will
+ * block forever.
+ * <p>
+ * @param rmiSocketFactoryTimeoutMillis
+ */
+ void setRmiSocketFactoryTimeoutMillis( int rmiSocketFactoryTimeoutMillis );
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/behavior/IRemoteCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/behavior/IRemoteCacheAttributes.java
new file mode 100644
index 0000000..494c630
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/behavior/IRemoteCacheAttributes.java
@@ -0,0 +1,182 @@
+package org.apache.commons.jcs3.auxiliary.remote.behavior;
+
+import java.util.List;
+
+import org.apache.commons.jcs3.auxiliary.remote.RemoteLocation;
+
+/*
+ * 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.
+ */
+
+/**
+ * This specifies what a remote cache configuration object should look like.
+ */
+public interface IRemoteCacheAttributes
+ extends ICommonRemoteCacheAttributes
+{
+ /**
+ * If RECEIVE is false then the remote cache will not register a listener with the remote
+ * server. This allows you to configure a remote server as a repository from which you can get
+ * and to which you put, but from which you do not receive any notifications. That is, you will
+ * not receive updates or removes.
+ * <p>
+ * If you set this option to false, you should set your local memory size to 0.
+ */
+ boolean DEFAULT_RECEIVE = true;
+
+ /**
+ * The number of elements the zombie queue will hold. This queue is used to store events if we
+ * loose our connection with the server.
+ */
+ int DEFAULT_ZOMBIE_QUEUE_MAX_SIZE = 1000;
+
+ /**
+ * Gets the failoverIndex attribute of the IRemoteCacheAttributes object.
+ * <p>
+ * This specifies which server in the list we are listening to if the number is greater than 0
+ * we will try to move to 0 position the primary is added as position 1 if it is present
+ * <p>
+ * @return The failoverIndex value
+ */
+ int getFailoverIndex();
+
+ /**
+ * Sets the failoverIndex attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @param p The new failoverIndex value
+ */
+ void setFailoverIndex( int p );
+
+ /**
+ * Gets the failovers attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @return The failovers value
+ */
+ List<RemoteLocation> getFailovers();
+
+ /**
+ * Sets the failovers attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @param failovers The new failovers value
+ */
+ void setFailovers( List<RemoteLocation> failovers );
+
+ /**
+ * Gets the localPort attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @return The localPort value
+ */
+ int getLocalPort();
+
+ /**
+ * Sets the localPort attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @param p The new localPort value
+ */
+ void setLocalPort( int p );
+
+ /**
+ * Gets the failoverServers attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @return The failoverServers value
+ */
+ String getFailoverServers();
+
+ /**
+ * Sets the failoverServers attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @param s The new failoverServers value
+ */
+ void setFailoverServers( String s );
+
+ /**
+ * The thread pool the remote cache should use. At first this will only be for gets.
+ * <p>
+ * The default name is "remote_cache_client"
+ * <p>
+ * @return the name of the pool
+ */
+ String getThreadPoolName();
+
+ /**
+ * Set the name of the pool to use. Pools should be defined in the cache.ccf.
+ * <p>
+ * @param name
+ */
+ void setThreadPoolName( String name );
+
+ /**
+ * -1 and 0 mean no timeout, this is the default if the timeout is -1 or 0, no threadpool will
+ * be used.
+ * <p>
+ * @return the time in millis
+ */
+ int getGetTimeoutMillis();
+
+ /**
+ * -1 means no timeout, this is the default if the timeout is -1 or 0, no threadpool will be
+ * used. If the timeout is greater than 0 a threadpool will be used for get requests.
+ * <p>
+ * @param millis
+ */
+ void setGetTimeoutMillis( int millis );
+
+ /**
+ * By default this option is true. If you set it to false, you will not receive updates or
+ * removes from the remote server.
+ * <p>
+ * @param receive
+ */
+ void setReceive( boolean receive );
+
+ /**
+ * If RECEIVE is false then the remote cache will not register a listener with the remote
+ * server. This allows you to configure a remote server as a repository from which you can get
+ * and to which you put, but from which you do not receive any notifications. That is, you will
+ * not receive updates or removes.
+ * <p>
+ * If you set this option to false, you should set your local memory size to 0.
+ * <p>
+ * The remote cache manager uses this value to decide whether or not to register a listener.
+ * <p>
+ * It makes no sense to configure a cluster remote cache to no receive.
+ * <p>
+ * Since a non-receiving remote cache client will not register a listener, it will not have a
+ * listener id assigned from the server. As such the remote server cannot determine if it is a
+ * cluster or a normal client. It will assume that it is a normal client.
+ * <p>
+ * @return the receive value.
+ */
+ boolean isReceive();
+
+ /**
+ * The number of elements the zombie queue will hold. This queue is used to store events if we
+ * loose our connection with the server.
+ * <p>
+ * @param zombieQueueMaxSize The zombieQueueMaxSize to set.
+ */
+ void setZombieQueueMaxSize( int zombieQueueMaxSize );
+
+ /**
+ * The number of elements the zombie queue will hold. This queue is used to store events if we
+ * loose our connection with the server.
+ * <p>
+ * @return Returns the zombieQueueMaxSize.
+ */
+ int getZombieQueueMaxSize();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/behavior/IRemoteCacheClient.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/behavior/IRemoteCacheClient.java
new file mode 100644
index 0000000..013e9a9
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/behavior/IRemoteCacheClient.java
@@ -0,0 +1,61 @@
+package org.apache.commons.jcs3.auxiliary.remote.behavior;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCache;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+
+/**
+ * This defines the behavior expected of a remote cache client. This extends Auxiliary cache which
+ * in turn extends ICache.
+ * <p>
+ * I'd like generalize this a bit.
+ * <p>
+ * @author Aaron Smuts
+ */
+public interface IRemoteCacheClient<K, V>
+ extends AuxiliaryCache<K, V>
+{
+ /**
+ * Replaces the current remote cache service handle with the given handle. If the current remote
+ * is a Zombie, the propagate the events that may be queued to the restored service.
+ * <p>
+ * @param remote ICacheServiceNonLocal -- the remote server or proxy to the remote server
+ */
+ void fixCache( ICacheServiceNonLocal<?, ?> remote );
+
+ /**
+ * Gets the listenerId attribute of the RemoteCacheListener object.
+ * <p>
+ * All requests to the remote cache must include a listener id. This allows the server to avoid
+ * sending updates the the listener associated with this client.
+ * <p>
+ * @return The listenerId value
+ */
+ long getListenerId();
+
+ /**
+ * This returns the listener associated with this remote cache. TODO we should try to get this
+ * out of the interface.
+ * <p>
+ * @return IRemoteCacheListener
+ */
+ IRemoteCacheListener<K, V> getListener();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/behavior/IRemoteCacheConstants.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/behavior/IRemoteCacheConstants.java
new file mode 100644
index 0000000..515db6a
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/behavior/IRemoteCacheConstants.java
@@ -0,0 +1,70 @@
+package org.apache.commons.jcs3.auxiliary.remote.behavior;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+
+
+/**
+ * This holds constants that are used by the remote cache.
+ */
+public interface IRemoteCacheConstants
+{
+ /** Mapping to props file value */
+ String REMOTE_CACHE_SERVICE_VAL = ICacheServiceNonLocal.class.getName();
+
+ /** The prefix for cache server config. */
+ String CACHE_SERVER_PREFIX = "jcs.remotecache";
+
+ /**
+ * I'm trying to migrate everything to use this prefix. All those below will be replaced. Any of
+ * the RemoteCacheServerAttributes can be configured this way.
+ */
+ String CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX = CACHE_SERVER_PREFIX + ".serverattributes";
+
+ /**
+ * This is the name of the class that will be used for an object specific socket factory.
+ */
+ String CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX = CACHE_SERVER_PREFIX + ".customrmisocketfactory";
+
+ /** Property prefix, should be jcs.remote but this would break existing config. */
+ String PROPERTY_PREFIX = "remote";
+
+ /** Mapping to props file value */
+ String SOCKET_TIMEOUT_MILLIS = PROPERTY_PREFIX + ".cache.rmiSocketFactoryTimeoutMillis";
+
+ /** Mapping to props file value */
+ String REMOTE_CACHE_SERVICE_NAME = PROPERTY_PREFIX + ".cache.service.name";
+
+ /** Mapping to props file value */
+ String TOMCAT_XML = PROPERTY_PREFIX + ".tomcat.xml";
+
+ /** Mapping to props file value */
+ String TOMCAT_ON = PROPERTY_PREFIX + ".tomcat.on";
+
+ /** Mapping to props file value */
+ String REMOTE_CACHE_SERVICE_PORT = PROPERTY_PREFIX + ".cache.service.port";
+
+ /** Mapping to props file value */
+ String REMOTE_LOCAL_CLUSTER_CONSISTENCY = PROPERTY_PREFIX + ".cluster.LocalClusterConsistency";
+
+ /** Mapping to props file value */
+ String REMOTE_ALLOW_CLUSTER_GET = PROPERTY_PREFIX + ".cluster.AllowClusterGet";
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/behavior/IRemoteCacheDispatcher.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/behavior/IRemoteCacheDispatcher.java
new file mode 100644
index 0000000..0f08947
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/behavior/IRemoteCacheDispatcher.java
@@ -0,0 +1,46 @@
+package org.apache.commons.jcs3.auxiliary.remote.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.auxiliary.remote.value.RemoteCacheRequest;
+import org.apache.commons.jcs3.auxiliary.remote.value.RemoteCacheResponse;
+
+/**
+ * In the future, this can be used as a generic dispatcher abstraction.
+ * <p>
+ * At the time of creation, only the http remote cache uses it. The RMI remote could be converted to
+ * use it as well.
+ */
+public interface IRemoteCacheDispatcher
+{
+ /**
+ * All requests will go through this method. The dispatcher implementation will send the request
+ * remotely.
+ * <p>
+ * @param remoteCacheRequest
+ * @return RemoteCacheResponse
+ * @throws IOException
+ */
+ <K, V, T>
+ RemoteCacheResponse<T> dispatchRequest( RemoteCacheRequest<K, V> remoteCacheRequest )
+ throws IOException;
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/behavior/IRemoteCacheListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/behavior/IRemoteCacheListener.java
new file mode 100644
index 0000000..fd5673b
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/behavior/IRemoteCacheListener.java
@@ -0,0 +1,81 @@
+package org.apache.commons.jcs3.auxiliary.remote.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.rmi.Remote;
+
+import org.apache.commons.jcs3.auxiliary.remote.server.behavior.RemoteType;
+import org.apache.commons.jcs3.engine.behavior.ICacheListener;
+
+/**
+ * Listens for remote cache event notification ( rmi callback ).
+ */
+public interface IRemoteCacheListener<K, V>
+ extends ICacheListener<K, V>, Remote
+{
+ /**
+ * Get the id to be used by this manager.
+ * <p>
+ * @return long
+ * @throws IOException
+ */
+ @Override
+ long getListenerId()
+ throws IOException;
+
+ /**
+ * Set the id to be used by this manager. The remote cache server identifies clients by this id.
+ * The value will be set by the server through the remote cache listener.
+ * <p>
+ * @param id
+ * @throws IOException
+ */
+ @Override
+ void setListenerId( long id )
+ throws IOException;
+
+ /**
+ * Gets the remoteType attribute of the IRemoteCacheListener object
+ * <p>
+ * @return The remoteType value
+ * @throws IOException
+ */
+ RemoteType getRemoteType()
+ throws IOException;
+
+ /**
+ * This is for debugging. It allows the remote cache server to log the address of any listeners
+ * that register.
+ * <p>
+ * @return the local host address.
+ * @throws IOException
+ */
+ String getLocalHostAddress()
+ throws IOException;
+
+ /**
+ * Deregisters itself.
+ * <p>
+ * @throws IOException
+ */
+ void dispose()
+ throws IOException;
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/behavior/IRemoteHttpCacheConstants.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/behavior/IRemoteHttpCacheConstants.java
new file mode 100644
index 0000000..281554a
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/behavior/IRemoteHttpCacheConstants.java
@@ -0,0 +1,31 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.behavior;
+
+/*
+ * 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.
+ */
+
+/** Constants used throughout the HTTP remote cache. */
+public interface IRemoteHttpCacheConstants
+{
+ /** The prefix for cache server config. */
+ String HTTP_CACHE_SERVER_PREFIX = "jcs.remotehttpcache";
+
+ /** All of the RemoteHttpCacheServiceAttributes can be configured this way. */
+ String HTTP_CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX = HTTP_CACHE_SERVER_PREFIX
+ + ".serverattributes";
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/AbstractHttpClient.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/AbstractHttpClient.java
new file mode 100644
index 0000000..832a75b
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/AbstractHttpClient.java
@@ -0,0 +1,154 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.client;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpVersion;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.config.CookieSpecs;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.methods.RequestBuilder;
+import org.apache.http.impl.client.HttpClientBuilder;
+
+/**
+ * This class simply configures the http multithreaded connection manager.
+ * <p>
+ * This is abstract because it can do anything. Child classes can overwrite whatever they want.
+ */
+public abstract class AbstractHttpClient
+{
+ /** The client */
+ private final HttpClient httpClient;
+
+ /** The protocol version */
+ private HttpVersion httpVersion;
+
+ /** Configuration settings. */
+ private final RemoteHttpCacheAttributes remoteHttpCacheAttributes;
+
+ /** The Logger. */
+ private static final Log log = LogManager.getLog( AbstractHttpClient.class );
+
+ /**
+ * Sets the default Properties File and Heading, and creates the HttpClient and connection
+ * manager.
+ * <p>
+ * @param remoteHttpCacheAttributes
+ */
+ public AbstractHttpClient( RemoteHttpCacheAttributes remoteHttpCacheAttributes )
+ {
+ this.remoteHttpCacheAttributes = remoteHttpCacheAttributes;
+
+ String httpVersion = getRemoteHttpCacheAttributes().getHttpVersion();
+ if ( "1.1".equals( httpVersion ) )
+ {
+ this.httpVersion = HttpVersion.HTTP_1_1;
+ }
+ else if ( "1.0".equals( httpVersion ) )
+ {
+ this.httpVersion = HttpVersion.HTTP_1_0;
+ }
+ else
+ {
+ log.warn( "Unrecognized value for 'httpVersion': [{0}], defaulting to 1.1",
+ httpVersion );
+ this.httpVersion = HttpVersion.HTTP_1_1;
+ }
+
+ HttpClientBuilder builder = HttpClientBuilder.create();
+ configureClient(builder);
+ this.httpClient = builder.build();
+ }
+
+ /**
+ * Configures the http client.
+ *
+ * @param builder client builder to configure
+ */
+ protected void configureClient(HttpClientBuilder builder)
+ {
+ if ( getRemoteHttpCacheAttributes().getMaxConnectionsPerHost() > 0 )
+ {
+ builder.setMaxConnTotal(getRemoteHttpCacheAttributes().getMaxConnectionsPerHost());
+ builder.setMaxConnPerRoute(getRemoteHttpCacheAttributes().getMaxConnectionsPerHost());
+ }
+
+ builder.setDefaultRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(getRemoteHttpCacheAttributes().getConnectionTimeoutMillis())
+ .setSocketTimeout(getRemoteHttpCacheAttributes().getSocketTimeoutMillis())
+ // By default we instruct HttpClient to ignore cookies.
+ .setCookieSpec(CookieSpecs.IGNORE_COOKIES)
+ .build());
+ }
+
+ /**
+ * Execute the web service call
+ * <p>
+ * @param builder builder for the post request
+ *
+ * @return the call response
+ *
+ * @throws IOException on i/o error
+ */
+ protected final HttpResponse doWebserviceCall( RequestBuilder builder )
+ throws IOException
+ {
+ preProcessWebserviceCall( builder.setVersion(httpVersion) );
+ HttpUriRequest request = builder.build();
+ HttpResponse httpResponse = this.httpClient.execute( request );
+ postProcessWebserviceCall( request, httpResponse );
+
+ return httpResponse;
+ }
+
+ /**
+ * Called before the execute call on the client.
+ * <p>
+ * @param requestBuilder http method request builder
+ *
+ * @throws IOException
+ */
+ protected abstract void preProcessWebserviceCall( RequestBuilder requestBuilder )
+ throws IOException;
+
+ /**
+ * Called after the execute call on the client.
+ * <p>
+ * @param request http request
+ * @param httpState result of execution
+ *
+ * @throws IOException
+ */
+ protected abstract void postProcessWebserviceCall( HttpUriRequest request, HttpResponse httpState )
+ throws IOException;
+
+ /**
+ * @return the remoteHttpCacheAttributes
+ */
+ protected RemoteHttpCacheAttributes getRemoteHttpCacheAttributes()
+ {
+ return remoteHttpCacheAttributes;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCache.java
new file mode 100644
index 0000000..340be23
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCache.java
@@ -0,0 +1,113 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.client;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.auxiliary.remote.AbstractRemoteAuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheListener;
+import org.apache.commons.jcs3.engine.ZombieCacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This uses an http client as the service.
+ */
+public class RemoteHttpCache<K, V>
+ extends AbstractRemoteAuxiliaryCache<K, V>
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog( RemoteHttpCache.class );
+
+ /** for error notifications */
+ private final RemoteHttpCacheMonitor monitor;
+
+ /** Keep the child copy here for the restore process. */
+ private final RemoteHttpCacheAttributes remoteHttpCacheAttributes;
+
+ /**
+ * Constructor for the RemoteCache object. This object communicates with a remote cache server.
+ * One of these exists for each region. This also holds a reference to a listener. The same
+ * listener is used for all regions for one remote server. Holding a reference to the listener
+ * allows this object to know the listener id assigned by the remote cache.
+ * <p>
+ * @param remoteHttpCacheAttributes
+ * @param remote
+ * @param listener
+ * @param monitor the cache monitor
+ */
+ public RemoteHttpCache( RemoteHttpCacheAttributes remoteHttpCacheAttributes, ICacheServiceNonLocal<K, V> remote,
+ IRemoteCacheListener<K, V> listener, RemoteHttpCacheMonitor monitor )
+ {
+ super( remoteHttpCacheAttributes, remote, listener );
+
+ this.remoteHttpCacheAttributes = remoteHttpCacheAttributes;
+ this.monitor = monitor;
+ }
+
+ /**
+ * Nothing right now. This should setup a zombie and initiate recovery.
+ * <p>
+ * @param ex
+ * @param msg
+ * @param eventName
+ * @throws IOException
+ */
+ @Override
+ protected void handleException( Exception ex, String msg, String eventName )
+ throws IOException
+ {
+ // we should not switch if the existing is a zombie.
+ if ( !( getRemoteCacheService() instanceof ZombieCacheServiceNonLocal ) )
+ {
+ String message = "Disabling remote cache due to error: " + msg;
+ logError( cacheName, "", message );
+ log.error( message, ex );
+
+ setRemoteCacheService( new ZombieCacheServiceNonLocal<>( getRemoteCacheAttributes().getZombieQueueMaxSize() ) );
+
+ monitor.notifyError( this );
+ }
+
+ if ( ex instanceof IOException )
+ {
+ throw (IOException) ex;
+ }
+ throw new IOException( ex.getMessage() );
+ }
+
+ /**
+ * @return url of service
+ */
+ @Override
+ public String getEventLoggingExtraInfo()
+ {
+ return null;
+ }
+
+ /**
+ * @return the remoteHttpCacheAttributes
+ */
+ public RemoteHttpCacheAttributes getRemoteHttpCacheAttributes()
+ {
+ return remoteHttpCacheAttributes;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheAttributes.java
new file mode 100644
index 0000000..68d008a
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheAttributes.java
@@ -0,0 +1,228 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.client;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes;
+
+/** Http client specific settings. */
+public class RemoteHttpCacheAttributes
+ extends RemoteCacheAttributes
+{
+ /** Don't change. */
+ private static final long serialVersionUID = -5944327125140505212L;
+
+ /** http verison to use. */
+ private static final String DEFAULT_HTTP_VERSION = "1.1";
+
+ /** The max connections allowed per host */
+ private int maxConnectionsPerHost = 100;
+
+ /** The socket timeout. */
+ private int socketTimeoutMillis = 3000;
+
+ /** The socket connections timeout */
+ private int connectionTimeoutMillis = 5000;
+
+ /** http verison to use. */
+ private String httpVersion = DEFAULT_HTTP_VERSION;
+
+ /** The cache name will be included on the parameters */
+ private boolean includeCacheNameAsParameter = true;
+
+ /** keys and patterns will be included in the parameters */
+ private boolean includeKeysAndPatternsAsParameter = true;
+
+ /** keys and patterns will be included in the parameters */
+ private boolean includeRequestTypeasAsParameter = true;
+
+ /** The complete URL to the service. */
+ private String url;
+
+ /** The default classname for the client. */
+ public static final String DEFAULT_REMOTE_HTTP_CLIENT_CLASS_NAME = RemoteHttpCacheClient.class.getName();
+
+ /** This allows users to inject their own client implementation. */
+ private String remoteHttpClientClassName = DEFAULT_REMOTE_HTTP_CLIENT_CLASS_NAME;
+
+ /**
+ * @param maxConnectionsPerHost the maxConnectionsPerHost to set
+ */
+ public void setMaxConnectionsPerHost( int maxConnectionsPerHost )
+ {
+ this.maxConnectionsPerHost = maxConnectionsPerHost;
+ }
+
+ /**
+ * @return the maxConnectionsPerHost
+ */
+ public int getMaxConnectionsPerHost()
+ {
+ return maxConnectionsPerHost;
+ }
+
+ /**
+ * @param socketTimeoutMillis the socketTimeoutMillis to set
+ */
+ public void setSocketTimeoutMillis( int socketTimeoutMillis )
+ {
+ this.socketTimeoutMillis = socketTimeoutMillis;
+ }
+
+ /**
+ * @return the socketTimeoutMillis
+ */
+ public int getSocketTimeoutMillis()
+ {
+ return socketTimeoutMillis;
+ }
+
+ /**
+ * @param httpVersion the httpVersion to set
+ */
+ public void setHttpVersion( String httpVersion )
+ {
+ this.httpVersion = httpVersion;
+ }
+
+ /**
+ * @return the httpVersion
+ */
+ public String getHttpVersion()
+ {
+ return httpVersion;
+ }
+
+ /**
+ * @param connectionTimeoutMillis the connectionTimeoutMillis to set
+ */
+ public void setConnectionTimeoutMillis( int connectionTimeoutMillis )
+ {
+ this.connectionTimeoutMillis = connectionTimeoutMillis;
+ }
+
+ /**
+ * @return the connectionTimeoutMillis
+ */
+ public int getConnectionTimeoutMillis()
+ {
+ return connectionTimeoutMillis;
+ }
+
+ /**
+ * @param includeCacheNameInURL the includeCacheNameInURL to set
+ */
+ public void setIncludeCacheNameAsParameter( boolean includeCacheNameInURL )
+ {
+ this.includeCacheNameAsParameter = includeCacheNameInURL;
+ }
+
+ /**
+ * @return the includeCacheNameInURL
+ */
+ public boolean isIncludeCacheNameAsParameter()
+ {
+ return includeCacheNameAsParameter;
+ }
+
+ /**
+ * @param includeKeysAndPatternsInURL the includeKeysAndPatternsInURL to set
+ */
+ public void setIncludeKeysAndPatternsAsParameter( boolean includeKeysAndPatternsInURL )
+ {
+ this.includeKeysAndPatternsAsParameter = includeKeysAndPatternsInURL;
+ }
+
+ /**
+ * @return the includeKeysAndPatternsInURL
+ */
+ public boolean isIncludeKeysAndPatternsAsParameter()
+ {
+ return includeKeysAndPatternsAsParameter;
+ }
+
+ /**
+ * @param includeRequestTypeasAsParameter the includeRequestTypeasAsParameter to set
+ */
+ public void setIncludeRequestTypeasAsParameter( boolean includeRequestTypeasAsParameter )
+ {
+ this.includeRequestTypeasAsParameter = includeRequestTypeasAsParameter;
+ }
+
+ /**
+ * @return the includeRequestTypeasAsParameter
+ */
+ public boolean isIncludeRequestTypeasAsParameter()
+ {
+ return includeRequestTypeasAsParameter;
+ }
+
+ /**
+ * @param url the url to set
+ */
+ public void setUrl( String url )
+ {
+ this.url = url;
+ }
+
+ /**
+ * @return the url
+ */
+ public String getUrl()
+ {
+ return url;
+ }
+
+ /**
+ * @param remoteHttpClientClassName the remoteHttpClientClassName to set
+ */
+ public void setRemoteHttpClientClassName( String remoteHttpClientClassName )
+ {
+ this.remoteHttpClientClassName = remoteHttpClientClassName;
+ }
+
+ /**
+ * @return the remoteHttpClientClassName
+ */
+ public String getRemoteHttpClientClassName()
+ {
+ return remoteHttpClientClassName;
+ }
+
+ /**
+ * @return String details
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\n RemoteHttpCacheAttributes" );
+ buf.append( "\n maxConnectionsPerHost = [" + getMaxConnectionsPerHost() + "]" );
+ buf.append( "\n socketTimeoutMillis = [" + getSocketTimeoutMillis() + "]" );
+ buf.append( "\n httpVersion = [" + getHttpVersion() + "]" );
+ buf.append( "\n connectionTimeoutMillis = [" + getConnectionTimeoutMillis() + "]" );
+ buf.append( "\n includeCacheNameAsParameter = [" + isIncludeCacheNameAsParameter() + "]" );
+ buf.append( "\n includeKeysAndPatternsAsParameter = [" + isIncludeKeysAndPatternsAsParameter() + "]" );
+ buf.append( "\n includeRequestTypeasAsParameter = [" + isIncludeRequestTypeasAsParameter() + "]" );
+ buf.append( "\n url = [" + getUrl() + "]" );
+ buf.append( "\n remoteHttpClientClassName = [" + getRemoteHttpClientClassName() + "]" );
+ buf.append( super.toString() );
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheClient.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheClient.java
new file mode 100644
index 0000000..444240f
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheClient.java
@@ -0,0 +1,484 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.client;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheDispatcher;
+import org.apache.commons.jcs3.auxiliary.remote.http.client.behavior.IRemoteHttpCacheClient;
+import org.apache.commons.jcs3.auxiliary.remote.util.RemoteCacheRequestFactory;
+import org.apache.commons.jcs3.auxiliary.remote.value.RemoteCacheRequest;
+import org.apache.commons.jcs3.auxiliary.remote.value.RemoteCacheResponse;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/** This is the service used by the remote http auxiliary cache. */
+public class RemoteHttpCacheClient<K, V>
+ implements IRemoteHttpCacheClient<K, V>
+{
+ /** The Logger. */
+ private static final Log log = LogManager.getLog( RemoteHttpCacheClient.class );
+
+ /** The internal client. */
+ private IRemoteCacheDispatcher remoteDispatcher;
+
+ /** The remote attributes */
+ private RemoteHttpCacheAttributes remoteHttpCacheAttributes;
+
+ /** Set to true when initialize is called */
+ private boolean initialized = false;
+
+ /** For factory construction. */
+ public RemoteHttpCacheClient()
+ {
+ // does nothing
+ }
+
+ /**
+ * Constructs a client.
+ * <p>
+ * @param attributes
+ */
+ public RemoteHttpCacheClient( RemoteHttpCacheAttributes attributes )
+ {
+ setRemoteHttpCacheAttributes( attributes );
+ initialize( attributes );
+ }
+
+ /**
+ * The provides an extension point. If you want to extend this and use a special dispatcher,
+ * here is the place to do it.
+ * <p>
+ * @param attributes
+ */
+ @Override
+ public void initialize( RemoteHttpCacheAttributes attributes )
+ {
+ setRemoteDispatcher( new RemoteHttpCacheDispatcher( attributes ) );
+
+ log.info( "Created remote Dispatcher. {0}", () -> getRemoteDispatcher() );
+ setInitialized( true );
+ }
+
+ /**
+ * Create a request, process, extract the payload.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @return ICacheElement
+ * @throws IOException
+ */
+ @Override
+ public ICacheElement<K, V> get( String cacheName, K key )
+ throws IOException
+ {
+ return get( cacheName, key, 0 );
+ }
+
+ /**
+ * Create a request, process, extract the payload.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @return ICacheElement
+ * @throws IOException
+ */
+ @Override
+ public ICacheElement<K, V> get( String cacheName, K key, long requesterId )
+ throws IOException
+ {
+ if ( !isInitialized() )
+ {
+ String message = "The Remote Http Client is not initialized. Cannot process request.";
+ log.warn( message );
+ throw new IOException( message );
+ }
+ RemoteCacheRequest<K, Serializable> remoteHttpCacheRequest =
+ RemoteCacheRequestFactory.createGetRequest( cacheName, key, requesterId );
+
+ RemoteCacheResponse<ICacheElement<K, V>> remoteHttpCacheResponse =
+ getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest );
+
+ log.debug( "Get [{0}] = {1}", key, remoteHttpCacheResponse );
+
+ if ( remoteHttpCacheResponse != null)
+ {
+ return remoteHttpCacheResponse.getPayload();
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets multiple items from the cache matching the pattern.
+ * <p>
+ * @param cacheName
+ * @param pattern
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache matching the pattern.
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern )
+ throws IOException
+ {
+ return getMatching( cacheName, pattern, 0 );
+ }
+
+ /**
+ * Gets multiple items from the cache matching the pattern.
+ * <p>
+ * @param cacheName
+ * @param pattern
+ * @param requesterId
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache matching the pattern.
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern, long requesterId )
+ throws IOException
+ {
+ if ( !isInitialized() )
+ {
+ String message = "The Remote Http Client is not initialized. Cannot process request.";
+ log.warn( message );
+ throw new IOException( message );
+ }
+
+ RemoteCacheRequest<K, V> remoteHttpCacheRequest =
+ RemoteCacheRequestFactory.createGetMatchingRequest( cacheName, pattern, requesterId );
+
+ RemoteCacheResponse<Map<K, ICacheElement<K, V>>> remoteHttpCacheResponse =
+ getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest );
+
+ log.debug( "GetMatching [{0}] = {1}", pattern, remoteHttpCacheResponse );
+
+ return remoteHttpCacheResponse.getPayload();
+ }
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * @param cacheName
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys )
+ throws IOException
+ {
+ return getMultiple( cacheName, keys, 0 );
+ }
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * @param cacheName
+ * @param keys
+ * @param requesterId
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys, long requesterId )
+ throws IOException
+ {
+ if ( !isInitialized() )
+ {
+ String message = "The Remote Http Client is not initialized. Cannot process request.";
+ log.warn( message );
+ throw new IOException( message );
+ }
+
+ RemoteCacheRequest<K, V> remoteHttpCacheRequest =
+ RemoteCacheRequestFactory.createGetMultipleRequest( cacheName, keys, requesterId );
+
+ RemoteCacheResponse<Map<K, ICacheElement<K, V>>> remoteHttpCacheResponse =
+ getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest );
+
+ log.debug( "GetMultiple [{0}] = {1}", keys, remoteHttpCacheResponse );
+
+ return remoteHttpCacheResponse.getPayload();
+ }
+
+ /**
+ * Removes the given key from the specified cache.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @throws IOException
+ */
+ @Override
+ public void remove( String cacheName, K key )
+ throws IOException
+ {
+ remove( cacheName, key, 0 );
+ }
+
+ /**
+ * Removes the given key from the specified cache.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @throws IOException
+ */
+ @Override
+ public void remove( String cacheName, K key, long requesterId )
+ throws IOException
+ {
+ if ( !isInitialized() )
+ {
+ String message = "The Remote Http Client is not initialized. Cannot process request.";
+ log.warn( message );
+ throw new IOException( message );
+ }
+
+ RemoteCacheRequest<K, V> remoteHttpCacheRequest =
+ RemoteCacheRequestFactory.createRemoveRequest( cacheName, key, requesterId );
+
+ getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest );
+ }
+
+ /**
+ * Remove all keys from the specified cache.
+ * <p>
+ * @param cacheName
+ * @throws IOException
+ */
+ @Override
+ public void removeAll( String cacheName )
+ throws IOException
+ {
+ removeAll( cacheName, 0 );
+ }
+
+ /**
+ * Remove all keys from the sepcified cache.
+ * <p>
+ * @param cacheName
+ * @param requesterId
+ * @throws IOException
+ */
+ @Override
+ public void removeAll( String cacheName, long requesterId )
+ throws IOException
+ {
+ if ( !isInitialized() )
+ {
+ String message = "The Remote Http Client is not initialized. Cannot process request.";
+ log.warn( message );
+ throw new IOException( message );
+ }
+
+ RemoteCacheRequest<K, V> remoteHttpCacheRequest =
+ RemoteCacheRequestFactory.createRemoveAllRequest( cacheName, requesterId );
+
+ getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest );
+ }
+
+ /**
+ * Puts a cache item to the cache.
+ * <p>
+ * @param item
+ * @throws IOException
+ */
+ @Override
+ public void update( ICacheElement<K, V> item )
+ throws IOException
+ {
+ update( item, 0 );
+ }
+
+ /**
+ * Puts a cache item to the cache.
+ * <p>
+ * @param cacheElement
+ * @param requesterId
+ * @throws IOException
+ */
+ @Override
+ public void update( ICacheElement<K, V> cacheElement, long requesterId )
+ throws IOException
+ {
+ if ( !isInitialized() )
+ {
+ String message = "The Remote Http Client is not initialized. Cannot process request.";
+ log.warn( message );
+ throw new IOException( message );
+ }
+
+ RemoteCacheRequest<K, V> remoteHttpCacheRequest =
+ RemoteCacheRequestFactory.createUpdateRequest( cacheElement, requesterId );
+
+ getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest );
+ }
+
+ /**
+ * Frees the specified cache.
+ * <p>
+ * @param cacheName
+ * @throws IOException
+ */
+ @Override
+ public void dispose( String cacheName )
+ throws IOException
+ {
+ if ( !isInitialized() )
+ {
+ String message = "The Remote Http Client is not initialized. Cannot process request.";
+ log.warn( message );
+ throw new IOException( message );
+ }
+
+ RemoteCacheRequest<K, V> remoteHttpCacheRequest =
+ RemoteCacheRequestFactory.createDisposeRequest( cacheName, 0 );
+
+ getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest );
+ }
+
+ /**
+ * Frees the specified cache.
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ public void release()
+ throws IOException
+ {
+ // noop
+ }
+
+ /**
+ * Return the keys in this cache.
+ * <p>
+ * @param cacheName the name of the cache
+ * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCache#getKeySet()
+ */
+ @Override
+ public Set<K> getKeySet( String cacheName ) throws IOException
+ {
+ if ( !isInitialized() )
+ {
+ String message = "The Remote Http Client is not initialized. Cannot process request.";
+ log.warn( message );
+ throw new IOException( message );
+ }
+
+ RemoteCacheRequest<String, String> remoteHttpCacheRequest =
+ RemoteCacheRequestFactory.createGetKeySetRequest(cacheName, 0 );
+
+ RemoteCacheResponse<Set<K>> remoteHttpCacheResponse = getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest );
+
+ if ( remoteHttpCacheResponse != null && remoteHttpCacheResponse.getPayload() != null )
+ {
+ return remoteHttpCacheResponse.getPayload();
+ }
+
+ return Collections.emptySet();
+ }
+
+ /**
+ * Make and alive request.
+ * <p>
+ * @return true if we make a successful alive request.
+ * @throws IOException
+ */
+ @Override
+ public boolean isAlive()
+ throws IOException
+ {
+ if ( !isInitialized() )
+ {
+ String message = "The Remote Http Client is not initialized. Cannot process request.";
+ log.warn( message );
+ throw new IOException( message );
+ }
+
+ RemoteCacheRequest<K, V> remoteHttpCacheRequest = RemoteCacheRequestFactory.createAliveCheckRequest( 0 );
+ RemoteCacheResponse<String> remoteHttpCacheResponse =
+ getRemoteDispatcher().dispatchRequest( remoteHttpCacheRequest );
+
+ if ( remoteHttpCacheResponse != null )
+ {
+ return remoteHttpCacheResponse.isSuccess();
+ }
+
+ return false;
+ }
+
+ /**
+ * @param remoteDispatcher the remoteDispatcher to set
+ */
+ public void setRemoteDispatcher( IRemoteCacheDispatcher remoteDispatcher )
+ {
+ this.remoteDispatcher = remoteDispatcher;
+ }
+
+ /**
+ * @return the remoteDispatcher
+ */
+ public IRemoteCacheDispatcher getRemoteDispatcher()
+ {
+ return remoteDispatcher;
+ }
+
+ /**
+ * @param remoteHttpCacheAttributes the remoteHttpCacheAttributes to set
+ */
+ public void setRemoteHttpCacheAttributes( RemoteHttpCacheAttributes remoteHttpCacheAttributes )
+ {
+ this.remoteHttpCacheAttributes = remoteHttpCacheAttributes;
+ }
+
+ /**
+ * @return the remoteHttpCacheAttributes
+ */
+ public RemoteHttpCacheAttributes getRemoteHttpCacheAttributes()
+ {
+ return remoteHttpCacheAttributes;
+ }
+
+ /**
+ * @param initialized the initialized to set
+ */
+ protected void setInitialized( boolean initialized )
+ {
+ this.initialized = initialized;
+ }
+
+ /**
+ * @return the initialized
+ */
+ protected boolean isInitialized()
+ {
+ return initialized;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheDispatcher.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheDispatcher.java
new file mode 100644
index 0000000..6073771
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheDispatcher.java
@@ -0,0 +1,196 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.client;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheDispatcher;
+import org.apache.commons.jcs3.auxiliary.remote.value.RemoteCacheRequest;
+import org.apache.commons.jcs3.auxiliary.remote.value.RemoteCacheResponse;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+import org.apache.http.HttpException;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.methods.RequestBuilder;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.util.EntityUtils;
+
+/** Calls the service. */
+public class RemoteHttpCacheDispatcher
+ extends AbstractHttpClient
+ implements IRemoteCacheDispatcher
+{
+ /** Parameter encoding */
+ private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
+
+ /** Named of the parameter */
+ private static final String PARAMETER_REQUEST_TYPE = "RequestType";
+
+ /** Named of the parameter */
+ private static final String PARAMETER_KEY = "Key";
+
+ /** Named of the parameter */
+ private static final String PARAMETER_CACHE_NAME = "CacheName";
+
+ /** The Logger. */
+ private static final Log log = LogManager.getLog( RemoteHttpCacheDispatcher.class );
+
+ /** This needs to be standard, since the other side is standard */
+ private final StandardSerializer serializer = new StandardSerializer();
+
+ /**
+ * @param remoteHttpCacheAttributes
+ */
+ public RemoteHttpCacheDispatcher( RemoteHttpCacheAttributes remoteHttpCacheAttributes )
+ {
+ super( remoteHttpCacheAttributes );
+ }
+
+ /**
+ * All requests will go through this method.
+ * <p>
+ * TODO consider taking in a URL instead of using the one in the configuration.
+ * <p>
+ * @param remoteCacheRequest
+ * @return RemoteCacheResponse
+ * @throws IOException
+ */
+ @Override
+ public <K, V, T>
+ RemoteCacheResponse<T> dispatchRequest( RemoteCacheRequest<K, V> remoteCacheRequest )
+ throws IOException
+ {
+ try
+ {
+ byte[] requestAsByteArray = serializer.serialize( remoteCacheRequest );
+
+ byte[] responseAsByteArray = processRequest( requestAsByteArray,
+ remoteCacheRequest,
+ getRemoteHttpCacheAttributes().getUrl());
+
+ RemoteCacheResponse<T> remoteCacheResponse = null;
+ try
+ {
+ remoteCacheResponse = serializer.deSerialize( responseAsByteArray, null );
+ }
+ catch ( ClassNotFoundException e )
+ {
+ log.error( "Couldn't deserialize the response.", e );
+ }
+ return remoteCacheResponse;
+ }
+ catch ( Exception e )
+ {
+ throw new IOException("Problem dispatching request.", e);
+ }
+ }
+
+ /**
+ * Process single request
+ *
+ * @param requestAsByteArray request body
+ * @param remoteCacheRequest the cache request
+ * @param url target url
+ *
+ * @return byte[] - the response
+ *
+ * @throws IOException
+ * @throws HttpException
+ */
+ protected <K, V> byte[] processRequest( byte[] requestAsByteArray,
+ RemoteCacheRequest<K, V> remoteCacheRequest, String url )
+ throws IOException, HttpException
+ {
+ RequestBuilder builder = RequestBuilder.post( url ).setCharset( DEFAULT_ENCODING );
+
+ if ( getRemoteHttpCacheAttributes().isIncludeCacheNameAsParameter()
+ && remoteCacheRequest.getCacheName() != null )
+ {
+ builder.addParameter( PARAMETER_CACHE_NAME, remoteCacheRequest.getCacheName() );
+ }
+ if ( getRemoteHttpCacheAttributes().isIncludeKeysAndPatternsAsParameter() )
+ {
+ String keyValue = "";
+ switch ( remoteCacheRequest.getRequestType() )
+ {
+ case GET:
+ case REMOVE:
+ case GET_KEYSET:
+ keyValue = remoteCacheRequest.getKey().toString();
+ break;
+ case GET_MATCHING:
+ keyValue = remoteCacheRequest.getPattern();
+ break;
+ case GET_MULTIPLE:
+ keyValue = remoteCacheRequest.getKeySet().toString();
+ break;
+ case UPDATE:
+ keyValue = remoteCacheRequest.getCacheElement().getKey().toString();
+ break;
+ default:
+ break;
+ }
+ builder.addParameter( PARAMETER_KEY, keyValue );
+ }
+ if ( getRemoteHttpCacheAttributes().isIncludeRequestTypeasAsParameter() )
+ {
+ builder.addParameter( PARAMETER_REQUEST_TYPE,
+ remoteCacheRequest.getRequestType().toString() );
+ }
+
+ builder.setEntity(new ByteArrayEntity( requestAsByteArray ));
+ HttpResponse httpResponse = doWebserviceCall( builder );
+ byte[] response = EntityUtils.toByteArray( httpResponse.getEntity() );
+ return response;
+ }
+
+ /**
+ * Called before the execute call on the client.
+ * <p>
+ * @param requestBuilder http method request builder
+ *
+ * @throws IOException
+ */
+ @Override
+ protected void preProcessWebserviceCall( RequestBuilder requestBuilder )
+ throws IOException
+ {
+ // do nothing. Child can override.
+ }
+
+ /**
+ * Called after the execute call on the client.
+ * <p>
+ * @param request http request
+ * @param httpState result of execution
+ *
+ * @throws IOException
+ */
+ @Override
+ protected void postProcessWebserviceCall( HttpUriRequest request, HttpResponse httpState )
+ throws IOException
+ {
+ // do nothing. Child can override.
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheFactory.java
new file mode 100644
index 0000000..91e4281
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheFactory.java
@@ -0,0 +1,146 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.client;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheFactory;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCacheNoWait;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheClient;
+import org.apache.commons.jcs3.auxiliary.remote.http.client.behavior.IRemoteHttpCacheClient;
+import org.apache.commons.jcs3.auxiliary.remote.server.behavior.RemoteType;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.config.OptionConverter;
+
+/**
+ * The RemoteCacheFactory creates remote caches for the cache hub. It returns a no wait facade which
+ * is a wrapper around a no wait. The no wait object is either an active connection to a remote
+ * cache or a balking zombie if the remote cache is not accessible. It should be transparent to the
+ * clients.
+ */
+public class RemoteHttpCacheFactory
+ extends AbstractAuxiliaryCacheFactory
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( RemoteHttpCacheFactory.class );
+
+ /** Monitor thread instance */
+ private RemoteHttpCacheMonitor monitor;
+
+ /**
+ * For LOCAL clients we get a handle to all the failovers, but we do not register a listener
+ * with them. We create the RemoteCacheManager, but we do not get a cache.
+ * <p>
+ * The failover runner will get a cache from the manager. When the primary is restored it will
+ * tell the manager for the failover to deregister the listener.
+ * <p>
+ * @param iaca
+ * @param cacheMgr
+ * @param cacheEventLogger
+ * @param elementSerializer
+ * @return AuxiliaryCache
+ */
+ @Override
+ public <K, V> AuxiliaryCache<K, V> createCache( AuxiliaryCacheAttributes iaca, ICompositeCacheManager cacheMgr,
+ ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
+ {
+ RemoteHttpCacheAttributes rca = (RemoteHttpCacheAttributes) iaca;
+
+ // TODO, use the configured value.
+ rca.setRemoteType( RemoteType.LOCAL );
+
+ RemoteHttpClientListener<K, V> listener = new RemoteHttpClientListener<>( rca, cacheMgr, elementSerializer );
+
+ IRemoteHttpCacheClient<K, V> remoteService = createRemoteHttpCacheClientForAttributes(rca);
+
+ IRemoteCacheClient<K, V> remoteCacheClient =
+ new RemoteHttpCache<>( rca, remoteService, listener, monitor );
+ remoteCacheClient.setCacheEventLogger( cacheEventLogger );
+ remoteCacheClient.setElementSerializer( elementSerializer );
+
+ RemoteCacheNoWait<K, V> remoteCacheNoWait = new RemoteCacheNoWait<>( remoteCacheClient );
+ remoteCacheNoWait.setCacheEventLogger( cacheEventLogger );
+ remoteCacheNoWait.setElementSerializer( elementSerializer );
+
+ return remoteCacheNoWait;
+ }
+
+ /**
+ * This is an extension point. The manager and other classes will only create
+ * RemoteHttpCacheClient through this method.
+
+ * @param cattr the cache configuration
+ * @return the client instance
+ */
+ protected <V, K> IRemoteHttpCacheClient<K, V> createRemoteHttpCacheClientForAttributes(RemoteHttpCacheAttributes cattr)
+ {
+ IRemoteHttpCacheClient<K, V> remoteService = OptionConverter.instantiateByClassName( cattr
+ .getRemoteHttpClientClassName(), null );
+
+ if ( remoteService == null )
+ {
+ log.info( "Creating the default client for {0}",
+ () -> cattr.getCacheName());
+ remoteService = new RemoteHttpCacheClient<>();
+ }
+
+ remoteService.initialize( cattr );
+ return remoteService;
+ }
+
+ /**
+ * @see org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheFactory#initialize()
+ */
+ @Override
+ public void initialize()
+ {
+ super.initialize();
+ monitor = new RemoteHttpCacheMonitor(this);
+ monitor.setDaemon(true);
+ monitor.start();
+ }
+
+ /**
+ * @see org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheFactory#dispose()
+ */
+ @Override
+ public void dispose()
+ {
+ if (monitor != null)
+ {
+ monitor.notifyShutdown();
+ try
+ {
+ monitor.join(5000);
+ }
+ catch (InterruptedException e)
+ {
+ // swallow
+ }
+ monitor = null;
+ }
+
+ super.dispose();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheMonitor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheMonitor.java
new file mode 100644
index 0000000..34e3ae4
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheMonitor.java
@@ -0,0 +1,136 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.client;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheMonitor;
+import org.apache.commons.jcs3.auxiliary.remote.http.client.behavior.IRemoteHttpCacheClient;
+import org.apache.commons.jcs3.engine.CacheStatus;
+
+/**
+ * Upon the notification of a connection error, the monitor changes to operate in a time driven
+ * mode. That is, it attempts to recover the connections on a periodic basis. When all failed
+ * connections are restored, it changes back to the failure driven mode.
+ */
+public class RemoteHttpCacheMonitor extends AbstractAuxiliaryCacheMonitor
+{
+ /** Set of remote caches to monitor. This are added on error, if not before. */
+ private final ConcurrentHashMap<RemoteHttpCache<?, ?>, RemoteHttpCache<?, ?>> remoteHttpCaches;
+
+ /** Factory instance */
+ private RemoteHttpCacheFactory factory = null;
+
+ /**
+ * Constructor for the RemoteCacheMonitor object
+ *
+ * @param factory the factory to set
+ */
+ public RemoteHttpCacheMonitor(RemoteHttpCacheFactory factory)
+ {
+ super("JCS-RemoteHttpCacheMonitor");
+ this.factory = factory;
+ this.remoteHttpCaches = new ConcurrentHashMap<>();
+ setIdlePeriod(3000L);
+ }
+
+ /**
+ * Notifies the cache monitor that an error occurred, and kicks off the error recovery process.
+ * <p>
+ * @param remoteCache
+ */
+ public void notifyError( RemoteHttpCache<?, ?> remoteCache )
+ {
+ if ( log.isInfoEnabled() )
+ {
+ log.info( "Notified of an error. " + remoteCache );
+ }
+
+ remoteHttpCaches.put( remoteCache, remoteCache );
+ notifyError();
+ }
+
+ /**
+ * Clean up all resources before shutdown
+ */
+ @Override
+ protected void dispose()
+ {
+ this.remoteHttpCaches.clear();
+ }
+
+ // Avoid the use of any synchronization in the process of monitoring for
+ // performance reasons.
+ // If exception is thrown owing to synchronization,
+ // just skip the monitoring until the next round.
+ /** Main processing method for the RemoteHttpCacheMonitor object */
+ @Override
+ protected void doWork()
+ {
+ // If no factory has been set, skip
+ if (factory == null)
+ {
+ return;
+ }
+
+ // If any cache is in error, it strongly suggests all caches
+ // managed by the same RmicCacheManager instance are in error. So we fix
+ // them once and for all.
+ for (RemoteHttpCache<?, ?> remoteCache : this.remoteHttpCaches.values())
+ {
+ try
+ {
+ if ( remoteCache.getStatus() == CacheStatus.ERROR )
+ {
+ RemoteHttpCacheAttributes attributes = remoteCache.getRemoteHttpCacheAttributes();
+
+ IRemoteHttpCacheClient<Serializable, Serializable> remoteService =
+ factory.createRemoteHttpCacheClientForAttributes( attributes );
+
+ if ( log.isInfoEnabled() )
+ {
+ log.info( "Performing Alive check on service " + remoteService );
+ }
+ // If we can't fix them, just skip and re-try in
+ // the next round.
+ if ( remoteService.isAlive() )
+ {
+ remoteCache.fixCache( remoteService );
+ }
+ else
+ {
+ allright.set(false);
+ }
+ break;
+ }
+ }
+ catch ( IOException ex )
+ {
+ allright.set(false);
+ // Problem encountered in fixing the caches managed by a
+ // RemoteCacheManager instance.
+ // Soldier on to the next RemoteHttpCache.
+ log.error( ex );
+ }
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpClientListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpClientListener.java
new file mode 100644
index 0000000..0247204
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpClientListener.java
@@ -0,0 +1,52 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.client;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.remote.AbstractRemoteCacheListener;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+
+/** Does nothing */
+public class RemoteHttpClientListener<K, V>
+ extends AbstractRemoteCacheListener<K, V>
+{
+ /**
+ * Only need one since it does work for all regions, just reference by multiple region names.
+ * <p>
+ * The constructor exports this object, making it available to receive incoming calls. The
+ * callback port is anonymous unless a local port value was specified in the configuration.
+ * <p>
+ * @param irca cache configuration
+ * @param cacheMgr the cache hub
+ * @param elementSerializer a custom serializer
+ */
+ public RemoteHttpClientListener( IRemoteCacheAttributes irca, ICompositeCacheManager cacheMgr, IElementSerializer elementSerializer )
+ {
+ super( irca, cacheMgr, elementSerializer );
+ }
+
+ /** Nothing */
+ @Override
+ public void dispose()
+ {
+ // noop
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/behavior/IRemoteHttpCacheClient.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/behavior/IRemoteHttpCacheClient.java
new file mode 100644
index 0000000..1d6933a
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/client/behavior/IRemoteHttpCacheClient.java
@@ -0,0 +1,51 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.client.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.auxiliary.remote.http.client.RemoteHttpCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+
+
+/**
+ * It's not entirely clear that this interface is needed. I simply wanted the initialization method.
+ * This could be added to the ICacheSerice method.
+ */
+public interface IRemoteHttpCacheClient<K, V>
+ extends ICacheServiceNonLocal<K, V>
+{
+ /**
+ * The provides an extension point. If you want to extend this and use a special dispatcher,
+ * here is the place to do it.
+ * <p>
+ * @param attributes
+ */
+ void initialize( RemoteHttpCacheAttributes attributes );
+
+ /**
+ * Make and alive request.
+ * <p>
+ * @return true if we make a successful alive request.
+ * @throws IOException
+ */
+ boolean isAlive()
+ throws IOException;
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/server/AbstractRemoteCacheService.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/server/AbstractRemoteCacheService.java
new file mode 100644
index 0000000..e84e575
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/server/AbstractRemoteCacheService.java
@@ -0,0 +1,601 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.server;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.logging.CacheEvent;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEvent;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This class contains common methods for remote cache services. Eventually I hope to extract out
+ * much of the RMI server to use this as well. I'm starting with the Http service.
+ */
+public abstract class AbstractRemoteCacheService<K, V>
+ implements ICacheServiceNonLocal<K, V>
+{
+ /** An optional event logger */
+ private transient ICacheEventLogger cacheEventLogger;
+
+ /** The central hub */
+ private ICompositeCacheManager cacheManager;
+
+ /** Name of the event log source. */
+ private String eventLogSourceName = "AbstractRemoteCacheService";
+
+ /** Number of puts into the cache. */
+ private int puts = 0;
+
+ /** The interval at which we will log updates. */
+ private final int logInterval = 100;
+
+ /** log instance */
+ private static final Log log = LogManager.getLog( AbstractRemoteCacheService.class );
+
+ /**
+ * Creates the super with the needed items.
+ * <p>
+ * @param cacheManager
+ * @param cacheEventLogger
+ */
+ public AbstractRemoteCacheService( ICompositeCacheManager cacheManager, ICacheEventLogger cacheEventLogger )
+ {
+ this.cacheManager = cacheManager;
+ this.cacheEventLogger = cacheEventLogger;
+ }
+
+ /**
+ * @param item
+ * @throws IOException
+ */
+ @Override
+ public void update( ICacheElement<K, V> item )
+ throws IOException
+ {
+ update( item, 0 );
+ }
+
+ /**
+ * The internal processing is wrapped in event logging calls.
+ * <p>
+ * @param item
+ * @param requesterId
+ * @throws IOException
+ */
+ @Override
+ public void update( ICacheElement<K, V> item, long requesterId )
+ throws IOException
+ {
+ ICacheEvent<ICacheElement<K, V>> cacheEvent = createICacheEvent( item, requesterId, ICacheEventLogger.UPDATE_EVENT );
+ try
+ {
+ logUpdateInfo( item );
+
+ processUpdate( item, requesterId );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * The internal processing is wrapped in event logging calls.
+ * <p>
+ * @param item
+ * @param requesterId
+ * @throws IOException
+ */
+ abstract void processUpdate( ICacheElement<K, V> item, long requesterId )
+ throws IOException;
+
+ /**
+ * Log some details.
+ * <p>
+ * @param item
+ */
+ private void logUpdateInfo( ICacheElement<K, V> item )
+ {
+ if ( log.isInfoEnabled() )
+ {
+ // not thread safe, but it doesn't have to be accurate
+ puts++;
+ if ( puts % logInterval == 0 )
+ {
+ log.info( "puts = {0}", puts );
+ }
+ }
+
+ log.debug( "In update, put [{0}] in [{1}]", () -> item.getKey(),
+ () -> item.getCacheName() );
+ }
+
+ /**
+ * Returns a cache value from the specified remote cache; or null if the cache or key does not
+ * exist.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @return ICacheElement
+ * @throws IOException
+ */
+ @Override
+ public ICacheElement<K, V> get( String cacheName, K key )
+ throws IOException
+ {
+ return this.get( cacheName, key, 0 );
+ }
+
+ /**
+ * Returns a cache bean from the specified cache; or null if the key does not exist.
+ * <p>
+ * Adding the requestor id, allows the cache to determine the source of the get.
+ * <p>
+ * The internal processing is wrapped in event logging calls.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @return ICacheElement
+ * @throws IOException
+ */
+ @Override
+ public ICacheElement<K, V> get( String cacheName, K key, long requesterId )
+ throws IOException
+ {
+ ICacheElement<K, V> element = null;
+ ICacheEvent<K> cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.GET_EVENT );
+ try
+ {
+ element = processGet( cacheName, key, requesterId );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ return element;
+ }
+
+ /**
+ * Returns a cache bean from the specified cache; or null if the key does not exist.
+ * <p>
+ * Adding the requestor id, allows the cache to determine the source of the get.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @return ICacheElement
+ * @throws IOException
+ */
+ abstract ICacheElement<K, V> processGet( String cacheName, K key, long requesterId )
+ throws IOException;
+
+ /**
+ * Gets all matching items.
+ * <p>
+ * @param cacheName
+ * @param pattern
+ * @return Map of keys and wrapped objects
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern )
+ throws IOException
+ {
+ return getMatching( cacheName, pattern, 0 );
+ }
+
+ /**
+ * Retrieves all matching keys.
+ * <p>
+ * @param cacheName
+ * @param pattern
+ * @param requesterId
+ * @return Map of keys and wrapped objects
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern, long requesterId )
+ throws IOException
+ {
+ ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, pattern, requesterId,
+ ICacheEventLogger.GETMATCHING_EVENT );
+ try
+ {
+ return processGetMatching( cacheName, pattern, requesterId );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Retrieves all matching keys.
+ * <p>
+ * @param cacheName
+ * @param pattern
+ * @param requesterId
+ * @return Map of keys and wrapped objects
+ * @throws IOException
+ */
+ abstract Map<K, ICacheElement<K, V>> processGetMatching( String cacheName, String pattern, long requesterId )
+ throws IOException;
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * @param cacheName
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys )
+ throws IOException
+ {
+ return this.getMultiple( cacheName, keys, 0 );
+ }
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * The internal processing is wrapped in event logging calls.
+ * <p>
+ * @param cacheName
+ * @param keys
+ * @param requesterId
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys, long requesterId )
+ throws IOException
+ {
+ ICacheEvent<Serializable> cacheEvent = createICacheEvent( cacheName, (Serializable) keys, requesterId,
+ ICacheEventLogger.GETMULTIPLE_EVENT );
+ try
+ {
+ return processGetMultiple( cacheName, keys, requesterId );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * @param cacheName
+ * @param keys
+ * @param requesterId
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ * @throws IOException
+ */
+ abstract Map<K, ICacheElement<K, V>> processGetMultiple( String cacheName, Set<K> keys, long requesterId )
+ throws IOException;
+
+ /**
+ * Return the keys in this cache.
+ * <p>
+ * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCache#getKeySet()
+ */
+ @Override
+ public Set<K> getKeySet( String cacheName )
+ {
+ return processGetKeySet( cacheName );
+ }
+
+ /**
+ * Gets the set of keys of objects currently in the cache.
+ * <p>
+ * @param cacheName
+ * @return Set
+ */
+ public Set<K> processGetKeySet( String cacheName )
+ {
+ CompositeCache<K, V> cache = getCacheManager().getCache( cacheName );
+
+ return cache.getKeySet();
+ }
+
+ /**
+ * Removes the given key from the specified remote cache. Defaults the listener id to 0.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @throws IOException
+ */
+ @Override
+ public void remove( String cacheName, K key )
+ throws IOException
+ {
+ remove( cacheName, key, 0 );
+ }
+
+ /**
+ * Remove the key from the cache region and don't tell the source listener about it.
+ * <p>
+ * The internal processing is wrapped in event logging calls.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @throws IOException
+ */
+ @Override
+ public void remove( String cacheName, K key, long requesterId )
+ throws IOException
+ {
+ ICacheEvent<K> cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.REMOVE_EVENT );
+ try
+ {
+ processRemove( cacheName, key, requesterId );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Remove the key from the cache region and don't tell the source listener about it.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @throws IOException
+ */
+ abstract void processRemove( String cacheName, K key, long requesterId )
+ throws IOException;
+
+ /**
+ * Remove all keys from the specified remote cache.
+ * <p>
+ * @param cacheName
+ * @throws IOException
+ */
+ @Override
+ public void removeAll( String cacheName )
+ throws IOException
+ {
+ removeAll( cacheName, 0 );
+ }
+
+ /**
+ * Remove all keys from the specified remote cache.
+ * <p>
+ * The internal processing is wrapped in event logging calls.
+ * <p>
+ * @param cacheName
+ * @param requesterId
+ * @throws IOException
+ */
+ @Override
+ public void removeAll( String cacheName, long requesterId )
+ throws IOException
+ {
+ ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, "all", requesterId, ICacheEventLogger.REMOVEALL_EVENT );
+ try
+ {
+ processRemoveAll( cacheName, requesterId );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Remove all keys from the specified remote cache.
+ * <p>
+ * @param cacheName
+ * @param requesterId
+ * @throws IOException
+ */
+ abstract void processRemoveAll( String cacheName, long requesterId )
+ throws IOException;
+
+ /**
+ * Frees the specified remote cache.
+ * <p>
+ * @param cacheName
+ * @throws IOException
+ */
+ @Override
+ public void dispose( String cacheName )
+ throws IOException
+ {
+ dispose( cacheName, 0 );
+ }
+
+ /**
+ * Frees the specified remote cache.
+ * <p>
+ * @param cacheName
+ * @param requesterId
+ * @throws IOException
+ */
+ public void dispose( String cacheName, long requesterId )
+ throws IOException
+ {
+ ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, "none", requesterId, ICacheEventLogger.DISPOSE_EVENT );
+ try
+ {
+ processDispose( cacheName, requesterId );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * @param cacheName
+ * @param requesterId
+ * @throws IOException
+ */
+ abstract void processDispose( String cacheName, long requesterId )
+ throws IOException;
+
+ /**
+ * Gets the stats attribute of the RemoteCacheServer object.
+ * <p>
+ * @return The stats value
+ * @throws IOException
+ */
+ public String getStats()
+ throws IOException
+ {
+ return cacheManager.getStats();
+ }
+
+ /**
+ * Logs an event if an event logger is configured.
+ * <p>
+ * @param item
+ * @param requesterId
+ * @param eventName
+ * @return ICacheEvent
+ */
+ protected ICacheEvent<ICacheElement<K, V>> createICacheEvent( ICacheElement<K, V> item, long requesterId, String eventName )
+ {
+ if ( cacheEventLogger == null )
+ {
+ return new CacheEvent<>();
+ }
+ String ipAddress = getExtraInfoForRequesterId( requesterId );
+ return cacheEventLogger.createICacheEvent( getEventLogSourceName(), item.getCacheName(), eventName, ipAddress,
+ item );
+ }
+
+ /**
+ * Logs an event if an event logger is configured.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @param eventName
+ * @return ICacheEvent
+ */
+ protected <T> ICacheEvent<T> createICacheEvent( String cacheName, T key, long requesterId, String eventName )
+ {
+ if ( cacheEventLogger == null )
+ {
+ return new CacheEvent<>();
+ }
+ String ipAddress = getExtraInfoForRequesterId( requesterId );
+ return cacheEventLogger.createICacheEvent( getEventLogSourceName(), cacheName, eventName, ipAddress, key );
+ }
+
+ /**
+ * Logs an event if an event logger is configured.
+ * <p>
+ * @param source
+ * @param eventName
+ * @param optionalDetails
+ */
+ protected void logApplicationEvent( String source, String eventName, String optionalDetails )
+ {
+ if ( cacheEventLogger != null )
+ {
+ cacheEventLogger.logApplicationEvent( source, eventName, optionalDetails );
+ }
+ }
+
+ /**
+ * Logs an event if an event logger is configured.
+ * <p>
+ * @param cacheEvent
+ */
+ protected <T> void logICacheEvent( ICacheEvent<T> cacheEvent )
+ {
+ if ( cacheEventLogger != null )
+ {
+ cacheEventLogger.logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Ip address for the client, if one is stored.
+ * <p>
+ * Protected for testing.
+ * <p>
+ * @param requesterId
+ * @return String
+ */
+ protected abstract String getExtraInfoForRequesterId( long requesterId );
+
+ /**
+ * Allows it to be injected.
+ * <p>
+ * @param cacheEventLogger
+ */
+ public void setCacheEventLogger( ICacheEventLogger cacheEventLogger )
+ {
+ this.cacheEventLogger = cacheEventLogger;
+ }
+
+ /**
+ * @param cacheManager the cacheManager to set
+ */
+ protected void setCacheManager( ICompositeCacheManager cacheManager )
+ {
+ this.cacheManager = cacheManager;
+ }
+
+ /**
+ * @return the cacheManager
+ */
+ protected ICompositeCacheManager getCacheManager()
+ {
+ return cacheManager;
+ }
+
+ /**
+ * @param eventLogSourceName the eventLogSourceName to set
+ */
+ protected void setEventLogSourceName( String eventLogSourceName )
+ {
+ this.eventLogSourceName = eventLogSourceName;
+ }
+
+ /**
+ * @return the eventLogSourceName
+ */
+ protected String getEventLogSourceName()
+ {
+ return eventLogSourceName;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/server/RemoteHttpCacheServerAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/server/RemoteHttpCacheServerAttributes.java
new file mode 100644
index 0000000..aa14823
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/server/RemoteHttpCacheServerAttributes.java
@@ -0,0 +1,95 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.server;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheAttributes;
+
+/**
+ * Configuration for the RemoteHttpCacheServer. Most of these properties are used only by the
+ * service.
+ */
+public class RemoteHttpCacheServerAttributes
+ extends AbstractAuxiliaryCacheAttributes
+{
+ /** Don't change. */
+ private static final long serialVersionUID = -3987239306108780496L;
+
+ /** Can a cluster remote put to other remotes */
+ private boolean localClusterConsistency = true;
+
+ /** Can a cluster remote get from other remotes */
+ private boolean allowClusterGet = true;
+
+ /**
+ * Should cluster updates be propagated to the locals
+ * <p>
+ * @return The localClusterConsistency value
+ */
+ public boolean isLocalClusterConsistency()
+ {
+ return localClusterConsistency;
+ }
+
+ /**
+ * Should cluster updates be propagated to the locals
+ * <p>
+ * @param r The new localClusterConsistency value
+ */
+ public void setLocalClusterConsistency( boolean r )
+ {
+ this.localClusterConsistency = r;
+ }
+
+ /**
+ * Should gets from non-cluster clients be allowed to get from other remote auxiliaries.
+ * <p>
+ * @return The localClusterConsistency value
+ */
+ public boolean isAllowClusterGet()
+ {
+ return allowClusterGet;
+ }
+
+ /**
+ * Should we try to get from other cluster servers if we don't find the items locally.
+ * <p>
+ * @param r The new localClusterConsistency value
+ */
+ public void setAllowClusterGet( boolean r )
+ {
+ allowClusterGet = r;
+ }
+
+ /**
+ * @return String details
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\nRemoteHttpCacheServiceAttributes" );
+ buf.append( "\n cacheName = [" + this.getCacheName() + "]" );
+ buf.append( "\n allowClusterGet = [" + this.isAllowClusterGet() + "]" );
+ buf.append( "\n localClusterConsistency = [" + this.isLocalClusterConsistency() + "]" );
+ buf.append( "\n eventQueueType = [" + this.getEventQueueType() + "]" );
+ buf.append( "\n eventQueuePoolName = [" + this.getEventQueuePoolName() + "]" );
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/server/RemoteHttpCacheService.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/server/RemoteHttpCacheService.java
new file mode 100644
index 0000000..4f0c251
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/server/RemoteHttpCacheService.java
@@ -0,0 +1,269 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.server;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+
+/**
+ * This does the work. It's called by the processor. The base class wraps the processing calls in
+ * event logs, if an event logger is present.
+ * <p>
+ * For now we assume that all clients are non-cluster clients. And listener notification is not
+ * supported.
+ */
+public class RemoteHttpCacheService<K, V>
+ extends AbstractRemoteCacheService<K, V>
+{
+ /** The name used in the event logs. */
+ private static final String EVENT_LOG_SOURCE_NAME = "RemoteHttpCacheServer";
+
+ /** The configuration */
+ private final RemoteHttpCacheServerAttributes remoteHttpCacheServerAttributes;
+
+ /**
+ * Create a process with a cache manager.
+ * <p>
+ * @param cacheManager
+ * @param remoteHttpCacheServerAttributes
+ * @param cacheEventLogger
+ */
+ public RemoteHttpCacheService( ICompositeCacheManager cacheManager,
+ RemoteHttpCacheServerAttributes remoteHttpCacheServerAttributes,
+ ICacheEventLogger cacheEventLogger )
+ {
+ super( cacheManager, cacheEventLogger );
+ setEventLogSourceName( EVENT_LOG_SOURCE_NAME );
+ this.remoteHttpCacheServerAttributes = remoteHttpCacheServerAttributes;
+ }
+
+ /**
+ * Processes a get request.
+ * <p>
+ * If isAllowClusterGet is enabled we will treat this as a normal request or non-remote origins.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @return ICacheElement
+ * @throws IOException
+ */
+ @Override
+ public ICacheElement<K, V> processGet( String cacheName, K key, long requesterId )
+ throws IOException
+ {
+ CompositeCache<K, V> cache = getCacheManager().getCache( cacheName );
+
+ boolean keepLocal = !remoteHttpCacheServerAttributes.isAllowClusterGet();
+ if ( keepLocal )
+ {
+ return cache.localGet( key );
+ }
+ else
+ {
+ return cache.get( key );
+ }
+ }
+
+ /**
+ * Processes a get request.
+ * <p>
+ * If isAllowClusterGet is enabled we will treat this as a normal request of non-remote
+ * origination.
+ * <p>
+ * @param cacheName
+ * @param keys
+ * @param requesterId
+ * @return Map
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> processGetMultiple( String cacheName, Set<K> keys, long requesterId )
+ throws IOException
+ {
+ CompositeCache<K, V> cache = getCacheManager().getCache( cacheName );
+
+ boolean keepLocal = !remoteHttpCacheServerAttributes.isAllowClusterGet();
+ if ( keepLocal )
+ {
+ return cache.localGetMultiple( keys );
+ }
+ else
+ {
+ return cache.getMultiple( keys );
+ }
+ }
+
+ /**
+ * Processes a get request.
+ * <p>
+ * If isAllowClusterGet is enabled we will treat this as a normal request of non-remote
+ * origination.
+ * <p>
+ * @param cacheName
+ * @param pattern
+ * @param requesterId
+ * @return Map
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> processGetMatching( String cacheName, String pattern, long requesterId )
+ throws IOException
+ {
+ CompositeCache<K, V> cache = getCacheManager().getCache( cacheName );
+
+ boolean keepLocal = !remoteHttpCacheServerAttributes.isAllowClusterGet();
+ if ( keepLocal )
+ {
+ return cache.localGetMatching( pattern );
+ }
+ else
+ {
+ return cache.getMatching( pattern );
+ }
+ }
+
+ /**
+ * Processes an update request.
+ * <p>
+ * If isLocalClusterConsistency is enabled we will treat this as a normal request of non-remote
+ * origination.
+ * <p>
+ * @param item
+ * @param requesterId
+ * @throws IOException
+ */
+ @Override
+ public void processUpdate( ICacheElement<K, V> item, long requesterId )
+ throws IOException
+ {
+ CompositeCache<K, V> cache = getCacheManager().getCache( item.getCacheName() );
+
+ boolean keepLocal = !remoteHttpCacheServerAttributes.isLocalClusterConsistency();
+ if ( keepLocal )
+ {
+ cache.localUpdate( item );
+ }
+ else
+ {
+ cache.update( item );
+ }
+ }
+
+ /**
+ * Processes a remove request.
+ * <p>
+ * If isLocalClusterConsistency is enabled we will treat this as a normal request of non-remote
+ * origination.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @throws IOException
+ */
+ @Override
+ public void processRemove( String cacheName, K key, long requesterId )
+ throws IOException
+ {
+ CompositeCache<K, V> cache = getCacheManager().getCache( cacheName );
+
+ boolean keepLocal = !remoteHttpCacheServerAttributes.isLocalClusterConsistency();
+ if ( keepLocal )
+ {
+ cache.localRemove( key );
+ }
+ else
+ {
+ cache.remove( key );
+ }
+ }
+
+ /**
+ * Processes a removeAll request.
+ * <p>
+ * If isLocalClusterConsistency is enabled we will treat this as a normal request of non-remote
+ * origination.
+ * <p>
+ * @param cacheName
+ * @param requesterId
+ * @throws IOException
+ */
+ @Override
+ public void processRemoveAll( String cacheName, long requesterId )
+ throws IOException
+ {
+ CompositeCache<K, V> cache = getCacheManager().getCache( cacheName );
+
+ boolean keepLocal = !remoteHttpCacheServerAttributes.isLocalClusterConsistency();
+ if ( keepLocal )
+ {
+ cache.localRemoveAll();
+ }
+ else
+ {
+ cache.removeAll();
+ }
+ }
+
+ /**
+ * Processes a shutdown request.
+ * <p>
+ * @param cacheName
+ * @param requesterId
+ * @throws IOException
+ */
+ @Override
+ public void processDispose( String cacheName, long requesterId )
+ throws IOException
+ {
+ CompositeCache<K, V> cache = getCacheManager().getCache( cacheName );
+ cache.dispose();
+ }
+
+ /**
+ * This general method should be deprecated.
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ public void release()
+ throws IOException
+ {
+ //nothing.
+ }
+
+ /**
+ * This is called by the event log.
+ * <p>
+ * @param requesterId
+ * @return requesterId + ""
+ */
+ @Override
+ protected String getExtraInfoForRequesterId( long requesterId )
+ {
+ return requesterId + "";
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/server/RemoteHttpCacheServlet.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/server/RemoteHttpCacheServlet.java
new file mode 100644
index 0000000..280278b
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/http/server/RemoteHttpCacheServlet.java
@@ -0,0 +1,380 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.server;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheConfigurator;
+import org.apache.commons.jcs3.auxiliary.remote.http.behavior.IRemoteHttpCacheConstants;
+import org.apache.commons.jcs3.auxiliary.remote.value.RemoteCacheRequest;
+import org.apache.commons.jcs3.auxiliary.remote.value.RemoteCacheResponse;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.io.ObjectInputStreamClassLoaderAware;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.config.PropertySetter;
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+
+/**
+ * This servlet simply reads and writes objects. The requests are packaged in a general wrapper. The
+ * processor works on the wrapper object and returns a response wrapper.
+ */
+public class RemoteHttpCacheServlet
+ extends HttpServlet
+{
+ /** Don't change. */
+ private static final long serialVersionUID = 8752849397531933346L;
+
+ /** The Logger. */
+ private static final Log log = LogManager.getLog( RemoteHttpCacheServlet.class );
+
+ /** The cache manager */
+ private static CompositeCacheManager cacheMgr;
+
+ /** The service that does the work. */
+ private static ICacheServiceNonLocal<Serializable, Serializable> remoteCacheService;
+
+ /** This needs to be standard, since the other side is standard */
+ private final StandardSerializer serializer = new StandardSerializer();
+
+ /** Number of service calls. */
+ private int serviceCalls = 0;
+
+ /** The interval at which we will log the count. */
+ private final int logInterval = 100;
+
+ /**
+ * Initializes the cache.
+ * <p>
+ * This provides an easy extension point. Simply extend this servlet and override the init
+ * method to change the way the properties are loaded.
+ * @param config
+ * @throws ServletException
+ */
+ @Override
+ public void init( ServletConfig config )
+ throws ServletException
+ {
+ try
+ {
+ cacheMgr = CompositeCacheManager.getInstance();
+ }
+ catch (CacheException e)
+ {
+ throw new ServletException(e);
+ }
+
+ remoteCacheService = createRemoteHttpCacheService( cacheMgr );
+
+ super.init( config );
+ }
+
+ /**
+ * Read the request, call the processor, write the response.
+ * <p>
+ * @param request
+ * @param response
+ * @throws ServletException
+ * @throws IOException
+ */
+ @Override
+ public void service( HttpServletRequest request, HttpServletResponse response )
+ throws ServletException, IOException
+ {
+ incrementServiceCallCount();
+ log.debug( "Servicing a request. {0}", request );
+
+ RemoteCacheRequest<Serializable, Serializable> remoteRequest = readRequest( request );
+ RemoteCacheResponse<Object> cacheResponse = processRequest( remoteRequest );
+
+ writeResponse( response, cacheResponse );
+ }
+
+ /**
+ * Read the request from the input stream.
+ * <p>
+ * @param request
+ * @return RemoteHttpCacheRequest
+ */
+ protected RemoteCacheRequest<Serializable, Serializable> readRequest( HttpServletRequest request )
+ {
+ RemoteCacheRequest<Serializable, Serializable> remoteRequest = null;
+ try
+ {
+ InputStream inputStream = request.getInputStream();
+ log.debug( "After getting input stream and before reading it" );
+
+ remoteRequest = readRequestFromStream( inputStream );
+ }
+ catch ( Exception e )
+ {
+ log.error( "Could not get a RemoteHttpCacheRequest object from the input stream.", e );
+ }
+ return remoteRequest;
+ }
+
+ /**
+ * Reads the response from the stream and then closes it.
+ * <p>
+ * @param inputStream
+ * @return RemoteHttpCacheRequest
+ * @throws IOException
+ * @throws ClassNotFoundException
+ */
+ protected RemoteCacheRequest<Serializable, Serializable> readRequestFromStream( InputStream inputStream )
+ throws IOException, ClassNotFoundException
+ {
+ ObjectInputStream ois = new ObjectInputStreamClassLoaderAware( inputStream, null );
+
+ @SuppressWarnings("unchecked") // Need to cast from Object
+ RemoteCacheRequest<Serializable, Serializable> remoteRequest
+ = (RemoteCacheRequest<Serializable, Serializable>) ois.readObject();
+ ois.close();
+ return remoteRequest;
+ }
+
+ /**
+ * Write the response to the output stream.
+ * <p>
+ * @param response
+ * @param cacheResponse
+ */
+ protected void writeResponse( HttpServletResponse response, RemoteCacheResponse<Object> cacheResponse )
+ {
+ try
+ {
+ response.setContentType( "application/octet-stream" );
+
+ byte[] responseAsByteAray = serializer.serialize( cacheResponse );
+ response.setContentLength( responseAsByteAray.length );
+
+ OutputStream outputStream = response.getOutputStream();
+ log.debug( "Opened output stream. Response size: {0}",
+ () -> responseAsByteAray.length );
+ // WRITE
+ outputStream.write( responseAsByteAray );
+ outputStream.flush();
+ outputStream.close();
+ }
+ catch ( IOException e )
+ {
+ log.error( "Problem writing response. {0}", cacheResponse, e );
+ }
+ }
+
+ /**
+ * Processes the request. It will call the appropriate method on the service
+ * <p>
+ * @param request
+ * @return RemoteHttpCacheResponse, never null
+ */
+ protected RemoteCacheResponse<Object> processRequest( RemoteCacheRequest<Serializable, Serializable> request )
+ {
+ RemoteCacheResponse<Object> response = new RemoteCacheResponse<>();
+
+ if ( request == null )
+ {
+ String message = "The request is null. Cannot process";
+ log.warn( message );
+ response.setSuccess( false );
+ response.setErrorMessage( message );
+ }
+ else
+ {
+ try
+ {
+ switch ( request.getRequestType() )
+ {
+ case GET:
+ ICacheElement<Serializable, Serializable> element =
+ remoteCacheService.get( request.getCacheName(), request.getKey(), request.getRequesterId() );
+ response.setPayload(element);
+ break;
+ case GET_MULTIPLE:
+ Map<Serializable, ICacheElement<Serializable, Serializable>> elementMap =
+ remoteCacheService.getMultiple( request.getCacheName(), request.getKeySet(), request.getRequesterId() );
+ if ( elementMap != null )
+ {
+ Map<Serializable, ICacheElement<Serializable, Serializable>> map = new HashMap<>();
+ map.putAll(elementMap);
+ response.setPayload(map);
+ }
+ break;
+ case GET_MATCHING:
+ Map<Serializable, ICacheElement<Serializable, Serializable>> elementMapMatching =
+ remoteCacheService.getMatching( request.getCacheName(), request.getPattern(), request.getRequesterId() );
+ if ( elementMapMatching != null )
+ {
+ Map<Serializable, ICacheElement<Serializable, Serializable>> map = new HashMap<>();
+ map.putAll(elementMapMatching);
+ response.setPayload(map);
+ }
+ break;
+ case REMOVE:
+ remoteCacheService.remove( request.getCacheName(), request.getKey(), request.getRequesterId() );
+ break;
+ case REMOVE_ALL:
+ remoteCacheService.removeAll( request.getCacheName(), request.getRequesterId() );
+ break;
+ case UPDATE:
+ remoteCacheService.update( request.getCacheElement(), request.getRequesterId() );
+ break;
+ case ALIVE_CHECK:
+ case DISPOSE:
+ response.setSuccess( true );
+ // DO NOTHING
+ break;
+ case GET_KEYSET:
+ Set<Serializable> keys = remoteCacheService.getKeySet( request.getCacheName() );
+ response.setPayload( keys );
+ break;
+ default:
+ String message = "Unknown event type. Cannot process " + request;
+ log.warn( message );
+ response.setSuccess( false );
+ response.setErrorMessage( message );
+ break;
+ }
+ }
+ catch ( IOException e )
+ {
+ String message = "Problem processing request. " + request + " Error: " + e.getMessage();
+ log.error( message, e );
+ response.setSuccess( false );
+ response.setErrorMessage( message );
+ }
+ }
+
+ return response;
+ }
+
+ /**
+ * Configures the attributes and the event logger and constructs a service.
+ * <p>
+ * @param cacheManager
+ * @return RemoteHttpCacheService
+ */
+ protected <K, V> RemoteHttpCacheService<K, V> createRemoteHttpCacheService( ICompositeCacheManager cacheManager )
+ {
+ Properties props = cacheManager.getConfigurationProperties();
+ ICacheEventLogger cacheEventLogger = configureCacheEventLogger( props );
+ RemoteHttpCacheServerAttributes attributes = configureRemoteHttpCacheServerAttributes( props );
+
+ RemoteHttpCacheService<K, V> service = new RemoteHttpCacheService<>( cacheManager, attributes, cacheEventLogger );
+ log.info( "Created new RemoteHttpCacheService {0}", service );
+ return service;
+ }
+
+ /**
+ * Tries to get the event logger.
+ * <p>
+ * @param props
+ * @return ICacheEventLogger
+ */
+ protected ICacheEventLogger configureCacheEventLogger( Properties props )
+ {
+ ICacheEventLogger cacheEventLogger = AuxiliaryCacheConfigurator
+ .parseCacheEventLogger( props, IRemoteHttpCacheConstants.HTTP_CACHE_SERVER_PREFIX );
+
+ return cacheEventLogger;
+ }
+
+ /**
+ * Configure.
+ * <p>
+ * jcs.remotehttpcache.serverattributes.ATTRIBUTENAME=ATTRIBUTEVALUE
+ * <p>
+ * @param prop
+ * @return RemoteCacheServerAttributesconfigureRemoteCacheServerAttributes
+ */
+ protected RemoteHttpCacheServerAttributes configureRemoteHttpCacheServerAttributes( Properties prop )
+ {
+ RemoteHttpCacheServerAttributes rcsa = new RemoteHttpCacheServerAttributes();
+
+ // configure automatically
+ PropertySetter.setProperties( rcsa, prop,
+ IRemoteHttpCacheConstants.HTTP_CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + "." );
+
+ return rcsa;
+ }
+
+ /**
+ * @param rcs the remoteCacheService to set
+ */
+ protected void setRemoteCacheService(ICacheServiceNonLocal<Serializable, Serializable> rcs)
+ {
+ remoteCacheService = rcs;
+ }
+
+ /**
+ * Log some details.
+ */
+ private void incrementServiceCallCount()
+ {
+ // not thread safe, but it doesn't have to be accurate
+ serviceCalls++;
+ if ( log.isInfoEnabled() )
+ {
+ if ( serviceCalls % logInterval == 0 )
+ {
+ log.info( "serviceCalls = {0}", serviceCalls );
+ }
+ }
+ }
+
+ /** Release the cache manager. */
+ @Override
+ public void destroy()
+ {
+ log.info( "Servlet Destroyed, shutting down JCS." );
+
+ cacheMgr.shutDown();
+ }
+
+ /**
+ * Get servlet information
+ * <p>
+ * @return basic info
+ */
+ @Override
+ public String getServletInfo()
+ {
+ return "RemoteHttpCacheServlet";
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/package.html b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/package.html
similarity index 100%
rename from commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/package.html
rename to commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/package.html
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/RegistryKeepAliveRunner.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/RegistryKeepAliveRunner.java
new file mode 100644
index 0000000..25febd0
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/RegistryKeepAliveRunner.java
@@ -0,0 +1,196 @@
+package org.apache.commons.jcs3.auxiliary.remote.server;
+
+/*
+ * 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.
+ */
+
+import java.rmi.Naming;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.registry.Registry;
+
+import org.apache.commons.jcs3.auxiliary.remote.RemoteUtils;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This class tries to keep the registry alive. If if is able to create a registry, it will also
+ * rebind the remote cache server.
+ */
+public class RegistryKeepAliveRunner
+ implements Runnable
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( RegistryKeepAliveRunner.class );
+
+ /** The URL of the service to look for. */
+ private final String namingURL;
+
+ /** The service name. */
+ private final String serviceName;
+
+ /** the port on which to start the registry */
+ private final int registryPort;
+
+ /** An optional event logger */
+ private ICacheEventLogger cacheEventLogger;
+
+ /** the registry */
+ private Registry registry;
+
+ /**
+ * @param registryHost - Hostname of the registry
+ * @param registryPort - the port on which to start the registry
+ * @param serviceName
+ */
+ public RegistryKeepAliveRunner( String registryHost, int registryPort, String serviceName )
+ {
+ this.namingURL = RemoteUtils.getNamingURL(registryHost, registryPort, serviceName);
+ this.serviceName = serviceName;
+ this.registryPort = registryPort;
+ }
+
+ /**
+ * Tries to lookup the server. If unsuccessful it will rebind the server using the factory
+ * rebind method.
+ * <p>
+ */
+ @Override
+ public void run()
+ {
+ checkAndRestoreIfNeeded();
+ }
+
+ /**
+ * Tries to lookup the server. If unsuccessful it will rebind the server using the factory
+ * rebind method.
+ */
+ protected void checkAndRestoreIfNeeded()
+ {
+ log.debug( "looking up server {0}", namingURL );
+
+ try
+ {
+ Object obj = Naming.lookup( namingURL );
+
+ // Successful connection to the remote server.
+ String message = "RMI registry looks fine. Found [" + obj + "] in registry [" + namingURL + "]";
+ if ( cacheEventLogger != null )
+ {
+ cacheEventLogger.logApplicationEvent( "RegistryKeepAliveRunner", "Naming.lookup", message );
+ }
+ log.debug( message );
+ }
+ catch ( Exception ex )
+ {
+ // Failed to connect to the remote server.
+ String message = "Problem finding server at [" + namingURL
+ + "]. Will attempt to start registry and rebind.";
+ log.error( message, ex );
+ if ( cacheEventLogger != null )
+ {
+ cacheEventLogger.logError( "RegistryKeepAliveRunner", "Naming.lookup", message + ":" + ex.getMessage() );
+ }
+ createAndRegister( serviceName );
+ }
+ }
+
+ /**
+ * Creates the registry and registers the server.
+ * <p>
+ * @param serviceName the service name
+ */
+ protected void createAndRegister( String serviceName )
+ {
+ createReqistry( serviceName );
+ registerServer( serviceName );
+ }
+
+ /**
+ * Try to create the registry. Log errors
+ * <p>
+ * @param serviceName the service name
+ */
+ protected void createReqistry( String serviceName )
+ {
+ // TODO: Refactor method signature. This is ugly but required to keep the binary API compatibility
+ this.registry = RemoteUtils.createRegistry(registryPort);
+
+ if ( cacheEventLogger != null )
+ {
+ if (this.registry != null)
+ {
+ cacheEventLogger.logApplicationEvent( "RegistryKeepAliveRunner", "createRegistry",
+ "Successfully created registry [" + serviceName + "]." );
+ }
+ else
+ {
+ cacheEventLogger.logError( "RegistryKeepAliveRunner", "createRegistry",
+ "Could not start registry [" + serviceName + "]." );
+ }
+ }
+ }
+
+ /**
+ * Try to rebind the server.
+ * <p>
+ * @param serviceName the service name
+ */
+ protected void registerServer( String serviceName )
+ {
+ try
+ {
+ // try to rebind anyway
+ Remote server = RemoteCacheServerFactory.getRemoteCacheServer();
+
+ if ( server == null )
+ {
+ throw new RemoteException( "Cannot register the server until it is created." );
+ }
+
+ this.registry.rebind( serviceName, server );
+ String message = "Successfully rebound server to registry [" + serviceName + "].";
+ if ( cacheEventLogger != null )
+ {
+ cacheEventLogger.logApplicationEvent( "RegistryKeepAliveRunner", "registerServer", message );
+ }
+ log.info( message );
+ }
+ catch ( RemoteException e )
+ {
+ String message = "Could not rebind server to registry [" + serviceName + "].";
+ log.error( message, e );
+ if ( cacheEventLogger != null )
+ {
+ cacheEventLogger.logError( "RegistryKeepAliveRunner", "registerServer", message + ":"
+ + e.getMessage() );
+ }
+ }
+ }
+
+ /**
+ * Allows it to be injected.
+ * <p>
+ * @param cacheEventLogger
+ */
+ public void setCacheEventLogger( ICacheEventLogger cacheEventLogger )
+ {
+ this.cacheEventLogger = cacheEventLogger;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServer.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServer.java
new file mode 100644
index 0000000..fb7f5a4
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServer.java
@@ -0,0 +1,1528 @@
+package org.apache.commons.jcs3.auxiliary.remote.server;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.rmi.RemoteException;
+import java.rmi.registry.Registry;
+import java.rmi.server.RMISocketFactory;
+import java.rmi.server.UnicastRemoteObject;
+import java.rmi.server.Unreferenced;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheListener;
+import org.apache.commons.jcs3.auxiliary.remote.server.behavior.IRemoteCacheServer;
+import org.apache.commons.jcs3.auxiliary.remote.server.behavior.IRemoteCacheServerAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.server.behavior.RemoteType;
+import org.apache.commons.jcs3.engine.CacheEventQueueFactory;
+import org.apache.commons.jcs3.engine.CacheListeners;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheEventQueue;
+import org.apache.commons.jcs3.engine.behavior.ICacheListener;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+import org.apache.commons.jcs3.engine.logging.CacheEvent;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEvent;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.timing.ElapsedTimer;
+
+/**
+ * This class provides remote cache services. The remote cache server propagates events from local
+ * caches to other local caches. It can also store cached data, making it available to new clients.
+ * <p>
+ * Remote cache servers can be clustered. If the cache used by this remote cache is configured to
+ * use a remote cache of type cluster, the two remote caches will communicate with each other.
+ * Remote and put requests can be sent from one remote to another. If they are configured to
+ * broadcast such event to their client, then remove an puts can be sent to all locals in the
+ * cluster.
+ * <p>
+ * Get requests are made between clustered servers if AllowClusterGet is true. You can setup several
+ * clients to use one remote server and several to use another. The get local will be distributed
+ * between the two servers. Since caches are usually high get and low put, this should allow you to
+ * scale.
+ */
+public class RemoteCacheServer<K, V>
+ extends UnicastRemoteObject
+ implements IRemoteCacheServer<K, V>, Unreferenced
+{
+ public static final String DFEAULT_REMOTE_CONFIGURATION_FILE = "/remote.cache.ccf";
+
+ /** For serialization. Don't change. */
+ private static final long serialVersionUID = -8072345435941473116L;
+
+ /** log instance */
+ private static final Log log = LogManager.getLog( RemoteCacheServer.class );
+
+ /** Number of puts into the cache. */
+ private int puts = 0;
+
+ /** Maps cache name to CacheListeners object. association of listeners (regions). */
+ private final transient ConcurrentMap<String, CacheListeners<K, V>> cacheListenersMap =
+ new ConcurrentHashMap<>();
+
+ /** maps cluster listeners to regions. */
+ private final transient ConcurrentMap<String, CacheListeners<K, V>> clusterListenersMap =
+ new ConcurrentHashMap<>();
+
+ /** The central hub */
+ private transient CompositeCacheManager cacheManager;
+
+ /** relates listener id with a type */
+ private final ConcurrentMap<Long, RemoteType> idTypeMap = new ConcurrentHashMap<>();
+
+ /** relates listener id with an ip address */
+ private final ConcurrentMap<Long, String> idIPMap = new ConcurrentHashMap<>();
+
+ /** Used to get the next listener id. */
+ private final int[] listenerId = new int[1];
+
+ /** Configuration settings. */
+ // package protected for access by unit test code
+ final IRemoteCacheServerAttributes remoteCacheServerAttributes;
+
+ /** The interval at which we will log updates. */
+ private final int logInterval = 100;
+
+ /** An optional event logger */
+ private transient ICacheEventLogger cacheEventLogger;
+
+ /**
+ * Constructor for the RemoteCacheServer object. This initializes the server with the values
+ * from the properties object.
+ * <p>
+ * @param rcsa
+ * @param config cache hub configuration
+ * @throws RemoteException
+ */
+ protected RemoteCacheServer( IRemoteCacheServerAttributes rcsa, Properties config )
+ throws RemoteException
+ {
+ super( rcsa.getServicePort() );
+ this.remoteCacheServerAttributes = rcsa;
+ init( config );
+ }
+
+ /**
+ * Constructor for the RemoteCacheServer object. This initializes the server with the values
+ * from the properties object.
+ * <p>
+ * @param rcsa
+ * @param config cache hub configuration
+ * @param customRMISocketFactory
+ * @throws RemoteException
+ */
+ protected RemoteCacheServer( IRemoteCacheServerAttributes rcsa, Properties config, RMISocketFactory customRMISocketFactory )
+ throws RemoteException
+ {
+ super( rcsa.getServicePort(), customRMISocketFactory, customRMISocketFactory );
+ this.remoteCacheServerAttributes = rcsa;
+ init( config );
+ }
+
+ /**
+ * Initialize the RMI Cache Server from a properties object.
+ * <p>
+ * @param prop the configuration properties
+ * @throws RemoteException if the configuration of the cache manager instance fails
+ */
+ private void init( Properties prop ) throws RemoteException
+ {
+ try
+ {
+ cacheManager = createCacheManager( prop );
+ }
+ catch (CacheException e)
+ {
+ throw new RemoteException(e.getMessage(), e);
+ }
+
+ // cacheManager would have created a number of ICache objects.
+ // Use these objects to set up the cacheListenersMap.
+ cacheManager.getCacheNames().forEach(name -> {
+ CompositeCache<K, V> cache = cacheManager.getCache( name );
+ cacheListenersMap.put( name, new CacheListeners<>( cache ) );
+ });
+ }
+
+ /**
+ * Subclass can override this method to create the specific cache manager.
+ * <p>
+ * @param prop the configuration object.
+ * @return The cache hub configured with this configuration.
+ *
+ * @throws CacheException if the configuration cannot be loaded
+ */
+ private CompositeCacheManager createCacheManager( Properties prop ) throws CacheException
+ {
+ CompositeCacheManager hub = CompositeCacheManager.getUnconfiguredInstance();
+ hub.configure( prop );
+ return hub;
+ }
+
+ /**
+ * Puts a cache bean to the remote cache and notifies all listeners which <br>
+ * <ol>
+ * <li>have a different listener id than the originating host;</li>
+ * <li>are currently subscribed to the related cache.</li>
+ * </ol>
+ * <p>
+ * @param item
+ * @throws IOException
+ */
+ public void put( ICacheElement<K, V> item )
+ throws IOException
+ {
+ update( item );
+ }
+
+ /**
+ * @param item
+ * @throws IOException
+ */
+ @Override
+ public void update( ICacheElement<K, V> item )
+ throws IOException
+ {
+ update( item, 0 );
+ }
+
+ /**
+ * The internal processing is wrapped in event logging calls.
+ * <p>
+ * @param item
+ * @param requesterId
+ * @throws IOException
+ */
+ @Override
+ public void update( ICacheElement<K, V> item, long requesterId )
+ throws IOException
+ {
+ ICacheEvent<ICacheElement<K, V>> cacheEvent = createICacheEvent( item, requesterId, ICacheEventLogger.UPDATE_EVENT );
+ try
+ {
+ processUpdate( item, requesterId );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * An update can come from either a local cache's remote auxiliary, or it can come from a remote
+ * server. A remote server is considered a a source of type cluster.
+ * <p>
+ * If the update came from a cluster, then we should tell the cache manager that this was a
+ * remote put. This way, any lateral and remote auxiliaries configured for the region will not
+ * be updated. This is basically how a remote listener works when plugged into a local cache.
+ * <p>
+ * If the cluster is configured to keep local cluster consistency, then all listeners will be
+ * updated. This allows cluster server A to update cluster server B and then B to update its
+ * clients if it is told to keep local cluster consistency. Otherwise, server A will update
+ * server B and B will not tell its clients. If you cluster using lateral caches for instance,
+ * this is how it will work. Updates to a cluster node, will never get to the leaves. The remote
+ * cluster, with local cluster consistency, allows you to update leaves. This basically allows
+ * you to have a failover remote server.
+ * <p>
+ * Since currently a cluster will not try to get from other cluster servers, you can scale a bit
+ * with a cluster configuration. Puts and removes will be broadcasted to all clients, but the
+ * get load on a remote server can be reduced.
+ * <p>
+ * @param item
+ * @param requesterId
+ */
+ private void processUpdate( ICacheElement<K, V> item, long requesterId )
+ {
+ ElapsedTimer timer = new ElapsedTimer();
+ logUpdateInfo( item );
+
+ try
+ {
+ CacheListeners<K, V> cacheDesc = getCacheListeners( item.getCacheName() );
+ /* Object val = */item.getVal();
+
+ boolean fromCluster = isRequestFromCluster( requesterId );
+
+ log.debug( "In update, requesterId = [{0}] fromCluster = {1}", requesterId, fromCluster );
+
+ // ordered cache item update and notification.
+ synchronized ( cacheDesc )
+ {
+ try
+ {
+ CompositeCache<K, V> c = (CompositeCache<K, V>) cacheDesc.cache;
+
+ // If the source of this request was not from a cluster,
+ // then consider it a local update. The cache manager will
+ // try to
+ // update all auxiliaries.
+ //
+ // This requires that two local caches not be connected to
+ // two clustered remote caches. The failover runner will
+ // have to make sure of this. ALos, the local cache needs
+ // avoid updating this source. Will need to pass the source
+ // id somehow. The remote cache should update all local
+ // caches
+ // but not update the cluster source. Cluster remote caches
+ // should only be updated by the server and not the
+ // RemoteCache.
+ if ( fromCluster )
+ {
+ log.debug( "Put FROM cluster, NOT updating other auxiliaries for region. "
+ + " requesterId [{0}]", requesterId );
+ c.localUpdate( item );
+ }
+ else
+ {
+ log.debug( "Put NOT from cluster, updating other auxiliaries for region. "
+ + " requesterId [{0}]", requesterId );
+ c.update( item );
+ }
+ }
+ catch ( IOException ce )
+ {
+ // swallow
+ log.info( "Exception caught updating item. requesterId [{0}]: {1}",
+ requesterId, ce.getMessage() );
+ }
+
+ // UPDATE LOCALS IF A REQUEST COMES FROM A CLUSTER
+ // IF LOCAL CLUSTER CONSISTENCY IS CONFIGURED
+ if ( !fromCluster || ( fromCluster && remoteCacheServerAttributes.isLocalClusterConsistency() ) )
+ {
+ ICacheEventQueue<K, V>[] qlist = getEventQList( cacheDesc, requesterId );
+ log.debug( "qlist.length = {0}", qlist.length );
+ for ( int i = 0; i < qlist.length; i++ )
+ {
+ qlist[i].addPutEvent( item );
+ }
+ }
+ }
+ }
+ catch ( IOException e )
+ {
+ if ( cacheEventLogger != null )
+ {
+ cacheEventLogger.logError( "RemoteCacheServer", ICacheEventLogger.UPDATE_EVENT, e.getMessage()
+ + " REGION: " + item.getCacheName() + " ITEM: " + item );
+ }
+
+ log.error( "Trouble in Update. requesterId [{0}]", requesterId, e );
+ }
+
+ // TODO use JAMON for timing
+ log.debug( "put took {0} ms.", () -> timer.getElapsedTime());
+ }
+
+ /**
+ * Log some details.
+ * <p>
+ * @param item
+ */
+ private void logUpdateInfo( ICacheElement<K, V> item )
+ {
+ // not thread safe, but it doesn't have to be 100% accurate
+ puts++;
+
+ if ( log.isInfoEnabled() )
+ {
+ if ( puts % logInterval == 0 )
+ {
+ log.info( "puts = {0}", puts );
+ }
+ }
+
+ log.debug( "In update, put [{0}] in [{1}]",
+ () -> item.getKey(), () -> item.getCacheName() );
+ }
+
+ /**
+ * Returns a cache value from the specified remote cache; or null if the cache or key does not
+ * exist.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @return ICacheElement
+ * @throws IOException
+ */
+ @Override
+ public ICacheElement<K, V> get( String cacheName, K key )
+ throws IOException
+ {
+ return this.get( cacheName, key, 0 );
+ }
+
+ /**
+ * Returns a cache bean from the specified cache; or null if the key does not exist.
+ * <p>
+ * Adding the requestor id, allows the cache to determine the source of the get.
+ * <p>
+ * The internal processing is wrapped in event logging calls.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @return ICacheElement
+ * @throws IOException
+ */
+ @Override
+ public ICacheElement<K, V> get( String cacheName, K key, long requesterId )
+ throws IOException
+ {
+ ICacheElement<K, V> element = null;
+ ICacheEvent<K> cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.GET_EVENT );
+ try
+ {
+ element = processGet( cacheName, key, requesterId );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ return element;
+ }
+
+ /**
+ * Returns a cache bean from the specified cache; or null if the key does not exist.
+ * <p>
+ * Adding the requester id, allows the cache to determine the source of the get.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @return ICacheElement
+ */
+ private ICacheElement<K, V> processGet( String cacheName, K key, long requesterId )
+ {
+ boolean fromCluster = isRequestFromCluster( requesterId );
+
+ log.debug( "get [{0}] from cache [{1}] requesterId = [{2}] fromCluster = {3}",
+ key, cacheName, requesterId, fromCluster );
+
+ CacheListeners<K, V> cacheDesc = getCacheListeners( cacheName );
+
+ ICacheElement<K, V> element = getFromCacheListeners( key, fromCluster, cacheDesc, null );
+ return element;
+ }
+
+ /**
+ * Gets the item from the associated cache listeners.
+ * <p>
+ * @param key
+ * @param fromCluster
+ * @param cacheDesc
+ * @param element
+ * @return ICacheElement
+ */
+ private ICacheElement<K, V> getFromCacheListeners( K key, boolean fromCluster, CacheListeners<K, V> cacheDesc,
+ ICacheElement<K, V> element )
+ {
+ ICacheElement<K, V> returnElement = element;
+
+ if ( cacheDesc != null )
+ {
+ CompositeCache<K, V> c = (CompositeCache<K, V>) cacheDesc.cache;
+
+ // If we have a get come in from a client and we don't have the item
+ // locally, we will allow the cache to look in other non local sources,
+ // such as a remote cache or a lateral.
+ //
+ // Since remote servers never get from clients and clients never go
+ // remote from a remote call, this
+ // will not result in any loops.
+ //
+ // This is the only instance I can think of where we allow a remote get
+ // from a remote call. The purpose is to allow remote cache servers to
+ // talk to each other. If one goes down, you want it to be able to get
+ // data from those that were up when the failed server comes back o
+ // line.
+
+ if ( !fromCluster && this.remoteCacheServerAttributes.isAllowClusterGet() )
+ {
+ log.debug( "NonLocalGet. fromCluster [{0}] AllowClusterGet [{1}]",
+ fromCluster, this.remoteCacheServerAttributes.isAllowClusterGet() );
+ returnElement = c.get( key );
+ }
+ else
+ {
+ // Gets from cluster type remote will end up here.
+ // Gets from all clients will end up here if allow cluster get is
+ // false.
+ log.debug( "LocalGet. fromCluster [{0}] AllowClusterGet [{1}]",
+ fromCluster, this.remoteCacheServerAttributes.isAllowClusterGet() );
+ returnElement = c.localGet( key );
+ }
+ }
+
+ return returnElement;
+ }
+
+ /**
+ * Gets all matching items.
+ * <p>
+ * @param cacheName
+ * @param pattern
+ * @return Map of keys and wrapped objects
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern )
+ throws IOException
+ {
+ return getMatching( cacheName, pattern, 0 );
+ }
+
+ /**
+ * Retrieves all matching keys.
+ * <p>
+ * @param cacheName
+ * @param pattern
+ * @param requesterId
+ * @return Map of keys and wrapped objects
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern, long requesterId )
+ throws IOException
+ {
+ ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, pattern, requesterId,
+ ICacheEventLogger.GETMATCHING_EVENT );
+ try
+ {
+ return processGetMatching( cacheName, pattern, requesterId );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Retrieves all matching keys.
+ * <p>
+ * @param cacheName
+ * @param pattern
+ * @param requesterId
+ * @return Map of keys and wrapped objects
+ */
+ protected Map<K, ICacheElement<K, V>> processGetMatching( String cacheName, String pattern, long requesterId )
+ {
+ boolean fromCluster = isRequestFromCluster( requesterId );
+
+ log.debug( "getMatching [{0}] from cache [{1}] requesterId = [{2}] fromCluster = {3}",
+ pattern, cacheName, requesterId, fromCluster );
+
+ CacheListeners<K, V> cacheDesc = null;
+ try
+ {
+ cacheDesc = getCacheListeners( cacheName );
+ }
+ catch ( Exception e )
+ {
+ log.error( "Problem getting listeners.", e );
+
+ if ( cacheEventLogger != null )
+ {
+ cacheEventLogger.logError( "RemoteCacheServer", ICacheEventLogger.GETMATCHING_EVENT, e.getMessage()
+ + cacheName + " pattern: " + pattern );
+ }
+ }
+
+ return getMatchingFromCacheListeners( pattern, fromCluster, cacheDesc );
+ }
+
+ /**
+ * Gets the item from the associated cache listeners.
+ * <p>
+ * @param pattern
+ * @param fromCluster
+ * @param cacheDesc
+ * @return Map of keys to results
+ */
+ private Map<K, ICacheElement<K, V>> getMatchingFromCacheListeners( String pattern, boolean fromCluster, CacheListeners<K, V> cacheDesc )
+ {
+ Map<K, ICacheElement<K, V>> elements = null;
+ if ( cacheDesc != null )
+ {
+ CompositeCache<K, V> c = (CompositeCache<K, V>) cacheDesc.cache;
+
+ // We always want to go remote and then merge the items. But this can lead to inconsistencies after
+ // failover recovery. Removed items may show up. There is no good way to prevent this.
+ // We should make it configurable.
+
+ if ( !fromCluster && this.remoteCacheServerAttributes.isAllowClusterGet() )
+ {
+ log.debug( "NonLocalGetMatching. fromCluster [{0}] AllowClusterGet [{1}]",
+ fromCluster, this.remoteCacheServerAttributes.isAllowClusterGet() );
+ elements = c.getMatching( pattern );
+ }
+ else
+ {
+ // Gets from cluster type remote will end up here.
+ // Gets from all clients will end up here if allow cluster get is
+ // false.
+
+ log.debug( "LocalGetMatching. fromCluster [{0}] AllowClusterGet [{1}]",
+ fromCluster, this.remoteCacheServerAttributes.isAllowClusterGet() );
+ elements = c.localGetMatching( pattern );
+ }
+ }
+ return elements;
+ }
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * @param cacheName
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys )
+ throws IOException
+ {
+ return this.getMultiple( cacheName, keys, 0 );
+ }
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * The internal processing is wrapped in event logging calls.
+ * <p>
+ * @param cacheName
+ * @param keys
+ * @param requesterId
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys, long requesterId )
+ throws IOException
+ {
+ ICacheEvent<Serializable> cacheEvent = createICacheEvent( cacheName, (Serializable) keys, requesterId,
+ ICacheEventLogger.GETMULTIPLE_EVENT );
+ try
+ {
+ return processGetMultiple( cacheName, keys, requesterId );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * @param cacheName
+ * @param keys
+ * @param requesterId
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ */
+ private Map<K, ICacheElement<K, V>> processGetMultiple( String cacheName, Set<K> keys, long requesterId )
+ {
+ boolean fromCluster = isRequestFromCluster( requesterId );
+
+ log.debug( "getMultiple [{0}] from cache [{1}] requesterId = [{2}] fromCluster = {3}",
+ keys, cacheName, requesterId, fromCluster );
+
+ CacheListeners<K, V> cacheDesc = getCacheListeners( cacheName );
+ Map<K, ICacheElement<K, V>> elements = getMultipleFromCacheListeners( keys, null, fromCluster, cacheDesc );
+ return elements;
+ }
+
+ /**
+ * Since a non-receiving remote cache client will not register a listener, it will not have a
+ * listener id assigned from the server. As such the remote server cannot determine if it is a
+ * cluster or a normal client. It will assume that it is a normal client.
+ * <p>
+ * @param requesterId
+ * @return true is from a cluster.
+ */
+ private boolean isRequestFromCluster( long requesterId )
+ {
+ RemoteType remoteTypeL = idTypeMap.get( Long.valueOf( requesterId ) );
+ return remoteTypeL == RemoteType.CLUSTER;
+ }
+
+ /**
+ * Gets the items from the associated cache listeners.
+ * <p>
+ * @param keys
+ * @param elements
+ * @param fromCluster
+ * @param cacheDesc
+ * @return Map
+ */
+ private Map<K, ICacheElement<K, V>> getMultipleFromCacheListeners( Set<K> keys, Map<K, ICacheElement<K, V>> elements, boolean fromCluster, CacheListeners<K, V> cacheDesc )
+ {
+ Map<K, ICacheElement<K, V>> returnElements = elements;
+
+ if ( cacheDesc != null )
+ {
+ CompositeCache<K, V> c = (CompositeCache<K, V>) cacheDesc.cache;
+
+ // If we have a getMultiple come in from a client and we don't have the item
+ // locally, we will allow the cache to look in other non local sources,
+ // such as a remote cache or a lateral.
+ //
+ // Since remote servers never get from clients and clients never go
+ // remote from a remote call, this
+ // will not result in any loops.
+ //
+ // This is the only instance I can think of where we allow a remote get
+ // from a remote call. The purpose is to allow remote cache servers to
+ // talk to each other. If one goes down, you want it to be able to get
+ // data from those that were up when the failed server comes back on
+ // line.
+
+ if ( !fromCluster && this.remoteCacheServerAttributes.isAllowClusterGet() )
+ {
+ log.debug( "NonLocalGetMultiple. fromCluster [{0}] AllowClusterGet [{1}]",
+ fromCluster, this.remoteCacheServerAttributes.isAllowClusterGet() );
+
+ returnElements = c.getMultiple( keys );
+ }
+ else
+ {
+ // Gets from cluster type remote will end up here.
+ // Gets from all clients will end up here if allow cluster get is
+ // false.
+
+ log.debug( "LocalGetMultiple. fromCluster [{0}] AllowClusterGet [{1}]",
+ fromCluster, this.remoteCacheServerAttributes.isAllowClusterGet() );
+
+ returnElements = c.localGetMultiple( keys );
+ }
+ }
+
+ return returnElements;
+ }
+
+ /**
+ * Return the keys in the cache.
+ * <p>
+ * @param cacheName the name of the cache region
+ * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCache#getKeySet()
+ */
+ @Override
+ public Set<K> getKeySet(String cacheName) throws IOException
+ {
+ return processGetKeySet( cacheName );
+ }
+
+ /**
+ * Gets the set of keys of objects currently in the cache.
+ * <p>
+ * @param cacheName
+ * @return Set
+ */
+ protected Set<K> processGetKeySet( String cacheName )
+ {
+ CacheListeners<K, V> cacheDesc = getCacheListeners( cacheName );
+
+ if ( cacheDesc == null )
+ {
+ return Collections.emptySet();
+ }
+
+ CompositeCache<K, V> c = (CompositeCache<K, V>) cacheDesc.cache;
+ return c.getKeySet();
+ }
+
+ /**
+ * Removes the given key from the specified remote cache. Defaults the listener id to 0.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @throws IOException
+ */
+ @Override
+ public void remove( String cacheName, K key )
+ throws IOException
+ {
+ remove( cacheName, key, 0 );
+ }
+
+ /**
+ * Remove the key from the cache region and don't tell the source listener about it.
+ * <p>
+ * The internal processing is wrapped in event logging calls.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @throws IOException
+ */
+ @Override
+ public void remove( String cacheName, K key, long requesterId )
+ throws IOException
+ {
+ ICacheEvent<K> cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.REMOVE_EVENT );
+ try
+ {
+ processRemove( cacheName, key, requesterId );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Remove the key from the cache region and don't tell the source listener about it.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @throws IOException
+ */
+ private void processRemove( String cacheName, K key, long requesterId )
+ throws IOException
+ {
+ log.debug( "remove [{0}] from cache [{1}]", key, cacheName );
+
+ CacheListeners<K, V> cacheDesc = cacheListenersMap.get( cacheName );
+
+ boolean fromCluster = isRequestFromCluster( requesterId );
+
+ if ( cacheDesc != null )
+ {
+ // best attempt to achieve ordered cache item removal and
+ // notification.
+ synchronized ( cacheDesc )
+ {
+ boolean removeSuccess = false;
+
+ // No need to notify if it was not cached.
+ CompositeCache<K, V> c = (CompositeCache<K, V>) cacheDesc.cache;
+
+ if ( fromCluster )
+ {
+ log.debug( "Remove FROM cluster, NOT updating other auxiliaries for region" );
+ removeSuccess = c.localRemove( key );
+ }
+ else
+ {
+ log.debug( "Remove NOT from cluster, updating other auxiliaries for region" );
+ removeSuccess = c.remove( key );
+ }
+
+ log.debug( "remove [{0}] from cache [{1}] success (was it found) = {2}",
+ key, cacheName, removeSuccess );
+
+ // UPDATE LOCALS IF A REQUEST COMES FROM A CLUSTER
+ // IF LOCAL CLUSTER CONSISTENCY IS CONFIGURED
+ if ( !fromCluster || ( fromCluster && remoteCacheServerAttributes.isLocalClusterConsistency() ) )
+ {
+ ICacheEventQueue<K, V>[] qlist = getEventQList( cacheDesc, requesterId );
+
+ for ( int i = 0; i < qlist.length; i++ )
+ {
+ qlist[i].addRemoveEvent( key );
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Remove all keys from the specified remote cache.
+ * <p>
+ * @param cacheName
+ * @throws IOException
+ */
+ @Override
+ public void removeAll( String cacheName )
+ throws IOException
+ {
+ removeAll( cacheName, 0 );
+ }
+
+ /**
+ * Remove all keys from the specified remote cache.
+ * <p>
+ * The internal processing is wrapped in event logging calls.
+ * <p>
+ * @param cacheName
+ * @param requesterId
+ * @throws IOException
+ */
+ @Override
+ public void removeAll( String cacheName, long requesterId )
+ throws IOException
+ {
+ ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, "all", requesterId, ICacheEventLogger.REMOVEALL_EVENT );
+ try
+ {
+ processRemoveAll( cacheName, requesterId );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Remove all keys from the specified remote cache.
+ * <p>
+ * @param cacheName
+ * @param requesterId
+ * @throws IOException
+ */
+ private void processRemoveAll( String cacheName, long requesterId )
+ throws IOException
+ {
+ CacheListeners<K, V> cacheDesc = cacheListenersMap.get( cacheName );
+
+ boolean fromCluster = isRequestFromCluster( requesterId );
+
+ if ( cacheDesc != null )
+ {
+ // best attempt to achieve ordered cache item removal and
+ // notification.
+ synchronized ( cacheDesc )
+ {
+ // No need to broadcast, or notify if it was not cached.
+ CompositeCache<K, V> c = (CompositeCache<K, V>) cacheDesc.cache;
+
+ if ( fromCluster )
+ {
+ log.debug( "RemoveALL FROM cluster, NOT updating other auxiliaries for region" );
+ c.localRemoveAll();
+ }
+ else
+ {
+ log.debug( "RemoveALL NOT from cluster, updating other auxiliaries for region" );
+ c.removeAll();
+ }
+
+ // update registered listeners
+ if ( !fromCluster || ( fromCluster && remoteCacheServerAttributes.isLocalClusterConsistency() ) )
+ {
+ ICacheEventQueue<K, V>[] qlist = getEventQList( cacheDesc, requesterId );
+
+ for ( int i = 0; i < qlist.length; i++ )
+ {
+ qlist[i].addRemoveAllEvent();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * How many put events have we received.
+ * <p>
+ * @return puts
+ */
+ // Currently only intended for use by unit tests
+ int getPutCount()
+ {
+ return puts;
+ }
+
+ /**
+ * Frees the specified remote cache.
+ * <p>
+ * @param cacheName
+ * @throws IOException
+ */
+ @Override
+ public void dispose( String cacheName )
+ throws IOException
+ {
+ dispose( cacheName, 0 );
+ }
+
+ /**
+ * Frees the specified remote cache.
+ * <p>
+ * @param cacheName
+ * @param requesterId
+ * @throws IOException
+ */
+ public void dispose( String cacheName, long requesterId )
+ throws IOException
+ {
+ ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, "none", requesterId, ICacheEventLogger.DISPOSE_EVENT );
+ try
+ {
+ processDispose( cacheName, requesterId );
+ }
+ finally
+ {
+ logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * @param cacheName
+ * @param requesterId
+ * @throws IOException
+ */
+ private void processDispose( String cacheName, long requesterId )
+ throws IOException
+ {
+ log.info( "Dispose request received from listener [{0}]", requesterId );
+
+ CacheListeners<K, V> cacheDesc = cacheListenersMap.get( cacheName );
+
+ // this is dangerous
+ if ( cacheDesc != null )
+ {
+ // best attempt to achieve ordered free-cache-op and notification.
+ synchronized ( cacheDesc )
+ {
+ ICacheEventQueue<K, V>[] qlist = getEventQList( cacheDesc, requesterId );
+
+ for ( int i = 0; i < qlist.length; i++ )
+ {
+ qlist[i].addDisposeEvent();
+ }
+ cacheManager.freeCache( cacheName );
+ }
+ }
+ }
+
+ /**
+ * Frees all remote caches.
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ public void release()
+ throws IOException
+ {
+ for (CacheListeners<K, V> cacheDesc : cacheListenersMap.values())
+ {
+ ICacheEventQueue<K, V>[] qlist = getEventQList( cacheDesc, 0 );
+
+ for ( int i = 0; i < qlist.length; i++ )
+ {
+ qlist[i].addDisposeEvent();
+ }
+ }
+ cacheManager.release();
+ }
+
+ /**
+ * Returns the cache listener for the specified cache. Creates the cache and the cache
+ * descriptor if they do not already exist.
+ * <p>
+ * @param cacheName
+ * @return The cacheListeners value
+ */
+ protected CacheListeners<K, V> getCacheListeners( String cacheName )
+ {
+ CacheListeners<K, V> cacheListeners = cacheListenersMap.computeIfAbsent(cacheName, key -> {
+ CompositeCache<K, V> cache = cacheManager.getCache(key);
+ return new CacheListeners<>( cache );
+ });
+
+ return cacheListeners;
+ }
+
+ /**
+ * Gets the clusterListeners attribute of the RemoteCacheServer object.
+ * <p>
+ * TODO may be able to remove this
+ * @param cacheName
+ * @return The clusterListeners value
+ */
+ protected CacheListeners<K, V> getClusterListeners( String cacheName )
+ {
+ CacheListeners<K, V> cacheListeners = clusterListenersMap.computeIfAbsent(cacheName, key -> {
+ CompositeCache<K, V> cache = cacheManager.getCache( cacheName );
+ return new CacheListeners<>( cache );
+ });
+
+ return cacheListeners;
+ }
+
+ /**
+ * Gets the eventQList attribute of the RemoteCacheServer object. This returns the event queues
+ * stored in the cacheListeners object for a particular region, if the queue is not for this
+ * requester.
+ * <p>
+ * Basically, this makes sure that a request from a particular local cache, identified by its
+ * listener id, does not result in a call to that same listener.
+ * <p>
+ * @param cacheListeners
+ * @param requesterId
+ * @return The eventQList value
+ */
+ @SuppressWarnings("unchecked") // No generic arrays in java
+ private ICacheEventQueue<K, V>[] getEventQList( CacheListeners<K, V> cacheListeners, long requesterId )
+ {
+ ICacheEventQueue<K, V>[] list = cacheListeners.eventQMap.values().toArray( new ICacheEventQueue[0] );
+ int count = 0;
+ // Set those not qualified to null; Count those qualified.
+ for ( int i = 0; i < list.length; i++ )
+ {
+ ICacheEventQueue<K, V> q = list[i];
+ if ( q.isWorking() && q.getListenerId() != requesterId )
+ {
+ count++;
+ }
+ else
+ {
+ list[i] = null;
+ }
+ }
+ if ( count == list.length )
+ {
+ // All qualified.
+ return list;
+ }
+
+ // Returns only the qualified.
+ ICacheEventQueue<K, V>[] qq = new ICacheEventQueue[count];
+ count = 0;
+ for ( int i = 0; i < list.length; i++ )
+ {
+ if ( list[i] != null )
+ {
+ qq[count++] = list[i];
+ }
+ }
+ return qq;
+ }
+
+ /**
+ * Removes dead event queues. Should clean out deregistered listeners.
+ * <p>
+ * @param eventQMap
+ */
+ private static <KK, VV> void cleanupEventQMap( Map<Long, ICacheEventQueue<KK, VV>> eventQMap )
+ {
+ // this does not care if the q is alive (i.e. if
+ // there are active threads; it cares if the queue
+ // is working -- if it has not encountered errors
+ // above the failure threshold
+ eventQMap.entrySet().removeIf(e -> !e.getValue().isWorking());
+ }
+
+ /**
+ * Subscribes to the specified remote cache.
+ * <p>
+ * If the client id is 0, then the remote cache server will increment it's local count and
+ * assign an id to the client.
+ * <p>
+ * @param cacheName the specified remote cache.
+ * @param listener object to notify for cache changes. must be synchronized since there are
+ * remote calls involved.
+ * @throws IOException
+ */
+ @Override
+ @SuppressWarnings("unchecked") // Need to cast to specific return type from getClusterListeners()
+ public <KK, VV> void addCacheListener( String cacheName, ICacheListener<KK, VV> listener )
+ throws IOException
+ {
+ if ( cacheName == null || listener == null )
+ {
+ throw new IllegalArgumentException( "cacheName and listener must not be null" );
+ }
+ CacheListeners<KK, VV> cacheListeners;
+
+ IRemoteCacheListener<KK, VV> ircl = (IRemoteCacheListener<KK, VV>) listener;
+
+ String listenerAddress = ircl.getLocalHostAddress();
+
+ RemoteType remoteType = ircl.getRemoteType();
+ if ( remoteType == RemoteType.CLUSTER )
+ {
+ log.debug( "adding cluster listener, listenerAddress [{0}]", listenerAddress );
+ cacheListeners = (CacheListeners<KK, VV>)getClusterListeners( cacheName );
+ }
+ else
+ {
+ log.debug( "adding normal listener, listenerAddress [{0}]", listenerAddress );
+ cacheListeners = (CacheListeners<KK, VV>)getCacheListeners( cacheName );
+ }
+ Map<Long, ICacheEventQueue<KK, VV>> eventQMap = cacheListeners.eventQMap;
+ cleanupEventQMap( eventQMap );
+
+ // synchronized ( listenerId )
+ synchronized ( ICacheListener.class )
+ {
+ long id = 0;
+ try
+ {
+ id = listener.getListenerId();
+ // clients probably shouldn't do this.
+ if ( id == 0 )
+ {
+ // must start at one so the next gets recognized
+ long listenerIdB = nextListenerId();
+ log.debug( "listener id={0} addded for cache [{1}], listenerAddress [{2}]",
+ listenerIdB & 0xff, cacheName, listenerAddress );
+ listener.setListenerId( listenerIdB );
+ id = listenerIdB;
+
+ // in case it needs synchronization
+ String message = "Adding vm listener under new id = [" + listenerIdB + "], listenerAddress ["
+ + listenerAddress + "]";
+ logApplicationEvent( "RemoteCacheServer", "addCacheListener", message );
+ log.info( message );
+ }
+ else
+ {
+ String message = "Adding listener under existing id = [" + id + "], listenerAddress ["
+ + listenerAddress + "]";
+ logApplicationEvent( "RemoteCacheServer", "addCacheListener", message );
+ log.info( message );
+ // should confirm the the host is the same as we have on
+ // record, just in case a client has made a mistake.
+ }
+
+ // relate the type to an id
+ this.idTypeMap.put( Long.valueOf( id ), remoteType);
+ if ( listenerAddress != null )
+ {
+ this.idIPMap.put( Long.valueOf( id ), listenerAddress );
+ }
+ }
+ catch ( IOException ioe )
+ {
+ String message = "Problem setting listener id, listenerAddress [" + listenerAddress + "]";
+ log.error( message, ioe );
+
+ if ( cacheEventLogger != null )
+ {
+ cacheEventLogger.logError( "RemoteCacheServer", "addCacheListener", message + " - "
+ + ioe.getMessage() );
+ }
+ }
+
+ CacheEventQueueFactory<KK, VV> fact = new CacheEventQueueFactory<>();
+ ICacheEventQueue<KK, VV> q = fact.createCacheEventQueue( listener, id, cacheName, remoteCacheServerAttributes
+ .getEventQueuePoolName(), remoteCacheServerAttributes.getEventQueueType() );
+
+ eventQMap.put(Long.valueOf(listener.getListenerId()), q);
+
+ log.info( cacheListeners );
+ }
+ }
+
+ /**
+ * Subscribes to all remote caches.
+ * <p>
+ * @param listener The feature to be added to the CacheListener attribute
+ * @throws IOException
+ */
+ @Override
+ public <KK, VV> void addCacheListener( ICacheListener<KK, VV> listener )
+ throws IOException
+ {
+ for (String cacheName : cacheListenersMap.keySet())
+ {
+ addCacheListener( cacheName, listener );
+
+ log.debug( "Adding listener for cache [{0}]", cacheName );
+ }
+ }
+
+ /**
+ * Unsubscribe this listener from this region. If the listener is registered, it will be removed
+ * from the event queue map list.
+ * <p>
+ * @param cacheName
+ * @param listener
+ * @throws IOException
+ */
+ @Override
+ public <KK, VV> void removeCacheListener( String cacheName, ICacheListener<KK, VV> listener )
+ throws IOException
+ {
+ removeCacheListener( cacheName, listener.getListenerId() );
+ }
+
+ /**
+ * Unsubscribe this listener from this region. If the listener is registered, it will be removed
+ * from the event queue map list.
+ * <p>
+ * @param cacheName
+ * @param listenerId
+ */
+ public void removeCacheListener( String cacheName, long listenerId )
+ {
+ String message = "Removing listener for cache region = [" + cacheName + "] and listenerId [" + listenerId + "]";
+ logApplicationEvent( "RemoteCacheServer", "removeCacheListener", message );
+ log.info( message );
+
+ boolean isClusterListener = isRequestFromCluster( listenerId );
+
+ CacheListeners<K, V> cacheDesc = null;
+
+ if ( isClusterListener )
+ {
+ cacheDesc = getClusterListeners( cacheName );
+ }
+ else
+ {
+ cacheDesc = getCacheListeners( cacheName );
+ }
+ Map<Long, ICacheEventQueue<K, V>> eventQMap = cacheDesc.eventQMap;
+ cleanupEventQMap( eventQMap );
+ ICacheEventQueue<K, V> q = eventQMap.remove( Long.valueOf( listenerId ) );
+
+ if ( q != null )
+ {
+ log.debug( "Found queue for cache region = [{0}] and listenerId [{1}]",
+ cacheName, listenerId );
+ q.destroy();
+ cleanupEventQMap( eventQMap );
+ }
+ else
+ {
+ log.debug( "Did not find queue for cache region = [{0}] and listenerId [{1}]",
+ cacheName, listenerId );
+ }
+
+ // cleanup
+ idTypeMap.remove( Long.valueOf( listenerId ) );
+ idIPMap.remove( Long.valueOf( listenerId ) );
+
+ log.info( "After removing listener [{0}] cache region {1} listener size [{2}]",
+ listenerId, cacheName, eventQMap.size() );
+ }
+
+ /**
+ * Unsubscribes from all remote caches.
+ * <p>
+ * @param listener
+ * @throws IOException
+ */
+ @Override
+ public <KK, VV> void removeCacheListener( ICacheListener<KK, VV> listener )
+ throws IOException
+ {
+ for (String cacheName : cacheListenersMap.keySet())
+ {
+ removeCacheListener( cacheName, listener );
+
+ log.info( "Removing listener for cache [{0}]", cacheName );
+ }
+ }
+
+ /**
+ * Shuts down the remote server.
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ public void shutdown()
+ throws IOException
+ {
+ shutdown("", Registry.REGISTRY_PORT);
+ }
+
+ /**
+ * Shuts down a server at a particular host and port. Then it calls shutdown on the cache
+ * itself.
+ * <p>
+ * @param host
+ * @param port
+ * @throws IOException
+ */
+ @Override
+ public void shutdown( String host, int port )
+ throws IOException
+ {
+ log.info( "Received shutdown request. Shutting down server." );
+
+ synchronized (listenerId)
+ {
+ for (String cacheName : cacheListenersMap.keySet())
+ {
+ for (int i = 0; i <= listenerId[0]; i++)
+ {
+ removeCacheListener( cacheName, i );
+ }
+
+ log.info( "Removing listener for cache [{0}]", cacheName );
+ }
+
+ cacheListenersMap.clear();
+ clusterListenersMap.clear();
+ }
+ RemoteCacheServerFactory.shutdownImpl( host, port );
+ this.cacheManager.shutDown();
+ }
+
+ /**
+ * Called by the RMI runtime sometime after the runtime determines that the reference list, the
+ * list of clients referencing the remote object, becomes empty.
+ */
+ // TODO: test out the DGC.
+ @Override
+ public void unreferenced()
+ {
+ log.info( "*** Server now unreferenced and subject to GC. ***" );
+ }
+
+ /**
+ * Returns the next generated listener id [0,255].
+ * <p>
+ * @return the listener id of a client. This should be unique for this server.
+ */
+ private long nextListenerId()
+ {
+ long id = 0;
+ if ( listenerId[0] == Integer.MAX_VALUE )
+ {
+ synchronized ( listenerId )
+ {
+ id = listenerId[0];
+ listenerId[0] = 0;
+ // TODO: record & check if the generated id is currently being
+ // used by a valid listener. Currently if the id wraps after
+ // Long.MAX_VALUE,
+ // we just assume it won't collide with an existing listener who
+ // is live.
+ }
+ }
+ else
+ {
+ synchronized ( listenerId )
+ {
+ id = ++listenerId[0];
+ }
+ }
+ return id;
+ }
+
+ /**
+ * Gets the stats attribute of the RemoteCacheServer object.
+ * <p>
+ * @return The stats value
+ * @throws IOException
+ */
+ @Override
+ public String getStats()
+ throws IOException
+ {
+ return cacheManager.getStats();
+ }
+
+ /**
+ * Logs an event if an event logger is configured.
+ * <p>
+ * @param item
+ * @param requesterId
+ * @param eventName
+ * @return ICacheEvent
+ */
+ private ICacheEvent<ICacheElement<K, V>> createICacheEvent( ICacheElement<K, V> item, long requesterId, String eventName )
+ {
+ if ( cacheEventLogger == null )
+ {
+ return new CacheEvent<>();
+ }
+ String ipAddress = getExtraInfoForRequesterId( requesterId );
+ return cacheEventLogger
+ .createICacheEvent( "RemoteCacheServer", item.getCacheName(), eventName, ipAddress, item );
+ }
+
+ /**
+ * Logs an event if an event logger is configured.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @param eventName
+ * @return ICacheEvent
+ */
+ private <T> ICacheEvent<T> createICacheEvent( String cacheName, T key, long requesterId, String eventName )
+ {
+ if ( cacheEventLogger == null )
+ {
+ return new CacheEvent<>();
+ }
+ String ipAddress = getExtraInfoForRequesterId( requesterId );
+ return cacheEventLogger.createICacheEvent( "RemoteCacheServer", cacheName, eventName, ipAddress, key );
+ }
+
+ /**
+ * Logs an event if an event logger is configured.
+ * <p>
+ * @param source
+ * @param eventName
+ * @param optionalDetails
+ */
+ protected void logApplicationEvent( String source, String eventName, String optionalDetails )
+ {
+ if ( cacheEventLogger != null )
+ {
+ cacheEventLogger.logApplicationEvent( source, eventName, optionalDetails );
+ }
+ }
+
+ /**
+ * Logs an event if an event logger is configured.
+ * <p>
+ * @param cacheEvent
+ */
+ protected <T> void logICacheEvent( ICacheEvent<T> cacheEvent )
+ {
+ if ( cacheEventLogger != null )
+ {
+ cacheEventLogger.logICacheEvent( cacheEvent );
+ }
+ }
+
+ /**
+ * Ip address for the client, if one is stored.
+ * <p>
+ * Protected for testing.
+ * <p>
+ * @param requesterId
+ * @return String
+ */
+ protected String getExtraInfoForRequesterId( long requesterId )
+ {
+ String ipAddress = idIPMap.get( Long.valueOf( requesterId ) );
+ return ipAddress;
+ }
+
+ /**
+ * Allows it to be injected.
+ * <p>
+ * @param cacheEventLogger
+ */
+ public void setCacheEventLogger( ICacheEventLogger cacheEventLogger )
+ {
+ this.cacheEventLogger = cacheEventLogger;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServerAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServerAttributes.java
new file mode 100644
index 0000000..b890d7c
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServerAttributes.java
@@ -0,0 +1,214 @@
+package org.apache.commons.jcs3.auxiliary.remote.server;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.remote.CommonRemoteCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.server.behavior.IRemoteCacheServerAttributes;
+
+/**
+ * These attributes are used to configure the remote cache server.
+ */
+public class RemoteCacheServerAttributes
+ extends CommonRemoteCacheAttributes
+ implements IRemoteCacheServerAttributes
+{
+ /** Don't change */
+ private static final long serialVersionUID = -2741662082869155365L;
+
+ /** port the server will listen to */
+ private int servicePort = 0;
+
+ /** Can a cluster remote get from other remotes */
+ private boolean allowClusterGet = true;
+
+ /** The config file, the initialization is multistage. Remote cache then composite cache. */
+ private String configFileName = "";
+
+ /** Should we start the registry */
+ private final boolean DEFAULT_START_REGISTRY = true;
+
+ /** Should we start the registry */
+ private boolean startRegistry = DEFAULT_START_REGISTRY;
+
+ /** Should we try to keep the registry alive */
+ private final boolean DEFAULT_USE_REGISTRY_KEEP_ALIVE = true;
+
+ /** Should we try to keep the registry alive */
+ private boolean useRegistryKeepAlive = DEFAULT_USE_REGISTRY_KEEP_ALIVE;
+
+ /** The delay between runs */
+ private long registryKeepAliveDelayMillis = 15 * 1000;
+
+ /** Default constructor for the RemoteCacheAttributes object */
+ public RemoteCacheServerAttributes()
+ {
+ super();
+ }
+
+ /**
+ * Gets the localPort attribute of the RemoteCacheAttributes object
+ * <p>
+ * @return The localPort value
+ */
+ @Override
+ public int getServicePort()
+ {
+ return this.servicePort;
+ }
+
+ /**
+ * Sets the localPort attribute of the RemoteCacheAttributes object
+ * <p>
+ * @param p The new localPort value
+ */
+ @Override
+ public void setServicePort( int p )
+ {
+ this.servicePort = p;
+ }
+
+ /**
+ * Should gets from non-cluster clients be allowed to get from other remote auxiliaries.
+ * <p>
+ * @return The localClusterConsistency value
+ */
+ @Override
+ public boolean isAllowClusterGet()
+ {
+ return allowClusterGet;
+ }
+
+ /**
+ * Should we try to get from other cluster servers if we don't find the items locally.
+ * <p>
+ * @param r The new localClusterConsistency value
+ */
+ @Override
+ public void setAllowClusterGet( boolean r )
+ {
+ allowClusterGet = r;
+ }
+
+ /**
+ * Gets the ConfigFileName attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @return The clusterServers value
+ */
+ @Override
+ public String getConfigFileName()
+ {
+ return configFileName;
+ }
+
+ /**
+ * Sets the ConfigFileName attribute of the IRemoteCacheAttributes object
+ * <p>
+ * @param s The new clusterServers value
+ */
+ @Override
+ public void setConfigFileName( String s )
+ {
+ configFileName = s;
+ }
+
+ /**
+ * Should we try to keep the registry alive
+ * <p>
+ * @param useRegistryKeepAlive the useRegistryKeepAlive to set
+ */
+ @Override
+ public void setUseRegistryKeepAlive( boolean useRegistryKeepAlive )
+ {
+ this.useRegistryKeepAlive = useRegistryKeepAlive;
+ }
+
+ /**
+ * Should we start the registry
+ * <p>
+ * @param startRegistry the startRegistry to set
+ * @deprecated Always true, to be removed
+ */
+ @Deprecated
+ @Override
+ public void setStartRegistry( boolean startRegistry )
+ {
+ this.startRegistry = startRegistry;
+ }
+
+ /**
+ * Should we start the registry
+ * <p>
+ * @return the startRegistry
+ * @deprecated Always true, to be removed
+ */
+ @Deprecated
+ @Override
+ public boolean isStartRegistry()
+ {
+ return startRegistry;
+ }
+
+ /**
+ * Should we try to keep the registry alive
+ * <p>
+ * @return the useRegistryKeepAlive
+ */
+ @Override
+ public boolean isUseRegistryKeepAlive()
+ {
+ return useRegistryKeepAlive;
+ }
+
+ /**
+ * @param registryKeepAliveDelayMillis the registryKeepAliveDelayMillis to set
+ */
+ @Override
+ public void setRegistryKeepAliveDelayMillis( long registryKeepAliveDelayMillis )
+ {
+ this.registryKeepAliveDelayMillis = registryKeepAliveDelayMillis;
+ }
+
+ /**
+ * @return the registryKeepAliveDelayMillis
+ */
+ @Override
+ public long getRegistryKeepAliveDelayMillis()
+ {
+ return registryKeepAliveDelayMillis;
+ }
+
+ /**
+ * @return String details
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder(super.toString());
+ buf.append( "\n servicePort = [" + this.getServicePort() + "]" );
+ buf.append( "\n allowClusterGet = [" + this.isAllowClusterGet() + "]" );
+ buf.append( "\n configFileName = [" + this.getConfigFileName() + "]" );
+ buf.append( "\n rmiSocketFactoryTimeoutMillis = [" + this.getRmiSocketFactoryTimeoutMillis() + "]" );
+ buf.append( "\n useRegistryKeepAlive = [" + this.isUseRegistryKeepAlive() + "]" );
+ buf.append( "\n registryKeepAliveDelayMillis = [" + this.getRegistryKeepAliveDelayMillis() + "]" );
+ buf.append( "\n eventQueueType = [" + this.getEventQueueType() + "]" );
+ buf.append( "\n eventQueuePoolName = [" + this.getEventQueuePoolName() + "]" );
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServerFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServerFactory.java
new file mode 100644
index 0000000..9a1c85f
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServerFactory.java
@@ -0,0 +1,487 @@
+package org.apache.commons.jcs3.auxiliary.remote.server;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.rmi.Naming;
+import java.rmi.NotBoundException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.registry.Registry;
+import java.rmi.server.RMISocketFactory;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.Properties;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheConfigurator;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteUtils;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheConstants;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceAdmin;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.config.OptionConverter;
+import org.apache.commons.jcs3.utils.config.PropertySetter;
+import org.apache.commons.jcs3.utils.threadpool.DaemonThreadFactory;
+
+/**
+ * Provides remote cache services. This creates remote cache servers and can proxy command line
+ * requests to a running server.
+ */
+public class RemoteCacheServerFactory
+ implements IRemoteCacheConstants
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( RemoteCacheServerFactory.class );
+
+ /** The single instance of the RemoteCacheServer object. */
+ private static RemoteCacheServer<?, ?> remoteCacheServer;
+
+ /** The name of the service. */
+ private static String serviceName = IRemoteCacheConstants.REMOTE_CACHE_SERVICE_VAL;
+
+ /** Executes the registry keep alive. */
+ private static ScheduledExecutorService keepAliveDaemon;
+
+ /** A reference to the registry. */
+ private static Registry registry = null;
+
+ /** Constructor for the RemoteCacheServerFactory object. */
+ private RemoteCacheServerFactory()
+ {
+ super();
+ }
+
+ /**
+ * This will allow you to get stats from the server, etc. Perhaps we should provide methods on
+ * the factory to do this instead.
+ * <p>
+ * A remote cache is either a local cache or a cluster cache.
+ * </p>
+ * @return Returns the remoteCacheServer.
+ */
+ @SuppressWarnings("unchecked") // Need cast to specific RemoteCacheServer
+ public static <K, V> RemoteCacheServer<K, V> getRemoteCacheServer()
+ {
+ return (RemoteCacheServer<K, V>)remoteCacheServer;
+ }
+
+ // ///////////////////// Startup/shutdown methods. //////////////////
+ /**
+ * Starts up the remote cache server on this JVM, and binds it to the registry on the given host
+ * and port.
+ * <p>
+ * A remote cache is either a local cache or a cluster cache.
+ * <p>
+ * @param host
+ * @param port
+ * @param props
+ * @throws IOException
+ */
+ public static void startup( String host, int port, Properties props)
+ throws IOException
+ {
+ if ( remoteCacheServer != null )
+ {
+ throw new IllegalArgumentException( "Server already started." );
+ }
+
+ synchronized ( RemoteCacheServer.class )
+ {
+ if ( remoteCacheServer != null )
+ {
+ return;
+ }
+ if ( host == null )
+ {
+ host = "";
+ }
+
+ RemoteCacheServerAttributes rcsa = configureRemoteCacheServerAttributes(props);
+
+ // These should come from the file!
+ rcsa.setRemoteLocation( host, port );
+ log.info( "Creating server with these attributes: {0}", rcsa );
+
+ setServiceName( rcsa.getRemoteServiceName() );
+
+ RMISocketFactory customRMISocketFactory = configureObjectSpecificCustomFactory( props );
+
+ RemoteUtils.configureGlobalCustomSocketFactory( rcsa.getRmiSocketFactoryTimeoutMillis() );
+
+ // CONFIGURE THE EVENT LOGGER
+ ICacheEventLogger cacheEventLogger = configureCacheEventLogger( props );
+
+ // CREATE SERVER
+ if ( customRMISocketFactory != null )
+ {
+ remoteCacheServer = new RemoteCacheServer<>( rcsa, props, customRMISocketFactory );
+ }
+ else
+ {
+ remoteCacheServer = new RemoteCacheServer<>( rcsa, props );
+ }
+
+ remoteCacheServer.setCacheEventLogger( cacheEventLogger );
+
+ // START THE REGISTRY
+ registry = RemoteUtils.createRegistry(port);
+
+ // REGISTER THE SERVER
+ registerServer( serviceName, remoteCacheServer );
+
+ // KEEP THE REGISTRY ALIVE
+ if ( rcsa.isUseRegistryKeepAlive() )
+ {
+ if ( keepAliveDaemon == null )
+ {
+ keepAliveDaemon = Executors.newScheduledThreadPool(1,
+ new DaemonThreadFactory("JCS-RemoteCacheServerFactory-"));
+ }
+ RegistryKeepAliveRunner runner = new RegistryKeepAliveRunner( host, port, serviceName );
+ runner.setCacheEventLogger( cacheEventLogger );
+ keepAliveDaemon.scheduleAtFixedRate(runner, 0, rcsa.getRegistryKeepAliveDelayMillis(), TimeUnit.MILLISECONDS);
+ }
+ }
+ }
+
+ /**
+ * Tries to get the event logger by new and old config styles.
+ * <p>
+ * @param props
+ * @return ICacheEventLogger
+ */
+ protected static ICacheEventLogger configureCacheEventLogger( Properties props )
+ {
+ ICacheEventLogger cacheEventLogger = AuxiliaryCacheConfigurator
+ .parseCacheEventLogger( props, IRemoteCacheConstants.CACHE_SERVER_PREFIX );
+
+ // try the old way
+ if ( cacheEventLogger == null )
+ {
+ cacheEventLogger = AuxiliaryCacheConfigurator.parseCacheEventLogger( props,
+ IRemoteCacheConstants.PROPERTY_PREFIX );
+ }
+ return cacheEventLogger;
+ }
+
+ /**
+ * This configures an object specific custom factory. This will be configured for just this
+ * object in the registry. This can be null.
+ * <p>
+ * @param props
+ * @return RMISocketFactory
+ */
+ protected static RMISocketFactory configureObjectSpecificCustomFactory( Properties props )
+ {
+ RMISocketFactory customRMISocketFactory =
+ OptionConverter.instantiateByKey( props, CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX, null );
+
+ if ( customRMISocketFactory != null )
+ {
+ PropertySetter.setProperties( customRMISocketFactory, props, CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX
+ + "." );
+ log.info( "Will use server specific custom socket factory. {0}",
+ customRMISocketFactory );
+ }
+ else
+ {
+ log.info( "No server specific custom socket factory defined." );
+ }
+ return customRMISocketFactory;
+ }
+
+ /**
+ * Registers the server with the registry. I broke this off because we might want to have code
+ * that will restart a dead registry. It will need to rebind the server.
+ * <p>
+ * @param serviceName the name of the service
+ * @param server the server object to bind
+ * @throws RemoteException
+ */
+ protected static void registerServer(String serviceName, Remote server )
+ throws RemoteException
+ {
+ if ( server == null )
+ {
+ throw new RemoteException( "Cannot register the server until it is created." );
+ }
+
+ if ( registry == null )
+ {
+ throw new RemoteException( "Cannot register the server: Registry is null." );
+ }
+
+ log.info( "Binding server to {0}", serviceName );
+
+ registry.rebind( serviceName, server );
+ }
+
+ /**
+ * Configure.
+ * <p>
+ * jcs.remotecache.serverattributes.ATTRIBUTENAME=ATTRIBUTEVALUE
+ * <p>
+ * @param prop
+ * @return RemoteCacheServerAttributesconfigureRemoteCacheServerAttributes
+ */
+ protected static RemoteCacheServerAttributes configureRemoteCacheServerAttributes( Properties prop )
+ {
+ RemoteCacheServerAttributes rcsa = new RemoteCacheServerAttributes();
+
+ // configure automatically
+ PropertySetter.setProperties( rcsa, prop, CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + "." );
+
+ configureManuallyIfValuesArePresent( prop, rcsa );
+
+ return rcsa;
+ }
+
+ /**
+ * This looks for the old config values.
+ * <p>
+ * @param prop
+ * @param rcsa
+ */
+ private static void configureManuallyIfValuesArePresent( Properties prop, RemoteCacheServerAttributes rcsa )
+ {
+ // DEPRECATED CONFIG
+ String servicePortStr = prop.getProperty( REMOTE_CACHE_SERVICE_PORT );
+ if ( servicePortStr != null )
+ {
+ try
+ {
+ int servicePort = Integer.parseInt( servicePortStr );
+ rcsa.setServicePort( servicePort );
+ log.debug( "Remote cache service uses port number {0}", servicePort );
+ }
+ catch ( NumberFormatException ignore )
+ {
+ log.debug( "Remote cache service port property {0}" +
+ " not specified. An anonymous port will be used.", REMOTE_CACHE_SERVICE_PORT );
+ }
+ }
+
+ String socketTimeoutMillisStr = prop.getProperty( SOCKET_TIMEOUT_MILLIS );
+ if ( socketTimeoutMillisStr != null )
+ {
+ try
+ {
+ int rmiSocketFactoryTimeoutMillis = Integer.parseInt( socketTimeoutMillisStr );
+ rcsa.setRmiSocketFactoryTimeoutMillis( rmiSocketFactoryTimeoutMillis );
+ log.debug( "Remote cache socket timeout {0} ms.", rmiSocketFactoryTimeoutMillis );
+ }
+ catch ( NumberFormatException ignore )
+ {
+ log.debug( "Remote cache socket timeout property {0}" +
+ " not specified. The default will be used.", SOCKET_TIMEOUT_MILLIS );
+ }
+ }
+
+ String lccStr = prop.getProperty( REMOTE_LOCAL_CLUSTER_CONSISTENCY );
+ if ( lccStr != null )
+ {
+ boolean lcc = Boolean.parseBoolean( lccStr );
+ rcsa.setLocalClusterConsistency( lcc );
+ }
+
+ String acgStr = prop.getProperty( REMOTE_ALLOW_CLUSTER_GET );
+ if ( acgStr != null )
+ {
+ boolean acg = Boolean.parseBoolean( lccStr );
+ rcsa.setAllowClusterGet( acg );
+ }
+
+ // Register the RemoteCacheServer remote object in the registry.
+ rcsa.setRemoteServiceName(
+ prop.getProperty( REMOTE_CACHE_SERVICE_NAME, REMOTE_CACHE_SERVICE_VAL ).trim() );
+ }
+
+ /**
+ * Unbinds the remote server.
+ * <p>
+ * @param host
+ * @param port
+ * @throws IOException
+ */
+ static void shutdownImpl( String host, int port )
+ throws IOException
+ {
+ synchronized ( RemoteCacheServer.class )
+ {
+ if ( remoteCacheServer == null )
+ {
+ return;
+ }
+ log.info( "Unbinding host={0}, port={1}, serviceName={2}",
+ host, port, getServiceName() );
+ try
+ {
+ Naming.unbind( RemoteUtils.getNamingURL(host, port, getServiceName()) );
+ }
+ catch ( MalformedURLException ex )
+ {
+ // impossible case.
+ throw new IllegalArgumentException( ex.getMessage() + "; host=" + host + ", port=" + port
+ + ", serviceName=" + getServiceName() );
+ }
+ catch ( NotBoundException ex )
+ {
+ // ignore.
+ }
+ remoteCacheServer.release();
+ remoteCacheServer = null;
+
+ // Shut down keepalive scheduler
+ if ( keepAliveDaemon != null )
+ {
+ keepAliveDaemon.shutdownNow();
+ keepAliveDaemon = null;
+ }
+
+ // Try to release registry
+ if (registry != null)
+ {
+ UnicastRemoteObject.unexportObject(registry, true);
+ registry = null;
+ }
+ }
+ }
+
+ /**
+ * Creates an local RMI registry on the default port, starts up the remote cache server, and
+ * binds it to the registry.
+ * <p>
+ * A remote cache is either a local cache or a cluster cache.
+ * <p>
+ * @param args The command line arguments
+ * @throws Exception
+ */
+ public static void main( String[] args )
+ throws Exception
+ {
+ Properties prop = args.length > 0 ? RemoteUtils.loadProps( args[args.length - 1] ) : new Properties();
+
+ int port;
+ try
+ {
+ port = Integer.parseInt( prop.getProperty( "registry.port" ) );
+ }
+ catch ( NumberFormatException ex )
+ {
+ port = Registry.REGISTRY_PORT;
+ }
+
+ // shutdown
+ if ( args.length > 0 && args[0].toLowerCase().indexOf( "-shutdown" ) != -1 )
+ {
+ try
+ {
+ ICacheServiceAdmin admin = lookupCacheServiceAdmin(prop, port);
+ admin.shutdown();
+ }
+ catch ( Exception ex )
+ {
+ log.error( "Problem calling shutdown.", ex );
+ }
+ log.debug( "done." );
+ System.exit( 0 );
+ }
+
+ // STATS
+ if ( args.length > 0 && args[0].toLowerCase().indexOf( "-stats" ) != -1 )
+ {
+ log.debug( "getting cache stats" );
+
+ try
+ {
+ ICacheServiceAdmin admin = lookupCacheServiceAdmin(prop, port);
+
+ try
+ {
+// System.out.println( admin.getStats().toString() );
+ log.debug( admin.getStats() );
+ }
+ catch ( IOException es )
+ {
+ log.error( es );
+ }
+ }
+ catch ( Exception ex )
+ {
+ log.error( "Problem getting stats.", ex );
+ }
+ log.debug( "done." );
+ System.exit( 0 );
+ }
+
+ // startup.
+ String host = prop.getProperty( "registry.host" );
+
+ if ( host == null || host.trim().equals( "" ) || host.trim().equals( "localhost" ) )
+ {
+ log.debug( "main> creating registry on the localhost" );
+ RemoteUtils.createRegistry( port );
+ }
+ log.debug( "main> starting up RemoteCacheServer" );
+ startup( host, port, prop);
+ log.debug( "main> done" );
+ }
+
+ /**
+ * Look up the remote cache service admin instance
+ *
+ * @param config the configuration properties
+ * @param port the local port
+ * @return the admin object instance
+ *
+ * @throws Exception if lookup fails
+ */
+ private static ICacheServiceAdmin lookupCacheServiceAdmin(Properties config, int port) throws Exception
+ {
+ String remoteServiceName = config.getProperty( REMOTE_CACHE_SERVICE_NAME, REMOTE_CACHE_SERVICE_VAL ).trim();
+ String registry = RemoteUtils.getNamingURL("", port, remoteServiceName);
+
+ log.debug( "looking up server {0}", registry );
+ Object obj = Naming.lookup( registry );
+ log.debug( "server found" );
+
+ return (ICacheServiceAdmin) obj;
+ }
+
+ /**
+ * @param serviceName the serviceName to set
+ */
+ protected static void setServiceName( String serviceName )
+ {
+ RemoteCacheServerFactory.serviceName = serviceName;
+ }
+
+ /**
+ * @return the serviceName
+ */
+ protected static String getServiceName()
+ {
+ return serviceName;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheStartupServlet.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheStartupServlet.java
new file mode 100644
index 0000000..d9966ae
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheStartupServlet.java
@@ -0,0 +1,283 @@
+package org.apache.commons.jcs3.auxiliary.remote.server;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.UnknownHostException;
+import java.nio.charset.StandardCharsets;
+import java.util.Properties;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteUtils;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.net.HostNameUtil;
+
+/**
+ * This servlet can be used to startup the JCS remote cache. It is easy to
+ * deploy the remote server in a tomcat base. This give you an easy way to
+ * monitor its activity.
+ * <p>
+ * <code>
+ * servlet>
+ <servlet-name>JCSRemoteCacheStartupServlet</servlet-name>
+ <servlet-class>
+ org.apache.commons.jcs3.auxiliary.remote.server.RemoteCacheStartupServlet
+ </servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+
+ <servlet-mapping>
+ <servlet-name>JCSRemoteCacheStartupServlet</servlet-name>
+ <url-pattern>/jcs</url-pattern>
+ </servlet-mapping>
+ * </code>
+ *
+ * @author Aaron Smuts
+ */
+public class RemoteCacheStartupServlet
+ extends HttpServlet
+{
+ /** Don't change */
+ private static final long serialVersionUID = 1L;
+
+ /** The logger */
+ private static final Log log = LogManager.getLog(RemoteCacheStartupServlet.class);
+
+ /** The default port to start the registry on. */
+ private static final int DEFAULT_REGISTRY_PORT = 1101;
+
+ /** properties file name */
+ private static final String DEFAULT_PROPS_FILE_NAME = "/cache.ccf";
+
+ /** properties file name, must set prior to calling get instance */
+ private String propsFileName = DEFAULT_PROPS_FILE_NAME;
+
+ /** Configuration properties */
+ private int registryPort = DEFAULT_REGISTRY_PORT;
+
+ /** Configuration properties */
+ private String registryHost = null;
+
+ /**
+ * Starts the registry and then tries to bind to it.
+ * <p>
+ * Gets the port from a props file. Uses the local host name for the
+ * registry host. Tries to start the registry, ignoring failure. Starts the
+ * server.
+ * <p>
+ *
+ * @throws ServletException
+ */
+ @Override
+ public void init()
+ throws ServletException
+ {
+ super.init();
+
+ loadInitParams();
+ Properties props = loadPropertiesFromFile();
+
+ if (registryHost == null)
+ {
+ // we will always use the local machine for the registry
+ try
+ {
+ registryHost = HostNameUtil.getLocalHostAddress();
+ }
+ catch (UnknownHostException e)
+ {
+ log.error("Could not get local address to use for the registry!", e);
+ }
+ }
+
+ log.debug("registryHost = [{0}]", registryHost);
+
+ if ("localhost".equals(registryHost) || "127.0.0.1".equals(registryHost))
+ {
+ log.warn("The local address [{0}] is INVALID. Other machines must "
+ + "be able to use the address to reach this server.", registryHost);
+ }
+
+ try
+ {
+ if (props == null)
+ {
+ throw new ServletException("Could not load configuration from " + propsFileName);
+ }
+
+ RemoteCacheServerFactory.startup(registryHost, registryPort, props);
+ log.info("Remote JCS Server started with properties from {0}", propsFileName);
+ }
+ catch (IOException e)
+ {
+ throw new ServletException("Problem starting remote cache server.", e);
+ }
+ }
+
+ /**
+ * It just dumps the stats.
+ * <p>
+ *
+ * @param request
+ * @param response
+ * @throws ServletException
+ * @throws IOException
+ */
+ @Override
+ protected void service(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException
+ {
+ String stats = "";
+
+ try
+ {
+ stats = CompositeCacheManager.getInstance().getStats();
+ }
+ catch (CacheException e)
+ {
+ throw new ServletException(e);
+ }
+
+ log.info(stats);
+
+ try
+ {
+ String characterEncoding = response.getCharacterEncoding();
+ if (characterEncoding == null)
+ {
+ characterEncoding = StandardCharsets.UTF_8.name();
+ response.setCharacterEncoding(characterEncoding);
+ }
+ OutputStream os = response.getOutputStream();
+ os.write(stats.getBytes(characterEncoding));
+ os.close();
+ }
+ catch (IOException e)
+ {
+ log.error("Problem writing response.", e);
+ }
+ }
+
+ /**
+ * shuts the cache down.
+ */
+ @Override
+ public void destroy()
+ {
+ super.destroy();
+
+ log.info("Shutting down remote cache ");
+
+ try
+ {
+ RemoteCacheServerFactory.shutdownImpl(registryHost, registryPort);
+ }
+ catch (IOException e)
+ {
+ log.error("Problem shutting down.", e);
+ }
+
+ try
+ {
+ CompositeCacheManager.getInstance().shutDown();
+ }
+ catch (CacheException e)
+ {
+ log.error("Could not retrieve cache manager instance", e);
+ }
+ }
+
+ /**
+ * Load configuration values from config file if possible
+ */
+ private Properties loadPropertiesFromFile()
+ {
+ Properties props = null;
+
+ try
+ {
+ props = RemoteUtils.loadProps(propsFileName);
+ if (props != null)
+ {
+ registryHost = props.getProperty("registry.host", registryHost);
+ String portS = props.getProperty("registry.port", String.valueOf(registryPort));
+ setRegistryPort(portS);
+ }
+ }
+ catch (IOException e)
+ {
+ log.error("Problem loading props.", e);
+ }
+
+ return props;
+ }
+
+ /**
+ * Load configuration values from init params if possible
+ */
+ private void loadInitParams()
+ {
+ ServletConfig config = getServletConfig();
+ String _propsFileName = config.getInitParameter("propsFileName");
+ if (null != _propsFileName)
+ {
+ this.propsFileName = _propsFileName;
+ }
+ String _registryHost = config.getInitParameter("registryHost");
+ if (null != _registryHost)
+ {
+ this.registryHost = _registryHost;
+ }
+ String regPortString = config.getInitParameter("registryPort");
+ if (null != regPortString)
+ {
+ setRegistryPort(regPortString);
+ }
+ }
+
+ /**
+ * Set registry port from string If the string cannot be parsed, the default
+ * value is used
+ *
+ * @param portS
+ */
+ private void setRegistryPort(String portS)
+ {
+ try
+ {
+ this.registryPort = Integer.parseInt(portS);
+ }
+ catch (NumberFormatException e)
+ {
+ log.error("Problem converting port to an int.", e);
+ this.registryPort = DEFAULT_REGISTRY_PORT;
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/TimeoutConfigurableRMISocketFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/TimeoutConfigurableRMISocketFactory.java
new file mode 100644
index 0000000..8ca5b73
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/TimeoutConfigurableRMISocketFactory.java
@@ -0,0 +1,111 @@
+package org.apache.commons.jcs3.auxiliary.remote.server;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.rmi.server.RMISocketFactory;
+
+/**
+ * This can be injected into the the remote cache server as follows:
+ *
+ * <pre>
+ * jcs.remotecache.customrmisocketfactory=org.apache.commons.jcs3.auxiliary.remote.server.TimeoutConfigurableRMISocketFactory
+ * jcs.remotecache.customrmisocketfactory.readTimeout=5000
+ * jcs.remotecache.customrmisocketfactory.openTimeout=5000
+ * </pre>
+ */
+public class TimeoutConfigurableRMISocketFactory
+ extends RMISocketFactory
+ implements Serializable
+{
+ /** Don't change. */
+ private static final long serialVersionUID = 1489909775271203334L;
+
+ /** The socket read timeout */
+ private int readTimeout = 5000;
+
+ /** The socket open timeout */
+ private int openTimeout = 5000;
+
+ /**
+ * @param port
+ * @return ServerSocket
+ * @throws IOException
+ */
+ @Override
+ public ServerSocket createServerSocket( int port )
+ throws IOException
+ {
+ return new ServerSocket( port );
+ }
+
+ /**
+ * @param host
+ * @param port
+ * @return Socket
+ * @throws IOException
+ */
+ @Override
+ public Socket createSocket( String host, int port )
+ throws IOException
+ {
+ Socket socket = new Socket();
+ socket.setSoTimeout( readTimeout );
+ socket.setSoLinger( false, 0 );
+ socket.connect( new InetSocketAddress( host, port ), openTimeout );
+ return socket;
+ }
+
+ /**
+ * @param readTimeout the readTimeout to set
+ */
+ public void setReadTimeout( int readTimeout )
+ {
+ this.readTimeout = readTimeout;
+ }
+
+ /**
+ * @return the readTimeout
+ */
+ public int getReadTimeout()
+ {
+ return readTimeout;
+ }
+
+ /**
+ * @param openTimeout the openTimeout to set
+ */
+ public void setOpenTimeout( int openTimeout )
+ {
+ this.openTimeout = openTimeout;
+ }
+
+ /**
+ * @return the openTimeout
+ */
+ public int getOpenTimeout()
+ {
+ return openTimeout;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/behavior/IRemoteCacheServer.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/behavior/IRemoteCacheServer.java
new file mode 100644
index 0000000..ef06bc0
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/behavior/IRemoteCacheServer.java
@@ -0,0 +1,38 @@
+package org.apache.commons.jcs3.auxiliary.remote.server.behavior;
+
+import java.rmi.Remote;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheObserver;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceAdmin;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+
+/*
+ * 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.
+ */
+
+/**
+ * Interface for managing Remote objects
+ *
+ * @author Thomas Vandahl
+ *
+ */
+public interface IRemoteCacheServer<K, V>
+ extends ICacheServiceNonLocal<K, V>, ICacheObserver, ICacheServiceAdmin, Remote
+{
+ // empty
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/behavior/IRemoteCacheServerAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/behavior/IRemoteCacheServerAttributes.java
new file mode 100644
index 0000000..830be83
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/behavior/IRemoteCacheServerAttributes.java
@@ -0,0 +1,122 @@
+package org.apache.commons.jcs3.auxiliary.remote.server.behavior;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.remote.behavior.ICommonRemoteCacheAttributes;
+
+/**
+ * This defines the minimal behavior for the objects that are used to configure
+ * the remote cache server.
+ */
+public interface IRemoteCacheServerAttributes
+ extends ICommonRemoteCacheAttributes
+{
+ /**
+ * Gets the localPort attribute of the IRemoteCacheAttributes object.
+ * <p>
+ * @return The localPort value
+ */
+ int getServicePort();
+
+ /**
+ * Sets the localPort attribute of the IRemoteCacheAttributes object.
+ * <p>
+ * @param p
+ * The new localPort value
+ */
+ void setServicePort( int p );
+
+ /**
+ * Should we try to get remotely when the request does not come in from a
+ * cluster. If local L1 asks remote server R1 for element A and R1 doesn't
+ * have it, should R1 look remotely? The difference is between a local and a
+ * remote update. The local update stays local. Normal updates, removes,
+ * etc, stay local when they come from a client. If this is set to true,
+ * then they can go remote.
+ * <p>
+ * @return The localClusterConsistency value
+ */
+ boolean isAllowClusterGet();
+
+ /**
+ * Should cluster updates be propagated to the locals.
+ * <p>
+ * @param r
+ * The new localClusterConsistency value
+ */
+ void setAllowClusterGet( boolean r );
+
+ /**
+ * Gets the ConfigFileName attribute of the IRemoteCacheAttributes object.
+ * <p>
+ * @return The configuration file name
+ */
+ String getConfigFileName();
+
+ /**
+ * Sets the ConfigFileName attribute of the IRemoteCacheAttributes object.
+ * <p>
+ * @param s
+ * The new configuration file name
+ */
+ void setConfigFileName( String s );
+
+ /**
+ * Should we try to keep the registry alive
+ * <p>
+ * @param useRegistryKeepAlive the useRegistryKeepAlive to set
+ */
+ void setUseRegistryKeepAlive( boolean useRegistryKeepAlive );
+
+ /**
+ * Should we start the registry
+ * <p>
+ * @param startRegistry the startRegistry to set
+ * @deprecated Always true, to be removed
+ */
+ @Deprecated
+ void setStartRegistry( boolean startRegistry );
+
+ /**
+ * Should we start the registry
+ * <p>
+ * @return the startRegistry
+ * @deprecated Always true, to be removed
+ */
+ @Deprecated
+ boolean isStartRegistry();
+
+ /**
+ * Should we try to keep the registry alive
+ * <p>
+ * @return the useRegistryKeepAlive
+ */
+ boolean isUseRegistryKeepAlive();
+
+ /**
+ * @param registryKeepAliveDelayMillis the registryKeepAliveDelayMillis to set
+ */
+ void setRegistryKeepAliveDelayMillis( long registryKeepAliveDelayMillis );
+
+ /**
+ * @return the registryKeepAliveDelayMillis
+ */
+ long getRegistryKeepAliveDelayMillis();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/behavior/RemoteType.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/behavior/RemoteType.java
new file mode 100644
index 0000000..c9be16b
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/server/behavior/RemoteType.java
@@ -0,0 +1,32 @@
+package org.apache.commons.jcs3.auxiliary.remote.server.behavior;
+
+/*
+ * 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.
+ */
+
+/**
+ * Enum to describe the mode of the remote cache
+ */
+public enum RemoteType
+{
+ /** A remote cache is either a local cache or a cluster cache */
+ LOCAL,
+
+ /** A remote cache is either a local cache or a cluster cache */
+ CLUSTER
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/util/RemoteCacheRequestFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/util/RemoteCacheRequestFactory.java
new file mode 100644
index 0000000..1de2457
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/util/RemoteCacheRequestFactory.java
@@ -0,0 +1,201 @@
+package org.apache.commons.jcs3.auxiliary.remote.util;
+
+/*
+ * 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.
+ */
+
+import java.util.Set;
+
+import org.apache.commons.jcs3.auxiliary.remote.value.RemoteCacheRequest;
+import org.apache.commons.jcs3.auxiliary.remote.value.RemoteRequestType;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This creates request objects. You could write your own client and use the objects from this
+ * factory.
+ */
+public class RemoteCacheRequestFactory
+{
+ /** The Logger. */
+ private static final Log log = LogManager.getLog( RemoteCacheRequestFactory.class );
+
+ /**
+ * Create generic request
+ * @param cacheName cache name
+ * @param requestType type of request
+ * @param requesterId id of requester
+ * @return the request
+ */
+ private static <K, V> RemoteCacheRequest<K, V> createRequest(String cacheName, RemoteRequestType requestType, long requesterId)
+ {
+ RemoteCacheRequest<K, V> request = new RemoteCacheRequest<>();
+ request.setCacheName( cacheName );
+ request.setRequestType( requestType );
+ request.setRequesterId( requesterId );
+
+ log.debug( "Created: {0}", request );
+
+ return request;
+ }
+
+ /**
+ * Creates a get Request.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @return RemoteHttpCacheRequest
+ */
+ public static <K, V> RemoteCacheRequest<K, V> createGetRequest( String cacheName, K key, long requesterId )
+ {
+ RemoteCacheRequest<K, V> request = createRequest(cacheName, RemoteRequestType.GET, requesterId);
+ request.setKey( key );
+
+ return request;
+ }
+
+ /**
+ * Creates a getMatching Request.
+ * <p>
+ * @param cacheName
+ * @param pattern
+ * @param requesterId
+ * @return RemoteHttpCacheRequest
+ */
+ public static <K, V> RemoteCacheRequest<K, V> createGetMatchingRequest( String cacheName, String pattern, long requesterId )
+ {
+ RemoteCacheRequest<K, V> request = createRequest(cacheName, RemoteRequestType.GET_MATCHING, requesterId);
+ request.setPattern( pattern );
+
+ return request;
+ }
+
+ /**
+ * Creates a getMultiple Request.
+ * <p>
+ * @param cacheName
+ * @param keys
+ * @param requesterId
+ * @return RemoteHttpCacheRequest
+ */
+ public static <K, V> RemoteCacheRequest<K, V> createGetMultipleRequest( String cacheName, Set<K> keys, long requesterId )
+ {
+ RemoteCacheRequest<K, V> request = createRequest(cacheName, RemoteRequestType.GET_MULTIPLE, requesterId);
+ request.setKeySet(keys);
+
+ return request;
+ }
+
+ /**
+ * Creates a remove Request.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @return RemoteHttpCacheRequest
+ */
+ public static <K, V> RemoteCacheRequest<K, V> createRemoveRequest( String cacheName, K key, long requesterId )
+ {
+ RemoteCacheRequest<K, V> request = createRequest(cacheName, RemoteRequestType.REMOVE, requesterId);
+ request.setKey( key );
+
+ return request;
+ }
+
+ /**
+ * Creates a GetKeySet Request.
+ * <p>
+ * @param cacheName
+ * @param requesterId
+ * @return RemoteHttpCacheRequest
+ */
+ public static RemoteCacheRequest<String, String> createGetKeySetRequest( String cacheName, long requesterId )
+ {
+ RemoteCacheRequest<String, String> request = createRequest(cacheName, RemoteRequestType.GET_KEYSET, requesterId);
+ request.setKey( cacheName );
+
+ return request;
+ }
+
+ /**
+ * Creates a removeAll Request.
+ * <p>
+ * @param cacheName
+ * @param requesterId
+ * @return RemoteHttpCacheRequest
+ */
+ public static <K, V> RemoteCacheRequest<K, V> createRemoveAllRequest( String cacheName, long requesterId )
+ {
+ RemoteCacheRequest<K, V> request = createRequest(cacheName, RemoteRequestType.REMOVE_ALL, requesterId);
+
+ return request;
+ }
+
+ /**
+ * Creates a dispose Request.
+ * <p>
+ * @param cacheName
+ * @param requesterId
+ * @return RemoteHttpCacheRequest
+ */
+ public static <K, V> RemoteCacheRequest<K, V> createDisposeRequest( String cacheName, long requesterId )
+ {
+ RemoteCacheRequest<K, V> request = createRequest(cacheName, RemoteRequestType.DISPOSE, requesterId);
+
+ return request;
+ }
+
+ /**
+ * Creates an Update Request.
+ * <p>
+ * @param cacheElement
+ * @param requesterId
+ * @return RemoteHttpCacheRequest
+ */
+ public static <K, V> RemoteCacheRequest<K, V> createUpdateRequest( ICacheElement<K, V> cacheElement, long requesterId )
+ {
+ RemoteCacheRequest<K, V> request = createRequest(null, RemoteRequestType.UPDATE, requesterId);
+ if ( cacheElement != null )
+ {
+ request.setCacheName( cacheElement.getCacheName() );
+ request.setCacheElement( cacheElement );
+ request.setKey( cacheElement.getKey() );
+ }
+ else
+ {
+ log.error( "Can't create a proper update request for a null cache element." );
+ }
+
+ return request;
+ }
+
+ /**
+ * Creates an alive check Request.
+ * <p>
+ * @param requesterId
+ * @return RemoteHttpCacheRequest
+ */
+ public static <K, V> RemoteCacheRequest<K, V> createAliveCheckRequest( long requesterId )
+ {
+ RemoteCacheRequest<K, V> request = createRequest(null, RemoteRequestType.ALIVE_CHECK, requesterId);
+
+ return request;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/value/RemoteCacheRequest.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/value/RemoteCacheRequest.java
new file mode 100644
index 0000000..0eb378a
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/value/RemoteCacheRequest.java
@@ -0,0 +1,187 @@
+package org.apache.commons.jcs3.auxiliary.remote.value;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+import java.util.Set;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/**
+ * The basic request wrapper. The different types of requests are differentiated by their types.
+ * <p>
+ * Rather than creating sub object types, I created on object that has values for all types of
+ * requests.
+ */
+public class RemoteCacheRequest<K, V>
+ implements Serializable
+{
+ /** Don't change. */
+ private static final long serialVersionUID = -8858447417390442569L;
+
+ /** The request type specifies the type of request: get, put, remove, . . */
+ private RemoteRequestType requestType = null;
+
+ /** Used to identify the source. Same as listener id on the client side. */
+ private long requesterId = 0;
+
+ /** The name of the region */
+ private String cacheName;
+
+ /** The key, if this request has a key. */
+ private K key;
+
+ /** The keySet, if this request has a keySet. Only getMultiple requests. */
+ private Set<K> keySet;
+
+ /** The pattern, if this request uses a pattern. Only getMatching requests. */
+ private String pattern;
+
+ /** The ICacheEleemnt, if this request contains a value. Only update requests will have this. */
+ private ICacheElement<K, V> cacheElement;
+
+ /**
+ * @param requestType the requestType to set
+ */
+ public void setRequestType( RemoteRequestType requestType )
+ {
+ this.requestType = requestType;
+ }
+
+ /**
+ * @return the requestType
+ */
+ public RemoteRequestType getRequestType()
+ {
+ return requestType;
+ }
+
+ /**
+ * @param cacheName the cacheName to set
+ */
+ public void setCacheName( String cacheName )
+ {
+ this.cacheName = cacheName;
+ }
+
+ /**
+ * @return the cacheName
+ */
+ public String getCacheName()
+ {
+ return cacheName;
+ }
+
+ /**
+ * @param key the key to set
+ */
+ public void setKey( K key )
+ {
+ this.key = key;
+ }
+
+ /**
+ * @return the key
+ */
+ public K getKey()
+ {
+ return key;
+ }
+
+ /**
+ * @param pattern the pattern to set
+ */
+ public void setPattern( String pattern )
+ {
+ this.pattern = pattern;
+ }
+
+ /**
+ * @return the pattern
+ */
+ public String getPattern()
+ {
+ return pattern;
+ }
+
+ /**
+ * @param cacheElement the cacheElement to set
+ */
+ public void setCacheElement( ICacheElement<K, V> cacheElement )
+ {
+ this.cacheElement = cacheElement;
+ }
+
+ /**
+ * @return the cacheElement
+ */
+ public ICacheElement<K, V> getCacheElement()
+ {
+ return cacheElement;
+ }
+
+ /**
+ * @param requesterId the requesterId to set
+ */
+ public void setRequesterId( long requesterId )
+ {
+ this.requesterId = requesterId;
+ }
+
+ /**
+ * @return the requesterId
+ */
+ public long getRequesterId()
+ {
+ return requesterId;
+ }
+
+ /**
+ * @param keySet the keySet to set
+ */
+ public void setKeySet( Set<K> keySet )
+ {
+ this.keySet = keySet;
+ }
+
+ /**
+ * @return the keySet
+ */
+ public Set<K> getKeySet()
+ {
+ return keySet;
+ }
+
+ /** @return string */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\nRemoteHttpCacheRequest" );
+ buf.append( "\n requesterId [" + getRequesterId() + "]" );
+ buf.append( "\n requestType [" + getRequestType() + "]" );
+ buf.append( "\n cacheName [" + getCacheName() + "]" );
+ buf.append( "\n key [" + getKey() + "]" );
+ buf.append( "\n keySet [" + getKeySet() + "]" );
+ buf.append( "\n pattern [" + getPattern() + "]" );
+ buf.append( "\n cacheElement [" + getCacheElement() + "]" );
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/value/RemoteCacheResponse.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/value/RemoteCacheResponse.java
new file mode 100644
index 0000000..0b346c5
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/value/RemoteCacheResponse.java
@@ -0,0 +1,105 @@
+package org.apache.commons.jcs3.auxiliary.remote.value;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+
+/**
+ * This is the response wrapper. The servlet wraps all different type of responses in one of these
+ * objects.
+ */
+public class RemoteCacheResponse<T>
+ implements Serializable
+{
+ /** Don't change. */
+ private static final long serialVersionUID = -8858447417390442568L;
+
+ /** Was the event processed without error */
+ private boolean success = true;
+
+ /** Simple error messaging */
+ private String errorMessage;
+
+ /**
+ * The payload. Typically a key / ICacheElement<K, V> map. A normal get will return a map with one
+ * record.
+ */
+ private T payload;
+
+ /**
+ * @param success the success to set
+ */
+ public void setSuccess( boolean success )
+ {
+ this.success = success;
+ }
+
+ /**
+ * @return the success
+ */
+ public boolean isSuccess()
+ {
+ return success;
+ }
+
+ /**
+ * @param errorMessage the errorMessage to set
+ */
+ public void setErrorMessage( String errorMessage )
+ {
+ this.errorMessage = errorMessage;
+ }
+
+ /**
+ * @return the errorMessage
+ */
+ public String getErrorMessage()
+ {
+ return errorMessage;
+ }
+
+ /**
+ * @param payload the payload to set
+ */
+ public void setPayload( T payload )
+ {
+ this.payload = payload;
+ }
+
+ /**
+ * @return the payload
+ */
+ public T getPayload()
+ {
+ return payload;
+ }
+
+ /** @return string */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\nRemoteHttpCacheResponse" );
+ buf.append( "\n success [" + isSuccess() + "]" );
+ buf.append( "\n payload [" + getPayload() + "]" );
+ buf.append( "\n errorMessage [" + getErrorMessage() + "]" );
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/value/RemoteRequestType.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/value/RemoteRequestType.java
new file mode 100644
index 0000000..6a81e0d
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/auxiliary/remote/value/RemoteRequestType.java
@@ -0,0 +1,53 @@
+package org.apache.commons.jcs3.auxiliary.remote.value;
+
+/*
+ * 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.
+ */
+
+/**
+ * The different types of requests
+ */
+public enum RemoteRequestType
+{
+ /** Alive check request type. */
+ ALIVE_CHECK,
+
+ /** Get request type. */
+ GET,
+
+ /** Get Multiple request type. */
+ GET_MULTIPLE,
+
+ /** Get Matching request type. */
+ GET_MATCHING,
+
+ /** Update request type. */
+ UPDATE,
+
+ /** Remove request type. */
+ REMOVE,
+
+ /** Remove All request type. */
+ REMOVE_ALL,
+
+ /** Get keys request type. */
+ GET_KEYSET,
+
+ /** Dispose request type. */
+ DISPOSE,
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/AbstractCacheEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/AbstractCacheEventQueue.java
new file mode 100644
index 0000000..c0eaba3
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/AbstractCacheEventQueue.java
@@ -0,0 +1,437 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheEventQueue;
+import org.apache.commons.jcs3.engine.behavior.ICacheListener;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * An abstract base class to the different implementations
+ */
+public abstract class AbstractCacheEventQueue<K, V>
+ implements ICacheEventQueue<K, V>
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog( AbstractCacheEventQueue.class );
+
+ /** default */
+ protected static final int DEFAULT_WAIT_TO_DIE_MILLIS = 10000;
+
+ /**
+ * time to wait for an event before snuffing the background thread if the queue is empty. make
+ * configurable later
+ */
+ private int waitToDieMillis = DEFAULT_WAIT_TO_DIE_MILLIS;
+
+ /**
+ * When the events are pulled off the queue, then tell the listener to handle the specific event
+ * type. The work is done by the listener.
+ */
+ private ICacheListener<K, V> listener;
+
+ /** Id of the listener registered with this queue */
+ private long listenerId;
+
+ /** The cache region name, if applicable. */
+ private String cacheName;
+
+ /** Maximum number of failures before we buy the farm. */
+ private int maxFailure;
+
+ /** in milliseconds */
+ private int waitBeforeRetry;
+
+ /**
+ * This means that the queue is functional. If we reached the max number of failures, the queue
+ * is marked as non functional and will never work again.
+ */
+ private final AtomicBoolean working = new AtomicBoolean(true);
+
+ /**
+ * Returns the time to wait for events before killing the background thread.
+ * <p>
+ * @return int
+ */
+ public int getWaitToDieMillis()
+ {
+ return waitToDieMillis;
+ }
+
+ /**
+ * Sets the time to wait for events before killing the background thread.
+ * <p>
+ * @param wtdm the ms for the q to sit idle.
+ */
+ public void setWaitToDieMillis( int wtdm )
+ {
+ waitToDieMillis = wtdm;
+ }
+
+ /**
+ * Creates a brief string identifying the listener and the region.
+ * <p>
+ * @return String debugging info.
+ */
+ @Override
+ public String toString()
+ {
+ return "CacheEventQueue [listenerId=" + listenerId + ", cacheName=" + cacheName + "]";
+ }
+
+ /**
+ * @return The listenerId value
+ */
+ @Override
+ public long getListenerId()
+ {
+ return listenerId;
+ }
+
+ /**
+ * @return the cacheName
+ */
+ protected String getCacheName()
+ {
+ return cacheName;
+ }
+
+ /**
+ * Initializes the queue.
+ * <p>
+ * @param listener
+ * @param listenerId
+ * @param cacheName
+ * @param maxFailure
+ * @param waitBeforeRetry
+ */
+ protected void initialize( ICacheListener<K, V> listener, long listenerId, String cacheName, int maxFailure,
+ int waitBeforeRetry)
+ {
+ if ( listener == null )
+ {
+ throw new IllegalArgumentException( "listener must not be null" );
+ }
+
+ this.listener = listener;
+ this.listenerId = listenerId;
+ this.cacheName = cacheName;
+ this.maxFailure = maxFailure <= 0 ? 3 : maxFailure;
+ this.waitBeforeRetry = waitBeforeRetry <= 0 ? 500 : waitBeforeRetry;
+
+ log.debug( "Constructed: {0}", this );
+ }
+
+ /**
+ * This adds a put event to the queue. When it is processed, the element will be put to the
+ * listener.
+ * <p>
+ * @param ce The feature to be added to the PutEvent attribute
+ * @throws IOException
+ */
+ @Override
+ public void addPutEvent( ICacheElement<K, V> ce )
+ {
+ put( new PutEvent( ce ) );
+ }
+
+ /**
+ * This adds a remove event to the queue. When processed the listener's remove method will be
+ * called for the key.
+ * <p>
+ * @param key The feature to be added to the RemoveEvent attribute
+ * @throws IOException
+ */
+ @Override
+ public void addRemoveEvent( K key )
+ {
+ put( new RemoveEvent( key ) );
+ }
+
+ /**
+ * This adds a remove all event to the queue. When it is processed, all elements will be removed
+ * from the cache.
+ */
+ @Override
+ public void addRemoveAllEvent()
+ {
+ put( new RemoveAllEvent() );
+ }
+
+ /**
+ * This adds a dispose event to the queue. When it is processed, the cache is shut down
+ */
+ @Override
+ public void addDisposeEvent()
+ {
+ put( new DisposeEvent() );
+ }
+
+ /**
+ * Adds an event to the queue.
+ * <p>
+ * @param event
+ */
+ protected abstract void put( AbstractCacheEvent event );
+
+
+ // /////////////////////////// Inner classes /////////////////////////////
+ /**
+ * Retries before declaring failure.
+ * <p>
+ * @author asmuts
+ */
+ protected abstract class AbstractCacheEvent implements Runnable
+ {
+ /** Number of failures encountered processing this event. */
+ int failures = 0;
+
+ /**
+ * Main processing method for the AbstractCacheEvent object
+ */
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void run()
+ {
+ try
+ {
+ doRun();
+ }
+ catch ( IOException e )
+ {
+ log.warn( e );
+ if ( ++failures >= maxFailure )
+ {
+ log.warn( "Error while running event from Queue: {0}. "
+ + "Dropping Event and marking Event Queue as "
+ + "non-functional.", this );
+ destroy();
+ return;
+ }
+ log.info( "Error while running event from Queue: {0}. "
+ + "Retrying...", this );
+ try
+ {
+ Thread.sleep( waitBeforeRetry );
+ run();
+ }
+ catch ( InterruptedException ie )
+ {
+ log.warn( "Interrupted while sleeping for retry on event "
+ + "{0}.", this );
+ destroy();
+ }
+ }
+ }
+
+ /**
+ * @throws IOException
+ */
+ protected abstract void doRun()
+ throws IOException;
+ }
+
+ /**
+ * An element should be put in the cache.
+ * <p>
+ * @author asmuts
+ */
+ protected class PutEvent
+ extends AbstractCacheEvent
+ {
+ /** The element to put to the listener */
+ private final ICacheElement<K, V> ice;
+
+ /**
+ * Constructor for the PutEvent object.
+ * <p>
+ * @param ice
+ */
+ PutEvent( ICacheElement<K, V> ice )
+ {
+ this.ice = ice;
+ }
+
+ /**
+ * Call put on the listener.
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ protected void doRun()
+ throws IOException
+ {
+ listener.handlePut( ice );
+ }
+
+ /**
+ * For debugging.
+ * <p>
+ * @return Info on the key and value.
+ */
+ @Override
+ public String toString()
+ {
+ return new StringBuilder( "PutEvent for key: " )
+ .append( ice.getKey() )
+ .append( " value: " )
+ .append( ice.getVal() )
+ .toString();
+ }
+
+ }
+
+ /**
+ * An element should be removed from the cache.
+ * <p>
+ * @author asmuts
+ */
+ protected class RemoveEvent
+ extends AbstractCacheEvent
+ {
+ /** The key to remove from the listener */
+ private final K key;
+
+ /**
+ * Constructor for the RemoveEvent object
+ * <p>
+ * @param key
+ */
+ RemoveEvent( K key )
+ {
+ this.key = key;
+ }
+
+ /**
+ * Call remove on the listener.
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ protected void doRun()
+ throws IOException
+ {
+ listener.handleRemove( cacheName, key );
+ }
+
+ /**
+ * For debugging.
+ * <p>
+ * @return Info on the key to remove.
+ */
+ @Override
+ public String toString()
+ {
+ return new StringBuilder( "RemoveEvent for " )
+ .append( key )
+ .toString();
+ }
+
+ }
+
+ /**
+ * All elements should be removed from the cache when this event is processed.
+ * <p>
+ * @author asmuts
+ */
+ protected class RemoveAllEvent
+ extends AbstractCacheEvent
+ {
+ /**
+ * Call removeAll on the listener.
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ protected void doRun()
+ throws IOException
+ {
+ listener.handleRemoveAll( cacheName );
+ }
+
+ /**
+ * For debugging.
+ * <p>
+ * @return The name of the event.
+ */
+ @Override
+ public String toString()
+ {
+ return "RemoveAllEvent";
+ }
+ }
+
+ /**
+ * The cache should be disposed when this event is processed.
+ * <p>
+ * @author asmuts
+ */
+ protected class DisposeEvent
+ extends AbstractCacheEvent
+ {
+ /**
+ * Called when gets to the end of the queue
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ protected void doRun()
+ throws IOException
+ {
+ listener.handleDispose( cacheName );
+ }
+
+ /**
+ * For debugging.
+ * <p>
+ * @return The name of the event.
+ */
+ @Override
+ public String toString()
+ {
+ return "DisposeEvent";
+ }
+ }
+
+ /**
+ * @return whether the queue is functional.
+ */
+ @Override
+ public boolean isWorking()
+ {
+ return working.get();
+ }
+
+ /**
+ * This means that the queue is functional. If we reached the max number of failures, the queue
+ * is marked as non functional and will never work again.
+ * <p>
+ * @param b
+ */
+ public void setWorking( boolean b )
+ {
+ working.set(b);
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheAdaptor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheAdaptor.java
new file mode 100644
index 0000000..60d5604
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheAdaptor.java
@@ -0,0 +1,137 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.engine.behavior.ICache;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheListener;
+
+/**
+ * Used for Cache-to-Cache messaging purposes. These are used in the balking
+ * facades in the lateral and remote caches.
+ */
+public class CacheAdaptor<K, V>
+ implements ICacheListener<K, V>
+{
+ /** The cache we are adapting. */
+ private final ICache<K, V> cache;
+
+ /** The unique id of this listener. */
+ private long listenerId = 0;
+
+ /**
+ * Sets the listenerId attribute of the CacheAdaptor object
+ * <p>
+ * @param id
+ * The new listenerId value
+ * @throws IOException
+ */
+ @Override
+ public void setListenerId( long id )
+ throws IOException
+ {
+ this.listenerId = id;
+ }
+
+ /**
+ * Gets the listenerId attribute of the CacheAdaptor object
+ * <p>
+ * @return The listenerId value
+ * @throws IOException
+ */
+ @Override
+ public long getListenerId()
+ throws IOException
+ {
+ return this.listenerId;
+ }
+
+ /**
+ * Constructor for the CacheAdaptor object
+ * <p>
+ * @param cache
+ */
+ public CacheAdaptor( ICache<K, V> cache )
+ {
+ this.cache = cache;
+ }
+
+ /**
+ * Puts an item into the cache.
+ * <p>
+ * @param item
+ * @throws IOException
+ */
+ @Override
+ public void handlePut( ICacheElement<K, V> item )
+ throws IOException
+ {
+ try
+ {
+ cache.update( item );
+ }
+ catch ( IOException e )
+ {
+ // swallow
+ }
+ }
+
+ /**
+ * Removes an item.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @throws IOException
+ */
+ @Override
+ public void handleRemove( String cacheName, K key )
+ throws IOException
+ {
+ cache.remove( key );
+ }
+
+ /**
+ * Clears the region.
+ * <p>
+ * @param cacheName
+ * @throws IOException
+ */
+ @Override
+ public void handleRemoveAll( String cacheName )
+ throws IOException
+ {
+ cache.removeAll();
+ }
+
+ /**
+ * Shutdown call.
+ * <p>
+ * @param cacheName
+ * @throws IOException
+ */
+ @Override
+ public void handleDispose( String cacheName )
+ throws IOException
+ {
+ cache.dispose();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheElement.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheElement.java
new file mode 100644
index 0000000..9d64993
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheElement.java
@@ -0,0 +1,160 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+
+/**
+ * Generic element wrapper. Often stuffed inside another.
+ */
+public class CacheElement<K, V>
+ implements ICacheElement<K, V>
+{
+ /** Don't change */
+ private static final long serialVersionUID = -6062305728297627263L;
+
+ /** The name of the cache region. This is a namespace. */
+ private final String cacheName;
+
+ /** This is the cache key by which the value can be referenced. */
+ private final K key;
+
+ /** This is the cached value, reference by the key. */
+ private final V val;
+
+ /**
+ * These attributes hold information about the element and what it is
+ * allowed to do.
+ */
+ private IElementAttributes attr;
+
+ /**
+ * Constructor for the CacheElement object
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param val
+ */
+ public CacheElement( String cacheName, K key, V val )
+ {
+ this.cacheName = cacheName;
+ this.key = key;
+ this.val = val;
+ }
+
+ /**
+ * Constructor for the CacheElement object
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param val
+ * @param attrArg
+ */
+ public CacheElement( String cacheName, K key, V val, IElementAttributes attrArg )
+ {
+ this(cacheName, key, val);
+ this.attr = attrArg;
+ }
+
+ /**
+ * Gets the cacheName attribute of the CacheElement object
+ * <p>
+ * @return The cacheName value
+ */
+ @Override
+ public String getCacheName()
+ {
+ return this.cacheName;
+ }
+
+ /**
+ * Gets the key attribute of the CacheElement object
+ * <p>
+ * @return The key value
+ */
+ @Override
+ public K getKey()
+ {
+ return this.key;
+ }
+
+ /**
+ * Gets the val attribute of the CacheElement object
+ * <p>
+ * @return The val value
+ */
+ @Override
+ public V getVal()
+ {
+ return this.val;
+ }
+
+ /**
+ * Sets the attributes attribute of the CacheElement object
+ * <p>
+ * @param attr
+ * The new IElementAttributes value
+ */
+ @Override
+ public void setElementAttributes( IElementAttributes attr )
+ {
+ this.attr = attr;
+ }
+
+ /**
+ * Gets the IElementAttributes attribute of the CacheElement object
+ * <p>
+ * @return The IElementAttributes value, never null
+ */
+ @Override
+ public IElementAttributes getElementAttributes()
+ {
+ // create default attributes if they are null
+ // this shouldn't happen, but could if a corrupt
+ // object was sent over the wire.
+ if ( this.attr == null )
+ {
+ this.attr = new ElementAttributes();
+ }
+ return this.attr;
+ }
+
+ /**
+ * @return a hash of the key only
+ */
+ @Override
+ public int hashCode()
+ {
+ return key.hashCode();
+ }
+
+ /**
+ * For debugging only.
+ * <p>
+ * @return String representation
+ */
+ @Override
+ public String toString()
+ {
+ return "[CacheElement: cacheName [" + cacheName + "], key [" + key + "], val [" + val + "], attr [" + attr
+ + "]";
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheElementSerialized.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheElementSerialized.java
new file mode 100644
index 0000000..c1b0bdc
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheElementSerialized.java
@@ -0,0 +1,77 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import java.util.Arrays;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElementSerialized;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+
+/** Either serialized value or the value should be null; */
+public class CacheElementSerialized<K, V>
+ extends CacheElement<K, V>
+ implements ICacheElementSerialized<K, V>
+{
+ /** Don't change. */
+ private static final long serialVersionUID = -7265084818647601874L;
+
+ /** The serialized value. */
+ private final byte[] serializedValue;
+
+ /**
+ * Constructs a usable wrapper.
+ * <p>
+ * @param cacheNameArg
+ * @param keyArg
+ * @param serializedValueArg
+ * @param elementAttributesArg
+ */
+ public CacheElementSerialized( String cacheNameArg, K keyArg, byte[] serializedValueArg,
+ IElementAttributes elementAttributesArg )
+ {
+ super(cacheNameArg, keyArg, null, elementAttributesArg);
+ this.serializedValue = serializedValueArg;
+ }
+
+ /** @return byte[] */
+ @Override
+ public byte[] getSerializedValue()
+ {
+ return this.serializedValue;
+ }
+
+ /**
+ * For debugging only.
+ * <p>
+ * @return debugging string.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\n CacheElementSerialized: " );
+ buf.append( "\n CacheName = [" + getCacheName() + "]" );
+ buf.append( "\n Key = [" + getKey() + "]" );
+ buf.append( "\n SerializedValue = " + Arrays.toString(getSerializedValue()) );
+ buf.append( "\n ElementAttributes = " + getElementAttributes() );
+ return buf.toString();
+ }
+
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheEventQueue.java
new file mode 100644
index 0000000..f764981
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheEventQueue.java
@@ -0,0 +1,95 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.engine.behavior.ICacheListener;
+import org.apache.commons.jcs3.utils.threadpool.PoolConfiguration;
+import org.apache.commons.jcs3.utils.threadpool.ThreadPoolManager;
+import org.apache.commons.jcs3.utils.threadpool.PoolConfiguration.WhenBlockedPolicy;
+
+/**
+ * An event queue is used to propagate ordered cache events to one and only one target listener.
+ */
+public class CacheEventQueue<K, V>
+ extends PooledCacheEventQueue<K, V>
+{
+ /** The type of queue -- there are pooled and single */
+ private static final QueueType queueType = QueueType.SINGLE;
+
+ /**
+ * Constructs with the specified listener and the cache name.
+ * <p>
+ * @param listener
+ * @param listenerId
+ * @param cacheName
+ */
+ public CacheEventQueue( ICacheListener<K, V> listener, long listenerId, String cacheName )
+ {
+ this( listener, listenerId, cacheName, 10, 500 );
+ }
+
+ /**
+ * Constructor for the CacheEventQueue object
+ * <p>
+ * @param listener
+ * @param listenerId
+ * @param cacheName
+ * @param maxFailure
+ * @param waitBeforeRetry
+ */
+ public CacheEventQueue( ICacheListener<K, V> listener, long listenerId, String cacheName, int maxFailure,
+ int waitBeforeRetry )
+ {
+ super( listener, listenerId, cacheName, maxFailure, waitBeforeRetry, null );
+ }
+
+ /**
+ * Initializes the queue.
+ * <p>
+ * @param listener
+ * @param listenerId
+ * @param cacheName
+ * @param maxFailure
+ * @param waitBeforeRetry
+ * @param threadPoolName
+ */
+ @Override
+ protected void initialize( ICacheListener<K, V> listener, long listenerId, String cacheName, int maxFailure,
+ int waitBeforeRetry, String threadPoolName )
+ {
+ super.initialize(listener, listenerId, cacheName, maxFailure, waitBeforeRetry);
+
+ // create a default pool with one worker thread to mimic the SINGLE queue behavior
+ pool = ThreadPoolManager.getInstance().createPool(
+ new PoolConfiguration(false, 0, 1, 0, getWaitToDieMillis(), WhenBlockedPolicy.RUN, 0),
+ "CacheEventQueue.QProcessor-" + getCacheName());
+ }
+
+ /**
+ * What type of queue is this.
+ * <p>
+ * @return queueType
+ */
+ @Override
+ public QueueType getQueueType()
+ {
+ return queueType;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheEventQueueFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheEventQueueFactory.java
new file mode 100644
index 0000000..a89a060
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheEventQueueFactory.java
@@ -0,0 +1,85 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.engine.behavior.ICacheEventQueue;
+import org.apache.commons.jcs3.engine.behavior.ICacheListener;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This class hands out event Queues. This allows us to change the implementation more easily. You
+ * can confugure the cache to use a custom type.
+ * <p>
+ * @author aaronsm
+ */
+public class CacheEventQueueFactory<K, V>
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog( CacheEventQueueFactory.class );
+
+ /**
+ * The most commonly used factory method.
+ * <p>
+ * @param listener
+ * @param listenerId
+ * @param cacheName
+ * @param threadPoolName
+ * @param poolType - SINGLE, POOLED
+ * @return ICacheEventQueue
+ */
+ public ICacheEventQueue<K, V> createCacheEventQueue( ICacheListener<K, V> listener, long listenerId, String cacheName,
+ String threadPoolName, ICacheEventQueue.QueueType poolType )
+ {
+ return createCacheEventQueue( listener, listenerId, cacheName, 10, 500, threadPoolName, poolType );
+ }
+
+ /**
+ * Fully configured event queue.
+ * <p>
+ * @param listener
+ * @param listenerId
+ * @param cacheName
+ * @param maxFailure
+ * @param waitBeforeRetry
+ * @param threadPoolName null is OK, if not a pooled event queue this is ignored
+ * @param poolType single or pooled
+ * @return ICacheEventQueue
+ */
+ public ICacheEventQueue<K, V> createCacheEventQueue( ICacheListener<K, V> listener, long listenerId, String cacheName,
+ int maxFailure, int waitBeforeRetry, String threadPoolName,
+ ICacheEventQueue.QueueType poolType )
+ {
+ log.debug( "threadPoolName = [{0}] poolType = {1}", threadPoolName, poolType );
+
+ ICacheEventQueue<K, V> eventQueue = null;
+ if ( poolType == null || ICacheEventQueue.QueueType.SINGLE == poolType )
+ {
+ eventQueue = new CacheEventQueue<>( listener, listenerId, cacheName, maxFailure, waitBeforeRetry );
+ }
+ else if ( ICacheEventQueue.QueueType.POOLED == poolType )
+ {
+ eventQueue = new PooledCacheEventQueue<>( listener, listenerId, cacheName, maxFailure, waitBeforeRetry,
+ threadPoolName );
+ }
+
+ return eventQueue;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheGroup.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheGroup.java
new file mode 100644
index 0000000..179aae7
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheGroup.java
@@ -0,0 +1,59 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+
+/**
+ * Holder for attributes specific to a group. The grouping functionality is on
+ * the way out.
+ */
+public class CacheGroup
+{
+ /** Element configuration. */
+ private IElementAttributes attr;
+
+ /** Constructor for the CacheGroup object */
+ public CacheGroup()
+ {
+ super();
+ }
+
+ /**
+ * Sets the attributes attribute of the CacheGroup object
+ * <p>
+ * @param attr
+ * The new attributes value
+ */
+ public void setElementAttributes( IElementAttributes attr )
+ {
+ this.attr = attr;
+ }
+
+ /**
+ * Gets the attrributes attribute of the CacheGroup object
+ * <p>
+ * @return The attrributes value
+ */
+ public IElementAttributes getElementAttrributes()
+ {
+ return attr;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheInfo.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheInfo.java
new file mode 100644
index 0000000..a303f6e
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheInfo.java
@@ -0,0 +1,47 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import java.rmi.dgc.VMID;
+
+/**
+ * This is a static variable holder for the distribution auxiliaries that need something like a vmid.
+ */
+public final class CacheInfo
+{
+ /** shouldn't be instantiated */
+ private CacheInfo()
+ {
+ super();
+ }
+
+ /**
+ * Used to identify a client, so we can run multiple clients off one host.
+ * Need since there is no way to identify a client other than by host in
+ * rmi.
+ * <p>
+ * TODO: may have some trouble in failover mode if the cache keeps its old
+ * id. We may need to reset this when moving into failover.
+ */
+ private static final VMID vmid = new VMID();
+
+ /** By default this is the hashcode of the VMID */
+ public static final long listenerId = vmid.hashCode();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheListeners.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheListeners.java
new file mode 100644
index 0000000..14a5b98
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheListeners.java
@@ -0,0 +1,79 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.commons.jcs3.engine.behavior.ICache;
+import org.apache.commons.jcs3.engine.behavior.ICacheEventQueue;
+
+/**
+ * Used to associates a set of [cache listener to cache event queue] for a
+ * cache.
+ */
+public class CacheListeners<K, V>
+{
+ /** The cache using the queue. */
+ public final ICache<K, V> cache;
+
+ /** Map ICacheListener to ICacheEventQueue */
+ public final ConcurrentMap<Long, ICacheEventQueue<K, V>> eventQMap =
+ new ConcurrentHashMap<>();
+
+ /**
+ * Constructs with the given cache.
+ * <p>
+ * @param cache
+ */
+ public CacheListeners( ICache<K, V> cache )
+ {
+ if ( cache == null )
+ {
+ throw new IllegalArgumentException( "cache must not be null" );
+ }
+ this.cache = cache;
+ }
+
+ /** @return info on the listeners */
+ @Override
+ public String toString()
+ {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append( "\n CacheListeners" );
+ if ( cache != null )
+ {
+ buffer.append( "\n Region = " + cache.getCacheName() );
+ }
+ if ( eventQMap != null )
+ {
+ buffer.append( "\n Event Queue Map " );
+ buffer.append( "\n size = " + eventQMap.size() );
+ eventQMap.forEach((key, value)
+ -> buffer.append( "\n Entry: key: ").append(key)
+ .append(", value: ").append(value));
+ }
+ else
+ {
+ buffer.append( "\n No Listeners. " );
+ }
+ return buffer.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheStatus.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheStatus.java
new file mode 100644
index 0000000..99bfc7f
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheStatus.java
@@ -0,0 +1,37 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+/**
+ * Cache statuses
+ * <p>
+ * @version $Id: CacheStatus.java 536904 2007-05-10 16:03:42Z tv $
+ */
+public enum CacheStatus
+{
+ /** Cache alive status. */
+ ALIVE,
+
+ /** Cache disposed status. */
+ DISPOSED,
+
+ /** Cache in error. */
+ ERROR
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheWatchRepairable.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheWatchRepairable.java
new file mode 100644
index 0000000..342479b
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CacheWatchRepairable.java
@@ -0,0 +1,170 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheListener;
+import org.apache.commons.jcs3.engine.behavior.ICacheObserver;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * Intercepts the requests to the underlying ICacheObserver object so that the listeners can be
+ * recorded locally for remote connection recovery purposes. (Durable subscription like those in JMS
+ * is not implemented at this stage for it can be too expensive.)
+ */
+public class CacheWatchRepairable
+ implements ICacheObserver
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( CacheWatchRepairable.class );
+
+ /** the underlying ICacheObserver. */
+ private ICacheObserver cacheWatch;
+
+ /** Map of cache regions. */
+ private final ConcurrentMap<String, Set<ICacheListener<?, ?>>> cacheMap =
+ new ConcurrentHashMap<>();
+
+ /**
+ * Replaces the underlying cache watch service and re-attaches all existing listeners to the new
+ * cache watch.
+ * <p>
+ * @param cacheWatch The new cacheWatch value
+ */
+ public void setCacheWatch( ICacheObserver cacheWatch )
+ {
+ this.cacheWatch = cacheWatch;
+ for (Map.Entry<String, Set<ICacheListener<?, ?>>> entry : cacheMap.entrySet())
+ {
+ String cacheName = entry.getKey();
+ for (ICacheListener<?, ?> listener : entry.getValue())
+ {
+ try
+ {
+ log.info( "Adding listener to cache watch. ICacheListener = "
+ + "{0} | ICacheObserver = {1}", listener, cacheWatch );
+ cacheWatch.addCacheListener( cacheName, listener );
+ }
+ catch ( IOException ex )
+ {
+ log.error( "Problem adding listener. ICacheListener = {0} | "
+ + "ICacheObserver = {1}", listener, cacheWatch, ex );
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds a feature to the CacheListener attribute of the CacheWatchRepairable object
+ * <p>
+ * @param cacheName The feature to be added to the CacheListener attribute
+ * @param obj The feature to be added to the CacheListener attribute
+ * @throws IOException
+ */
+ @Override
+ public <K, V> void addCacheListener( String cacheName, ICacheListener<K, V> obj )
+ throws IOException
+ {
+ // Record the added cache listener locally, regardless of whether the
+ // remote add-listener operation succeeds or fails.
+ Set<ICacheListener<?, ?>> listenerSet = cacheMap.computeIfAbsent(cacheName, key -> {
+ return new CopyOnWriteArraySet<>();
+ });
+
+ listenerSet.add( obj );
+
+ log.info( "Adding listener to cache watch. ICacheListener = {0} | "
+ + "ICacheObserver = {1} | cacheName = {2}", obj, cacheWatch,
+ cacheName );
+ cacheWatch.addCacheListener( cacheName, obj );
+ }
+
+ /**
+ * Adds a feature to the CacheListener attribute of the CacheWatchRepairable object
+ * <p>
+ * @param obj The feature to be added to the CacheListener attribute
+ * @throws IOException
+ */
+ @Override
+ public <K, V> void addCacheListener( ICacheListener<K, V> obj )
+ throws IOException
+ {
+ // Record the added cache listener locally, regardless of whether the
+ // remote add-listener operation succeeds or fails.
+ for (Set<ICacheListener<?, ?>> listenerSet : cacheMap.values())
+ {
+ listenerSet.add( obj );
+ }
+
+ log.info( "Adding listener to cache watch. ICacheListener = {0} | "
+ + "ICacheObserver = {1}", obj, cacheWatch );
+ cacheWatch.addCacheListener( obj );
+ }
+
+ /**
+ * Tell the server to release us.
+ * <p>
+ * @param cacheName
+ * @param obj
+ * @throws IOException
+ */
+ @Override
+ public <K, V> void removeCacheListener( String cacheName, ICacheListener<K, V> obj )
+ throws IOException
+ {
+ log.info( "removeCacheListener, cacheName [{0}]", cacheName );
+ // Record the removal locally, regardless of whether the remote
+ // remove-listener operation succeeds or fails.
+ Set<ICacheListener<?, ?>> listenerSet = cacheMap.get( cacheName );
+ if ( listenerSet != null )
+ {
+ listenerSet.remove( obj );
+ }
+ cacheWatch.removeCacheListener( cacheName, obj );
+ }
+
+ /**
+ * @param obj
+ * @throws IOException
+ */
+ @Override
+ public <K, V> void removeCacheListener( ICacheListener<K, V> obj )
+ throws IOException
+ {
+ log.info( "removeCacheListener, ICacheListener [{0}]", obj );
+
+ // Record the removal locally, regardless of whether the remote
+ // remove-listener operation succeeds or fails.
+ for (Set<ICacheListener<?, ?>> listenerSet : cacheMap.values())
+ {
+ log.debug( "Before removing [{0}] the listenerSet = {1}", obj,
+ listenerSet );
+ listenerSet.remove( obj );
+ }
+ cacheWatch.removeCacheListener( obj );
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CompositeCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CompositeCacheAttributes.java
new file mode 100644
index 0000000..ea9241f
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/CompositeCacheAttributes.java
@@ -0,0 +1,443 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
+
+/**
+ * The CompositeCacheAttributes defines the general cache region settings. If a region is not
+ * explicitly defined in the cache.ccf then it inherits the cache default settings.
+ * <p>
+ * If all the default attributes are not defined in the default region definition in the cache.ccf,
+ * the hard coded defaults will be used.
+ */
+public class CompositeCacheAttributes
+ implements ICompositeCacheAttributes
+{
+ /** Don't change */
+ private static final long serialVersionUID = 6754049978134196787L;
+
+ /** default lateral switch */
+ private static final boolean DEFAULT_USE_LATERAL = true;
+
+ /** default remote switch */
+ private static final boolean DEFAULT_USE_REMOTE = true;
+
+ /** default disk switch */
+ private static final boolean DEFAULT_USE_DISK = true;
+
+ /** default shrinker setting */
+ private static final boolean DEFAULT_USE_SHRINKER = false;
+
+ /** default max objects value */
+ private static final int DEFAULT_MAX_OBJECTS = 100;
+
+ /** default */
+ private static final int DEFAULT_MAX_MEMORY_IDLE_TIME_SECONDS = 60 * 120;
+
+ /** default interval to run the shrinker */
+ private static final int DEFAULT_SHRINKER_INTERVAL_SECONDS = 30;
+
+ /** default */
+ private static final int DEFAULT_MAX_SPOOL_PER_RUN = -1;
+
+ /** default */
+ private static final String DEFAULT_MEMORY_CACHE_NAME = "org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache";
+
+ /** Default number to send to disk at a time when memory fills. */
+ private static final int DEFAULT_CHUNK_SIZE = 2;
+
+ /** allow lateral caches */
+ private boolean useLateral = DEFAULT_USE_LATERAL;
+
+ /** allow remote caches */
+ private boolean useRemote = DEFAULT_USE_REMOTE;
+
+ /** Whether we should use a disk cache if it is configured. */
+ private boolean useDisk = DEFAULT_USE_DISK;
+
+ /** Whether or not we should run the memory shrinker thread. */
+ private boolean useMemoryShrinker = DEFAULT_USE_SHRINKER;
+
+ /** The maximum objects that the memory cache will be allowed to hold. */
+ private int maxObjs = DEFAULT_MAX_OBJECTS;
+
+ /** maxMemoryIdleTimeSeconds */
+ private long maxMemoryIdleTimeSeconds = DEFAULT_MAX_MEMORY_IDLE_TIME_SECONDS;
+
+ /** shrinkerIntervalSeconds */
+ private long shrinkerIntervalSeconds = DEFAULT_SHRINKER_INTERVAL_SECONDS;
+
+ /** The maximum number the shrinker will spool to disk per run. */
+ private int maxSpoolPerRun = DEFAULT_MAX_SPOOL_PER_RUN;
+
+ /** The name of this cache region. */
+ private String cacheName;
+
+ /** The name of the memory cache implementation class. */
+ private String memoryCacheName;
+
+ /** Set via DISK_USAGE_PATTERN_NAME */
+ private DiskUsagePattern diskUsagePattern = DiskUsagePattern.SWAP;
+
+ /** How many to spool to disk at a time. */
+ private int spoolChunkSize = DEFAULT_CHUNK_SIZE;
+
+ /**
+ * Constructor for the CompositeCacheAttributes object
+ */
+ public CompositeCacheAttributes()
+ {
+ super();
+ // set this as the default so the configuration is a bit simpler
+ memoryCacheName = DEFAULT_MEMORY_CACHE_NAME;
+ }
+
+ /**
+ * Sets the maxObjects attribute of the CompositeCacheAttributes object
+ * <p>
+ * @param maxObjs The new maxObjects value
+ */
+ @Override
+ public void setMaxObjects( int maxObjs )
+ {
+ this.maxObjs = maxObjs;
+ }
+
+ /**
+ * Gets the maxObjects attribute of the CompositeCacheAttributes object
+ * <p>
+ * @return The maxObjects value
+ */
+ @Override
+ public int getMaxObjects()
+ {
+ return this.maxObjs;
+ }
+
+ /**
+ * Sets the useDisk attribute of the CompositeCacheAttributes object
+ * <p>
+ * @param useDisk The new useDisk value
+ */
+ @Override
+ public void setUseDisk( boolean useDisk )
+ {
+ this.useDisk = useDisk;
+ }
+
+ /**
+ * Gets the useDisk attribute of the CompositeCacheAttributes object
+ * <p>
+ * @return The useDisk value
+ */
+ @Override
+ public boolean isUseDisk()
+ {
+ return useDisk;
+ }
+
+ /**
+ * Sets the useLateral attribute of the CompositeCacheAttributes object
+ * <p>
+ * @param b The new useLateral value
+ */
+ @Override
+ public void setUseLateral( boolean b )
+ {
+ this.useLateral = b;
+ }
+
+ /**
+ * Gets the useLateral attribute of the CompositeCacheAttributes object
+ * <p>
+ * @return The useLateral value
+ */
+ @Override
+ public boolean isUseLateral()
+ {
+ return this.useLateral;
+ }
+
+ /**
+ * Sets the useRemote attribute of the CompositeCacheAttributes object
+ * <p>
+ * @param useRemote The new useRemote value
+ */
+ @Override
+ public void setUseRemote( boolean useRemote )
+ {
+ this.useRemote = useRemote;
+ }
+
+ /**
+ * Gets the useRemote attribute of the CompositeCacheAttributes object
+ * <p>
+ * @return The useRemote value
+ */
+ @Override
+ public boolean isUseRemote()
+ {
+ return this.useRemote;
+ }
+
+ /**
+ * Sets the cacheName attribute of the CompositeCacheAttributes object
+ * <p>
+ * @param s The new cacheName value
+ */
+ @Override
+ public void setCacheName( String s )
+ {
+ this.cacheName = s;
+ }
+
+ /**
+ * Gets the cacheName attribute of the CompositeCacheAttributes object
+ * <p>
+ * @return The cacheName value
+ */
+ @Override
+ public String getCacheName()
+ {
+ return this.cacheName;
+ }
+
+ /**
+ * Sets the memoryCacheName attribute of the CompositeCacheAttributes object
+ * <p>
+ * @param s The new memoryCacheName value
+ */
+ @Override
+ public void setMemoryCacheName( String s )
+ {
+ this.memoryCacheName = s;
+ }
+
+ /**
+ * Gets the memoryCacheName attribute of the CompositeCacheAttributes object
+ * <p>
+ * @return The memoryCacheName value
+ */
+ @Override
+ public String getMemoryCacheName()
+ {
+ return this.memoryCacheName;
+ }
+
+ /**
+ * Whether the memory cache should perform background memory shrinkage.
+ * <p>
+ * @param useShrinker The new UseMemoryShrinker value
+ */
+ @Override
+ public void setUseMemoryShrinker( boolean useShrinker )
+ {
+ this.useMemoryShrinker = useShrinker;
+ }
+
+ /**
+ * Whether the memory cache should perform background memory shrinkage.
+ * <p>
+ * @return The UseMemoryShrinker value
+ */
+ @Override
+ public boolean isUseMemoryShrinker()
+ {
+ return this.useMemoryShrinker;
+ }
+
+ /**
+ * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space.
+ * <p>
+ * @param seconds The new MaxMemoryIdleTimeSeconds value
+ */
+ @Override
+ public void setMaxMemoryIdleTimeSeconds( long seconds )
+ {
+ this.maxMemoryIdleTimeSeconds = seconds;
+ }
+
+ /**
+ * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space.
+ * <p>
+ * @return The MaxMemoryIdleTimeSeconds value
+ */
+ @Override
+ public long getMaxMemoryIdleTimeSeconds()
+ {
+ return this.maxMemoryIdleTimeSeconds;
+ }
+
+ /**
+ * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space.
+ * This sets the shrinker interval.
+ * <p>
+ * @param seconds The new ShrinkerIntervalSeconds value
+ */
+ @Override
+ public void setShrinkerIntervalSeconds( long seconds )
+ {
+ this.shrinkerIntervalSeconds = seconds;
+ }
+
+ /**
+ * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space.
+ * This gets the shrinker interval.
+ * <p>
+ * @return The ShrinkerIntervalSeconds value
+ */
+ @Override
+ public long getShrinkerIntervalSeconds()
+ {
+ return this.shrinkerIntervalSeconds;
+ }
+
+ /**
+ * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space.
+ * This sets the maximum number of items to spool per run.
+ * <p>
+ * If the value is -1, then there is no limit to the number of items to be spooled.
+ * <p>
+ * @param maxSpoolPerRun The new maxSpoolPerRun value
+ */
+ @Override
+ public void setMaxSpoolPerRun( int maxSpoolPerRun )
+ {
+ this.maxSpoolPerRun = maxSpoolPerRun;
+ }
+
+ /**
+ * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space.
+ * This gets the maximum number of items to spool per run.
+ * <p>
+ * @return The maxSpoolPerRun value
+ */
+ @Override
+ public int getMaxSpoolPerRun()
+ {
+ return this.maxSpoolPerRun;
+ }
+
+ /**
+ * By default this is SWAP_ONLY.
+ * <p>
+ * @param diskUsagePattern The diskUsagePattern to set.
+ */
+ @Override
+ public void setDiskUsagePattern( DiskUsagePattern diskUsagePattern )
+ {
+ this.diskUsagePattern = diskUsagePattern;
+ }
+
+ /**
+ * Translates the name to the disk usage pattern short value.
+ * <p>
+ * The allowed values are SWAP and UPDATE.
+ * <p>
+ * @param diskUsagePatternName The diskUsagePattern to set.
+ */
+ @Override
+ public void setDiskUsagePatternName( String diskUsagePatternName )
+ {
+ if ( diskUsagePatternName != null )
+ {
+ String name = diskUsagePatternName.toUpperCase().trim();
+ if ( name.startsWith( "SWAP" ) )
+ {
+ this.setDiskUsagePattern( DiskUsagePattern.SWAP );
+ }
+ else if ( name.startsWith( "UPDATE" ) )
+ {
+ this.setDiskUsagePattern( DiskUsagePattern.UPDATE );
+ }
+ }
+ }
+
+ /**
+ * Number to send to disk at at time when memory is full.
+ * <p>
+ * @return int
+ */
+ @Override
+ public int getSpoolChunkSize()
+ {
+ return spoolChunkSize;
+ }
+
+ /**
+ * Number to send to disk at a time.
+ * <p>
+ * @param spoolChunkSize
+ */
+ @Override
+ public void setSpoolChunkSize( int spoolChunkSize )
+ {
+ this.spoolChunkSize = spoolChunkSize;
+ }
+
+ /**
+ * @return Returns the diskUsagePattern.
+ */
+ @Override
+ public DiskUsagePattern getDiskUsagePattern()
+ {
+ return diskUsagePattern;
+ }
+
+ /**
+ * Dumps the core attributes.
+ * <p>
+ * @return For debugging.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder dump = new StringBuilder();
+
+ dump.append( "[ " );
+ dump.append( "useLateral = " ).append( useLateral );
+ dump.append( ", useRemote = " ).append( useRemote );
+ dump.append( ", useDisk = " ).append( useDisk );
+ dump.append( ", maxObjs = " ).append( maxObjs );
+ dump.append( ", maxSpoolPerRun = " ).append( maxSpoolPerRun );
+ dump.append( ", diskUsagePattern = " ).append( diskUsagePattern );
+ dump.append( ", spoolChunkSize = " ).append( spoolChunkSize );
+ dump.append( " ]" );
+
+ return dump.toString();
+ }
+
+ /**
+ * @see java.lang.Object#clone()
+ */
+ @Override
+ public ICompositeCacheAttributes clone()
+ {
+ try
+ {
+ return (ICompositeCacheAttributes)super.clone();
+ }
+ catch (CloneNotSupportedException e)
+ {
+ throw new RuntimeException("Clone not supported. This should never happen.", e);
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/ElementAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/ElementAttributes.java
new file mode 100644
index 0000000..077fc9c
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/ElementAttributes.java
@@ -0,0 +1,459 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.control.event.behavior.IElementEventHandler;
+
+/**
+ * This it the element attribute descriptor class. Each element in the cache has an ElementAttribute
+ * object associated with it. An ElementAttributes object can be associated with an element in 3
+ * ways:
+ * <ol>
+ * <li>When the item is put into the cache, you can associate an element attributes object.</li>
+ * <li>If not attributes object is include when the element is put into the cache, then the default
+ * attributes for the region will be used.</li>
+ * <li>The element attributes can be reset. This effectively results in a retrieval followed by a
+ * put. Hence, this is the same as 1.</li>
+ * </ol>
+ */
+public class ElementAttributes
+ implements IElementAttributes
+{
+ /** Don't change. */
+ private static final long serialVersionUID = 7814990748035017441L;
+
+ /** Can this item be flushed to disk */
+ private boolean IS_SPOOL = true;
+
+ /** Is this item laterally distributable */
+ private boolean IS_LATERAL = true;
+
+ /** Can this item be sent to the remote cache */
+ private boolean IS_REMOTE = true;
+
+ /**
+ * You can turn off expiration by setting this to true. This causes the cache to bypass both max
+ * life and idle time expiration.
+ */
+ private boolean IS_ETERNAL = true;
+
+ /** Max life seconds */
+ private long maxLife = -1;
+
+ /**
+ * The maximum time an entry can be idle. Setting this to -1 causes the idle time check to be
+ * ignored.
+ */
+ private long maxIdleTime = -1;
+
+ /** The byte size of the field. Must be manually set. */
+ private int size = 0;
+
+ /** The creation time. This is used to enforce the max life. */
+ private long createTime = 0;
+
+ /** The last access time. This is used to enforce the max idel time. */
+ private long lastAccessTime = 0;
+
+ /**
+ * The list of Event handlers to use. This is transient, since the event handlers cannot usually
+ * be serialized. This means that you cannot attach a post serialization event to an item.
+ * <p>
+ * TODO we need to check that when an item is passed to a non-local cache that if the local
+ * cache had a copy with event handlers, that those handlers are used.
+ */
+ private transient ArrayList<IElementEventHandler> eventHandlers;
+
+ private long timeFactor = 1000;
+
+ /**
+ * Constructor for the IElementAttributes object
+ */
+ public ElementAttributes()
+ {
+ this.createTime = System.currentTimeMillis();
+ this.lastAccessTime = this.createTime;
+ }
+
+ /**
+ * Constructor for the IElementAttributes object
+ * <p>
+ * @param attr
+ */
+ protected ElementAttributes( ElementAttributes attr )
+ {
+ IS_ETERNAL = attr.IS_ETERNAL;
+
+ // waterfall onto disk, for pure disk set memory to 0
+ IS_SPOOL = attr.IS_SPOOL;
+
+ // lateral
+ IS_LATERAL = attr.IS_LATERAL;
+
+ // central rmi store
+ IS_REMOTE = attr.IS_REMOTE;
+
+ maxLife = attr.maxLife;
+ // time-to-live
+ maxIdleTime = attr.maxIdleTime;
+ size = attr.size;
+ }
+
+ /**
+ * Sets the maxLife attribute of the IAttributes object.
+ * <p>
+ * @param mls The new MaxLifeSeconds value
+ */
+ @Override
+ public void setMaxLife(long mls)
+ {
+ this.maxLife = mls;
+ }
+
+ /**
+ * Sets the maxLife attribute of the IAttributes object. How many seconds it can live after
+ * creation.
+ * <p>
+ * If this is exceeded the element will not be returned, instead it will be removed. It will be
+ * removed on retrieval, or removed actively if the memory shrinker is turned on.
+ * @return The MaxLifeSeconds value
+ */
+ @Override
+ public long getMaxLife()
+ {
+ return this.maxLife;
+ }
+
+ /**
+ * Sets the idleTime attribute of the IAttributes object. This is the maximum time the item can
+ * be idle in the cache, that is not accessed.
+ * <p>
+ * If this is exceeded the element will not be returned, instead it will be removed. It will be
+ * removed on retrieval, or removed actively if the memory shrinker is turned on.
+ * @param idle The new idleTime value
+ */
+ @Override
+ public void setIdleTime( long idle )
+ {
+ this.maxIdleTime = idle;
+ }
+
+ /**
+ * Size in bytes. This is not used except in the admin pages. It will be 0 by default
+ * and is only updated when the element is serialized.
+ * <p>
+ * @param size The new size value
+ */
+ @Override
+ public void setSize( int size )
+ {
+ this.size = size;
+ }
+
+ /**
+ * Gets the size attribute of the IAttributes object
+ * <p>
+ * @return The size value
+ */
+ @Override
+ public int getSize()
+ {
+ return size;
+ }
+
+ /**
+ * Gets the createTime attribute of the IAttributes object.
+ * <p>
+ * This should be the current time in milliseconds returned by the sysutem call when the element
+ * is put in the cache.
+ * <p>
+ * Putting an item in the cache overrides any existing items.
+ * @return The createTime value
+ */
+ @Override
+ public long getCreateTime()
+ {
+ return createTime;
+ }
+
+ /**
+ * Sets the createTime attribute of the IElementAttributes object
+ */
+ public void setCreateTime()
+ {
+ createTime = System.currentTimeMillis();
+ }
+
+ /**
+ * Gets the idleTime attribute of the IAttributes object.
+ * <p>
+ * @return The idleTime value
+ */
+ @Override
+ public long getIdleTime()
+ {
+ return this.maxIdleTime;
+ }
+
+ /**
+ * Gets the time left to live of the IAttributes object.
+ * <p>
+ * This is the (max life + create time) - current time.
+ * @return The TimeToLiveSeconds value
+ */
+ @Override
+ public long getTimeToLiveSeconds()
+ {
+ final long now = System.currentTimeMillis();
+ final long timeFactorForMilliseconds = getTimeFactorForMilliseconds();
+ return ( this.getCreateTime() + this.getMaxLife() * timeFactorForMilliseconds - now ) / 1000;
+ }
+
+ /**
+ * Gets the LastAccess attribute of the IAttributes object.
+ * <p>
+ * @return The LastAccess value.
+ */
+ @Override
+ public long getLastAccessTime()
+ {
+ return this.lastAccessTime;
+ }
+
+ /**
+ * Sets the LastAccessTime as now of the IElementAttributes object
+ */
+ @Override
+ public void setLastAccessTimeNow()
+ {
+ this.lastAccessTime = System.currentTimeMillis();
+ }
+
+ /**
+ * only for use from test code
+ */
+ public void setLastAccessTime(long time)
+ {
+ this.lastAccessTime = time;
+ }
+
+ /**
+ * Can this item be spooled to disk
+ * <p>
+ * By default this is true.
+ * @return The spoolable value
+ */
+ @Override
+ public boolean getIsSpool()
+ {
+ return this.IS_SPOOL;
+ }
+
+ /**
+ * Sets the isSpool attribute of the IElementAttributes object
+ * <p>
+ * By default this is true.
+ * @param val The new isSpool value
+ */
+ @Override
+ public void setIsSpool( boolean val )
+ {
+ this.IS_SPOOL = val;
+ }
+
+ /**
+ * Is this item laterally distributable. Can it be sent to auxiliaries of type lateral.
+ * <p>
+ * By default this is true.
+ * @return The isLateral value
+ */
+ @Override
+ public boolean getIsLateral()
+ {
+ return this.IS_LATERAL;
+ }
+
+ /**
+ * Sets the isLateral attribute of the IElementAttributes object
+ * <p>
+ * By default this is true.
+ * @param val The new isLateral value
+ */
+ @Override
+ public void setIsLateral( boolean val )
+ {
+ this.IS_LATERAL = val;
+ }
+
+ /**
+ * Can this item be sent to the remote cache
+ * @return true if the item can be sent to a remote auxiliary
+ */
+ @Override
+ public boolean getIsRemote()
+ {
+ return this.IS_REMOTE;
+ }
+
+ /**
+ * Sets the isRemote attribute of the ElementAttributes object
+ * @param val The new isRemote value
+ */
+ @Override
+ public void setIsRemote( boolean val )
+ {
+ this.IS_REMOTE = val;
+ }
+
+ /**
+ * You can turn off expiration by setting this to true. The max life value will be ignored.
+ * <p>
+ * @return true if the item cannot expire.
+ */
+ @Override
+ public boolean getIsEternal()
+ {
+ return this.IS_ETERNAL;
+ }
+
+ /**
+ * Sets the isEternal attribute of the ElementAttributes object. True means that the item should
+ * never expire. If can still be removed if it is the least recently used, and you are using the
+ * LRUMemory cache. it just will not be filtered for expiration by the cache hub.
+ * <p>
+ * @param val The new isEternal value
+ */
+ @Override
+ public void setIsEternal( boolean val )
+ {
+ this.IS_ETERNAL = val;
+ }
+
+ /**
+ * Adds a ElementEventHandler. Handler's can be registered for multiple events. A registered
+ * handler will be called at every recognized event.
+ * <p>
+ * The alternative would be to register handlers for each event. Or maybe The handler interface
+ * should have a method to return whether it cares about certain events.
+ * <p>
+ * @param eventHandler The ElementEventHandler to be added to the list.
+ */
+ @Override
+ public void addElementEventHandler( IElementEventHandler eventHandler )
+ {
+ // lazy here, no concurrency problems expected
+ if ( this.eventHandlers == null )
+ {
+ this.eventHandlers = new ArrayList<>();
+ }
+ this.eventHandlers.add( eventHandler );
+ }
+
+ /**
+ * Sets the eventHandlers of the IElementAttributes object.
+ * <p>
+ * This add the references to the local list. Subsequent changes in the caller's list will not
+ * be reflected.
+ * <p>
+ * @param eventHandlers List of IElementEventHandler objects
+ */
+ @Override
+ public void addElementEventHandlers( List<IElementEventHandler> eventHandlers )
+ {
+ if ( eventHandlers == null )
+ {
+ return;
+ }
+
+ for (IElementEventHandler handler : eventHandlers)
+ {
+ addElementEventHandler(handler);
+ }
+ }
+
+ @Override
+ public long getTimeFactorForMilliseconds()
+ {
+ return timeFactor;
+ }
+
+ @Override
+ public void setTimeFactorForMilliseconds(long factor)
+ {
+ this.timeFactor = factor;
+ }
+
+ /**
+ * Gets the elementEventHandlers. Returns null if none exist. Makes checking easy.
+ * <p>
+ * @return The elementEventHandlers List of IElementEventHandler objects
+ */
+ @Override
+ public ArrayList<IElementEventHandler> getElementEventHandlers()
+ {
+ return this.eventHandlers;
+ }
+
+ /**
+ * For logging and debugging the element IElementAttributes.
+ * <p>
+ * @return String info about the values.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder dump = new StringBuilder();
+
+ dump.append( "[ IS_LATERAL = " ).append( IS_LATERAL );
+ dump.append( ", IS_SPOOL = " ).append( IS_SPOOL );
+ dump.append( ", IS_REMOTE = " ).append( IS_REMOTE );
+ dump.append( ", IS_ETERNAL = " ).append( IS_ETERNAL );
+ dump.append( ", MaxLifeSeconds = " ).append( this.getMaxLife() );
+ dump.append( ", IdleTime = " ).append( this.getIdleTime() );
+ dump.append( ", CreateTime = " ).append( this.getCreateTime() );
+ dump.append( ", LastAccessTime = " ).append( this.getLastAccessTime() );
+ dump.append( ", getTimeToLiveSeconds() = " ).append( String.valueOf( getTimeToLiveSeconds() ) );
+ dump.append( ", createTime = " ).append( String.valueOf( createTime ) ).append( " ]" );
+
+ return dump.toString();
+ }
+
+ /**
+ * @see java.lang.Object#clone()
+ */
+ @Override
+ public IElementAttributes clone()
+ {
+ try
+ {
+ ElementAttributes c = (ElementAttributes) super.clone();
+ c.setCreateTime();
+ return c;
+ }
+ catch (CloneNotSupportedException e)
+ {
+ throw new RuntimeException("Clone not supported. This should never happen.", e);
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/PooledCacheEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/PooledCacheEventQueue.java
new file mode 100644
index 0000000..5fdfc0d
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/PooledCacheEventQueue.java
@@ -0,0 +1,191 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadPoolExecutor;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheListener;
+import org.apache.commons.jcs3.engine.stats.StatElement;
+import org.apache.commons.jcs3.engine.stats.Stats;
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.threadpool.ThreadPoolManager;
+
+/**
+ * An event queue is used to propagate ordered cache events to one and only one target listener.
+ * <p>
+ * This is a modified version of the experimental version. It uses a PooledExecutor and a
+ * BoundedBuffer to queue up events and execute them as threads become available.
+ * <p>
+ * The PooledExecutor is static, because presumably these processes will be IO bound, so throwing
+ * more than a few threads at them will serve no purpose other than to saturate the IO interface. In
+ * light of this, having one thread per region seems unnecessary. This may prove to be false.
+ */
+public class PooledCacheEventQueue<K, V>
+ extends AbstractCacheEventQueue<K, V>
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog( PooledCacheEventQueue.class );
+
+ /** The type of event queue */
+ private static final QueueType queueType = QueueType.POOLED;
+
+ /** The Thread Pool to execute events with. */
+ protected ExecutorService pool = null;
+
+ /** The Thread Pool queue */
+ protected BlockingQueue<Runnable> queue = null;
+
+ /**
+ * Constructor for the CacheEventQueue object
+ * <p>
+ * @param listener
+ * @param listenerId
+ * @param cacheName
+ * @param maxFailure
+ * @param waitBeforeRetry
+ * @param threadPoolName
+ */
+ public PooledCacheEventQueue( ICacheListener<K, V> listener, long listenerId, String cacheName, int maxFailure,
+ int waitBeforeRetry, String threadPoolName )
+ {
+ initialize( listener, listenerId, cacheName, maxFailure, waitBeforeRetry, threadPoolName );
+ }
+
+ /**
+ * Initializes the queue.
+ * <p>
+ * @param listener
+ * @param listenerId
+ * @param cacheName
+ * @param maxFailure
+ * @param waitBeforeRetry
+ * @param threadPoolName
+ */
+ protected void initialize( ICacheListener<K, V> listener, long listenerId, String cacheName, int maxFailure,
+ int waitBeforeRetry, String threadPoolName )
+ {
+ super.initialize(listener, listenerId, cacheName, maxFailure, waitBeforeRetry);
+
+ // this will share the same pool with other event queues by default.
+ pool = ThreadPoolManager.getInstance().getExecutorService(
+ (threadPoolName == null) ? "cache_event_queue" : threadPoolName );
+
+ if (pool instanceof ThreadPoolExecutor)
+ {
+ queue = ((ThreadPoolExecutor) pool).getQueue();
+ }
+ }
+
+ /**
+ * @return the queue type
+ */
+ @Override
+ public QueueType getQueueType()
+ {
+ return queueType;
+ }
+
+ /**
+ * Destroy the queue. Interrupt all threads.
+ */
+ @Override
+ public synchronized void destroy()
+ {
+ if ( isWorking() )
+ {
+ setWorking(false);
+ pool.shutdownNow();
+ log.info( "Cache event queue destroyed: {0}", this );
+ }
+ }
+
+ /**
+ * Adds an event to the queue.
+ * <p>
+ * @param event
+ */
+ @Override
+ protected void put( AbstractCacheEvent event )
+ {
+ pool.execute( event );
+ }
+
+ /**
+ * @return IStats
+ */
+ @Override
+ public IStats getStatistics()
+ {
+ IStats stats = new Stats();
+ stats.setTypeName( "Pooled Cache Event Queue" );
+
+ ArrayList<IStatElement<?>> elems = new ArrayList<>();
+
+ elems.add(new StatElement<>( "Working", Boolean.valueOf(isWorking()) ) );
+ elems.add(new StatElement<>( "Empty", Boolean.valueOf(this.isEmpty()) ) );
+
+ if ( queue != null )
+ {
+ elems.add(new StatElement<>( "Queue Size", Integer.valueOf(queue.size()) ) );
+ elems.add(new StatElement<>( "Queue Capacity", Integer.valueOf(queue.remainingCapacity()) ) );
+ }
+
+ stats.setStatElements( elems );
+
+ return stats;
+ }
+
+ /**
+ * If the Queue is using a bounded channel we can determine the size. If it is zero or we can't
+ * determine the size, we return true.
+ * <p>
+ * @return whether or not there are items in the queue
+ */
+ @Override
+ public boolean isEmpty()
+ {
+ return size() == 0;
+ }
+
+ /**
+ * Returns the number of elements in the queue. If the queue cannot determine the size
+ * accurately it will return 0.
+ * <p>
+ * @return number of items in the queue.
+ */
+ @Override
+ public int size()
+ {
+ if ( queue == null )
+ {
+ return 0;
+ }
+ else
+ {
+ return queue.size();
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/ZombieCacheService.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/ZombieCacheService.java
new file mode 100644
index 0000000..5f4ac84
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/ZombieCacheService.java
@@ -0,0 +1,151 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheService;
+import org.apache.commons.jcs3.engine.behavior.IZombie;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * Zombie adapter for any cache service. Balks at every call.
+ */
+public class ZombieCacheService<K, V>
+ implements ICacheService<K, V>, IZombie
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog( ZombieCacheService.class );
+
+ /**
+ * @param item
+ */
+ public void put( ICacheElement<K, V> item )
+ {
+ log.debug( "Zombie put for item {0}", item );
+ // zombies have no inner life
+ }
+
+ /**
+ * Does nothing.
+ * <p>
+ * @param item
+ */
+ @Override
+ public void update( ICacheElement<K, V> item )
+ {
+ // zombies have no inner life
+ }
+
+ /**
+ * @param cacheName
+ * @param key
+ * @return null. zombies have no internal data
+ */
+ @Override
+ public ICacheElement<K, V> get( String cacheName, K key )
+ {
+ return null;
+ }
+
+ /**
+ * Returns an empty map. Zombies have no internal data.
+ * <p>
+ * @param cacheName
+ * @param keys
+ * @return Collections.EMPTY_MAP
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys )
+ {
+ return Collections.emptyMap();
+ }
+
+ /**
+ * Returns an empty map. Zombies have no internal data.
+ * <p>
+ * @param cacheName
+ * @param pattern
+ * @return Collections.EMPTY_MAP
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern )
+ {
+ return Collections.emptyMap();
+ }
+
+ /**
+ * Logs the get to debug, but always balks.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param container
+ * @return null always
+ */
+ public Serializable get( String cacheName, K key, boolean container )
+ {
+ log.debug( "Zombie get for key [{0}] cacheName [{1}] container [{2}]",
+ key, cacheName, container);
+ // zombies have no inner life
+ return null;
+ }
+
+ /**
+ * @param cacheName
+ * @param key
+ */
+ @Override
+ public void remove( String cacheName, K key )
+ {
+ // zombies have no inner life
+ }
+
+ /**
+ * @param cacheName
+ */
+ @Override
+ public void removeAll( String cacheName )
+ {
+ // zombies have no inner life
+ }
+
+ /**
+ * @param cacheName
+ */
+ @Override
+ public void dispose( String cacheName )
+ {
+ // zombies have no inner life
+ }
+
+ /**
+ * Frees all caches.
+ */
+ @Override
+ public void release()
+ {
+ // zombies have no inner life
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/ZombieCacheServiceNonLocal.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/ZombieCacheServiceNonLocal.java
new file mode 100644
index 0000000..10cd1a7
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/ZombieCacheServiceNonLocal.java
@@ -0,0 +1,316 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.timing.ElapsedTimer;
+
+/**
+ * Zombie adapter for the non local cache services. It just balks if there is no queue configured.
+ * <p>
+ * If a queue is configured, then events will be added to the queue. The idea is that when proper
+ * operation is restored, the non local cache will walk the queue. The queue must be bounded so it
+ * does not eat memory.
+ * <p>
+ * This originated in the remote cache.
+ */
+public class ZombieCacheServiceNonLocal<K, V>
+ extends ZombieCacheService<K, V>
+ implements ICacheServiceNonLocal<K, V>
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( ZombieCacheServiceNonLocal.class );
+
+ /** How big can the queue grow. */
+ private int maxQueueSize = 0;
+
+ /** The queue */
+ private final ConcurrentLinkedQueue<ZombieEvent> queue;
+
+ /**
+ * Default.
+ */
+ public ZombieCacheServiceNonLocal()
+ {
+ queue = new ConcurrentLinkedQueue<>();
+ }
+
+ /**
+ * Sets the maximum number of items that will be allowed on the queue.
+ * <p>
+ * @param maxQueueSize
+ */
+ public ZombieCacheServiceNonLocal( int maxQueueSize )
+ {
+ this.maxQueueSize = maxQueueSize;
+ queue = new ConcurrentLinkedQueue<>();
+ }
+
+ /**
+ * Gets the number of items on the queue.
+ * <p>
+ * @return size of the queue.
+ */
+ public int getQueueSize()
+ {
+ return queue.size();
+ }
+
+ private void addQueue(ZombieEvent event)
+ {
+ queue.add(event);
+ if (queue.size() > maxQueueSize)
+ {
+ queue.poll(); // drop oldest entry
+ }
+ }
+
+ /**
+ * Adds an update event to the queue if the maxSize is greater than 0;
+ * <p>
+ * @param item ICacheElement
+ * @param listenerId - identifies the caller.
+ */
+ @Override
+ public void update( ICacheElement<K, V> item, long listenerId )
+ {
+ if ( maxQueueSize > 0 )
+ {
+ PutEvent<K, V> event = new PutEvent<>( item, listenerId );
+ addQueue( event );
+ }
+ // Zombies have no inner life
+ }
+
+ /**
+ * Adds a removeAll event to the queue if the maxSize is greater than 0;
+ * <p>
+ * @param cacheName - region name
+ * @param key - item key
+ * @param listenerId - identifies the caller.
+ */
+ @Override
+ public void remove( String cacheName, K key, long listenerId )
+ {
+ if ( maxQueueSize > 0 )
+ {
+ RemoveEvent<K> event = new RemoveEvent<>( cacheName, key, listenerId );
+ addQueue( event );
+ }
+ // Zombies have no inner life
+ }
+
+ /**
+ * Adds a removeAll event to the queue if the maxSize is greater than 0;
+ * <p>
+ * @param cacheName - name of the region
+ * @param listenerId - identifies the caller.
+ */
+ @Override
+ public void removeAll( String cacheName, long listenerId )
+ {
+ if ( maxQueueSize > 0 )
+ {
+ RemoveAllEvent event = new RemoveAllEvent( cacheName, listenerId );
+ addQueue( event );
+ }
+ // Zombies have no inner life
+ }
+
+ /**
+ * Does nothing. Gets are synchronous and cannot be added to a queue.
+ * <p>
+ * @param cacheName - region name
+ * @param key - item key
+ * @param requesterId - identifies the caller.
+ * @return null
+ * @throws IOException
+ */
+ @Override
+ public ICacheElement<K, V> get( String cacheName, K key, long requesterId )
+ throws IOException
+ {
+ // Zombies have no inner life
+ return null;
+ }
+
+ /**
+ * Does nothing.
+ * <p>
+ * @param cacheName
+ * @param pattern
+ * @param requesterId
+ * @return empty map
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern, long requesterId )
+ throws IOException
+ {
+ return Collections.emptyMap();
+ }
+
+ /**
+ * @param cacheName - region name
+ * @param keys - item key
+ * @param requesterId - identity of the caller
+ * @return an empty map. zombies have no internal data
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys, long requesterId )
+ {
+ return new HashMap<>();
+ }
+
+ /**
+ * Does nothing.
+ * <p>
+ * @param cacheName - region name
+ * @return empty set
+ */
+ @Override
+ public Set<K> getKeySet( String cacheName )
+ {
+ return Collections.emptySet();
+ }
+
+ /**
+ * Walk the queue, calling the service for each queue operation.
+ * <p>
+ * @param service
+ * @throws Exception
+ */
+ public synchronized void propagateEvents( ICacheServiceNonLocal<K, V> service )
+ throws Exception
+ {
+ int cnt = 0;
+ log.info( "Propagating events to the new ICacheServiceNonLocal." );
+ ElapsedTimer timer = new ElapsedTimer();
+ while ( !queue.isEmpty() )
+ {
+ cnt++;
+
+ // for each item, call the appropriate service method
+ ZombieEvent event = queue.poll();
+
+ if ( event instanceof PutEvent )
+ {
+ @SuppressWarnings("unchecked") // Type checked by instanceof
+ PutEvent<K, V> putEvent = (PutEvent<K, V>) event;
+ service.update( putEvent.element, event.requesterId );
+ }
+ else if ( event instanceof RemoveEvent )
+ {
+ @SuppressWarnings("unchecked") // Type checked by instanceof
+ RemoveEvent<K> removeEvent = (RemoveEvent<K>) event;
+ service.remove( event.cacheName, removeEvent.key, event.requesterId );
+ }
+ else if ( event instanceof RemoveAllEvent )
+ {
+ service.removeAll( event.cacheName, event.requesterId );
+ }
+ }
+ log.info( "Propagated {0} events to the new ICacheServiceNonLocal in {1}",
+ cnt, timer.getElapsedTimeString() );
+ }
+
+ /**
+ * Base of the other events.
+ */
+ protected static abstract class ZombieEvent
+ {
+ /** The name of the region. */
+ String cacheName;
+
+ /** The id of the requester */
+ long requesterId;
+ }
+
+ /**
+ * A basic put event.
+ */
+ private static class PutEvent<K, V>
+ extends ZombieEvent
+ {
+ /** The element to put */
+ ICacheElement<K, V> element;
+
+ /**
+ * Set the element
+ * @param element
+ * @param requesterId
+ */
+ public PutEvent( ICacheElement<K, V> element, long requesterId )
+ {
+ this.requesterId = requesterId;
+ this.element = element;
+ }
+ }
+
+ /**
+ * A basic Remove event.
+ */
+ private static class RemoveEvent<K>
+ extends ZombieEvent
+ {
+ /** The key to remove */
+ K key;
+
+ /**
+ * Set the element
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ */
+ public RemoveEvent( String cacheName, K key, long requesterId )
+ {
+ this.cacheName = cacheName;
+ this.requesterId = requesterId;
+ this.key = key;
+ }
+ }
+
+ /**
+ * A basic RemoveAll event.
+ */
+ private static class RemoveAllEvent
+ extends ZombieEvent
+ {
+ /**
+ * @param cacheName
+ * @param requesterId
+ */
+ public RemoveAllEvent( String cacheName, long requesterId )
+ {
+ this.cacheName = cacheName;
+ this.requesterId = requesterId;
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/ZombieCacheWatch.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/ZombieCacheWatch.java
new file mode 100644
index 0000000..8fbac80
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/ZombieCacheWatch.java
@@ -0,0 +1,73 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.engine.behavior.ICacheListener;
+import org.apache.commons.jcs3.engine.behavior.ICacheObserver;
+import org.apache.commons.jcs3.engine.behavior.IZombie;
+
+/**
+ * Zombie Observer.
+ */
+public class ZombieCacheWatch
+ implements ICacheObserver, IZombie
+{
+ /**
+ * Adds a feature to the CacheListener attribute of the ZombieCacheWatch object
+ * <p>
+ * @param cacheName The feature to be added to the CacheListener attribute
+ * @param obj The feature to be added to the CacheListener attribute
+ */
+ @Override
+ public <K, V> void addCacheListener( String cacheName, ICacheListener<K, V> obj )
+ {
+ // empty
+ }
+
+ /**
+ * Adds a feature to the CacheListener attribute of the ZombieCacheWatch object
+ * <p>
+ * @param obj The feature to be added to the CacheListener attribute
+ */
+ @Override
+ public <K, V> void addCacheListener( ICacheListener<K, V> obj )
+ {
+ // empty
+ }
+
+ /**
+ * @param cacheName
+ * @param obj
+ */
+ @Override
+ public <K, V> void removeCacheListener( String cacheName, ICacheListener<K, V> obj )
+ {
+ // empty
+ }
+
+ /**
+ * @param obj
+ */
+ @Override
+ public <K, V> void removeCacheListener( ICacheListener<K, V> obj )
+ {
+ // empty
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICache.java
new file mode 100644
index 0000000..8735fca
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICache.java
@@ -0,0 +1,144 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.match.behavior.IKeyMatcher;
+
+/**
+ * This is the top level interface for all cache like structures. It defines the methods used
+ * internally by JCS to access, modify, and instrument such structures.
+ *
+ * This allows for a suite of reusable components for accessing such structures, for example
+ * asynchronous access via an event queue.
+ */
+public interface ICache<K, V>
+ extends ICacheType
+{
+ /** Delimiter of a cache name component. This is used for hierarchical deletion */
+ String NAME_COMPONENT_DELIMITER = ":";
+
+ /**
+ * Puts an item to the cache.
+ *
+ * @param element
+ * @throws IOException
+ */
+ void update( ICacheElement<K, V> element )
+ throws IOException;
+
+ /**
+ * Gets an item from the cache.
+ *
+ * @param key
+ * @return a cache element, or null if there is no data in cache for this key
+ * @throws IOException
+ */
+ ICacheElement<K, V> get( K key )
+ throws IOException;
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ *
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no data in cache for any of these keys
+ * @throws IOException
+ */
+ Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
+ throws IOException;
+
+ /**
+ * Gets items from the cache matching the given pattern. Items from memory will replace those from remote sources.
+ *
+ * This only works with string keys. It's too expensive to do a toString on every key.
+ *
+ * Auxiliaries will do their best to handle simple expressions. For instance, the JDBC disk cache will convert * to % and . to _
+ *
+ * @param pattern
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no data matching the pattern.
+ * @throws IOException
+ */
+ Map<K, ICacheElement<K, V>> getMatching(String pattern)
+ throws IOException;
+
+ /**
+ * Removes an item from the cache.
+ *
+ * @param key
+ * @return false if there was an error in removal
+ * @throws IOException
+ */
+ boolean remove( K key )
+ throws IOException;
+
+ /**
+ * Removes all cached items from the cache.
+ *
+ * @throws IOException
+ */
+ void removeAll()
+ throws IOException;
+
+ /**
+ * Prepares for shutdown.
+ * @throws IOException
+ */
+ void dispose()
+ throws IOException;
+
+ /**
+ * Returns the current cache size in number of elements.
+ *
+ * @return number of elements
+ */
+ int getSize();
+
+ /**
+ * Returns the cache status.
+ *
+ * @return Alive or Error
+ */
+ CacheStatus getStatus();
+
+ /**
+ * Returns the cache stats.
+ *
+ * @return String of important historical information.
+ */
+ String getStats();
+
+ /**
+ * Returns the cache name.
+ *
+ * @return usually the region name.
+ */
+ String getCacheName();
+
+ /**
+ * Sets the key matcher used by get matching.
+ *
+ * @param keyMatcher
+ */
+ void setKeyMatcher( IKeyMatcher<K> keyMatcher );
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheElement.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheElement.java
new file mode 100644
index 0000000..e094212
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheElement.java
@@ -0,0 +1,74 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+
+/**
+ * Every item is the cache is wrapped in an ICacheElement. This contains
+ * information about the element: the region name, the key, the value, and the
+ * element attributes.
+ * <p>
+ * The element attributes have lots of useful information about each element,
+ * such as when they were created, how long they have to live, and if they are
+ * allowed to be spooled, etc.
+ *
+ */
+public interface ICacheElement<K, V>
+ extends Serializable
+{
+
+ /**
+ * Gets the cacheName attribute of the ICacheElement<K, V> object. The cacheName
+ * is also known as the region name.
+ *
+ * @return The cacheName value
+ */
+ String getCacheName();
+
+ /**
+ * Gets the key attribute of the ICacheElement<K, V> object
+ *
+ * @return The key value
+ */
+ K getKey();
+
+ /**
+ * Gets the val attribute of the ICacheElement<K, V> object
+ *
+ * @return The val value
+ */
+ V getVal();
+
+ /**
+ * Gets the attributes attribute of the ICacheElement<K, V> object
+ *
+ * @return The attributes value
+ */
+ IElementAttributes getElementAttributes();
+
+ /**
+ * Sets the attributes attribute of the ICacheElement<K, V> object
+ *
+ * @param attr
+ * The new attributes value
+ */
+ void setElementAttributes( IElementAttributes attr );
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheElementSerialized.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheElementSerialized.java
new file mode 100644
index 0000000..917394d
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheElementSerialized.java
@@ -0,0 +1,41 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+/**
+ * This interface defines the behavior of the serialized element wrapper.
+ * <p>
+ * The value is stored as a byte array. This should allow for a variety of serialization mechanisms.
+ * <p>
+ * This currently extends ICacheElement<K, V> for backward compatibility.
+ *<p>
+ * @author Aaron Smuts
+ */
+public interface ICacheElementSerialized<K, V>
+ extends ICacheElement<K, V>
+{
+ /**
+ * Gets the value attribute of the ICacheElementSerialized object. This is the value the client
+ * cached serialized by some mechanism.
+ *<p>
+ * @return The serialized value
+ */
+ byte[] getSerializedValue();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheEventQueue.java
new file mode 100644
index 0000000..7fec6ed
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheEventQueue.java
@@ -0,0 +1,125 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+
+/**
+ * Interface for a cache event queue. An event queue is used to propagate
+ * ordered cache events to one and only one target listener.
+ */
+public interface ICacheEventQueue<K, V>
+{
+ enum QueueType
+ {
+ /** Does not use a thread pool. */
+ SINGLE,
+
+ /** Uses a thread pool. */
+ POOLED
+ }
+
+ /**
+ * Return the type of event queue we are using, either single or pooled.
+ * <p>
+ * @return the queue type: single or pooled
+ */
+ QueueType getQueueType();
+
+ /**
+ * Adds a feature to the PutEvent attribute of the ICacheEventQueue object
+ * <p>
+ * @param ce
+ * The feature to be added to the PutEvent attribute
+ * @throws IOException
+ */
+ void addPutEvent( ICacheElement<K, V> ce )
+ throws IOException;
+
+ /**
+ * Adds a feature to the RemoveEvent attribute of the ICacheEventQueue
+ * object
+ * <p>
+ * @param key
+ * The feature to be added to the RemoveEvent attribute
+ * @throws IOException
+ */
+ void addRemoveEvent( K key )
+ throws IOException;
+
+ /**
+ * Adds a feature to the RemoveAllEvent attribute of the ICacheEventQueue
+ * object
+ * <p>
+ * @throws IOException
+ */
+ void addRemoveAllEvent()
+ throws IOException;
+
+ /**
+ * Adds a feature to the DisposeEvent attribute of the ICacheEventQueue
+ * object
+ * <p>
+ * @throws IOException
+ */
+ void addDisposeEvent()
+ throws IOException;
+
+ /**
+ * Gets the listenerId attribute of the ICacheEventQueue object
+ *
+ * @return The listenerId value
+ */
+ long getListenerId();
+
+ /** Description of the Method */
+ void destroy();
+
+ /**
+ * A Queue is working unless it has reached its max failure count.
+ * <p>
+ * @return boolean
+ */
+ boolean isWorking();
+
+ /**
+ * Returns the number of elements in the queue. If the queue cannot
+ * determine the size accurately it will return 1.
+ * <p>
+ * @return number of items in the queue.
+ */
+ int size();
+
+ /**
+ * Are there elements in the queue.
+ * <p>
+ * @return true if there are stil elements.
+ */
+ boolean isEmpty();
+
+ /**
+ * Returns the historical and statistical data for an event queue cache.
+ * <p>
+ * @return IStats
+ */
+ IStats getStatistics();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheListener.java
new file mode 100644
index 0000000..2c98b91
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheListener.java
@@ -0,0 +1,86 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+/**
+ * Used to receive a cache event notification.
+ * <p>
+ * Note: objects which implement this interface are local listeners to cache changes, whereas
+ * objects which implement IRmiCacheListener are remote listeners to cache changes.
+ */
+public interface ICacheListener<K, V>
+{
+ /**
+ * Notifies the subscribers for a cache entry update.
+ * <p>
+ * @param item
+ * @throws IOException
+ */
+ void handlePut( ICacheElement<K, V> item )
+ throws IOException;
+
+ /**
+ * Notifies the subscribers for a cache entry removal.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @throws IOException
+ */
+ void handleRemove( String cacheName, K key )
+ throws IOException;
+
+ /**
+ * Notifies the subscribers for a cache remove-all.
+ * <p>
+ * @param cacheName
+ * @throws IOException
+ */
+ void handleRemoveAll( String cacheName )
+ throws IOException;
+
+ /**
+ * Notifies the subscribers for freeing up the named cache.
+ * <p>
+ * @param cacheName
+ * @throws IOException
+ */
+ void handleDispose( String cacheName )
+ throws IOException;
+
+ /**
+ * sets unique identifier of listener home
+ * <p>
+ * @param id The new listenerId value
+ * @throws IOException
+ */
+ void setListenerId( long id )
+ throws IOException;
+
+ /**
+ * Gets the listenerId attribute of the ICacheListener object
+ * <p>
+ * @return The listenerId value
+ * @throws IOException
+ */
+ long getListenerId()
+ throws IOException;
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheObserver.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheObserver.java
new file mode 100644
index 0000000..dfb85ff
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheObserver.java
@@ -0,0 +1,78 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+/**
+ * Used to register interest in receiving cache changes. <br>
+ * <br>
+ * Note: server which implements this interface provides a local cache event
+ * notification service, whereas server which implements IRmiCacheWatch provides
+ * a remote cache event notification service.
+ *
+ */
+public interface ICacheObserver
+{
+ /**
+ * Subscribes to the specified cache.
+ *
+ * @param cacheName
+ * the specified cache.
+ * @param obj
+ * object to notify for cache changes.
+ * @throws IOException
+ */
+ <K, V> void addCacheListener( String cacheName, ICacheListener<K, V> obj )
+ throws IOException;
+
+ //, CacheNotFoundException;
+
+ /**
+ * Subscribes to all caches.
+ *
+ * @param obj
+ * object to notify for all cache changes.
+ * @throws IOException
+ */
+ <K, V> void addCacheListener( ICacheListener<K, V> obj )
+ throws IOException;
+
+ /**
+ * Unsubscribes from the specified cache.
+ * @param cacheName
+ *
+ * @param obj
+ * existing subscriber.
+ * @throws IOException
+ */
+ <K, V> void removeCacheListener( String cacheName, ICacheListener<K, V> obj )
+ throws IOException;
+
+ /**
+ * Unsubscribes from all caches.
+ *
+ * @param obj
+ * existing subscriber.
+ * @throws IOException
+ */
+ <K, V> void removeCacheListener( ICacheListener<K, V> obj )
+ throws IOException;
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheService.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheService.java
new file mode 100644
index 0000000..8900eef
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheService.java
@@ -0,0 +1,117 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.access.exception.ObjectExistsException;
+import org.apache.commons.jcs3.access.exception.ObjectNotFoundException;
+
+/**
+ * Used to retrieve and update the cache.
+ * <p>
+ * Note: server which implements this interface provides a local cache service, whereas server which
+ * implements IRmiCacheService provides a remote cache service.
+ */
+public interface ICacheService<K, V>
+{
+ /**
+ * Puts a cache item to the cache.
+ * <p>
+ * @param item
+ * @throws ObjectExistsException
+ * @throws IOException
+ */
+ void update( ICacheElement<K, V> item )
+ throws ObjectExistsException, IOException;
+
+ /**
+ * Returns a cache bean from the specified cache; or null if the key does not exist.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @return the ICacheElement<K, V> or null if not found
+ * @throws ObjectNotFoundException
+ * @throws IOException
+ */
+ ICacheElement<K, V> get( String cacheName, K key )
+ throws ObjectNotFoundException, IOException;
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * @param cacheName
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ * @throws ObjectNotFoundException
+ * @throws IOException
+ */
+ Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys )
+ throws ObjectNotFoundException, IOException;
+
+ /**
+ * Gets multiple items from the cache matching the pattern.
+ * <p>
+ * @param cacheName
+ * @param pattern
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache matching the pattern.
+ * @throws IOException
+ */
+ Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern )
+ throws IOException;
+
+ /**
+ * Removes the given key from the specified cache.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @throws IOException
+ */
+ void remove( String cacheName, K key )
+ throws IOException;
+
+ /**
+ * Remove all keys from the specified cache.
+ * @param cacheName
+ * @throws IOException
+ */
+ void removeAll( String cacheName )
+ throws IOException;
+
+ /**
+ * Frees the specified cache.
+ * <p>
+ * @param cacheName
+ * @throws IOException
+ */
+ void dispose( String cacheName )
+ throws IOException;
+
+ /**
+ * Frees all caches.
+ * @throws IOException
+ */
+ void release()
+ throws IOException;
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheServiceAdmin.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheServiceAdmin.java
new file mode 100644
index 0000000..5c5a012
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheServiceAdmin.java
@@ -0,0 +1,51 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+/**
+ * Description of the Interface
+ *
+ */
+public interface ICacheServiceAdmin
+{
+
+ /**
+ * Gets the stats attribute of the ICacheServiceAdmin object
+ *
+ * @return The stats value
+ * @throws IOException
+ */
+ String getStats()
+ throws IOException;
+
+ /** Description of the Method
+ * @throws IOException*/
+ void shutdown()
+ throws IOException;
+
+ /** Description of the Method
+ * @param host
+ * @param port
+ * @throws IOException*/
+ void shutdown( String host, int port )
+ throws IOException;
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheServiceNonLocal.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheServiceNonLocal.java
new file mode 100644
index 0000000..82041af
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheServiceNonLocal.java
@@ -0,0 +1,118 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.rmi.Remote;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Used to retrieve and update non local caches, such as the remote and lateral caches. Unlike
+ * ICacheService, the methods here have a requester id. This allows us to avoid propagating events
+ * to ourself.
+ * <p>
+ * TODO consider not extending ICacheService
+ */
+public interface ICacheServiceNonLocal<K, V>
+ extends Remote, ICacheService<K, V>
+{
+ /**
+ * Puts a cache item to the cache.
+ * <p>
+ * @param item
+ * @param requesterId
+ * @throws IOException
+ */
+ void update( ICacheElement<K, V> item, long requesterId )
+ throws IOException;
+
+ /**
+ * Removes the given key from the specified cache.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @throws IOException
+ */
+ void remove( String cacheName, K key, long requesterId )
+ throws IOException;
+
+ /**
+ * Remove all keys from the specified cache.
+ * <p>
+ * @param cacheName
+ * @param requesterId
+ * @throws IOException
+ */
+ void removeAll( String cacheName, long requesterId )
+ throws IOException;
+
+ /**
+ * Returns a cache bean from the specified cache; or null if the key does not exist.
+ * <p>
+ * Adding the requester id, allows the cache to determine the source of the get.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @return ICacheElement
+ * @throws IOException
+ */
+ ICacheElement<K, V> get( String cacheName, K key, long requesterId )
+ throws IOException;
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * @param cacheName
+ * @param keys
+ * @param requesterId
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ * @throws IOException
+ */
+ Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys, long requesterId )
+ throws IOException;
+
+ /**
+ * Gets multiple items from the cache matching the pattern.
+ * <p>
+ * @param cacheName
+ * @param pattern
+ * @param requesterId
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache matching the pattern.
+ * @throws IOException
+ */
+ Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern, long requesterId )
+ throws IOException;
+
+ /**
+ * Get a set of the keys for all elements in the cache.
+ * <p>
+ * @param cacheName the name of the cache
+ * @return a set of the key type
+ * TODO This should probably be done in chunks with a range passed in. This
+ * will be a problem if someone puts a 1,000,000 or so items in a
+ * region.
+ */
+ Set<K> getKeySet( String cacheName ) throws IOException;
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheType.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheType.java
new file mode 100644
index 0000000..1012ab8
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICacheType.java
@@ -0,0 +1,49 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+/**
+ * Interface implemented by a specific cache.
+ *
+ */
+public interface ICacheType
+{
+ enum CacheType {
+ /** Composite/ memory cache type, central hub. */
+ CACHE_HUB,
+
+ /** Disk cache type. */
+ DISK_CACHE,
+
+ /** Lateral cache type. */
+ LATERAL_CACHE,
+
+ /** Remote cache type. */
+ REMOTE_CACHE
+ }
+
+ /**
+ * Returns the cache type.
+ * <p>
+ * @return The cacheType value
+ */
+ CacheType getCacheType();
+
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICompositeCacheAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICompositeCacheAttributes.java
new file mode 100644
index 0000000..57451fa
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICompositeCacheAttributes.java
@@ -0,0 +1,244 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+
+/**
+ * This defines the minimal behavior for the Cache Configuration settings.
+ */
+public interface ICompositeCacheAttributes
+ extends Serializable, Cloneable
+{
+ enum DiskUsagePattern
+ {
+ /** Items will only go to disk when the memory limit is reached. This is the default. */
+ SWAP,
+
+ /**
+ * Items will go to disk on a normal put. If The disk usage pattern is UPDATE, the swap will be
+ * disabled.
+ */
+ UPDATE
+ }
+
+ /**
+ * SetMaxObjects is used to set the attribute to determine the maximum
+ * number of objects allowed in the memory cache. If the max number of
+ * objects or the cache size is set, the default for the one not set is
+ * ignored. If both are set, both are used to determine the capacity of the
+ * cache, i.e., object will be removed from the cache if either limit is
+ * reached. TODO: move to MemoryCache config file.
+ * <p>
+ * @param size
+ * The new maxObjects value
+ */
+ void setMaxObjects( int size );
+
+ /**
+ * Gets the maxObjects attribute of the ICompositeCacheAttributes object
+ * <p>
+ * @return The maxObjects value
+ */
+ int getMaxObjects();
+
+ /**
+ * Sets the useDisk attribute of the ICompositeCacheAttributes object
+ * <p>
+ * @param useDisk
+ * The new useDisk value
+ */
+ void setUseDisk( boolean useDisk );
+
+ /**
+ * Gets the useDisk attribute of the ICompositeCacheAttributes object
+ * <p>
+ * @return The useDisk value
+ */
+ boolean isUseDisk();
+
+ /**
+ * set whether the cache should use a lateral cache
+ * <p>
+ * @param d
+ * The new useLateral value
+ */
+ void setUseLateral( boolean d );
+
+ /**
+ * Gets the useLateral attribute of the ICompositeCacheAttributes object
+ * <p>
+ * @return The useLateral value
+ */
+ boolean isUseLateral();
+
+ /**
+ * Sets whether the cache is remote enabled
+ * <p>
+ * @param isRemote
+ * The new useRemote value
+ */
+ void setUseRemote( boolean isRemote );
+
+ /**
+ * returns whether the cache is remote enabled
+ * <p>
+ * @return The useRemote value
+ */
+ boolean isUseRemote();
+
+ /**
+ * Sets the name of the cache, referenced by the appropriate manager.
+ * <p>
+ * @param s
+ * The new cacheName value
+ */
+ void setCacheName( String s );
+
+ /**
+ * Gets the cacheName attribute of the ICompositeCacheAttributes object
+ * <p>
+ * @return The cacheName value
+ */
+ String getCacheName();
+
+ /**
+ * Sets the name of the MemoryCache, referenced by the appropriate manager.
+ * TODO: create a separate memory cache attribute class.
+ * <p>
+ * @param s
+ * The new memoryCacheName value
+ */
+ void setMemoryCacheName( String s );
+
+ /**
+ * Gets the memoryCacheName attribute of the ICompositeCacheAttributes
+ * object
+ * <p>
+ * @return The memoryCacheName value
+ */
+ String getMemoryCacheName();
+
+ /**
+ * Whether the memory cache should perform background memory shrinkage.
+ * <p>
+ * @param useShrinker
+ * The new UseMemoryShrinker value
+ */
+ void setUseMemoryShrinker( boolean useShrinker );
+
+ /**
+ * Whether the memory cache should perform background memory shrinkage.
+ * <p>
+ * @return The UseMemoryShrinker value
+ */
+ boolean isUseMemoryShrinker();
+
+ /**
+ * If UseMemoryShrinker is true the memory cache should auto-expire elements
+ * to reclaim space.
+ * <p>
+ * @param seconds
+ * The new MaxMemoryIdleTimeSeconds value
+ */
+ void setMaxMemoryIdleTimeSeconds( long seconds );
+
+ /**
+ * If UseMemoryShrinker is true the memory cache should auto-expire elements
+ * to reclaim space.
+ * <p>
+ * @return The MaxMemoryIdleTimeSeconds value
+ */
+ long getMaxMemoryIdleTimeSeconds();
+
+ /**
+ * If UseMemoryShrinker is true the memory cache should auto-expire elements
+ * to reclaim space. This sets the shrinker interval.
+ * <p>
+ * @param seconds
+ * The new ShrinkerIntervalSeconds value
+ */
+ void setShrinkerIntervalSeconds( long seconds );
+
+ /**
+ * If UseMemoryShrinker is true the memory cache should auto-expire elements
+ * to reclaim space. This gets the shrinker interval.
+ * <p>
+ * @return The ShrinkerIntervalSeconds value
+ */
+ long getShrinkerIntervalSeconds();
+
+ /**
+ * If UseMemoryShrinker is true the memory cache should auto-expire elements
+ * to reclaim space. This sets the maximum number of items to spool per run.
+ * <p>
+ * @param maxSpoolPerRun
+ * The new maxSpoolPerRun value
+ */
+ void setMaxSpoolPerRun( int maxSpoolPerRun );
+
+ /**
+ * If UseMemoryShrinker is true the memory cache should auto-expire elements
+ * to reclaim space. This gets the maximum number of items to spool per run.
+ * <p>
+ * @return The maxSpoolPerRun value
+ */
+ int getMaxSpoolPerRun();
+
+ /**
+ * By default this is SWAP_ONLY.
+ * <p>
+ * @param diskUsagePattern The diskUsagePattern to set.
+ */
+ void setDiskUsagePattern( DiskUsagePattern diskUsagePattern );
+
+ /**
+ * Translates the name to the disk usage pattern short value.
+ * <p>
+ * The allowed values are SWAP and UPDATE.
+ * <p>
+ * @param diskUsagePatternName The diskUsagePattern to set.
+ */
+ void setDiskUsagePatternName( String diskUsagePatternName );
+
+ /**
+ * @return Returns the diskUsagePattern.
+ */
+ DiskUsagePattern getDiskUsagePattern();
+
+ /**
+ * Number to send to disk at at time when memory is full.
+ * <p>
+ * @return int
+ */
+ int getSpoolChunkSize();
+
+ /**
+ * Number to send to disk at a time.
+ * <p>
+ * @param spoolChunkSize
+ */
+ void setSpoolChunkSize( int spoolChunkSize );
+
+ /**
+ * Clone object
+ */
+ ICompositeCacheAttributes clone();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICompositeCacheManager.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICompositeCacheManager.java
new file mode 100644
index 0000000..d24d7a9
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/ICompositeCacheManager.java
@@ -0,0 +1,64 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+import java.util.Properties;
+
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCache;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+
+/**
+ * I need the interface so I can plug in mock managers for testing.
+ *
+ * @author Aaron Smuts
+ */
+public interface ICompositeCacheManager extends IShutdownObservable
+{
+ /**
+ * Gets the cache attribute of the CacheHub object
+ *
+ * @param cacheName
+ * @return CompositeCache
+ */
+ <K, V> CompositeCache<K, V> getCache( String cacheName );
+
+ /**
+ * Gets the auxiliary cache attribute of the CacheHub object
+ *
+ * @param auxName
+ * @param cacheName
+ * @return AuxiliaryCache
+ */
+ <K, V> AuxiliaryCache<K, V> getAuxiliaryCache( String auxName, String cacheName );
+
+ /**
+ * This is exposed so other manager can get access to the props.
+ * <p>
+ * @return the configurationProperties
+ */
+ Properties getConfigurationProperties();
+
+ /**
+ * Gets stats for debugging.
+ * <p>
+ * @return String
+ */
+ String getStats();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IElementAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IElementAttributes.java
new file mode 100644
index 0000000..718cc00
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IElementAttributes.java
@@ -0,0 +1,204 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.jcs3.engine.control.event.behavior.IElementEventHandler;
+
+/**
+ * Interface for cache element attributes classes. Every item is the cache is associated with an
+ * element attributes object. It is used to track the life of the object as well as to restrict its
+ * behavior. By default, elements get a clone of the region's attributes.
+ */
+public interface IElementAttributes extends Serializable, Cloneable
+{
+ /**
+ * Sets the maxLife attribute of the IAttributes object.
+ * <p>
+ * @param mls The new MaxLifeSeconds value
+ */
+ void setMaxLife(long mls);
+
+ /**
+ * Sets the maxLife attribute of the IAttributes object. How many seconds it can live after
+ * creation.
+ * <p>
+ * If this is exceeded the element will not be returned, instead it will be removed. It will be
+ * removed on retrieval, or removed actively if the memory shrinker is turned on.
+ * @return The MaxLifeSeconds value
+ */
+ long getMaxLife();
+
+ /**
+ * Sets the idleTime attribute of the IAttributes object. This is the maximum time the item can
+ * be idle in the cache, that is not accessed.
+ * <p>
+ * If this is exceeded the element will not be returned, instead it will be removed. It will be
+ * removed on retrieval, or removed actively if the memory shrinker is turned on.
+ * @param idle The new idleTime value
+ */
+ void setIdleTime( long idle );
+
+ /**
+ * Size in bytes. This is not used except in the admin pages. It will be 0 by default
+ * and is only updated when the element is serialized.
+ * <p>
+ * @param size The new size value
+ */
+ void setSize( int size );
+
+ /**
+ * Gets the size attribute of the IAttributes object
+ * <p>
+ * @return The size value
+ */
+ int getSize();
+
+ /**
+ * Gets the createTime attribute of the IAttributes object.
+ * <p>
+ * This should be the current time in milliseconds returned by the sysutem call when the element
+ * is put in the cache.
+ * <p>
+ * Putting an item in the cache overrides any existing items.
+ * @return The createTime value
+ */
+ long getCreateTime();
+
+ /**
+ * Gets the LastAccess attribute of the IAttributes object.
+ * <p>
+ * @return The LastAccess value.
+ */
+ long getLastAccessTime();
+
+ /**
+ * Sets the LastAccessTime as now of the IElementAttributes object
+ */
+ void setLastAccessTimeNow();
+
+ /**
+ * Gets the idleTime attribute of the IAttributes object
+ * @return The idleTime value
+ */
+ long getIdleTime();
+
+ /**
+ * Gets the time left to live of the IAttributes object.
+ * <p>
+ * This is the (max life + create time) - current time.
+ * @return The TimeToLiveSeconds value
+ */
+ long getTimeToLiveSeconds();
+
+ /**
+ * Can this item be spooled to disk
+ * <p>
+ * By default this is true.
+ * @return The spoolable value
+ */
+ boolean getIsSpool();
+
+ /**
+ * Sets the isSpool attribute of the IElementAttributes object
+ * <p>
+ * By default this is true.
+ * @param val The new isSpool value
+ */
+ void setIsSpool( boolean val );
+
+ /**
+ * Is this item laterally distributable. Can it be sent to auxiliaries of type lateral.
+ * <p>
+ * By default this is true.
+ * @return The isLateral value
+ */
+ boolean getIsLateral();
+
+ /**
+ * Sets the isLateral attribute of the IElementAttributes object
+ * <p>
+ * By default this is true.
+ * @param val The new isLateral value
+ */
+ void setIsLateral( boolean val );
+
+ /**
+ * Can this item be sent to the remote cache.
+ * <p>
+ * By default this is true.
+ * @return The isRemote value
+ */
+ boolean getIsRemote();
+
+ /**
+ * Sets the isRemote attribute of the IElementAttributes object.
+ * <p>
+ * By default this is true.
+ * @param val The new isRemote value
+ */
+ void setIsRemote( boolean val );
+
+ /**
+ * This turns off expiration if it is true.
+ * @return The IsEternal value
+ */
+ boolean getIsEternal();
+
+ /**
+ * Sets the isEternal attribute of the IElementAttributes object
+ * @param val The new isEternal value
+ */
+ void setIsEternal( boolean val );
+
+ /**
+ * Adds a ElementEventHandler. Handler's can be registered for multiple events. A registered
+ * handler will be called at every recognized event.
+ * @param eventHandler The feature to be added to the ElementEventHandler
+ */
+ void addElementEventHandler( IElementEventHandler eventHandler );
+
+ /**
+ * Gets the elementEventHandlers.
+ * <p>
+ * Event handlers are transient. The only events defined are in memory events. All handlers are
+ * lost if the item goes to disk.
+ * @return The elementEventHandlers value, null if there are none
+ */
+ ArrayList<IElementEventHandler> getElementEventHandlers();
+
+ /**
+ * Sets the eventHandlers of the IElementAttributes object
+ * @param eventHandlers value
+ */
+ void addElementEventHandlers( List<IElementEventHandler> eventHandlers );
+
+ long getTimeFactorForMilliseconds();
+
+ void setTimeFactorForMilliseconds(long factor);
+
+ /**
+ * Clone object
+ */
+ IElementAttributes clone();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IElementSerializer.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IElementSerializer.java
new file mode 100644
index 0000000..ca91053
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IElementSerializer.java
@@ -0,0 +1,51 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+/**
+ * Defines the behavior for cache element serializers. This layer of abstraction allows us to plug
+ * in different serialization mechanisms, such as a compressing standard serializer.
+ * <p>
+ * @author Aaron Smuts
+ */
+public interface IElementSerializer
+{
+ /**
+ * Turns an object into a byte array.
+ * @param obj
+ * @return byte[]
+ * @throws IOException
+ */
+ <T> byte[] serialize( T obj )
+ throws IOException;
+
+ /**
+ * Turns a byte array into an object.
+ * @param bytes data bytes
+ * @param loader class loader to use
+ * @return Object
+ * @throws IOException
+ * @throws ClassNotFoundException thrown if we don't know the object.
+ */
+ <T> T deSerialize( byte[] bytes, ClassLoader loader )
+ throws IOException, ClassNotFoundException;
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IProvideScheduler.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IProvideScheduler.java
new file mode 100644
index 0000000..dc9907d
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IProvideScheduler.java
@@ -0,0 +1,38 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+import java.util.concurrent.ScheduledExecutorService;
+
+
+/**
+ * Marker interface for providers of the central ScheduledExecutorService
+ * <p>
+ * @author Thomas Vandahl
+ *
+ */
+public interface IProvideScheduler
+{
+ /**
+ * Get an instance of a central ScheduledExecutorService
+ * @return the central scheduler
+ */
+ ScheduledExecutorService getScheduledExecutorService();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IRequireScheduler.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IRequireScheduler.java
new file mode 100644
index 0000000..32a3906
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IRequireScheduler.java
@@ -0,0 +1,39 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+import java.util.concurrent.ScheduledExecutorService;
+
+
+/**
+ * Marker interface to allow the injection of a central ScheduledExecutorService
+ * for all modules requiring scheduled background operations.
+ * <p>
+ * @author Thomas Vandahl
+ *
+ */
+public interface IRequireScheduler
+{
+ /**
+ * Inject an instance of a central ScheduledExecutorService
+ * @param scheduledExecutor
+ */
+ void setScheduledExecutorService( ScheduledExecutorService scheduledExecutor );
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IShutdownObservable.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IShutdownObservable.java
new file mode 100644
index 0000000..a2d28dc
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IShutdownObservable.java
@@ -0,0 +1,55 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+/**
+ * ShutdownObservers can observe ShutdownObservable objects.
+ * The CacheManager is the primary observable that this is intended for.
+ * <p>
+ * Most shutdown operations will occur outside this framework for now. The initial
+ * goal is to allow background threads that are not reachable through any reference
+ * that the cache manager maintains to be killed on shutdown.
+ * <p>
+ * Perhaps the composite cache itself should be the observable object.
+ * It doesn't make much of a difference. There are some problems with
+ * region by region shutdown. Some auxiliaries are local. They will
+ * need to track when every region has shutdown before doing things like
+ * closing the socket with a lateral.
+ * <p>
+ * @author Aaron Smuts
+ *
+ */
+public interface IShutdownObservable
+{
+
+ /**
+ * Registers an observer with the observable object.
+ * @param observer
+ */
+ void registerShutdownObserver( IShutdownObserver observer );
+
+ /**
+ * Deregisters the observer with the observable.
+ *
+ * @param observer
+ */
+ void deregisterShutdownObserver( IShutdownObserver observer );
+
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IShutdownObserver.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IShutdownObserver.java
new file mode 100644
index 0000000..eef30c6
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IShutdownObserver.java
@@ -0,0 +1,41 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+/**
+ * This interface is required of all shutdown observers. These observers
+ * can observer ShutdownObservable objects. The CacheManager is the primary
+ * observable that this is intended for.
+ * <p>
+ * Most shutdown operations will occur outside this framework for now. The initial
+ * goal is to allow background threads that are not reachable through any reference
+ * that the cache manager maintains to be killed on shutdown.
+ *
+ * @author Aaron Smuts
+ *
+ */
+public interface IShutdownObserver
+{
+ /**
+ * Tells the observer that the observable has received a shutdown command.
+ *
+ */
+ void shutdown();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IZombie.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IZombie.java
new file mode 100644
index 0000000..bd99756
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/IZombie.java
@@ -0,0 +1,30 @@
+package org.apache.commons.jcs3.engine.behavior;
+
+/*
+ * 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.
+ */
+
+/**
+ * Interface to mark an object as zombie for error recovery purposes.
+ *
+ */
+public interface IZombie
+{
+ // Zombies have no inner life.
+ // No qaulia found.
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/package.html b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/package.html
similarity index 100%
rename from commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/behavior/package.html
rename to commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/behavior/package.html
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/CompositeCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/CompositeCache.java
new file mode 100644
index 0000000..75e51a1
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/CompositeCache.java
@@ -0,0 +1,1693 @@
+package org.apache.commons.jcs3.engine.control;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.access.exception.ObjectNotFoundException;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCache;
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.behavior.ICache;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.IRequireScheduler;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes.DiskUsagePattern;
+import org.apache.commons.jcs3.engine.control.event.ElementEvent;
+import org.apache.commons.jcs3.engine.control.event.behavior.ElementEventType;
+import org.apache.commons.jcs3.engine.control.event.behavior.IElementEvent;
+import org.apache.commons.jcs3.engine.control.event.behavior.IElementEventHandler;
+import org.apache.commons.jcs3.engine.control.event.behavior.IElementEventQueue;
+import org.apache.commons.jcs3.engine.control.group.GroupId;
+import org.apache.commons.jcs3.engine.match.KeyMatcherPatternImpl;
+import org.apache.commons.jcs3.engine.match.behavior.IKeyMatcher;
+import org.apache.commons.jcs3.engine.memory.behavior.IMemoryCache;
+import org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache;
+import org.apache.commons.jcs3.engine.memory.shrinking.ShrinkerThread;
+import org.apache.commons.jcs3.engine.stats.CacheStats;
+import org.apache.commons.jcs3.engine.stats.StatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.ICacheStats;
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This is the primary hub for a single cache/region. It controls the flow of items through the
+ * cache. The auxiliary and memory caches are plugged in here.
+ * <p>
+ * This is the core of a JCS region. Hence, this simple class is the core of JCS.
+ */
+public class CompositeCache<K, V>
+ implements ICache<K, V>, IRequireScheduler
+{
+ /** log instance */
+ private static final Log log = LogManager.getLog(CompositeCache.class);
+
+ /**
+ * EventQueue for handling element events. Lazy initialized. One for each region. To be more efficient, the manager
+ * should pass a shared queue in.
+ */
+ private IElementEventQueue elementEventQ;
+
+ /** Auxiliary caches. */
+ @SuppressWarnings("unchecked") // OK because this is an empty array
+ private AuxiliaryCache<K, V>[] auxCaches = new AuxiliaryCache[0];
+
+ /** is this alive? */
+ private final AtomicBoolean alive;
+
+ /** Region Elemental Attributes, default. */
+ private IElementAttributes attr;
+
+ /** Cache Attributes, for hub and memory auxiliary. */
+ private ICompositeCacheAttributes cacheAttr;
+
+ /** How many times update was called. */
+ private final AtomicLong updateCount;
+
+ /** How many times remove was called. */
+ private final AtomicLong removeCount;
+
+ /** Memory cache hit count */
+ private final AtomicLong hitCountRam;
+
+ /** Auxiliary cache hit count (number of times found in ANY auxiliary) */
+ private final AtomicLong hitCountAux;
+
+ /** Count of misses where element was not found. */
+ private final AtomicLong missCountNotFound;
+
+ /** Count of misses where element was expired. */
+ private final AtomicLong missCountExpired;
+
+ /** Cache manager. */
+ private CompositeCacheManager cacheManager = null;
+
+ /**
+ * The cache hub can only have one memory cache. This could be made more flexible in the future,
+ * but they are tied closely together. More than one doesn't make much sense.
+ */
+ private IMemoryCache<K, V> memCache;
+
+ /** Key matcher used by the getMatching API */
+ private IKeyMatcher<K> keyMatcher = new KeyMatcherPatternImpl<>();
+
+ private ScheduledFuture<?> future;
+
+ /**
+ * Constructor for the Cache object
+ * <p>
+ * @param cattr The cache attribute
+ * @param attr The default element attributes
+ */
+ public CompositeCache(ICompositeCacheAttributes cattr, IElementAttributes attr)
+ {
+ this.attr = attr;
+ this.cacheAttr = cattr;
+ this.alive = new AtomicBoolean(true);
+ this.updateCount = new AtomicLong(0);
+ this.removeCount = new AtomicLong(0);
+ this.hitCountRam = new AtomicLong(0);
+ this.hitCountAux = new AtomicLong(0);
+ this.missCountNotFound = new AtomicLong(0);
+ this.missCountExpired = new AtomicLong(0);
+
+ createMemoryCache(cattr);
+
+ log.info("Constructed cache with name [{0}] and cache attributes {1}",
+ cacheAttr.getCacheName(), cattr);
+ }
+
+ /**
+ * Injector for Element event queue
+ *
+ * @param queue
+ */
+ public void setElementEventQueue(IElementEventQueue queue)
+ {
+ this.elementEventQ = queue;
+ }
+
+ /**
+ * Injector for cache manager
+ *
+ * @param manager
+ */
+ public void setCompositeCacheManager(CompositeCacheManager manager)
+ {
+ this.cacheManager = manager;
+ }
+
+ /**
+ * @see org.apache.commons.jcs3.engine.behavior.IRequireScheduler#setScheduledExecutorService(java.util.concurrent.ScheduledExecutorService)
+ */
+ @Override
+ public void setScheduledExecutorService(ScheduledExecutorService scheduledExecutor)
+ {
+ if (cacheAttr.isUseMemoryShrinker())
+ {
+ future = scheduledExecutor.scheduleAtFixedRate(
+ new ShrinkerThread<>(this), 0, cacheAttr.getShrinkerIntervalSeconds(),
+ TimeUnit.SECONDS);
+ }
+ }
+
+ /**
+ * This sets the list of auxiliary caches for this region.
+ * <p>
+ * @param auxCaches
+ */
+ public void setAuxCaches(AuxiliaryCache<K, V>[] auxCaches)
+ {
+ this.auxCaches = auxCaches;
+ }
+
+ /**
+ * Get the list of auxiliary caches for this region.
+ * <p>
+ * @return an array of auxiliary caches, may be empty, never null
+ */
+ public AuxiliaryCache<K, V>[] getAuxCaches()
+ {
+ return this.auxCaches;
+ }
+
+ /**
+ * Standard update method.
+ * <p>
+ * @param ce
+ * @throws IOException
+ */
+ @Override
+ public void update(ICacheElement<K, V> ce)
+ throws IOException
+ {
+ update(ce, false);
+ }
+
+ /**
+ * Standard update method.
+ * <p>
+ * @param ce
+ * @throws IOException
+ */
+ public void localUpdate(ICacheElement<K, V> ce)
+ throws IOException
+ {
+ update(ce, true);
+ }
+
+ /**
+ * Put an item into the cache. If it is localOnly, then do no notify remote or lateral
+ * auxiliaries.
+ * <p>
+ * @param cacheElement the ICacheElement<K, V>
+ * @param localOnly Whether the operation should be restricted to local auxiliaries.
+ * @throws IOException
+ */
+ protected void update(ICacheElement<K, V> cacheElement, boolean localOnly)
+ throws IOException
+ {
+
+ if (cacheElement.getKey() instanceof String
+ && cacheElement.getKey().toString().endsWith(NAME_COMPONENT_DELIMITER))
+ {
+ throw new IllegalArgumentException("key must not end with " + NAME_COMPONENT_DELIMITER
+ + " for a put operation");
+ }
+ else if (cacheElement.getKey() instanceof GroupId)
+ {
+ throw new IllegalArgumentException("key cannot be a GroupId " + " for a put operation");
+ }
+
+ log.debug("Updating memory cache {0}", () -> cacheElement.getKey());
+
+ updateCount.incrementAndGet();
+ memCache.update(cacheElement);
+ updateAuxiliaries(cacheElement, localOnly);
+
+ cacheElement.getElementAttributes().setLastAccessTimeNow();
+ }
+
+ /**
+ * This method is responsible for updating the auxiliaries if they are present. If it is local
+ * only, any lateral and remote auxiliaries will not be updated.
+ * <p>
+ * Before updating an auxiliary it checks to see if the element attributes permit the operation.
+ * <p>
+ * Disk auxiliaries are only updated if the disk cache is not merely used as a swap. If the disk
+ * cache is merely a swap, then items will only go to disk when they overflow from memory.
+ * <p>
+ * This is called by update(cacheElement, localOnly) after it updates the memory cache.
+ * <p>
+ * This is protected to make it testable.
+ * <p>
+ * @param cacheElement
+ * @param localOnly
+ * @throws IOException
+ */
+ protected void updateAuxiliaries(ICacheElement<K, V> cacheElement, boolean localOnly)
+ throws IOException
+ {
+ // UPDATE AUXILLIARY CACHES
+ // There are 3 types of auxiliary caches: remote, lateral, and disk
+ // more can be added if future auxiliary caches don't fit the model
+ // You could run a database cache as either a remote or a local disk.
+ // The types would describe the purpose.
+ if (auxCaches.length > 0)
+ {
+ log.debug("Updating auxiliary caches");
+ }
+ else
+ {
+ log.debug("No auxiliary cache to update");
+ }
+
+ for (ICache<K, V> aux : auxCaches)
+ {
+ if (aux == null)
+ {
+ continue;
+ }
+
+ log.debug("Auxiliary cache type: {0}", aux.getCacheType());
+
+ switch (aux.getCacheType())
+ {
+ // SEND TO REMOTE STORE
+ case REMOTE_CACHE:
+ log.debug("ce.getElementAttributes().getIsRemote() = {0}",
+ () -> cacheElement.getElementAttributes().getIsRemote());
+
+ if (cacheElement.getElementAttributes().getIsRemote() && !localOnly)
+ {
+ try
+ {
+ // need to make sure the group cache understands that
+ // the key is a group attribute on update
+ aux.update(cacheElement);
+ log.debug("Updated remote store for {0} {1}",
+ cacheElement.getKey(), cacheElement);
+ }
+ catch (IOException ex)
+ {
+ log.error("Failure in updateExclude", ex);
+ }
+ }
+ break;
+
+ // SEND LATERALLY
+ case LATERAL_CACHE:
+ // lateral can't do the checking since it is dependent on the
+ // cache region restrictions
+ log.debug("lateralcache in aux list: cattr {0}", () -> cacheAttr.isUseLateral());
+ if (cacheAttr.isUseLateral() && cacheElement.getElementAttributes().getIsLateral() && !localOnly)
+ {
+ // DISTRIBUTE LATERALLY
+ // Currently always multicast even if the value is
+ // unchanged, to cause the cache item to move to the front.
+ aux.update(cacheElement);
+ log.debug("updated lateral cache for {0}", () -> cacheElement.getKey());
+ }
+ break;
+
+ // update disk if the usage pattern permits
+ case DISK_CACHE:
+ log.debug("diskcache in aux list: cattr {0}", () -> cacheAttr.isUseDisk());
+ if (cacheAttr.isUseDisk()
+ && cacheAttr.getDiskUsagePattern() == DiskUsagePattern.UPDATE
+ && cacheElement.getElementAttributes().getIsSpool())
+ {
+ aux.update(cacheElement);
+ log.debug("updated disk cache for {0}", () -> cacheElement.getKey());
+ }
+ break;
+
+ default: // CACHE_HUB
+ break;
+ }
+ }
+ }
+
+ /**
+ * Writes the specified element to any disk auxiliaries. Might want to rename this "overflow" in
+ * case the hub wants to do something else.
+ * <p>
+ * If JCS is not configured to use the disk as a swap, that is if the the
+ * CompositeCacheAttribute diskUsagePattern is not SWAP_ONLY, then the item will not be spooled.
+ * <p>
+ * @param ce The CacheElement
+ */
+ public void spoolToDisk(ICacheElement<K, V> ce)
+ {
+ // if the item is not spoolable, return
+ if (!ce.getElementAttributes().getIsSpool())
+ {
+ // there is an event defined for this.
+ handleElementEvent(ce, ElementEventType.SPOOLED_NOT_ALLOWED);
+ return;
+ }
+
+ boolean diskAvailable = false;
+
+ // SPOOL TO DISK.
+ for (ICache<K, V> aux : auxCaches)
+ {
+ if (aux != null && aux.getCacheType() == CacheType.DISK_CACHE)
+ {
+ diskAvailable = true;
+
+ if (cacheAttr.getDiskUsagePattern() == DiskUsagePattern.SWAP)
+ {
+ // write the last items to disk.2
+ try
+ {
+ handleElementEvent(ce, ElementEventType.SPOOLED_DISK_AVAILABLE);
+ aux.update(ce);
+ }
+ catch (IOException ex)
+ {
+ // impossible case.
+ log.error("Problem spooling item to disk cache.", ex);
+ throw new IllegalStateException(ex.getMessage());
+ }
+
+ log.debug("spoolToDisk done for: {0} on disk cache[{1}]",
+ () -> ce.getKey(), () -> aux.getCacheName());
+ }
+ else
+ {
+ log.debug("DiskCache available, but JCS is not configured "
+ + "to use the DiskCache as a swap.");
+ }
+ }
+ }
+
+ if (!diskAvailable)
+ {
+ handleElementEvent(ce, ElementEventType.SPOOLED_DISK_NOT_AVAILABLE);
+ }
+ }
+
+ /**
+ * Gets an item from the cache.
+ * <p>
+ * @param key
+ * @return element from the cache, or null if not present
+ * @see org.apache.commons.jcs3.engine.behavior.ICache#get(Object)
+ */
+ @Override
+ public ICacheElement<K, V> get(K key)
+ {
+ return get(key, false);
+ }
+
+ /**
+ * Do not try to go remote or laterally for this get.
+ * <p>
+ * @param key
+ * @return ICacheElement
+ */
+ public ICacheElement<K, V> localGet(K key)
+ {
+ return get(key, true);
+ }
+
+ /**
+ * Look in memory, then disk, remote, or laterally for this item. The order is dependent on the
+ * order in the cache.ccf file.
+ * <p>
+ * Do not try to go remote or laterally for this get if it is localOnly. Otherwise try to go
+ * remote or lateral if such an auxiliary is configured for this region.
+ * <p>
+ * @param key
+ * @param localOnly
+ * @return ICacheElement
+ */
+ protected ICacheElement<K, V> get(K key, boolean localOnly)
+ {
+ ICacheElement<K, V> element = null;
+
+ boolean found = false;
+
+ log.debug("get: key = {0}, localOnly = {1}", key, localOnly);
+
+ try
+ {
+ // First look in memory cache
+ element = memCache.get(key);
+
+ if (element != null)
+ {
+ // Found in memory cache
+ if (isExpired(element))
+ {
+ log.debug("{0} - Memory cache hit, but element expired",
+ () -> cacheAttr.getCacheName());
+
+ doExpires(element);
+ element = null;
+ }
+ else
+ {
+ log.debug("{0} - Memory cache hit", () -> cacheAttr.getCacheName());
+
+ // Update counters
+ hitCountRam.incrementAndGet();
+ }
+
+ found = true;
+ }
+ else
+ {
+ // Item not found in memory. If local invocation look in aux
+ // caches, even if not local look in disk auxiliaries
+ for (AuxiliaryCache<K, V> aux : auxCaches)
+ {
+ if (aux != null)
+ {
+ CacheType cacheType = aux.getCacheType();
+
+ if (!localOnly || cacheType == CacheType.DISK_CACHE)
+ {
+ log.debug("Attempting to get from aux [{0}] which is of type: {1}",
+ () -> aux.getCacheName(), () -> cacheType);
+
+ try
+ {
+ element = aux.get(key);
+ }
+ catch (IOException e)
+ {
+ log.error("Error getting from aux", e);
+ }
+ }
+
+ log.debug("Got CacheElement: {0}", element);
+
+ // Item found in one of the auxiliary caches.
+ if (element != null)
+ {
+ if (isExpired(element))
+ {
+ log.debug("{0} - Aux cache[{1}] hit, but element expired.",
+ () -> cacheAttr.getCacheName(), () -> aux.getCacheName());
+
+ // This will tell the remotes to remove the item
+ // based on the element's expiration policy. The elements attributes
+ // associated with the item when it created govern its behavior
+ // everywhere.
+ doExpires(element);
+ element = null;
+ }
+ else
+ {
+ log.debug("{0} - Aux cache[{1}] hit.",
+ () -> cacheAttr.getCacheName(), () -> aux.getCacheName());
+
+ // Update counters
+ hitCountAux.incrementAndGet();
+ copyAuxiliaryRetrievedItemToMemory(element);
+ }
+
+ found = true;
+
+ break;
+ }
+ }
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ log.error("Problem encountered getting element.", e);
+ }
+
+ if (!found)
+ {
+ missCountNotFound.incrementAndGet();
+
+ log.debug("{0} - Miss", () -> cacheAttr.getCacheName());
+ }
+
+ if (element != null)
+ {
+ element.getElementAttributes().setLastAccessTimeNow();
+ }
+
+ return element;
+ }
+
+ protected void doExpires(ICacheElement<K, V> element)
+ {
+ missCountExpired.incrementAndGet();
+ remove(element.getKey());
+ }
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
+ {
+ return getMultiple(keys, false);
+ }
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys. Do not try to go remote or
+ * laterally for this data.
+ * <p>
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ */
+ public Map<K, ICacheElement<K, V>> localGetMultiple(Set<K> keys)
+ {
+ return getMultiple(keys, true);
+ }
+
+ /**
+ * Look in memory, then disk, remote, or laterally for these items. The order is dependent on
+ * the order in the cache.ccf file. Keep looking in each cache location until either the element
+ * is found, or the method runs out of places to look.
+ * <p>
+ * Do not try to go remote or laterally for this get if it is localOnly. Otherwise try to go
+ * remote or lateral if such an auxiliary is configured for this region.
+ * <p>
+ * @param keys
+ * @param localOnly
+ * @return ICacheElement
+ */
+ protected Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys, boolean localOnly)
+ {
+ Map<K, ICacheElement<K, V>> elements = new HashMap<>();
+
+ log.debug("get: key = {0}, localOnly = {1}", keys, localOnly);
+
+ try
+ {
+ // First look in memory cache
+ elements.putAll(getMultipleFromMemory(keys));
+
+ // If fewer than all items were found in memory, then keep looking.
+ if (elements.size() != keys.size())
+ {
+ Set<K> remainingKeys = pruneKeysFound(keys, elements);
+ elements.putAll(getMultipleFromAuxiliaryCaches(remainingKeys, localOnly));
+ }
+ }
+ catch (IOException e)
+ {
+ log.error("Problem encountered getting elements.", e);
+ }
+
+ // if we didn't find all the elements, increment the miss count by the number of elements not found
+ if (elements.size() != keys.size())
+ {
+ missCountNotFound.addAndGet(keys.size() - elements.size());
+
+ log.debug("{0} - {1} Misses", () -> cacheAttr.getCacheName(),
+ () -> keys.size() - elements.size());
+ }
+
+ return elements;
+ }
+
+ /**
+ * Gets items for the keys in the set. Returns a map: key -> result.
+ * <p>
+ * @param keys
+ * @return the elements found in the memory cache
+ * @throws IOException
+ */
+ private Map<K, ICacheElement<K, V>> getMultipleFromMemory(Set<K> keys)
+ throws IOException
+ {
+ Map<K, ICacheElement<K, V>> elementsFromMemory = memCache.getMultiple(keys);
+ elementsFromMemory.entrySet().removeIf(entry -> {
+ ICacheElement<K, V> element = entry.getValue();
+ if (isExpired(element))
+ {
+ log.debug("{0} - Memory cache hit, but element expired",
+ () -> cacheAttr.getCacheName());
+
+ doExpires(element);
+ return true;
+ }
+ else
+ {
+ log.debug("{0} - Memory cache hit", () -> cacheAttr.getCacheName());
+
+ // Update counters
+ hitCountRam.incrementAndGet();
+ return false;
+ }
+ });
+
+ return elementsFromMemory;
+ }
+
+ /**
+ * If local invocation look in aux caches, even if not local look in disk auxiliaries.
+ * <p>
+ * @param keys
+ * @param localOnly
+ * @return the elements found in the auxiliary caches
+ * @throws IOException
+ */
+ private Map<K, ICacheElement<K, V>> getMultipleFromAuxiliaryCaches(Set<K> keys, boolean localOnly)
+ throws IOException
+ {
+ Map<K, ICacheElement<K, V>> elements = new HashMap<>();
+ Set<K> remainingKeys = new HashSet<>(keys);
+
+ for (AuxiliaryCache<K, V> aux : auxCaches)
+ {
+ if (aux != null)
+ {
+ Map<K, ICacheElement<K, V>> elementsFromAuxiliary =
+ new HashMap<>();
+
+ CacheType cacheType = aux.getCacheType();
+
+ if (!localOnly || cacheType == CacheType.DISK_CACHE)
+ {
+ log.debug("Attempting to get from aux [{0}] which is of type: {1}",
+ () -> aux.getCacheName(), () -> cacheType);
+
+ try
+ {
+ elementsFromAuxiliary.putAll(aux.getMultiple(remainingKeys));
+ }
+ catch (IOException e)
+ {
+ log.error("Error getting from aux", e);
+ }
+ }
+
+ log.debug("Got CacheElements: {0}", elementsFromAuxiliary);
+
+ processRetrievedElements(aux, elementsFromAuxiliary);
+ elements.putAll(elementsFromAuxiliary);
+
+ if (elements.size() == keys.size())
+ {
+ break;
+ }
+ else
+ {
+ remainingKeys = pruneKeysFound(keys, elements);
+ }
+ }
+ }
+
+ return elements;
+ }
+
+ /**
+ * Build a map of all the matching elements in all of the auxiliaries and memory.
+ * <p>
+ * @param pattern
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any matching keys
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching(String pattern)
+ {
+ return getMatching(pattern, false);
+ }
+
+ /**
+ * Build a map of all the matching elements in all of the auxiliaries and memory. Do not try to
+ * go remote or laterally for this data.
+ * <p>
+ * @param pattern
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any matching keys
+ */
+ public Map<K, ICacheElement<K, V>> localGetMatching(String pattern)
+ {
+ return getMatching(pattern, true);
+ }
+
+ /**
+ * Build a map of all the matching elements in all of the auxiliaries and memory. Items in
+ * memory will replace from the auxiliaries in the returned map. The auxiliaries are accessed in
+ * opposite order. It's assumed that those closer to home are better.
+ * <p>
+ * Do not try to go remote or laterally for this get if it is localOnly. Otherwise try to go
+ * remote or lateral if such an auxiliary is configured for this region.
+ * <p>
+ * @param pattern
+ * @param localOnly
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any matching keys
+ */
+ protected Map<K, ICacheElement<K, V>> getMatching(String pattern, boolean localOnly)
+ {
+ log.debug("get: pattern [{0}], localOnly = {1}", pattern, localOnly);
+
+ try
+ {
+ return Stream.concat(
+ getMatchingFromMemory(pattern).entrySet().stream(),
+ getMatchingFromAuxiliaryCaches(pattern, localOnly).entrySet().stream())
+ .collect(Collectors.toMap(
+ entry -> entry.getKey(),
+ entry -> entry.getValue(),
+ // Prefer memory entries
+ (mem, aux) -> mem));
+ }
+ catch (IOException e)
+ {
+ log.error("Problem encountered getting elements.", e);
+ }
+
+ return new HashMap<>();
+ }
+
+ /**
+ * Gets the key array from the memcache. Builds a set of matches. Calls getMultiple with the
+ * set. Returns a map: key -> result.
+ * <p>
+ * @param pattern
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any matching keys
+ * @throws IOException
+ */
+ protected Map<K, ICacheElement<K, V>> getMatchingFromMemory(String pattern)
+ throws IOException
+ {
+ // find matches in key array
+ // this avoids locking the memory cache, but it uses more memory
+ Set<K> keyArray = memCache.getKeySet();
+ Set<K> matchingKeys = getKeyMatcher().getMatchingKeysFromArray(pattern, keyArray);
+
+ // call get multiple
+ return getMultipleFromMemory(matchingKeys);
+ }
+
+ /**
+ * If local invocation look in aux caches, even if not local look in disk auxiliaries.
+ * <p>
+ * Moves in reverse order of definition. This will allow you to override those that are from the
+ * remote with those on disk.
+ * <p>
+ * @param pattern
+ * @param localOnly
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any matching keys
+ * @throws IOException
+ */
+ private Map<K, ICacheElement<K, V>> getMatchingFromAuxiliaryCaches(String pattern, boolean localOnly)
+ throws IOException
+ {
+ Map<K, ICacheElement<K, V>> elements = new HashMap<>();
+
+ for (int i = auxCaches.length - 1; i >= 0; i--)
+ {
+ AuxiliaryCache<K, V> aux = auxCaches[i];
+
+ if (aux != null)
+ {
+ Map<K, ICacheElement<K, V>> elementsFromAuxiliary =
+ new HashMap<>();
+
+ CacheType cacheType = aux.getCacheType();
+
+ if (!localOnly || cacheType == CacheType.DISK_CACHE)
+ {
+ log.debug("Attempting to get from aux [{0}] which is of type: {1}",
+ () -> aux.getCacheName(), () -> cacheType);
+
+ try
+ {
+ elementsFromAuxiliary.putAll(aux.getMatching(pattern));
+ }
+ catch (IOException e)
+ {
+ log.error("Error getting from aux", e);
+ }
+
+ log.debug("Got CacheElements: {0}", elementsFromAuxiliary);
+
+ processRetrievedElements(aux, elementsFromAuxiliary);
+ elements.putAll(elementsFromAuxiliary);
+ }
+ }
+ }
+
+ return elements;
+ }
+
+ /**
+ * Remove expired elements retrieved from an auxiliary. Update memory with good items.
+ * <p>
+ * @param aux the auxiliary cache instance
+ * @param elementsFromAuxiliary
+ * @throws IOException
+ */
+ private void processRetrievedElements(AuxiliaryCache<K, V> aux, Map<K, ICacheElement<K, V>> elementsFromAuxiliary)
+ throws IOException
+ {
+ elementsFromAuxiliary.entrySet().removeIf(entry -> {
+ ICacheElement<K, V> element = entry.getValue();
+
+ // Item found in one of the auxiliary caches.
+ if (element != null)
+ {
+ if (isExpired(element))
+ {
+ log.debug("{0} - Aux cache[{1}] hit, but element expired.",
+ () -> cacheAttr.getCacheName(), () -> aux.getCacheName());
+
+ // This will tell the remote caches to remove the item
+ // based on the element's expiration policy. The elements attributes
+ // associated with the item when it created govern its behavior
+ // everywhere.
+ doExpires(element);
+ return true;
+ }
+ else
+ {
+ log.debug("{0} - Aux cache[{1}] hit.",
+ () -> cacheAttr.getCacheName(), () -> aux.getCacheName());
+
+ // Update counters
+ hitCountAux.incrementAndGet();
+ try
+ {
+ copyAuxiliaryRetrievedItemToMemory(element);
+ }
+ catch (IOException e)
+ {
+ log.error("{0} failed to copy element to memory {1}",
+ cacheAttr.getCacheName(), element, e);
+ }
+ }
+ }
+
+ return false;
+ });
+ }
+
+ /**
+ * Copies the item to memory if the memory size is greater than 0. Only spool if the memory
+ * cache size is greater than 0, else the item will immediately get put into purgatory.
+ * <p>
+ * @param element
+ * @throws IOException
+ */
+ private void copyAuxiliaryRetrievedItemToMemory(ICacheElement<K, V> element)
+ throws IOException
+ {
+ if (memCache.getCacheAttributes().getMaxObjects() > 0)
+ {
+ memCache.update(element);
+ }
+ else
+ {
+ log.debug("Skipping memory update since no items are allowed in memory");
+ }
+ }
+
+ /**
+ * Returns a set of keys that were not found.
+ * <p>
+ * @param keys
+ * @param foundElements
+ * @return the original set of cache keys, minus any cache keys present in the map keys of the
+ * foundElements map
+ */
+ private Set<K> pruneKeysFound(Set<K> keys, Map<K, ICacheElement<K, V>> foundElements)
+ {
+ Set<K> remainingKeys = new HashSet<>(keys);
+ remainingKeys.removeAll(foundElements.keySet());
+
+ return remainingKeys;
+ }
+
+ /**
+ * Get a set of the keys for all elements in the cache
+ * <p>
+ * @return A set of the key type
+ */
+ public Set<K> getKeySet()
+ {
+ return getKeySet(false);
+ }
+
+ /**
+ * Get a set of the keys for all elements in the cache
+ * <p>
+ * @param localOnly true if only memory keys are requested
+ *
+ * @return A set of the key type
+ */
+ public Set<K> getKeySet(boolean localOnly)
+ {
+ HashSet<K> allKeys = new HashSet<>();
+
+ allKeys.addAll(memCache.getKeySet());
+ for (AuxiliaryCache<K, V> aux : auxCaches)
+ {
+ if (aux != null)
+ {
+ if(!localOnly || aux.getCacheType() == CacheType.DISK_CACHE)
+ {
+ try
+ {
+ allKeys.addAll(aux.getKeySet());
+ }
+ catch (IOException e)
+ {
+ // ignore
+ }
+ }
+ }
+ }
+ return allKeys;
+ }
+
+ /**
+ * Removes an item from the cache.
+ * <p>
+ * @param key
+ * @return true is it was removed
+ * @see org.apache.commons.jcs3.engine.behavior.ICache#remove(Object)
+ */
+ @Override
+ public boolean remove(K key)
+ {
+ return remove(key, false);
+ }
+
+ /**
+ * Do not propagate removeall laterally or remotely.
+ * <p>
+ * @param key
+ * @return true if the item was already in the cache.
+ */
+ public boolean localRemove(K key)
+ {
+ return remove(key, true);
+ }
+
+ /**
+ * fromRemote: If a remove call was made on a cache with both, then the remote should have been
+ * called. If it wasn't then the remote is down. we'll assume it is down for all. If it did come
+ * from the remote then the cache is remotely configured and lateral removal is unnecessary. If
+ * it came laterally then lateral removal is unnecessary. Does this assume that there is only
+ * one lateral and remote for the cache? Not really, the initial removal should take care of the
+ * problem if the source cache was similarly configured. Otherwise the remote cache, if it had
+ * no laterals, would remove all the elements from remotely configured caches, but if those
+ * caches had some other weird laterals that were not remotely configured, only laterally
+ * propagated then they would go out of synch. The same could happen for multiple remotes. If
+ * this looks necessary we will need to build in an identifier to specify the source of a
+ * removal.
+ * <p>
+ * @param key
+ * @param localOnly
+ * @return true if the item was in the cache, else false
+ */
+ protected boolean remove(K key, boolean localOnly)
+ {
+ removeCount.incrementAndGet();
+
+ boolean removed = false;
+
+ try
+ {
+ removed = memCache.remove(key);
+ }
+ catch (IOException e)
+ {
+ log.error(e);
+ }
+
+ // Removes from all auxiliary caches.
+ for (ICache<K, V> aux : auxCaches)
+ {
+ if (aux == null)
+ {
+ continue;
+ }
+
+ CacheType cacheType = aux.getCacheType();
+
+ // for now let laterals call remote remove but not vice versa
+ if (localOnly && (cacheType == CacheType.REMOTE_CACHE || cacheType == CacheType.LATERAL_CACHE))
+ {
+ continue;
+ }
+ try
+ {
+ log.debug("Removing {0} from cacheType {1}", key, cacheType);
+
+ boolean b = aux.remove(key);
+
+ // Don't take the remote removal into account.
+ if (!removed && cacheType != CacheType.REMOTE_CACHE)
+ {
+ removed = b;
+ }
+ }
+ catch (IOException ex)
+ {
+ log.error("Failure removing from aux", ex);
+ }
+ }
+
+ return removed;
+ }
+
+ /**
+ * Clears the region. This command will be sent to all auxiliaries. Some auxiliaries, such as
+ * the JDBC disk cache, can be configured to not honor removeAll requests.
+ * <p>
+ * @see org.apache.commons.jcs3.engine.behavior.ICache#removeAll()
+ */
+ @Override
+ public void removeAll()
+ throws IOException
+ {
+ removeAll(false);
+ }
+
+ /**
+ * Will not pass the remove message remotely.
+ * <p>
+ * @throws IOException
+ */
+ public void localRemoveAll()
+ throws IOException
+ {
+ removeAll(true);
+ }
+
+ /**
+ * Removes all cached items.
+ * <p>
+ * @param localOnly must pass in false to get remote and lateral aux's updated. This prevents
+ * looping.
+ * @throws IOException
+ */
+ protected void removeAll(boolean localOnly)
+ throws IOException
+ {
+ try
+ {
+ memCache.removeAll();
+
+ log.debug("Removed All keys from the memory cache.");
+ }
+ catch (IOException ex)
+ {
+ log.error("Trouble updating memory cache.", ex);
+ }
+
+ // Removes from all auxiliary disk caches.
+ for (ICache<K, V> aux : auxCaches)
+ {
+ if (aux != null && (aux.getCacheType() == CacheType.DISK_CACHE || !localOnly))
+ {
+ try
+ {
+ log.debug("Removing All keys from cacheType {0}",
+ () -> aux.getCacheType());
+
+ aux.removeAll();
+ }
+ catch (IOException ex)
+ {
+ log.error("Failure removing all from aux", ex);
+ }
+ }
+ }
+ }
+
+ /**
+ * Flushes all cache items from memory to auxiliary caches and close the auxiliary caches.
+ */
+ @Override
+ public void dispose()
+ {
+ dispose(false);
+ }
+
+ /**
+ * Invoked only by CacheManager. This method disposes of the auxiliaries one by one. For the
+ * disk cache, the items in memory are freed, meaning that they will be sent through the
+ * overflow channel to disk. After the auxiliaries are disposed, the memory cache is disposed.
+ * <p>
+ * @param fromRemote
+ */
+ public void dispose(boolean fromRemote)
+ {
+ // If already disposed, return immediately
+ if (alive.compareAndSet(true, false) == false)
+ {
+ return;
+ }
+
+ log.info("In DISPOSE, [{0}] fromRemote [{1}]",
+ () -> this.cacheAttr.getCacheName(), () -> fromRemote);
+
+ // Remove us from the cache managers list
+ // This will call us back but exit immediately
+ if (cacheManager != null)
+ {
+ cacheManager.freeCache(getCacheName(), fromRemote);
+ }
+
+ // Try to stop shrinker thread
+ if (future != null)
+ {
+ future.cancel(true);
+ }
+
+ // Now, shut down the event queue
+ if (elementEventQ != null)
+ {
+ elementEventQ.dispose();
+ elementEventQ = null;
+ }
+
+ // Dispose of each auxiliary cache, Remote auxiliaries will be
+ // skipped if 'fromRemote' is true.
+ for (ICache<K, V> aux : auxCaches)
+ {
+ try
+ {
+ // Skip this auxiliary if:
+ // - The auxiliary is null
+ // - The auxiliary is not alive
+ // - The auxiliary is remote and the invocation was remote
+ if (aux == null || aux.getStatus() != CacheStatus.ALIVE
+ || (fromRemote && aux.getCacheType() == CacheType.REMOTE_CACHE))
+ {
+ log.info("In DISPOSE, [{0}] SKIPPING auxiliary [{1}] fromRemote [{2}]",
+ () -> this.cacheAttr.getCacheName(), () -> aux.getCacheName(),
+ () -> fromRemote);
+ continue;
+ }
+
+ log.info("In DISPOSE, [{0}] auxiliary [{1}]",
+ () -> this.cacheAttr.getCacheName(), () -> aux.getCacheName());
+
+ // IT USED TO BE THE CASE THAT (If the auxiliary is not a lateral, or the cache
+ // attributes
+ // have 'getUseLateral' set, all the elements currently in
+ // memory are written to the lateral before disposing)
+ // I changed this. It was excessive. Only the disk cache needs the items, since only
+ // the disk cache is in a situation to not get items on a put.
+ if (aux.getCacheType() == CacheType.DISK_CACHE)
+ {
+ int numToFree = memCache.getSize();
+ memCache.freeElements(numToFree);
+
+ log.info("In DISPOSE, [{0}] put {1} into auxiliary [{2}]",
+ () -> this.cacheAttr.getCacheName(), () -> numToFree,
+ () -> aux.getCacheName());
+ }
+
+ // Dispose of the auxiliary
+ aux.dispose();
+ }
+ catch (IOException ex)
+ {
+ log.error("Failure disposing of aux.", ex);
+ }
+ }
+
+ log.info("In DISPOSE, [{0}] disposing of memory cache.",
+ () -> this.cacheAttr.getCacheName());
+ try
+ {
+ memCache.dispose();
+ }
+ catch (IOException ex)
+ {
+ log.error("Failure disposing of memCache", ex);
+ }
+ }
+
+ /**
+ * Calling save cause the entire contents of the memory cache to be flushed to all auxiliaries.
+ * Though this put is extremely fast, this could bog the cache and should be avoided. The
+ * dispose method should call a version of this. Good for testing.
+ */
+ public void save()
+ {
+ if (alive.compareAndSet(true, false) == false)
+ {
+ return;
+ }
+
+ for (ICache<K, V> aux : auxCaches)
+ {
+ try
+ {
+ if (aux.getStatus() == CacheStatus.ALIVE)
+ {
+ for (K key : memCache.getKeySet())
+ {
+ ICacheElement<K, V> ce = memCache.get(key);
+
+ if (ce != null)
+ {
+ aux.update(ce);
+ }
+ }
+ }
+ }
+ catch (IOException ex)
+ {
+ log.error("Failure saving aux caches.", ex);
+ }
+ }
+
+ log.debug("Called save for [{0}]", () -> cacheAttr.getCacheName());
+ }
+
+ /**
+ * Gets the size attribute of the Cache object. This return the number of elements, not the byte
+ * size.
+ * <p>
+ * @return The size value
+ */
+ @Override
+ public int getSize()
+ {
+ return memCache.getSize();
+ }
+
+ /**
+ * Gets the cacheType attribute of the Cache object.
+ * <p>
+ * @return The cacheType value
+ */
+ @Override
+ public CacheType getCacheType()
+ {
+ return CacheType.CACHE_HUB;
+ }
+
+ /**
+ * Gets the status attribute of the Cache object.
+ * <p>
+ * @return The status value
+ */
+ @Override
+ public CacheStatus getStatus()
+ {
+ return alive.get() ? CacheStatus.ALIVE : CacheStatus.DISPOSED;
+ }
+
+ /**
+ * Gets stats for debugging.
+ * <p>
+ * @return String
+ */
+ @Override
+ public String getStats()
+ {
+ return getStatistics().toString();
+ }
+
+ /**
+ * This returns data gathered for this region and all the auxiliaries it currently uses.
+ * <p>
+ * @return Statistics and Info on the Region.
+ */
+ public ICacheStats getStatistics()
+ {
+ ICacheStats stats = new CacheStats();
+ stats.setRegionName(this.getCacheName());
+
+ // store the composite cache stats first
+ ArrayList<IStatElement<?>> elems = new ArrayList<>();
+
+ elems.add(new StatElement<>("HitCountRam", Long.valueOf(getHitCountRam())));
+ elems.add(new StatElement<>("HitCountAux", Long.valueOf(getHitCountAux())));
+
+ stats.setStatElements(elems);
+
+ // memory + aux, memory is not considered an auxiliary internally
+ int total = auxCaches.length + 1;
+ ArrayList<IStats> auxStats = new ArrayList<>(total);
+
+ auxStats.add(getMemoryCache().getStatistics());
+
+ for (AuxiliaryCache<K, V> aux : auxCaches)
+ {
+ auxStats.add(aux.getStatistics());
+ }
+
+ // store the auxiliary stats
+ stats.setAuxiliaryCacheStats(auxStats);
+
+ return stats;
+ }
+
+ /**
+ * Gets the cacheName attribute of the Cache object. This is also known as the region name.
+ * <p>
+ * @return The cacheName value
+ */
+ @Override
+ public String getCacheName()
+ {
+ return cacheAttr.getCacheName();
+ }
+
+ /**
+ * Gets the default element attribute of the Cache object This returns a copy. It does not
+ * return a reference to the attributes.
+ * <p>
+ * @return The attributes value
+ */
+ public IElementAttributes getElementAttributes()
+ {
+ if (attr != null)
+ {
+ return attr.clone();
+ }
+ return null;
+ }
+
+ /**
+ * Sets the default element attribute of the Cache object.
+ * <p>
+ * @param attr
+ */
+ public void setElementAttributes(IElementAttributes attr)
+ {
+ this.attr = attr;
+ }
+
+ /**
+ * Gets the ICompositeCacheAttributes attribute of the Cache object.
+ * <p>
+ * @return The ICompositeCacheAttributes value
+ */
+ public ICompositeCacheAttributes getCacheAttributes()
+ {
+ return this.cacheAttr;
+ }
+
+ /**
+ * Sets the ICompositeCacheAttributes attribute of the Cache object.
+ * <p>
+ * @param cattr The new ICompositeCacheAttributes value
+ */
+ public void setCacheAttributes(ICompositeCacheAttributes cattr)
+ {
+ this.cacheAttr = cattr;
+ // need a better way to do this, what if it is in error
+ this.memCache.initialize(this);
+ }
+
+ /**
+ * Gets the elementAttributes attribute of the Cache object.
+ * <p>
+ * @param key
+ * @return The elementAttributes value
+ * @throws CacheException
+ * @throws IOException
+ */
+ public IElementAttributes getElementAttributes(K key)
+ throws CacheException, IOException
+ {
+ ICacheElement<K, V> ce = get(key);
+ if (ce == null)
+ {
+ throw new ObjectNotFoundException("key " + key + " is not found");
+ }
+ return ce.getElementAttributes();
+ }
+
+ /**
+ * Determine if the element is expired based on the values of the element attributes
+ *
+ * @param element the element
+ *
+ * @return true if the element is expired
+ */
+ public boolean isExpired(ICacheElement<K, V> element)
+ {
+ return isExpired(element, System.currentTimeMillis(),
+ ElementEventType.EXCEEDED_MAXLIFE_ONREQUEST,
+ ElementEventType.EXCEEDED_IDLETIME_ONREQUEST);
+ }
+
+ /**
+ * Check if the element is expired based on the values of the element attributes
+ *
+ * @param element the element
+ * @param timestamp the timestamp to compare to
+ * @param eventMaxlife the event to fire in case the max life time is exceeded
+ * @param eventIdle the event to fire in case the idle time is exceeded
+ *
+ * @return true if the element is expired
+ */
+ public boolean isExpired(ICacheElement<K, V> element, long timestamp,
+ ElementEventType eventMaxlife, ElementEventType eventIdle)
+ {
+ try
+ {
+ IElementAttributes attributes = element.getElementAttributes();
+
+ if (!attributes.getIsEternal())
+ {
+ // Remove if maxLifeSeconds exceeded
+ long maxLifeSeconds = attributes.getMaxLife();
+ long createTime = attributes.getCreateTime();
+
+ final long timeFactorForMilliseconds = attributes.getTimeFactorForMilliseconds();
+
+ if (maxLifeSeconds != -1 && (timestamp - createTime) > (maxLifeSeconds * timeFactorForMilliseconds))
+ {
+ log.debug("Exceeded maxLife: {0}", () -> element.getKey());
+
+ handleElementEvent(element, eventMaxlife);
+ return true;
+ }
+ long idleTime = attributes.getIdleTime();
+ long lastAccessTime = attributes.getLastAccessTime();
+
+ // Remove if maxIdleTime exceeded
+ // If you have a 0 size memory cache, then the last access will
+ // not get updated.
+ // you will need to set the idle time to -1.
+ if ((idleTime != -1) && (timestamp - lastAccessTime) > idleTime * timeFactorForMilliseconds)
+ {
+ log.debug("Exceeded maxIdle: {0}", () -> element.getKey());
+
+ handleElementEvent(element, eventIdle);
+ return true;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ log.error("Error determining expiration period, expiring", e);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * If there are event handlers for the item, then create an event and queue it up.
+ * <p>
+ * This does not call handle directly; instead the handler and the event are put into a queue.
+ * This prevents the event handling from blocking normal cache operations.
+ * <p>
+ * @param element the item
+ * @param eventType the event type
+ */
+ public void handleElementEvent(ICacheElement<K, V> element, ElementEventType eventType)
+ {
+ ArrayList<IElementEventHandler> eventHandlers = element.getElementAttributes().getElementEventHandlers();
+ if (eventHandlers != null)
+ {
+ log.debug("Element Handlers are registered. Create event type {0}", eventType);
+ if (elementEventQ == null)
+ {
+ log.warn("No element event queue available for cache {0}", getCacheName());
+ return;
+ }
+ IElementEvent<ICacheElement<K, V>> event = new ElementEvent<>(element, eventType);
+ for (IElementEventHandler hand : eventHandlers)
+ {
+ try
+ {
+ elementEventQ.addElementEvent(hand, event);
+ }
+ catch (IOException e)
+ {
+ log.error("Trouble adding element event to queue", e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Create the MemoryCache based on the config parameters.
+ * TODO: consider making this an auxiliary, despite its close tie to the CacheHub.
+ * TODO: might want to create a memory cache config file separate from that of the hub -- ICompositeCacheAttributes
+ * <p>
+ * @param cattr
+ */
+ private void createMemoryCache(ICompositeCacheAttributes cattr)
+ {
+ if (memCache == null)
+ {
+ try
+ {
+ Class<?> c = Class.forName(cattr.getMemoryCacheName());
+ @SuppressWarnings("unchecked") // Need cast
+ IMemoryCache<K, V> newInstance = (IMemoryCache<K, V>) c.newInstance();
+ memCache = newInstance;
+ memCache.initialize(this);
+ }
+ catch (Exception e)
+ {
+ log.warn("Failed to init mem cache, using: LRUMemoryCache", e);
+
+ this.memCache = new LRUMemoryCache<>();
+ this.memCache.initialize(this);
+ }
+ }
+ else
+ {
+ log.warn("Refusing to create memory cache -- already exists.");
+ }
+ }
+
+ /**
+ * Access to the memory cache for instrumentation.
+ * <p>
+ * @return the MemoryCache implementation
+ */
+ public IMemoryCache<K, V> getMemoryCache()
+ {
+ return memCache;
+ }
+
+ /**
+ * Number of times a requested item was found in the memory cache.
+ * <p>
+ * @return number of hits in memory
+ */
+ public long getHitCountRam()
+ {
+ return hitCountRam.get();
+ }
+
+ /**
+ * Number of times a requested item was found in and auxiliary cache.
+ * @return number of auxiliary hits.
+ */
+ public long getHitCountAux()
+ {
+ return hitCountAux.get();
+ }
+
+ /**
+ * Number of times a requested element was not found.
+ * @return number of misses.
+ */
+ public long getMissCountNotFound()
+ {
+ return missCountNotFound.get();
+ }
+
+ /**
+ * Number of times a requested element was found but was expired.
+ * @return number of found but expired gets.
+ */
+ public long getMissCountExpired()
+ {
+ return missCountExpired.get();
+ }
+
+ /**
+ * @return Returns the updateCount.
+ */
+ public long getUpdateCount()
+ {
+ return updateCount.get();
+ }
+
+ /**
+ * Sets the key matcher used by get matching.
+ * <p>
+ * @param keyMatcher
+ */
+ @Override
+ public void setKeyMatcher(IKeyMatcher<K> keyMatcher)
+ {
+ if (keyMatcher != null)
+ {
+ this.keyMatcher = keyMatcher;
+ }
+ }
+
+ /**
+ * Returns the key matcher used by get matching.
+ * <p>
+ * @return keyMatcher
+ */
+ public IKeyMatcher<K> getKeyMatcher()
+ {
+ return this.keyMatcher;
+ }
+
+ /**
+ * This returns the stats.
+ * <p>
+ * @return getStats()
+ */
+ @Override
+ public String toString()
+ {
+ return getStats();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/CompositeCacheConfigurator.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/CompositeCacheConfigurator.java
new file mode 100644
index 0000000..984149f
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/CompositeCacheConfigurator.java
@@ -0,0 +1,535 @@
+package org.apache.commons.jcs3.engine.control;
+
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheConfigurator;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheFactory;
+import org.apache.commons.jcs3.engine.behavior.ICache;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.behavior.IRequireScheduler;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.engine.match.KeyMatcherPatternImpl;
+import org.apache.commons.jcs3.engine.match.behavior.IKeyMatcher;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.config.OptionConverter;
+import org.apache.commons.jcs3.utils.config.PropertySetter;
+
+/**
+ * This class configures JCS based on a properties object.
+ * <p>
+ * This class is based on the log4j class org.apache.log4j.PropertyConfigurator which was made by:
+ * "Luke Blanshard" <Luke@quiq.com>"Mark DONSZELMANN" <Mark.Donszelmann@cern.ch>"Anders Kristensen"
+ * <akristensen@dynamicsoft.com>
+ */
+public class CompositeCacheConfigurator
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( CompositeCacheConfigurator.class );
+
+ /** The prefix of relevant system properties */
+ protected static final String SYSTEM_PROPERTY_KEY_PREFIX = "jcs";
+
+ /** normal region prefix */
+ protected static final String REGION_PREFIX = "jcs.region.";
+
+ /** system region prefix. might not be used */
+ protected static final String SYSTEM_REGION_PREFIX = "jcs.system.";
+
+ /** auxiliary prefix */
+ protected static final String AUXILIARY_PREFIX = "jcs.auxiliary.";
+
+ /** .attributes */
+ protected static final String ATTRIBUTE_PREFIX = ".attributes";
+
+ /** .cacheattributes */
+ protected static final String CACHE_ATTRIBUTE_PREFIX = ".cacheattributes";
+
+ /** .elementattributes */
+ protected static final String ELEMENT_ATTRIBUTE_PREFIX = ".elementattributes";
+
+ /**
+ * jcs.auxiliary.NAME.keymatcher=CLASSNAME
+ * <p>
+ * jcs.auxiliary.NAME.keymatcher.attributes.CUSTOMPROPERTY=VALUE
+ */
+ public static final String KEY_MATCHER_PREFIX = ".keymatcher";
+
+ /**
+ * Constructor for the CompositeCacheConfigurator object
+ */
+ public CompositeCacheConfigurator()
+ {
+ // empty
+ }
+
+ /**
+ * Create caches used internally. System status gives them creation priority.
+ *<p>
+ * @param props Configuration properties
+ * @param ccm Cache hub
+ */
+ protected void parseSystemRegions( Properties props, CompositeCacheManager ccm )
+ {
+ for (String key : props.stringPropertyNames() )
+ {
+ if ( key.startsWith( SYSTEM_REGION_PREFIX ) && key.indexOf( "attributes" ) == -1 )
+ {
+ String regionName = key.substring( SYSTEM_REGION_PREFIX.length() );
+ String auxiliaries = OptionConverter.findAndSubst( key, props );
+ ICache<?, ?> cache;
+ synchronized ( regionName )
+ {
+ cache = parseRegion( props, ccm, regionName, auxiliaries, null, SYSTEM_REGION_PREFIX );
+ }
+ ccm.addCache( regionName, cache );
+ }
+ }
+ }
+
+ /**
+ * Parse region elements.
+ *<p>
+ * @param props Configuration properties
+ * @param ccm Cache hub
+ */
+ protected void parseRegions( Properties props, CompositeCacheManager ccm )
+ {
+ List<String> regionNames = new ArrayList<>();
+
+ for (String key : props.stringPropertyNames() )
+ {
+ if ( key.startsWith( REGION_PREFIX ) && key.indexOf( "attributes" ) == -1 )
+ {
+ String regionName = key.substring( REGION_PREFIX.length() );
+ regionNames.add( regionName );
+ String auxiliaries = OptionConverter.findAndSubst( key, props );
+ ICache<?, ?> cache;
+ synchronized ( regionName )
+ {
+ cache = parseRegion( props, ccm, regionName, auxiliaries );
+ }
+ ccm.addCache( regionName, cache );
+ }
+ }
+
+ log.info( "Parsed regions {0}", regionNames );
+ }
+
+ /**
+ * Create cache region.
+ *<p>
+ * @param props Configuration properties
+ * @param ccm Cache hub
+ * @param regName Name of the cache region
+ * @param auxiliaries Comma separated list of auxiliaries
+ *
+ * @return CompositeCache
+ */
+ protected <K, V> CompositeCache<K, V> parseRegion(
+ Properties props, CompositeCacheManager ccm, String regName, String auxiliaries )
+ {
+ return parseRegion( props, ccm, regName, auxiliaries, null, REGION_PREFIX );
+ }
+
+ /**
+ * Get all the properties for a region and configure its cache.
+ * <p>
+ * This method tells the other parse method the name of the region prefix.
+ *<p>
+ * @param props Configuration properties
+ * @param ccm Cache hub
+ * @param regName Name of the cache region
+ * @param auxiliaries Comma separated list of auxiliaries
+ * @param cca Cache configuration
+ *
+ * @return CompositeCache
+ */
+ protected <K, V> CompositeCache<K, V> parseRegion(
+ Properties props, CompositeCacheManager ccm, String regName, String auxiliaries,
+ ICompositeCacheAttributes cca )
+ {
+ return parseRegion( props, ccm, regName, auxiliaries, cca, REGION_PREFIX );
+ }
+
+ /**
+ * Get all the properties for a region and configure its cache.
+ *<p>
+ * @param props Configuration properties
+ * @param ccm Cache hub
+ * @param regName Name of the cache region
+ * @param auxiliaries Comma separated list of auxiliaries
+ * @param cca Cache configuration
+ * @param regionPrefix Prefix for the region
+ *
+ * @return CompositeCache
+ */
+ protected <K, V> CompositeCache<K, V> parseRegion(
+ Properties props, CompositeCacheManager ccm, String regName, String auxiliaries,
+ ICompositeCacheAttributes cca, String regionPrefix )
+ {
+ // First, create or get the cache and element attributes, and create
+ // the cache.
+ IElementAttributes ea = parseElementAttributes( props, regName,
+ ccm.getDefaultElementAttributes(), regionPrefix );
+
+ ICompositeCacheAttributes instantiationCca = cca == null
+ ? parseCompositeCacheAttributes(props, regName, ccm.getDefaultCacheAttributes(), regionPrefix)
+ : cca;
+ CompositeCache<K, V> cache = newCache(instantiationCca, ea);
+
+ // Inject cache manager
+ cache.setCompositeCacheManager(ccm);
+
+ // Inject scheduler service
+ cache.setScheduledExecutorService(ccm.getScheduledExecutorService());
+
+ // Inject element event queue
+ cache.setElementEventQueue(ccm.getElementEventQueue());
+
+ if (cache.getMemoryCache() instanceof IRequireScheduler)
+ {
+ ((IRequireScheduler)cache.getMemoryCache()).setScheduledExecutorService(
+ ccm.getScheduledExecutorService());
+ }
+
+ if (auxiliaries != null)
+ {
+ // Next, create the auxiliaries for the new cache
+ List<AuxiliaryCache<K, V>> auxList = new ArrayList<>();
+
+ log.debug( "Parsing region name \"{0}\", value \"{1}\"", regName, auxiliaries );
+
+ // We must skip over ',' but not white space
+ StringTokenizer st = new StringTokenizer( auxiliaries, "," );
+
+ // If value is not in the form ", appender.." or "", then we should set
+ // the priority of the category.
+
+ if ( !( auxiliaries.startsWith( "," ) || auxiliaries.equals( "" ) ) )
+ {
+ // just to be on the safe side...
+ if ( !st.hasMoreTokens() )
+ {
+ return null;
+ }
+ }
+
+ AuxiliaryCache<K, V> auxCache;
+ String auxName;
+ while ( st.hasMoreTokens() )
+ {
+ auxName = st.nextToken().trim();
+ if ( auxName == null || auxName.equals( "," ) )
+ {
+ continue;
+ }
+ log.debug( "Parsing auxiliary named \"{0}\".", auxName );
+
+ auxCache = parseAuxiliary( props, ccm, auxName, regName );
+
+ if ( auxCache != null )
+ {
+ if (auxCache instanceof IRequireScheduler)
+ {
+ ((IRequireScheduler) auxCache).setScheduledExecutorService(
+ ccm.getScheduledExecutorService());
+ }
+
+ auxList.add( auxCache );
+ }
+ }
+
+ // Associate the auxiliaries with the cache
+ @SuppressWarnings("unchecked") // No generic arrays in java
+ AuxiliaryCache<K, V>[] auxArray = auxList.toArray( new AuxiliaryCache[0] );
+ cache.setAuxCaches( auxArray );
+ }
+
+ // Return the new cache
+ return cache;
+ }
+
+ protected <K, V> CompositeCache<K, V> newCache(
+ ICompositeCacheAttributes cca, IElementAttributes ea)
+ {
+ return new CompositeCache<>( cca, ea );
+ }
+
+ /**
+ * Get an ICompositeCacheAttributes for the listed region.
+ *<p>
+ * @param props Configuration properties
+ * @param regName the region name
+ * @param defaultCCAttr the default cache attributes
+ *
+ * @return ICompositeCacheAttributes
+ */
+ protected ICompositeCacheAttributes parseCompositeCacheAttributes( Properties props,
+ String regName, ICompositeCacheAttributes defaultCCAttr )
+ {
+ return parseCompositeCacheAttributes( props, regName, defaultCCAttr, REGION_PREFIX );
+ }
+
+ /**
+ * Get the main attributes for a region.
+ *<p>
+ * @param props Configuration properties
+ * @param regName the region name
+ * @param defaultCCAttr the default cache attributes
+ * @param regionPrefix the region prefix
+ *
+ * @return ICompositeCacheAttributes
+ */
+ protected ICompositeCacheAttributes parseCompositeCacheAttributes( Properties props,
+ String regName, ICompositeCacheAttributes defaultCCAttr, String regionPrefix )
+ {
+ ICompositeCacheAttributes ccAttr;
+
+ String attrName = regionPrefix + regName + CACHE_ATTRIBUTE_PREFIX;
+
+ // auxFactory was not previously initialized.
+ // String prefix = regionPrefix + regName + ATTRIBUTE_PREFIX;
+ ccAttr = OptionConverter.instantiateByKey( props, attrName, null );
+
+ if ( ccAttr == null )
+ {
+ log.info( "No special CompositeCacheAttributes class defined for "
+ + "key [{0}], using default class.", attrName );
+
+ ccAttr = defaultCCAttr;
+ }
+
+ log.debug( "Parsing options for \"{0}\"", attrName );
+
+ PropertySetter.setProperties( ccAttr, props, attrName + "." );
+ ccAttr.setCacheName( regName );
+
+ log.debug( "End of parsing for \"{0}\"", attrName );
+
+ // GET CACHE FROM FACTORY WITH ATTRIBUTES
+ ccAttr.setCacheName( regName );
+ return ccAttr;
+ }
+
+ /**
+ * Create the element attributes from the properties object for a cache region.
+ *<p>
+ * @param props Configuration properties
+ * @param regName the region name
+ * @param defaultEAttr the default element attributes
+ * @param regionPrefix the region prefix
+ *
+ * @return IElementAttributes
+ */
+ protected IElementAttributes parseElementAttributes( Properties props, String regName,
+ IElementAttributes defaultEAttr, String regionPrefix )
+ {
+ IElementAttributes eAttr;
+
+ String attrName = regionPrefix + regName + CompositeCacheConfigurator.ELEMENT_ATTRIBUTE_PREFIX;
+
+ // auxFactory was not previously initialized.
+ // String prefix = regionPrefix + regName + ATTRIBUTE_PREFIX;
+ eAttr = OptionConverter.instantiateByKey( props, attrName, null );
+ if ( eAttr == null )
+ {
+ log.info( "No special ElementAttribute class defined for key [{0}], "
+ + "using default class.", attrName );
+
+ eAttr = defaultEAttr;
+ }
+
+ log.debug( "Parsing options for \"{0}\"", attrName );
+
+ PropertySetter.setProperties( eAttr, props, attrName + "." );
+ // eAttr.setCacheName( regName );
+
+ log.debug( "End of parsing for \"{0}\"", attrName );
+
+ // GET CACHE FROM FACTORY WITH ATTRIBUTES
+ // eAttr.setCacheName( regName );
+ return eAttr;
+ }
+
+ /**
+ * Get an aux cache for the listed aux for a region.
+ *<p>
+ * @param props the configuration properties
+ * @param ccm Cache hub
+ * @param auxName the name of the auxiliary cache
+ * @param regName the name of the region.
+ * @return AuxiliaryCache
+ */
+ protected <K, V> AuxiliaryCache<K, V> parseAuxiliary( Properties props, CompositeCacheManager ccm,
+ String auxName, String regName )
+ {
+ log.debug( "parseAuxiliary {0}", auxName );
+
+ // GET CACHE
+ @SuppressWarnings("unchecked") // Common map for all caches
+ AuxiliaryCache<K, V> auxCache = (AuxiliaryCache<K, V>) ccm.getAuxiliaryCache(auxName, regName);
+
+ if (auxCache == null)
+ {
+ // GET FACTORY
+ AuxiliaryCacheFactory auxFac = ccm.registryFacGet( auxName );
+ if ( auxFac == null )
+ {
+ // auxFactory was not previously initialized.
+ String prefix = AUXILIARY_PREFIX + auxName;
+ auxFac = OptionConverter.instantiateByKey( props, prefix, null );
+ if ( auxFac == null )
+ {
+ log.error( "Could not instantiate auxFactory named \"{0}\"", auxName );
+ return null;
+ }
+
+ auxFac.setName( auxName );
+
+ if ( auxFac instanceof IRequireScheduler)
+ {
+ ((IRequireScheduler)auxFac).setScheduledExecutorService(ccm.getScheduledExecutorService());
+ }
+
+ auxFac.initialize();
+ ccm.registryFacPut( auxFac );
+ }
+
+ // GET ATTRIBUTES
+ AuxiliaryCacheAttributes auxAttr = ccm.registryAttrGet( auxName );
+ String attrName = AUXILIARY_PREFIX + auxName + ATTRIBUTE_PREFIX;
+ if ( auxAttr == null )
+ {
+ // auxFactory was not previously initialized.
+ String prefix = AUXILIARY_PREFIX + auxName + ATTRIBUTE_PREFIX;
+ auxAttr = OptionConverter.instantiateByKey( props, prefix, null );
+ if ( auxAttr == null )
+ {
+ log.error( "Could not instantiate auxAttr named \"{0}\"", attrName );
+ return null;
+ }
+ auxAttr.setName( auxName );
+ ccm.registryAttrPut( auxAttr );
+ }
+
+ auxAttr = auxAttr.clone();
+
+ log.debug( "Parsing options for \"{0}\"", attrName );
+
+ PropertySetter.setProperties( auxAttr, props, attrName + "." );
+ auxAttr.setCacheName( regName );
+
+ log.debug( "End of parsing for \"{0}\"", attrName );
+
+ // GET CACHE FROM FACTORY WITH ATTRIBUTES
+ auxAttr.setCacheName( regName );
+
+ String auxPrefix = AUXILIARY_PREFIX + auxName;
+
+ // CONFIGURE THE EVENT LOGGER
+ ICacheEventLogger cacheEventLogger =
+ AuxiliaryCacheConfigurator.parseCacheEventLogger( props, auxPrefix );
+
+ // CONFIGURE THE ELEMENT SERIALIZER
+ IElementSerializer elementSerializer =
+ AuxiliaryCacheConfigurator.parseElementSerializer( props, auxPrefix );
+
+ // CONFIGURE THE KEYMATCHER
+ //IKeyMatcher keyMatcher = parseKeyMatcher( props, auxPrefix );
+ // TODO add to factory interface
+
+ // Consider putting the compositeCache back in the factory interface
+ // since the manager may not know about it at this point.
+ // need to make sure the manager already has the cache
+ // before the auxiliary is created.
+ try
+ {
+ auxCache = auxFac.createCache( auxAttr, ccm, cacheEventLogger, elementSerializer );
+ }
+ catch (Exception e)
+ {
+ log.error( "Could not instantiate auxiliary cache named \"{0}\"", regName, e );
+ return null;
+ }
+
+ ccm.addAuxiliaryCache(auxName, regName, auxCache);
+ }
+
+ return auxCache;
+ }
+
+ /**
+ * Any property values will be replaced with system property values that match the key.
+ * <p>
+ * @param props
+ */
+ protected static void overrideWithSystemProperties( Properties props )
+ {
+ // override any setting with values from the system properties.
+ Properties sysProps = System.getProperties();
+ for (String key : sysProps.stringPropertyNames())
+ {
+ if ( key.startsWith( SYSTEM_PROPERTY_KEY_PREFIX ) )
+ {
+ log.info( "Using system property [[{0}] [{1}]]", () -> key,
+ () -> sysProps.getProperty( key ) );
+ props.setProperty( key, sysProps.getProperty( key ) );
+ }
+ }
+ }
+
+ /**
+ * Creates a custom key matcher if one is defined. Else, it uses the default.
+ * <p>
+ * @param props
+ * @param auxPrefix - ex. AUXILIARY_PREFIX + auxName
+ * @return IKeyMatcher
+ */
+ protected <K> IKeyMatcher<K> parseKeyMatcher( Properties props, String auxPrefix )
+ {
+
+ // auxFactory was not previously initialized.
+ String keyMatcherClassName = auxPrefix + KEY_MATCHER_PREFIX;
+ IKeyMatcher<K> keyMatcher = OptionConverter.instantiateByKey( props, keyMatcherClassName, null );
+ if ( keyMatcher != null )
+ {
+ String attributePrefix = auxPrefix + KEY_MATCHER_PREFIX + ATTRIBUTE_PREFIX;
+ PropertySetter.setProperties( keyMatcher, props, attributePrefix + "." );
+ log.info( "Using custom key matcher [{0}] for auxiliary [{1}]", keyMatcher, auxPrefix );
+ }
+ else
+ {
+ // use the default standard serializer
+ keyMatcher = new KeyMatcherPatternImpl<>();
+ log.info( "Using standard key matcher [{0}] for auxiliary [{1}]", keyMatcher, auxPrefix );
+ }
+ return keyMatcher;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/CompositeCacheManager.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/CompositeCacheManager.java
new file mode 100644
index 0000000..60bed12
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/CompositeCacheManager.java
@@ -0,0 +1,927 @@
+package org.apache.commons.jcs3.engine.control;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.management.ManagementFactory;
+import java.security.AccessControlException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.admin.JCSAdminBean;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheFactory;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheConstants;
+import org.apache.commons.jcs3.engine.CompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.ElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICache;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.IProvideScheduler;
+import org.apache.commons.jcs3.engine.behavior.IShutdownObserver;
+import org.apache.commons.jcs3.engine.behavior.ICacheType.CacheType;
+import org.apache.commons.jcs3.engine.control.event.ElementEventQueue;
+import org.apache.commons.jcs3.engine.control.event.behavior.IElementEventQueue;
+import org.apache.commons.jcs3.engine.stats.CacheStats;
+import org.apache.commons.jcs3.engine.stats.behavior.ICacheStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.config.OptionConverter;
+import org.apache.commons.jcs3.utils.threadpool.DaemonThreadFactory;
+import org.apache.commons.jcs3.utils.threadpool.ThreadPoolManager;
+import org.apache.commons.jcs3.utils.timing.ElapsedTimer;
+
+/**
+ * Manages a composite cache. This provides access to caches and is the primary way to shutdown the
+ * caching system as a whole.
+ * <p>
+ * The composite cache manager is responsible for creating / configuring cache regions. It serves as
+ * a factory for the ComositeCache class. The CompositeCache is the core of JCS, the hub for various
+ * auxiliaries.
+ */
+public class CompositeCacheManager
+ implements IRemoteCacheConstants, ICompositeCacheManager, IProvideScheduler
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( CompositeCacheManager.class );
+
+ /** JMX object name */
+ public static final String JMX_OBJECT_NAME = "org.apache.commons.jcs3:type=JCSAdminBean";
+
+ /** This is the name of the config file that we will look for by default. */
+ private static final String DEFAULT_CONFIG = "/cache.ccf";
+
+ /** default region prefix */
+ private static final String DEFAULT_REGION = "jcs.default";
+
+ /** Should we use system property substitutions. */
+ private static final boolean DEFAULT_USE_SYSTEM_PROPERTIES = true;
+
+ /** Once configured, you can force a reconfiguration of sorts. */
+ private static final boolean DEFAULT_FORCE_RECONFIGURATION = false;
+
+ /** Caches managed by this cache manager */
+ private final ConcurrentMap<String, ICache<?, ?>> caches = new ConcurrentHashMap<>();
+
+ /** Number of clients accessing this cache manager */
+ private final AtomicInteger clients = new AtomicInteger(0);
+
+ /** Default cache attributes for this cache manager */
+ private ICompositeCacheAttributes defaultCacheAttr = new CompositeCacheAttributes();
+
+ /** Default element attributes for this cache manager */
+ private IElementAttributes defaultElementAttr = new ElementAttributes();
+
+ /** Used to keep track of configured auxiliaries */
+ private final ConcurrentMap<String, AuxiliaryCacheFactory> auxiliaryFactoryRegistry =
+ new ConcurrentHashMap<>( );
+
+ /** Used to keep track of attributes for auxiliaries. */
+ private final ConcurrentMap<String, AuxiliaryCacheAttributes> auxiliaryAttributeRegistry =
+ new ConcurrentHashMap<>( );
+
+ /** Used to keep track of configured auxiliaries */
+ private final ConcurrentMap<String, AuxiliaryCache<?, ?>> auxiliaryCaches =
+ new ConcurrentHashMap<>( );
+
+ /** Properties with which this manager was configured. This is exposed for other managers. */
+ private Properties configurationProperties;
+
+ /** The default auxiliary caches to be used if not preconfigured */
+ private String defaultAuxValues;
+
+ /** The Singleton Instance */
+ private static CompositeCacheManager instance;
+
+ /** Stack for those waiting for notification of a shutdown. */
+ private final LinkedBlockingDeque<IShutdownObserver> shutdownObservers = new LinkedBlockingDeque<>();
+
+ /** The central background scheduler. */
+ private ScheduledExecutorService scheduledExecutor;
+
+ /** The central event queue. */
+ private IElementEventQueue elementEventQueue;
+
+ /** Shutdown hook thread instance */
+ private Thread shutdownHook;
+
+ /** Indicates whether the instance has been initialized. */
+ private boolean isInitialized = false;
+
+ /** Indicates whether configure has been called. */
+ private boolean isConfigured = false;
+
+ /** Indicates whether JMX bean has been registered. */
+ private boolean isJMXRegistered = false;
+
+ private String jmxName = JMX_OBJECT_NAME;
+
+ /**
+ * Gets the CacheHub instance. For backward compatibility, if this creates the instance it will
+ * attempt to configure it with the default configuration. If you want to configure from your
+ * own source, use {@link #getUnconfiguredInstance}and then call {@link #configure}
+ * <p>
+ * @return CompositeCacheManager
+ * @throws CacheException if the configuration cannot be loaded
+ */
+ public static synchronized CompositeCacheManager getInstance() throws CacheException
+ {
+ return getInstance( DEFAULT_CONFIG );
+ }
+
+ /**
+ * Initializes the cache manager using the props file for the given name.
+ * <p>
+ * @param propsFilename
+ * @return CompositeCacheManager configured from the give propsFileName
+ * @throws CacheException if the configuration cannot be loaded
+ */
+ public static synchronized CompositeCacheManager getInstance( String propsFilename ) throws CacheException
+ {
+ if ( instance == null )
+ {
+ log.info( "Instance is null, creating with config [{0}]", propsFilename );
+ instance = createInstance();
+ }
+
+ if (!instance.isInitialized())
+ {
+ instance.initialize();
+ }
+
+ if (!instance.isConfigured())
+ {
+ instance.configure( propsFilename );
+ }
+
+ instance.clients.incrementAndGet();
+
+ return instance;
+ }
+
+ /**
+ * Get a CacheHub instance which is not configured. If an instance already exists, it will be
+ * returned.
+ *<p>
+ * @return CompositeCacheManager
+ */
+ public static synchronized CompositeCacheManager getUnconfiguredInstance()
+ {
+ if ( instance == null )
+ {
+ log.info( "Instance is null, returning unconfigured instance" );
+ instance = createInstance();
+ }
+
+ if (!instance.isInitialized())
+ {
+ instance.initialize();
+ }
+
+ instance.clients.incrementAndGet();
+
+ return instance;
+ }
+
+ /**
+ * Simple factory method, must override in subclasses so getInstance creates / returns the
+ * correct object.
+ * <p>
+ * @return CompositeCacheManager
+ */
+ protected static CompositeCacheManager createInstance()
+ {
+ return new CompositeCacheManager();
+ }
+
+ /**
+ * Default constructor
+ */
+ protected CompositeCacheManager()
+ {
+ // empty
+ }
+
+ /** Creates a shutdown hook and starts the scheduler service */
+ protected void initialize()
+ {
+ if (!isInitialized)
+ {
+ this.shutdownHook = new Thread(() -> {
+ if ( isInitialized() )
+ {
+ log.info("Shutdown hook activated. Shutdown was not called. Shutting down JCS.");
+ shutDown();
+ }
+ });
+ try
+ {
+ Runtime.getRuntime().addShutdownHook( shutdownHook );
+ }
+ catch ( AccessControlException e )
+ {
+ log.error( "Could not register shutdown hook.", e );
+ }
+
+ this.scheduledExecutor = Executors.newScheduledThreadPool(4,
+ new DaemonThreadFactory("JCS-Scheduler-", Thread.MIN_PRIORITY));
+
+ // Register JMX bean
+ if (!isJMXRegistered && jmxName != null)
+ {
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ JCSAdminBean adminBean = new JCSAdminBean(this);
+ try
+ {
+ ObjectName jmxObjectName = new ObjectName(jmxName);
+ mbs.registerMBean(adminBean, jmxObjectName);
+ isJMXRegistered = true;
+ }
+ catch (Exception e)
+ {
+ log.warn( "Could not register JMX bean.", e );
+ }
+ }
+
+ isInitialized = true;
+ }
+ }
+
+ /**
+ * Get the element event queue
+ *
+ * @return the elementEventQueue
+ */
+ public IElementEventQueue getElementEventQueue()
+ {
+ return elementEventQueue;
+ }
+
+ /**
+ * Get the scheduler service
+ *
+ * @return the scheduledExecutor
+ */
+ @Override
+ public ScheduledExecutorService getScheduledExecutorService()
+ {
+ return scheduledExecutor;
+ }
+
+ /**
+ * Configure with default properties file
+ * @throws CacheException if the configuration cannot be loaded
+ */
+ public void configure() throws CacheException
+ {
+ configure( DEFAULT_CONFIG );
+ }
+
+ /**
+ * Configure from specific properties file.
+ * <p>
+ * @param propFile Path <u>within classpath </u> to load configuration from
+ * @throws CacheException if the configuration cannot be loaded
+ */
+ public void configure( String propFile ) throws CacheException
+ {
+ log.info( "Creating cache manager from config file: {0}", propFile );
+
+ Properties props = new Properties();
+
+ try (InputStream is = getClass().getResourceAsStream( propFile ))
+ {
+ props.load( is );
+ log.debug( "File [{0}] contained {1} properties", () -> propFile, () -> props.size());
+ }
+ catch ( IOException ex )
+ {
+ throw new CacheException("Failed to load properties for name [" + propFile + "]", ex);
+ }
+
+ configure( props );
+ }
+
+ /**
+ * Configure from properties object.
+ * <p>
+ * This method will call configure, instructing it to use system properties as a default.
+ * @param props
+ */
+ public void configure( Properties props )
+ {
+ configure( props, DEFAULT_USE_SYSTEM_PROPERTIES );
+ }
+
+ /**
+ * Configure from properties object, overriding with values from the system properties if
+ * instructed.
+ * <p>
+ * You can override a specific value by passing in a system property:
+ * <p>
+ * For example, you could override this value in the cache.ccf file by starting up your program
+ * with the argument: -Djcs.auxiliary.LTCP.attributes.TcpListenerPort=1111
+ * <p>
+ * @param props
+ * @param useSystemProperties -- if true, values starting with jcs will be put into the props
+ * file prior to configuring the cache.
+ */
+ public void configure( Properties props, boolean useSystemProperties )
+ {
+ configure( props, useSystemProperties, DEFAULT_FORCE_RECONFIGURATION );
+ }
+
+ /**
+ * Configure from properties object, overriding with values from the system properties if
+ * instructed.
+ * <p>
+ * You can override a specific value by passing in a system property:
+ * <p>
+ * For example, you could override this value in the cache.ccf file by starting up your program
+ * with the argument: -Djcs.auxiliary.LTCP.attributes.TcpListenerPort=1111
+ * <p>
+ * @param props
+ * @param useSystemProperties -- if true, values starting with jcs will be put into the props
+ * file prior to configuring the cache.
+ * @param forceReconfiguration - if the manager is already configured, we will try again. This
+ * may not work properly.
+ */
+ public synchronized void configure( Properties props, boolean useSystemProperties, boolean forceReconfiguration )
+ {
+ if ( props == null )
+ {
+ log.error( "No properties found. Please configure the cache correctly." );
+ return;
+ }
+
+ if ( isConfigured )
+ {
+ if ( !forceReconfiguration )
+ {
+ log.debug( "Configure called after the manager has been configured. "
+ + "Force reconfiguration is false. Doing nothing" );
+ return;
+ }
+ else
+ {
+ log.info( "Configure called after the manager has been configured. "
+ + "Force reconfiguration is true. Reconfiguring as best we can." );
+ }
+ }
+ if ( useSystemProperties )
+ {
+ CompositeCacheConfigurator.overrideWithSystemProperties( props );
+ }
+ doConfigure( props );
+ }
+
+ /**
+ * Configure the cache using the supplied properties.
+ * <p>
+ * @param properties assumed not null
+ */
+ private void doConfigure( Properties properties )
+ {
+ // We will expose this for managers that need raw properties.
+ this.configurationProperties = properties;
+
+ // set the props value and then configure the ThreadPoolManager
+ ThreadPoolManager.setProps( properties );
+ ThreadPoolManager poolMgr = ThreadPoolManager.getInstance();
+ log.debug( "ThreadPoolManager = {0}", poolMgr);
+
+ // Create event queue
+ this.elementEventQueue = new ElementEventQueue();
+
+ // configure the cache
+ CompositeCacheConfigurator configurator = newConfigurator();
+
+ ElapsedTimer timer = new ElapsedTimer();
+
+ // set default value list
+ this.defaultAuxValues = OptionConverter.findAndSubst( CompositeCacheManager.DEFAULT_REGION,
+ properties );
+
+ log.info( "Setting default auxiliaries to \"{0}\"", this.defaultAuxValues );
+
+ // set default cache attr
+ this.defaultCacheAttr = configurator.parseCompositeCacheAttributes( properties, "",
+ new CompositeCacheAttributes(), DEFAULT_REGION );
+
+ log.info( "setting defaultCompositeCacheAttributes to {0}", this.defaultCacheAttr );
+
+ // set default element attr
+ this.defaultElementAttr = configurator.parseElementAttributes( properties, "",
+ new ElementAttributes(), DEFAULT_REGION );
+
+ log.info( "setting defaultElementAttributes to {0}", this.defaultElementAttr );
+
+ // set up system caches to be used by non system caches
+ // need to make sure there is no circularity of reference
+ configurator.parseSystemRegions( properties, this );
+
+ // setup preconfigured caches
+ configurator.parseRegions( properties, this );
+
+ log.info( "Finished configuration in {0} ms.", () -> timer.getElapsedTime());
+
+ isConfigured = true;
+ }
+
+ /**
+ * Gets the defaultCacheAttributes attribute of the CacheHub object
+ * <p>
+ * @return The defaultCacheAttributes value
+ */
+ public ICompositeCacheAttributes getDefaultCacheAttributes()
+ {
+ return this.defaultCacheAttr.clone();
+ }
+
+ /**
+ * Gets the defaultElementAttributes attribute of the CacheHub object
+ * <p>
+ * @return The defaultElementAttributes value
+ */
+ public IElementAttributes getDefaultElementAttributes()
+ {
+ return this.defaultElementAttr.clone();
+ }
+
+ /**
+ * Gets the cache attribute of the CacheHub object
+ * <p>
+ * @param cacheName
+ * @return CompositeCache -- the cache region controller
+ */
+ @Override
+ public <K, V> CompositeCache<K, V> getCache( String cacheName )
+ {
+ return getCache( cacheName, getDefaultCacheAttributes() );
+ }
+
+ /**
+ * Gets the cache attribute of the CacheHub object
+ * <p>
+ * @param cacheName
+ * @param cattr
+ * @return CompositeCache
+ */
+ public <K, V> CompositeCache<K, V> getCache( String cacheName, ICompositeCacheAttributes cattr )
+ {
+ cattr.setCacheName( cacheName );
+ return getCache( cattr, getDefaultElementAttributes() );
+ }
+
+ /**
+ * Gets the cache attribute of the CacheHub object
+ * <p>
+ * @param cacheName
+ * @param cattr
+ * @param attr
+ * @return CompositeCache
+ */
+ public <K, V> CompositeCache<K, V> getCache( String cacheName, ICompositeCacheAttributes cattr, IElementAttributes attr )
+ {
+ cattr.setCacheName( cacheName );
+ return getCache( cattr, attr );
+ }
+
+ /**
+ * Gets the cache attribute of the CacheHub object
+ * <p>
+ * @param cattr
+ * @return CompositeCache
+ */
+ public <K, V> CompositeCache<K, V> getCache( ICompositeCacheAttributes cattr )
+ {
+ return getCache( cattr, getDefaultElementAttributes() );
+ }
+
+ /**
+ * If the cache has already been created, then the CacheAttributes and the element Attributes
+ * will be ignored. Currently there is no overriding the CacheAttributes once it is set up. You
+ * can change the default ElementAttributes for a region later.
+ * <p>
+ * Overriding the default elemental attributes will require changing the way the attributes are
+ * assigned to elements. Get cache creates a cache with defaults if none are specified. We might
+ * want to create separate method for creating/getting. . .
+ * <p>
+ * @param cattr
+ * @param attr
+ * @return CompositeCache
+ */
+ @SuppressWarnings("unchecked") // Need to cast because of common map for all caches
+ public <K, V> CompositeCache<K, V> getCache( ICompositeCacheAttributes cattr, IElementAttributes attr )
+ {
+ log.debug( "attr = {0}", attr );
+
+ CompositeCache<K, V> cache = (CompositeCache<K, V>) caches.computeIfAbsent(cattr.getCacheName(),
+ cacheName -> {
+ CompositeCacheConfigurator configurator = newConfigurator();
+ return configurator.parseRegion( this.getConfigurationProperties(), this, cacheName,
+ this.defaultAuxValues, cattr );
+ });
+
+ return cache;
+ }
+
+ protected CompositeCacheConfigurator newConfigurator() {
+ return new CompositeCacheConfigurator();
+ }
+
+ /**
+ * @param name
+ */
+ public void freeCache( String name )
+ {
+ freeCache( name, false );
+ }
+
+ /**
+ * @param name
+ * @param fromRemote
+ */
+ public void freeCache( String name, boolean fromRemote )
+ {
+ CompositeCache<?, ?> cache = (CompositeCache<?, ?>) caches.remove( name );
+
+ if ( cache != null )
+ {
+ cache.dispose( fromRemote );
+ }
+ }
+
+ /**
+ * Calls freeCache on all regions
+ */
+ public void shutDown()
+ {
+ synchronized (CompositeCacheManager.class)
+ {
+ // shutdown element event queue
+ if (this.elementEventQueue != null)
+ {
+ this.elementEventQueue.dispose();
+ }
+
+ // shutdown all scheduled jobs
+ this.scheduledExecutor.shutdownNow();
+
+ // shutdown all thread pools
+ ThreadPoolManager.dispose();
+
+ // notify any observers
+ IShutdownObserver observer = null;
+ while ((observer = shutdownObservers.poll()) != null)
+ {
+ observer.shutdown();
+ }
+
+ // Unregister JMX bean
+ if (isJMXRegistered)
+ {
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ try
+ {
+ ObjectName jmxObjectName = new ObjectName(jmxName);
+ mbs.unregisterMBean(jmxObjectName);
+ }
+ catch (Exception e)
+ {
+ log.warn( "Could not unregister JMX bean.", e );
+ }
+
+ isJMXRegistered = false;
+ }
+
+ // do the traditional shutdown of the regions.
+ getCacheNames().forEach(this::freeCache);
+
+ // shut down auxiliaries
+ for (String key : auxiliaryCaches.keySet())
+ {
+ try
+ {
+ freeAuxiliaryCache(key);
+ }
+ catch (IOException e)
+ {
+ log.warn("Auxiliary cache {0} failed to shut down", key, e);
+ }
+ }
+
+ // shut down factories
+ auxiliaryFactoryRegistry.values().forEach(AuxiliaryCacheFactory::dispose);
+
+ auxiliaryAttributeRegistry.clear();
+ auxiliaryFactoryRegistry.clear();
+
+ if (shutdownHook != null)
+ {
+ try
+ {
+ Runtime.getRuntime().removeShutdownHook(shutdownHook);
+ }
+ catch (IllegalStateException e)
+ {
+ // May fail if the JVM is already shutting down
+ }
+
+ this.shutdownHook = null;
+ }
+
+ isConfigured = false;
+ isInitialized = false;
+ }
+ }
+
+ /** */
+ public void release()
+ {
+ release( false );
+ }
+
+ /**
+ * @param fromRemote
+ */
+ private void release( boolean fromRemote )
+ {
+ synchronized ( CompositeCacheManager.class )
+ {
+ // Wait until called by the last client
+ if ( clients.decrementAndGet() > 0 )
+ {
+ log.debug( "Release called, but {0} remain", clients);
+ return;
+ }
+
+ log.debug( "Last client called release. There are {0} caches which will be disposed",
+ () -> caches.size());
+
+ caches.values().stream()
+ .filter(cache -> cache != null)
+ .forEach(cache -> {
+ ((CompositeCache<?, ?>)cache).dispose( fromRemote );
+ });
+ }
+ }
+
+ /**
+ * Returns a list of the current cache names.
+ * @return Set<String>
+ */
+ public Set<String> getCacheNames()
+ {
+ return caches.keySet();
+ }
+
+ /**
+ * @return ICacheType.CACHE_HUB
+ */
+ public CacheType getCacheType()
+ {
+ return CacheType.CACHE_HUB;
+ }
+
+ /**
+ * @param auxFac
+ */
+ public void registryFacPut( AuxiliaryCacheFactory auxFac )
+ {
+ auxiliaryFactoryRegistry.put( auxFac.getName(), auxFac );
+ }
+
+ /**
+ * @param name
+ * @return AuxiliaryCacheFactory
+ */
+ public AuxiliaryCacheFactory registryFacGet( String name )
+ {
+ return auxiliaryFactoryRegistry.get( name );
+ }
+
+ /**
+ * @param auxAttr
+ */
+ public void registryAttrPut( AuxiliaryCacheAttributes auxAttr )
+ {
+ auxiliaryAttributeRegistry.put( auxAttr.getName(), auxAttr );
+ }
+
+ /**
+ * @param name
+ * @return AuxiliaryCacheAttributes
+ */
+ public AuxiliaryCacheAttributes registryAttrGet( String name )
+ {
+ return auxiliaryAttributeRegistry.get( name );
+ }
+
+ /**
+ * Add a cache to the map of registered caches
+ *
+ * @param cacheName the region name
+ * @param cache the cache instance
+ */
+ public void addCache(String cacheName, ICache<?, ?> cache)
+ {
+ caches.put(cacheName, cache);
+ }
+
+ /**
+ * Add a cache to the map of registered auxiliary caches
+ *
+ * @param auxName the auxiliary name
+ * @param cacheName the region name
+ * @param cache the cache instance
+ */
+ public void addAuxiliaryCache(String auxName, String cacheName, AuxiliaryCache<?, ?> cache)
+ {
+ String key = String.format("aux.%s.region.%s", auxName, cacheName);
+ auxiliaryCaches.put(key, cache);
+ }
+
+ /**
+ * Get a cache from the map of registered auxiliary caches
+ *
+ * @param auxName the auxiliary name
+ * @param cacheName the region name
+ *
+ * @return the cache instance
+ */
+ @Override
+ @SuppressWarnings("unchecked") // because of common map for all auxiliary caches
+ public <K, V> AuxiliaryCache<K, V> getAuxiliaryCache(String auxName, String cacheName)
+ {
+ String key = String.format("aux.%s.region.%s", auxName, cacheName);
+ return (AuxiliaryCache<K, V>) auxiliaryCaches.get(key);
+ }
+
+ /**
+ * Dispose a cache and remove it from the map of registered auxiliary caches
+ *
+ * @param auxName the auxiliary name
+ * @param cacheName the region name
+ * @throws IOException if disposing of the cache fails
+ */
+ public void freeAuxiliaryCache(String auxName, String cacheName) throws IOException
+ {
+ String key = String.format("aux.%s.region.%s", auxName, cacheName);
+ freeAuxiliaryCache(key);
+ }
+
+ /**
+ * Dispose a cache and remove it from the map of registered auxiliary caches
+ *
+ * @param key the key into the map of auxiliaries
+ * @throws IOException if disposing of the cache fails
+ */
+ public void freeAuxiliaryCache(String key) throws IOException
+ {
+ AuxiliaryCache<?, ?> aux = auxiliaryCaches.remove( key );
+
+ if ( aux != null )
+ {
+ aux.dispose();
+ }
+ }
+
+ /**
+ * Gets stats for debugging. This calls gets statistics and then puts all the results in a
+ * string. This returns data for all regions.
+ * <p>
+ * @return String
+ */
+ @Override
+ public String getStats()
+ {
+ ICacheStats[] stats = getStatistics();
+ if ( stats == null )
+ {
+ return "NONE";
+ }
+
+ // force the array elements into a string.
+ StringBuilder buf = new StringBuilder();
+ Arrays.stream(stats).forEach(stat -> {
+ buf.append( "\n---------------------------\n" );
+ buf.append( stat );
+ });
+ return buf.toString();
+ }
+
+ /**
+ * This returns data gathered for all regions and all the auxiliaries they currently uses.
+ * <p>
+ * @return ICacheStats[]
+ */
+ public ICacheStats[] getStatistics()
+ {
+ List<ICacheStats> cacheStats = caches.values().stream()
+ .filter(cache -> cache != null)
+ .map(cache -> ((CompositeCache<?, ?>)cache).getStatistics() )
+ .collect(Collectors.toList());
+
+ return cacheStats.toArray( new CacheStats[0] );
+ }
+
+ /**
+ * Perhaps the composite cache itself should be the observable object. It doesn't make much of a
+ * difference. There are some problems with region by region shutdown. Some auxiliaries are
+ * global. They will need to track when every region has shutdown before doing things like
+ * closing the socket with a lateral.
+ * <p>
+ * @param observer
+ */
+ @Override
+ public void registerShutdownObserver( IShutdownObserver observer )
+ {
+ if (!shutdownObservers.contains(observer))
+ {
+ shutdownObservers.push( observer );
+ }
+ else
+ {
+ log.warn("Shutdown observer added twice {0}", observer);
+ }
+ }
+
+ /**
+ * @param observer
+ */
+ @Override
+ public void deregisterShutdownObserver( IShutdownObserver observer )
+ {
+ shutdownObservers.remove( observer );
+ }
+
+ /**
+ * This is exposed so other manager can get access to the props.
+ * <p>
+ * @return the configurationProperties
+ */
+ @Override
+ public Properties getConfigurationProperties()
+ {
+ return configurationProperties;
+ }
+
+ /**
+ * @return the isInitialized
+ */
+ public boolean isInitialized()
+ {
+ return isInitialized;
+ }
+
+ /**
+ * @return the isConfigured
+ */
+ public boolean isConfigured()
+ {
+ return isConfigured;
+ }
+
+ public void setJmxName(final String name)
+ {
+ if (isJMXRegistered)
+ {
+ throw new IllegalStateException("Too late, MBean registration is done");
+ }
+ jmxName = name;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/event/ElementEvent.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/event/ElementEvent.java
new file mode 100644
index 0000000..a53d985
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/event/ElementEvent.java
@@ -0,0 +1,74 @@
+package org.apache.commons.jcs3.engine.control.event;
+
+/*
+ * 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.
+ */
+
+import java.util.EventObject;
+
+import org.apache.commons.jcs3.engine.control.event.behavior.ElementEventType;
+import org.apache.commons.jcs3.engine.control.event.behavior.IElementEvent;
+
+/**
+ * Element events will trigger the creation of Element Event objects. This is a wrapper around the
+ * cache element that indicates the event triggered.
+ */
+public class ElementEvent<T>
+ extends EventObject
+ implements IElementEvent<T>
+{
+ /** Don't change */
+ private static final long serialVersionUID = -5364117411457467056L;
+
+ /** default event code */
+ private ElementEventType elementEvent = ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND;
+
+ /**
+ * Constructor for the ElementEvent object
+ * <p>
+ * @param source The Cache Element
+ * @param elementEvent The event id defined in the enum class.
+ */
+ public ElementEvent( T source, ElementEventType elementEvent )
+ {
+ super( source );
+ this.elementEvent = elementEvent;
+ }
+
+ /**
+ * Gets the elementEvent attribute of the ElementEvent object
+ * <p>
+ * @return The elementEvent value. The List of values is defined in ElementEventType.
+ */
+ @Override
+ public ElementEventType getElementEvent()
+ {
+ return elementEvent;
+ }
+
+ /**
+ * @return the source of the event.
+ */
+ @SuppressWarnings("unchecked") // Generified
+ @Override
+ public T getSource()
+ {
+ return (T) super.getSource();
+
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/event/ElementEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/event/ElementEventQueue.java
new file mode 100644
index 0000000..fdf2fa5
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/event/ElementEventQueue.java
@@ -0,0 +1,184 @@
+package org.apache.commons.jcs3.engine.control.event;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.concurrent.ExecutorService;
+
+import org.apache.commons.jcs3.engine.control.event.behavior.IElementEvent;
+import org.apache.commons.jcs3.engine.control.event.behavior.IElementEventHandler;
+import org.apache.commons.jcs3.engine.control.event.behavior.IElementEventQueue;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.threadpool.PoolConfiguration;
+import org.apache.commons.jcs3.utils.threadpool.ThreadPoolManager;
+import org.apache.commons.jcs3.utils.threadpool.PoolConfiguration.WhenBlockedPolicy;
+
+/**
+ * An event queue is used to propagate ordered cache events to one and only one target listener.
+ */
+public class ElementEventQueue
+ implements IElementEventQueue
+{
+ private static final String THREAD_PREFIX = "JCS-ElementEventQueue-";
+
+ /** The logger */
+ private static final Log log = LogManager.getLog( ElementEventQueue.class );
+
+ /** shutdown or not */
+ private boolean destroyed = false;
+
+ /** The worker thread pool. */
+ private ExecutorService queueProcessor;
+
+ /**
+ * Constructor for the ElementEventQueue object
+ */
+ public ElementEventQueue()
+ {
+ queueProcessor = ThreadPoolManager.getInstance().createPool(
+ new PoolConfiguration(false, 0, 1, 1, 0, WhenBlockedPolicy.RUN, 1), THREAD_PREFIX);
+
+ log.debug( "Constructed: {0}", this );
+ }
+
+ /**
+ * Dispose queue
+ */
+ @Override
+ public void dispose()
+ {
+ if ( !destroyed )
+ {
+ destroyed = true;
+
+ // synchronize on queue so the thread will not wait forever,
+ // and then interrupt the QueueProcessor
+ queueProcessor.shutdownNow();
+ queueProcessor = null;
+
+ log.info( "Element event queue destroyed: {0}", this );
+ }
+ }
+
+ /**
+ * Adds an ElementEvent to be handled
+ * @param hand The IElementEventHandler
+ * @param event The IElementEventHandler IElementEvent event
+ * @throws IOException
+ */
+ @Override
+ public <T> void addElementEvent( IElementEventHandler hand, IElementEvent<T> event )
+ throws IOException
+ {
+
+ log.debug( "Adding Event Handler to QUEUE, !destroyed = {0}", !destroyed );
+
+ if (destroyed)
+ {
+ log.warn("Event submitted to disposed element event queue {0}", event);
+ }
+ else
+ {
+ ElementEventRunner runner = new ElementEventRunner( hand, event );
+
+ log.debug( "runner = {0}", runner );
+
+ queueProcessor.execute(runner);
+ }
+ }
+
+ // /////////////////////////// Inner classes /////////////////////////////
+
+ /**
+ * Retries before declaring failure.
+ */
+ protected abstract class AbstractElementEventRunner
+ implements Runnable
+ {
+ /**
+ * Main processing method for the AbstractElementEvent object
+ */
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public void run()
+ {
+ try
+ {
+ doRun();
+ // happy and done.
+ }
+ catch ( IOException e )
+ {
+ // Too bad. The handler has problems.
+ log.warn( "Giving up element event handling {0}", ElementEventQueue.this, e );
+ }
+ }
+
+ /**
+ * This will do the work or trigger the work to be done.
+ * <p>
+ * @throws IOException
+ */
+ protected abstract void doRun()
+ throws IOException;
+ }
+
+ /**
+ * ElementEventRunner.
+ */
+ private class ElementEventRunner
+ extends AbstractElementEventRunner
+ {
+ /** the handler */
+ private final IElementEventHandler hand;
+
+ /** event */
+ private final IElementEvent<?> event;
+
+ /**
+ * Constructor for the PutEvent object.
+ * <p>
+ * @param hand
+ * @param event
+ * @throws IOException
+ */
+ @SuppressWarnings("synthetic-access")
+ ElementEventRunner( IElementEventHandler hand, IElementEvent<?> event )
+ throws IOException
+ {
+ log.debug( "Constructing {0}", this );
+ this.hand = hand;
+ this.event = event;
+ }
+
+ /**
+ * Tells the handler to handle the event.
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ protected void doRun()
+ throws IOException
+ {
+ hand.handleElementEvent( event );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/event/behavior/ElementEventType.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/event/behavior/ElementEventType.java
new file mode 100644
index 0000000..69b32f4
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/event/behavior/ElementEventType.java
@@ -0,0 +1,54 @@
+package org.apache.commons.jcs3.engine.control.event.behavior;
+
+/*
+ * 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.
+ */
+
+/**
+ * This describes the events that an item can encounter.
+ */
+public enum ElementEventType
+{
+ /** Background expiration */
+ EXCEEDED_MAXLIFE_BACKGROUND,
+
+ /*** Expiration discovered on request */
+ EXCEEDED_MAXLIFE_ONREQUEST,
+
+ /** Background expiration */
+ EXCEEDED_IDLETIME_BACKGROUND,
+
+ /** Expiration discovered on request */
+ EXCEEDED_IDLETIME_ONREQUEST,
+
+ /** Moving from memory to disk (what if no disk?) */
+ SPOOLED_DISK_AVAILABLE,
+
+ /** Moving from memory to disk (what if no disk?) */
+ SPOOLED_DISK_NOT_AVAILABLE,
+
+ /** Moving from memory to disk, but item is not spoolable */
+ SPOOLED_NOT_ALLOWED //,
+
+ /** Removed actively by a remove command. (Could distinguish between local and remote) */
+ //REMOVED,
+ /**
+ * Element was requested from cache. Not sure we ever want to implement this.
+ */
+ //GET
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/event/behavior/IElementEvent.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/event/behavior/IElementEvent.java
new file mode 100644
index 0000000..8dde606
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/event/behavior/IElementEvent.java
@@ -0,0 +1,42 @@
+package org.apache.commons.jcs3.engine.control.event.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+
+/**
+ * Defines how an element event object should behave.
+ */
+public interface IElementEvent<T>
+ extends Serializable
+{
+ /**
+ * Gets the elementEvent attribute of the IElementEvent object. This code is Contained in the
+ * IElememtEventConstants class.
+ *<p>
+ * @return The elementEvent value
+ */
+ ElementEventType getElementEvent();
+
+ /**
+ * @return the source of the event.
+ */
+ T getSource();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/event/behavior/IElementEventHandler.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/event/behavior/IElementEventHandler.java
new file mode 100644
index 0000000..00d426b
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/event/behavior/IElementEventHandler.java
@@ -0,0 +1,40 @@
+package org.apache.commons.jcs3.engine.control.event.behavior;
+
+/*
+ * 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.
+ */
+
+/**
+ * This interface defines the behavior for event handler. Event handlers are
+ * transient. They are not replicated and are not written to disk.
+ * <p>
+ * If you want an event handler by default for all elements in a region, then
+ * you can add it to the default element attributes. This way it will get created
+ * whenever an item gets put into the cache.
+ *
+ */
+public interface IElementEventHandler
+{
+ /**
+ * Handle events for this element. The events are typed.
+ *
+ * @param event
+ * The event created by the cache.
+ */
+ <T> void handleElementEvent( IElementEvent<T> event );
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/event/behavior/IElementEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/event/behavior/IElementEventQueue.java
new file mode 100644
index 0000000..0a25011
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/event/behavior/IElementEventQueue.java
@@ -0,0 +1,48 @@
+package org.apache.commons.jcs3.engine.control.event.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+/**
+ * Interface for an element event queue. An event queue is used to propagate
+ * ordered element events in one region.
+ *
+ */
+public interface IElementEventQueue
+{
+ /**
+ * Adds an ElementEvent to be handled
+ *
+ * @param hand
+ * The IElementEventHandler
+ * @param event
+ * The IElementEventHandler IElementEvent event
+ * @throws IOException
+ */
+ <T> void addElementEvent( IElementEventHandler hand, IElementEvent<T> event )
+ throws IOException;
+
+ /**
+ * Destroy the event queue
+ *
+ */
+ void dispose();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/group/GroupAttrName.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/group/GroupAttrName.java
new file mode 100644
index 0000000..9b69faf
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/group/GroupAttrName.java
@@ -0,0 +1,117 @@
+package org.apache.commons.jcs3.engine.control.group;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+
+/**
+ * Description of the Class
+ */
+public class GroupAttrName<T>
+ implements Serializable
+{
+ /** Don't change */
+ private static final long serialVersionUID = 1586079686300744198L;
+
+ /** Description of the Field */
+ public final GroupId groupId;
+
+ /** the name of the attribute */
+ public final T attrName;
+
+ /** Cached toString value */
+ private String toString;
+
+ /**
+ * Constructor for the GroupAttrName object
+ * @param groupId
+ * @param attrName
+ */
+ public GroupAttrName( GroupId groupId, T attrName )
+ {
+ this.groupId = groupId;
+ this.attrName = attrName;
+
+ if ( groupId == null )
+ {
+ throw new IllegalArgumentException( "groupId must not be null." );
+ }
+ }
+
+ /**
+ * Tests object equality.
+ * @param obj The <code>GroupAttrName</code> instance to test.
+ * @return Whether equal.
+ */
+ @Override
+ public boolean equals( Object obj )
+ {
+ if ( obj == null || !( obj instanceof GroupAttrName ) )
+ {
+ return false;
+ }
+ GroupAttrName<?> to = (GroupAttrName<?>) obj;
+
+ if (groupId.equals( to.groupId ))
+ {
+ if (attrName == null && to.attrName == null)
+ {
+ return true;
+ }
+ else if (attrName == null || to.attrName == null)
+ {
+ return false;
+ }
+
+ return attrName.equals( to.attrName );
+ }
+
+ return false;
+ }
+
+ /**
+ * @return A hash code based on the hash code of @ #groupid} and {@link #attrName}.
+ */
+ @Override
+ public int hashCode()
+ {
+ if (attrName == null)
+ {
+ return groupId.hashCode();
+ }
+
+ return groupId.hashCode() ^ attrName.hashCode();
+ }
+
+ /**
+ * @return the cached value.
+ */
+ @Override
+ public String toString()
+ {
+ if ( toString == null )
+ {
+ toString = "[GAN: groupId=" + groupId + ", attrName=" + attrName + "]";
+ }
+
+ return toString;
+ }
+
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/group/GroupId.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/group/GroupId.java
new file mode 100644
index 0000000..7decea7
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/group/GroupId.java
@@ -0,0 +1,103 @@
+package org.apache.commons.jcs3.engine.control.group;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+
+/**
+ * Used to avoid name conflict when group cache items are mixed with non-group cache items in the
+ * same cache.
+ */
+public class GroupId
+ implements Serializable
+{
+ /** Don't change. */
+ private static final long serialVersionUID = 4626368486444860133L;
+
+ /** Description of the Field */
+ public final String groupName;
+
+ /** the name of the region. */
+ public final String cacheName;
+
+ /** Cached toString value. */
+ private String toString;
+
+ /**
+ * Constructor for the GroupId object
+ * <p>
+ * @param cacheName
+ * @param groupName
+ */
+ public GroupId( String cacheName, String groupName )
+ {
+ this.cacheName = cacheName;
+ this.groupName = groupName;
+
+ if ( cacheName == null )
+ {
+ throw new IllegalArgumentException( "cacheName must not be null." );
+ }
+ if ( groupName == null )
+ {
+ throw new IllegalArgumentException( "groupName must not be null." );
+ }
+ }
+
+ /**
+ * @param obj
+ * @return cacheName.equals( g.cacheName ) &&groupName.equals( g.groupName );
+ */
+ @Override
+ public boolean equals( Object obj )
+ {
+ if ( obj == null || !( obj instanceof GroupId ) )
+ {
+ return false;
+ }
+ GroupId g = (GroupId) obj;
+ return cacheName.equals( g.cacheName ) && groupName.equals( g.groupName );
+ }
+
+ /**
+ * @return cacheName.hashCode() + groupName.hashCode();
+ */
+ @Override
+ public int hashCode()
+ {
+ return cacheName.hashCode() + groupName.hashCode();
+ }
+
+ /**
+ * Caches the value.
+ * <p>
+ * @return debugging string.
+ */
+ @Override
+ public String toString()
+ {
+ if ( toString == null )
+ {
+ toString = "[groupId=" + cacheName + ", " + groupName + ']';
+ }
+
+ return toString;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/package.html b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/package.html
similarity index 100%
rename from commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/package.html
rename to commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/control/package.html
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/logging/CacheEvent.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/logging/CacheEvent.java
new file mode 100644
index 0000000..16d011a
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/logging/CacheEvent.java
@@ -0,0 +1,177 @@
+package org.apache.commons.jcs3.engine.logging;
+
+/*
+ * 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.
+ */
+
+import java.util.Date;
+
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEvent;
+
+/** It's returned from create and passed into log. */
+public class CacheEvent<K>
+ implements ICacheEvent<K>
+{
+ /** Don't change. */
+ private static final long serialVersionUID = -5913139566421714330L;
+
+ /** The time at which this object was created. */
+ private final long createTime = System.currentTimeMillis();
+
+ /** The auxiliary or other source of the event. */
+ private String source;
+
+ /** The cache region */
+ private String region;
+
+ /** The event name: update, get, remove, etc. */
+ private String eventName;
+
+ /** disk location, ip, etc. */
+ private String optionalDetails;
+
+ /** The key that was put or retrieved. */
+ private K key;
+
+ /**
+ * @param source the source to set
+ */
+ @Override
+ public void setSource( String source )
+ {
+ this.source = source;
+ }
+
+ /**
+ * @return the source
+ */
+ @Override
+ public String getSource()
+ {
+ return source;
+ }
+
+ /**
+ * @param region the region to set
+ */
+ @Override
+ public void setRegion( String region )
+ {
+ this.region = region;
+ }
+
+ /**
+ * @return the region
+ */
+ @Override
+ public String getRegion()
+ {
+ return region;
+ }
+
+ /**
+ * @param eventName the eventName to set
+ */
+ @Override
+ public void setEventName( String eventName )
+ {
+ this.eventName = eventName;
+ }
+
+ /**
+ * @return the eventName
+ */
+ @Override
+ public String getEventName()
+ {
+ return eventName;
+ }
+
+ /**
+ * @param optionalDetails the optionalDetails to set
+ */
+ @Override
+ public void setOptionalDetails( String optionalDetails )
+ {
+ this.optionalDetails = optionalDetails;
+ }
+
+ /**
+ * @return the optionalDetails
+ */
+ @Override
+ public String getOptionalDetails()
+ {
+ return optionalDetails;
+ }
+
+ /**
+ * @param key the key to set
+ */
+ @Override
+ public void setKey( K key )
+ {
+ this.key = key;
+ }
+
+ /**
+ * @return the key
+ */
+ @Override
+ public K getKey()
+ {
+ return key;
+ }
+
+ /**
+ * The time at which this object was created.
+ * <p>
+ * @return the createTime
+ */
+ public long getCreateTime()
+ {
+ return createTime;
+ }
+
+ /**
+ * @return reflection toString
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append("CacheEvent: ").append(eventName).append(" Created: ").append(new Date(createTime));
+ if (source != null)
+ {
+ sb.append(" Source: ").append(source);
+ }
+ if (region != null)
+ {
+ sb.append(" Region: ").append(region);
+ }
+ if (key != null)
+ {
+ sb.append(" Key: ").append(key);
+ }
+ if (optionalDetails != null)
+ {
+ sb.append(" Details: ").append(optionalDetails);
+ }
+ return sb.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/logging/CacheEventLoggerDebugLogger.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/logging/CacheEventLoggerDebugLogger.java
new file mode 100644
index 0000000..bae2694
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/logging/CacheEventLoggerDebugLogger.java
@@ -0,0 +1,104 @@
+package org.apache.commons.jcs3.engine.logging;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEvent;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This implementation simple logs to a logger at debug level, for all events. It's mainly
+ * for testing. It isn't very useful otherwise.
+ */
+public class CacheEventLoggerDebugLogger
+ implements ICacheEventLogger
+{
+ /** This is the name of the category. */
+ private String logCategoryName = CacheEventLoggerDebugLogger.class.getName();
+
+ /** The logger. This is recreated on set logCategoryName */
+ private Log log = LogManager.getLog( logCategoryName );
+
+ /**
+ * @param source
+ * @param region
+ * @param eventName
+ * @param optionalDetails
+ * @param key
+ * @return ICacheEvent
+ */
+ @Override
+ public <T> ICacheEvent<T> createICacheEvent( String source, String region, String eventName,
+ String optionalDetails, T key )
+ {
+ ICacheEvent<T> event = new CacheEvent<>();
+ event.setSource( source );
+ event.setRegion( region );
+ event.setEventName( eventName );
+ event.setOptionalDetails( optionalDetails );
+ event.setKey( key );
+
+ return event;
+ }
+
+ /**
+ * @param source
+ * @param eventName
+ * @param optionalDetails
+ */
+ @Override
+ public void logApplicationEvent( String source, String eventName, String optionalDetails )
+ {
+ log.debug( "{0} | {1} | {2}", source, eventName, optionalDetails );
+ }
+
+ /**
+ * @param source
+ * @param eventName
+ * @param errorMessage
+ */
+ @Override
+ public void logError( String source, String eventName, String errorMessage )
+ {
+ log.debug( "{0} | {1} | {2}", source, eventName, errorMessage );
+ }
+
+ /**
+ * @param event
+ */
+ @Override
+ public <T> void logICacheEvent( ICacheEvent<T> event )
+ {
+ log.debug( event );
+ }
+
+ /**
+ * @param logCategoryName
+ */
+ public synchronized void setLogCategoryName( String logCategoryName )
+ {
+ if ( logCategoryName != null && !logCategoryName.equals( this.logCategoryName ) )
+ {
+ this.logCategoryName = logCategoryName;
+ log = LogManager.getLog( logCategoryName );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/logging/behavior/ICacheEvent.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/logging/behavior/ICacheEvent.java
new file mode 100644
index 0000000..0a9b018
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/logging/behavior/ICacheEvent.java
@@ -0,0 +1,77 @@
+package org.apache.commons.jcs3.engine.logging.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+
+/** Defines the common fields required by a cache event. */
+public interface ICacheEvent<K>
+ extends Serializable
+{
+ /**
+ * @param source the source to set
+ */
+ void setSource( String source );
+
+ /**
+ * @return the source
+ */
+ String getSource();
+
+ /**
+ * @param region the region to set
+ */
+ void setRegion( String region );
+
+ /**
+ * @return the region
+ */
+ String getRegion();
+
+ /**
+ * @param eventName the eventName to set
+ */
+ void setEventName( String eventName );
+
+ /**
+ * @return the eventName
+ */
+ String getEventName();
+
+ /**
+ * @param optionalDetails the optionalDetails to set
+ */
+ void setOptionalDetails( String optionalDetails );
+
+ /**
+ * @return the optionalDetails
+ */
+ String getOptionalDetails();
+
+ /**
+ * @param key the key to set
+ */
+ void setKey( K key );
+
+ /**
+ * @return the key
+ */
+ K getKey();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/logging/behavior/ICacheEventLogger.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/logging/behavior/ICacheEventLogger.java
new file mode 100644
index 0000000..2a798f9
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/logging/behavior/ICacheEventLogger.java
@@ -0,0 +1,92 @@
+package org.apache.commons.jcs3.engine.logging.behavior;
+
+/*
+ * 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.
+ */
+
+/**
+ * This defines the behavior for event logging. Auxiliaries will send events to injected event
+ * loggers.
+ * <p>
+ * In general all ICache interface methods should call the logger if one is configured. This will be
+ * done on an ad hoc basis for now. Various auxiliaries may have additional events.
+ */
+public interface ICacheEventLogger
+{
+ // TODO: Use enum
+ /** ICache update */
+ String UPDATE_EVENT = "update";
+
+ /** ICache get */
+ String GET_EVENT = "get";
+
+ /** ICache getMultiple */
+ String GETMULTIPLE_EVENT = "getMultiple";
+
+ /** ICache getMatching */
+ String GETMATCHING_EVENT = "getMatching";
+
+ /** ICache remove */
+ String REMOVE_EVENT = "remove";
+
+ /** ICache removeAll */
+ String REMOVEALL_EVENT = "removeAll";
+
+ /** ICache dispose */
+ String DISPOSE_EVENT = "dispose";
+
+ /** ICache enqueue. The time in the queue. */
+ //String ENQUEUE_EVENT = "enqueue";
+ /**
+ * Creates an event.
+ * <p>
+ * @param source - e.g. RemoteCacheServer
+ * @param region - the name of the region
+ * @param eventName - e.g. update, get, put, remove
+ * @param optionalDetails - any extra message
+ * @param key - the cache key
+ * @return ICacheEvent
+ */
+ <T> ICacheEvent<T> createICacheEvent( String source, String region,
+ String eventName, String optionalDetails, T key );
+
+ /**
+ * Logs an event.
+ * <p>
+ * @param event - the event created in createICacheEvent
+ */
+ <T> void logICacheEvent( ICacheEvent<T> event );
+
+ /**
+ * Logs an event. These are internal application events that do not correspond to ICache calls.
+ * <p>
+ * @param source - e.g. RemoteCacheServer
+ * @param eventName - e.g. update, get, put, remove
+ * @param optionalDetails - any extra message
+ */
+ void logApplicationEvent( String source, String eventName, String optionalDetails );
+
+ /**
+ * Logs an error.
+ * <p>
+ * @param source - e.g. RemoteCacheServer
+ * @param eventName - e.g. update, get, put, remove
+ * @param errorMessage - any error message
+ */
+ void logError( String source, String eventName, String errorMessage );
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/match/KeyMatcherPatternImpl.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/match/KeyMatcherPatternImpl.java
new file mode 100644
index 0000000..33bdb16
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/match/KeyMatcherPatternImpl.java
@@ -0,0 +1,51 @@
+package org.apache.commons.jcs3.engine.match;
+
+/*
+ * 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.
+ */
+
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import org.apache.commons.jcs3.engine.match.behavior.IKeyMatcher;
+
+/** This implementation of the KeyMatcher uses standard Java Pattern matching. */
+public class KeyMatcherPatternImpl<K>
+ implements IKeyMatcher<K>
+{
+ /** Serial version */
+ private static final long serialVersionUID = 6667352064144381264L;
+
+ /**
+ * Creates a pattern and find matches on the array.
+ * <p>
+ * @param pattern
+ * @param keyArray
+ * @return Set of the matching keys
+ */
+ @Override
+ public Set<K> getMatchingKeysFromArray( String pattern, Set<K> keyArray )
+ {
+ Pattern compiledPattern = Pattern.compile( pattern );
+
+ return keyArray.stream()
+ .filter(key -> compiledPattern.matcher(key.toString()).matches())
+ .collect(Collectors.toSet());
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/match/behavior/IKeyMatcher.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/match/behavior/IKeyMatcher.java
new file mode 100644
index 0000000..34619d1
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/match/behavior/IKeyMatcher.java
@@ -0,0 +1,36 @@
+package org.apache.commons.jcs3.engine.match.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+import java.util.Set;
+
+/** Key matchers need to implement this interface. */
+public interface IKeyMatcher<K> extends Serializable
+{
+ /**
+ * Creates a pattern and find matches on the array.
+ * <p>
+ * @param pattern
+ * @param keyArray
+ * @return Set of the matching keys
+ */
+ Set<K> getMatchingKeysFromArray( String pattern, Set<K> keyArray );
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/AbstractDoubleLinkedListMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/AbstractDoubleLinkedListMemoryCache.java
new file mode 100644
index 0000000..55479c5
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/AbstractDoubleLinkedListMemoryCache.java
@@ -0,0 +1,526 @@
+package org.apache.commons.jcs3.engine.memory;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.control.group.GroupAttrName;
+import org.apache.commons.jcs3.engine.memory.util.MemoryElementDescriptor;
+import org.apache.commons.jcs3.engine.stats.StatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.struct.DoubleLinkedList;
+
+/**
+ * This class contains methods that are common to memory caches using the double linked list, such
+ * as the LRU, MRU, FIFO, and LIFO caches.
+ * <p>
+ * Children can control the expiration algorithm by controlling the update and get. The last item in the list will be the one
+ * removed when the list fills. For instance LRU should more items to the front as they are used. FIFO should simply add new items
+ * to the front of the list.
+ */
+public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends AbstractMemoryCache<K, V>
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog(AbstractDoubleLinkedListMemoryCache.class);
+
+ /** thread-safe double linked list for lru */
+ protected DoubleLinkedList<MemoryElementDescriptor<K, V>> list; // TODO privatise
+
+ /**
+ * For post reflection creation initialization.
+ * <p>
+ *
+ * @param hub
+ */
+ @Override
+ public void initialize(CompositeCache<K, V> hub)
+ {
+ super.initialize(hub);
+ list = new DoubleLinkedList<>();
+ log.info("initialized MemoryCache for {0}", () -> getCacheName());
+ }
+
+ /**
+ * This is called by super initialize.
+ *
+ * NOTE: should return a thread safe map
+ *
+ * <p>
+ *
+ * @return new ConcurrentHashMap()
+ */
+ @Override
+ public ConcurrentMap<K, MemoryElementDescriptor<K, V>> createMap()
+ {
+ return new ConcurrentHashMap<>();
+ }
+
+ /**
+ * Calls the abstract method updateList.
+ * <p>
+ * If the max size is reached, an element will be put to disk.
+ * <p>
+ *
+ * @param ce
+ * The cache element, or entry wrapper
+ * @throws IOException
+ */
+ @Override
+ public final void update(ICacheElement<K, V> ce) throws IOException
+ {
+ putCnt.incrementAndGet();
+
+ lock.lock();
+ try
+ {
+ MemoryElementDescriptor<K, V> newNode = adjustListForUpdate(ce);
+
+ // this should be synchronized if we were not using a ConcurrentHashMap
+ final K key = newNode.getCacheElement().getKey();
+ MemoryElementDescriptor<K, V> oldNode = map.put(key, newNode);
+
+ // If the node was the same as an existing node, remove it.
+ if (oldNode != null && key.equals(oldNode.getCacheElement().getKey()))
+ {
+ list.remove(oldNode);
+ }
+ }
+ finally
+ {
+ lock.unlock();
+ }
+
+ // If we are over the max spool some
+ spoolIfNeeded();
+ }
+
+ /**
+ * Children implement this to control the cache expiration algorithm
+ * <p>
+ *
+ * @param ce
+ * @return MemoryElementDescriptor the new node
+ * @throws IOException
+ */
+ protected abstract MemoryElementDescriptor<K, V> adjustListForUpdate(ICacheElement<K, V> ce) throws IOException;
+
+ /**
+ * If the max size has been reached, spool.
+ * <p>
+ *
+ * @throws Error
+ */
+ private void spoolIfNeeded() throws Error
+ {
+ int size = map.size();
+ // If the element limit is reached, we need to spool
+
+ if (size <= this.getCacheAttributes().getMaxObjects())
+ {
+ return;
+ }
+
+ log.debug("In memory limit reached, spooling");
+
+ // Write the last 'chunkSize' items to disk.
+ int chunkSizeCorrected = Math.min(size, chunkSize);
+
+ log.debug("About to spool to disk cache, map size: {0}, max objects: {1}, "
+ + "maximum items to spool: {2}", () -> size,
+ () -> this.getCacheAttributes().getMaxObjects(),
+ () -> chunkSizeCorrected);
+
+ // The spool will put them in a disk event queue, so there is no
+ // need to pre-queue the queuing. This would be a bit wasteful
+ // and wouldn't save much time in this synchronous call.
+ lock.lock();
+
+ try
+ {
+ for (int i = 0; i < chunkSizeCorrected; i++)
+ {
+ ICacheElement<K, V> lastElement = spoolLastElement();
+ if (lastElement == null)
+ {
+ break;
+ }
+ }
+
+ // If this is out of the sync block it can detect a mismatch
+ // where there is none.
+ if (log.isDebugEnabled() && map.size() != list.size())
+ {
+ log.debug("update: After spool, size mismatch: map.size() = {0}, "
+ + "linked list size = {1}", map.size(), list.size());
+ }
+ }
+ finally
+ {
+ lock.unlock();
+ }
+
+ log.debug("update: After spool map size: {0} linked list size = {1}",
+ () -> map.size(), () -> list.size());
+ }
+
+ /**
+ * This instructs the memory cache to remove the <i>numberToFree</i> according to its eviction
+ * policy. For example, the LRUMemoryCache will remove the <i>numberToFree</i> least recently
+ * used items. These will be spooled to disk if a disk auxiliary is available.
+ * <p>
+ *
+ * @param numberToFree
+ * @return the number that were removed. if you ask to free 5, but there are only 3, you will
+ * get 3.
+ * @throws IOException
+ */
+ @Override
+ public int freeElements(int numberToFree) throws IOException
+ {
+ int freed = 0;
+
+ lock.lock();
+
+ try
+ {
+ for (; freed < numberToFree; freed++)
+ {
+ ICacheElement<K, V> element = spoolLastElement();
+ if (element == null)
+ {
+ break;
+ }
+ }
+ }
+ finally
+ {
+ lock.unlock();
+ }
+
+ return freed;
+ }
+
+ /**
+ * This spools the last element in the LRU, if one exists.
+ * <p>
+ *
+ * @return ICacheElement<K, V> if there was a last element, else null.
+ * @throws Error
+ */
+ private ICacheElement<K, V> spoolLastElement() throws Error
+ {
+ ICacheElement<K, V> toSpool = null;
+
+ final MemoryElementDescriptor<K, V> last = list.getLast();
+ if (last != null)
+ {
+ toSpool = last.getCacheElement();
+ if (toSpool != null)
+ {
+ getCompositeCache().spoolToDisk(toSpool);
+ if (map.remove(toSpool.getKey()) == null)
+ {
+ log.warn("update: remove failed for key: {0}", toSpool.getKey());
+
+ if (log.isTraceEnabled())
+ {
+ verifyCache();
+ }
+ }
+ }
+ else
+ {
+ throw new Error("update: last.ce is null!");
+ }
+
+ list.remove(last);
+ }
+
+ return toSpool;
+ }
+
+ /**
+ * @see org.apache.commons.jcs3.engine.memory.AbstractMemoryCache#get(java.lang.Object)
+ */
+ @Override
+ public ICacheElement<K, V> get(K key) throws IOException
+ {
+ ICacheElement<K, V> ce = super.get(key);
+
+ if (log.isTraceEnabled())
+ {
+ verifyCache();
+ }
+
+ return ce;
+ }
+
+ /**
+ * Adjust the list as needed for a get. This allows children to control the algorithm
+ * <p>
+ *
+ * @param me
+ */
+ protected abstract void adjustListForGet(MemoryElementDescriptor<K, V> me);
+
+ /**
+ * Update control structures after get
+ * (guarded by the lock)
+ *
+ * @param me the memory element descriptor
+ */
+ @Override
+ protected void lockedGetElement(MemoryElementDescriptor<K, V> me)
+ {
+ adjustListForGet(me);
+ }
+
+ /**
+ * Remove element from control structure
+ * (guarded by the lock)
+ *
+ * @param me the memory element descriptor
+ */
+ @Override
+ protected void lockedRemoveElement(MemoryElementDescriptor<K, V> me)
+ {
+ list.remove(me);
+ }
+
+ /**
+ * Removes all cached items from the cache control structures.
+ * (guarded by the lock)
+ */
+ @Override
+ protected void lockedRemoveAll()
+ {
+ list.removeAll();
+ }
+
+ // --------------------------- internal methods (linked list implementation)
+ /**
+ * Adds a new node to the start of the link list.
+ * <p>
+ *
+ * @param ce
+ * The feature to be added to the First
+ * @return MemoryElementDescriptor
+ */
+ protected MemoryElementDescriptor<K, V> addFirst(ICacheElement<K, V> ce)
+ {
+ lock.lock();
+ try
+ {
+ MemoryElementDescriptor<K, V> me = new MemoryElementDescriptor<>(ce);
+ list.addFirst(me);
+ if ( log.isTraceEnabled() )
+ {
+ verifyCache(ce.getKey());
+ }
+ return me;
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Adds a new node to the end of the link list.
+ * <p>
+ *
+ * @param ce
+ * The feature to be added to the First
+ * @return MemoryElementDescriptor
+ */
+ protected MemoryElementDescriptor<K, V> addLast(ICacheElement<K, V> ce)
+ {
+ lock.lock();
+ try
+ {
+ MemoryElementDescriptor<K, V> me = new MemoryElementDescriptor<>(ce);
+ list.addLast(me);
+ if ( log.isTraceEnabled() )
+ {
+ verifyCache(ce.getKey());
+ }
+ return me;
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+
+ // ---------------------------------------------------------- debug methods
+
+ /**
+ * Dump the cache entries from first to list for debugging.
+ */
+ @SuppressWarnings("unchecked")
+ // No generics for public fields
+ private void dumpCacheEntries()
+ {
+ log.trace("dumpingCacheEntries");
+ for (MemoryElementDescriptor<K, V> me = list.getFirst(); me != null; me = (MemoryElementDescriptor<K, V>) me.next)
+ {
+ log.trace("dumpCacheEntries> key={0}, val={1}",
+ me.getCacheElement().getKey(), me.getCacheElement().getVal());
+ }
+ }
+
+ /**
+ * Checks to see if all the items that should be in the cache are. Checks consistency between
+ * List and map.
+ */
+ @SuppressWarnings("unchecked")
+ // No generics for public fields
+ private void verifyCache()
+ {
+ boolean found = false;
+ log.trace("verifycache[{0}]: map contains {1} elements, linked list "
+ + "contains {2} elements", getCacheName(), map.size(),
+ list.size());
+ log.trace("verifycache: checking linked list by key ");
+ for (MemoryElementDescriptor<K, V> li = list.getFirst(); li != null; li = (MemoryElementDescriptor<K, V>) li.next)
+ {
+ K key = li.getCacheElement().getKey();
+ if (!map.containsKey(key))
+ {
+ log.error("verifycache[{0}]: map does not contain key : {1}",
+ getCacheName(), key);
+ log.error("key class={0}", key.getClass());
+ log.error("key hashcode={0}", key.hashCode());
+ log.error("key toString={0}", key.toString());
+ if (key instanceof GroupAttrName)
+ {
+ GroupAttrName<?> name = (GroupAttrName<?>) key;
+ log.error("GroupID hashcode={0}", name.groupId.hashCode());
+ log.error("GroupID.class={0}", name.groupId.getClass());
+ log.error("AttrName hashcode={0}", name.attrName.hashCode());
+ log.error("AttrName.class={0}", name.attrName.getClass());
+ }
+ dumpMap();
+ }
+ else if (map.get(key) == null)
+ {
+ log.error("verifycache[{0}]: linked list retrieval returned "
+ + "null for key: {1}", getCacheName(), key);
+ }
+ }
+
+ log.trace("verifycache: checking linked list by value ");
+ for (MemoryElementDescriptor<K, V> li = list.getFirst(); li != null; li = (MemoryElementDescriptor<K, V>) li.next)
+ {
+ if (!map.containsValue(li))
+ {
+ log.error("verifycache[{0}]: map does not contain value: {1}",
+ getCacheName(), li);
+ dumpMap();
+ }
+ }
+
+ log.trace("verifycache: checking via keysets!");
+ for (Object val : map.keySet())
+ {
+ found = false;
+
+ for (MemoryElementDescriptor<K, V> li = list.getFirst(); li != null; li = (MemoryElementDescriptor<K, V>) li.next)
+ {
+ if (val.equals(li.getCacheElement().getKey()))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ log.error("verifycache[{0}]: key not found in list : {1}",
+ getCacheName(), val);
+ dumpCacheEntries();
+ if (map.containsKey(val))
+ {
+ log.error("verifycache: map contains key");
+ }
+ else
+ {
+ log.error("verifycache: map does NOT contain key, what the HECK!");
+ }
+ }
+ }
+ }
+
+ /**
+ * Logs an error if an element that should be in the cache is not.
+ * <p>
+ *
+ * @param key
+ */
+ @SuppressWarnings("unchecked")
+ // No generics for public fields
+ private void verifyCache(K key)
+ {
+ boolean found = false;
+
+ // go through the linked list looking for the key
+ for (MemoryElementDescriptor<K, V> li = list.getFirst(); li != null; li = (MemoryElementDescriptor<K, V>) li.next)
+ {
+ if (li.getCacheElement().getKey() == key)
+ {
+ found = true;
+ log.trace("verifycache(key) key match: {0}", key);
+ break;
+ }
+ }
+ if (!found)
+ {
+ log.error("verifycache(key)[{0}], couldn't find key! : {1}",
+ getCacheName(), key);
+ }
+ }
+
+ /**
+ * This returns semi-structured information on the memory cache, such as the size, put count,
+ * hit count, and miss count.
+ * <p>
+ *
+ * @see org.apache.commons.jcs3.engine.memory.behavior.IMemoryCache#getStatistics()
+ */
+ @Override
+ public IStats getStatistics()
+ {
+ IStats stats = super.getStatistics();
+ stats.setTypeName( /* add algorithm name */"Memory Cache");
+
+ List<IStatElement<?>> elems = stats.getStatElements();
+
+ elems.add(new StatElement<>("List Size", Integer.valueOf(list.size())));
+
+ return stats;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/AbstractMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/AbstractMemoryCache.java
new file mode 100644
index 0000000..dec6227
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/AbstractMemoryCache.java
@@ -0,0 +1,513 @@
+package org.apache.commons.jcs3.engine.memory;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.stream.Collectors;
+
+import org.apache.commons.jcs3.engine.behavior.ICache;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.control.group.GroupAttrName;
+import org.apache.commons.jcs3.engine.control.group.GroupId;
+import org.apache.commons.jcs3.engine.memory.behavior.IMemoryCache;
+import org.apache.commons.jcs3.engine.memory.util.MemoryElementDescriptor;
+import org.apache.commons.jcs3.engine.stats.StatElement;
+import org.apache.commons.jcs3.engine.stats.Stats;
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This base includes some common code for memory caches.
+ */
+public abstract class AbstractMemoryCache<K, V>
+ implements IMemoryCache<K, V>
+{
+ /** Log instance */
+ private static final Log log = LogManager.getLog( AbstractMemoryCache.class );
+
+ /** Cache Attributes. Regions settings. */
+ private ICompositeCacheAttributes cacheAttributes;
+
+ /** The cache region this store is associated with */
+ private CompositeCache<K, V> cache;
+
+ /** How many to spool at a time. */
+ protected int chunkSize;
+
+ protected final Lock lock = new ReentrantLock();
+
+ /** Map where items are stored by key. This is created by the concrete child class. */
+ protected Map<K, MemoryElementDescriptor<K, V>> map;// TODO privatise
+
+ /** number of hits */
+ protected AtomicLong hitCnt;
+
+ /** number of misses */
+ protected AtomicLong missCnt;
+
+ /** number of puts */
+ protected AtomicLong putCnt;
+
+ /**
+ * For post reflection creation initialization
+ * <p>
+ * @param hub
+ */
+ @Override
+ public void initialize( CompositeCache<K, V> hub )
+ {
+ hitCnt = new AtomicLong(0);
+ missCnt = new AtomicLong(0);
+ putCnt = new AtomicLong(0);
+
+ this.cacheAttributes = hub.getCacheAttributes();
+ this.chunkSize = cacheAttributes.getSpoolChunkSize();
+ this.cache = hub;
+
+ this.map = createMap();
+ }
+
+ /**
+ * Children must implement this method. A FIFO implementation may use a tree map. An LRU might
+ * use a hashtable. The map returned should be threadsafe.
+ * <p>
+ * @return a threadsafe Map
+ */
+ public abstract Map<K, MemoryElementDescriptor<K, V>> createMap();
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
+ throws IOException
+ {
+ if (keys != null)
+ {
+ return keys.stream()
+ .map(key -> {
+ try
+ {
+ return get(key);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ })
+ .filter(element -> element != null)
+ .collect(Collectors.toMap(
+ element -> element.getKey(),
+ element -> element));
+ }
+
+ return new HashMap<>();
+ }
+
+ /**
+ * Get an item from the cache without affecting its last access time or position. Not all memory
+ * cache implementations can get quietly.
+ * <p>
+ * @param key Identifies item to find
+ * @return Element matching key if found, or null
+ * @throws IOException
+ */
+ @Override
+ public ICacheElement<K, V> getQuiet( K key )
+ throws IOException
+ {
+ ICacheElement<K, V> ce = null;
+
+ MemoryElementDescriptor<K, V> me = map.get( key );
+ if ( me != null )
+ {
+ log.debug( "{0}: MemoryCache quiet hit for {1}",
+ () -> getCacheName(), () -> key );
+
+ ce = me.getCacheElement();
+ }
+ else
+ {
+ log.debug( "{0}: MemoryCache quiet miss for {1}",
+ () -> getCacheName(), () -> key );
+ }
+
+ return ce;
+ }
+
+ /**
+ * Puts an item to the cache.
+ * <p>
+ * @param ce Description of the Parameter
+ * @throws IOException Description of the Exception
+ */
+ @Override
+ public abstract void update( ICacheElement<K, V> ce )
+ throws IOException;
+
+ /**
+ * Removes all cached items from the cache.
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ public void removeAll() throws IOException
+ {
+ lock.lock();
+ try
+ {
+ lockedRemoveAll();
+ map.clear();
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Removes all cached items from the cache control structures.
+ * (guarded by the lock)
+ */
+ protected abstract void lockedRemoveAll();
+
+ /**
+ * Prepares for shutdown. Reset statistics
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ public void dispose()
+ throws IOException
+ {
+ removeAll();
+ hitCnt.set(0);
+ missCnt.set(0);
+ putCnt.set(0);
+ log.info( "Memory Cache dispose called." );
+ }
+
+ /**
+ * @return statistics about the cache
+ */
+ @Override
+ public IStats getStatistics()
+ {
+ IStats stats = new Stats();
+ stats.setTypeName( "Abstract Memory Cache" );
+
+ ArrayList<IStatElement<?>> elems = new ArrayList<>();
+ stats.setStatElements(elems);
+
+ elems.add(new StatElement<>("Put Count", putCnt));
+ elems.add(new StatElement<>("Hit Count", hitCnt));
+ elems.add(new StatElement<>("Miss Count", missCnt));
+ elems.add(new StatElement<>( "Map Size", Integer.valueOf(getSize()) ) );
+
+ return stats;
+ }
+
+ /**
+ * Returns the current cache size.
+ * <p>
+ * @return The size value
+ */
+ @Override
+ public int getSize()
+ {
+ return this.map.size();
+ }
+
+ /**
+ * Returns the cache (aka "region") name.
+ * <p>
+ * @return The cacheName value
+ */
+ public String getCacheName()
+ {
+ String attributeCacheName = this.cacheAttributes.getCacheName();
+ if(attributeCacheName != null)
+ {
+ return attributeCacheName;
+ }
+ return cache.getCacheName();
+ }
+
+ /**
+ * Puts an item to the cache.
+ * <p>
+ * @param ce the item
+ */
+ @Override
+ public void waterfal( ICacheElement<K, V> ce )
+ {
+ this.cache.spoolToDisk( ce );
+ }
+
+ // ---------------------------------------------------------- debug method
+ /**
+ * Dump the cache map for debugging.
+ */
+ public void dumpMap()
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("dumpingMap");
+ map.entrySet().forEach(e ->
+ log.trace("dumpMap> key={0}, val={1}", e.getKey(),
+ e.getValue().getCacheElement().getVal()));
+ }
+ }
+
+ /**
+ * Returns the CacheAttributes.
+ * <p>
+ * @return The CacheAttributes value
+ */
+ @Override
+ public ICompositeCacheAttributes getCacheAttributes()
+ {
+ return this.cacheAttributes;
+ }
+
+ /**
+ * Sets the CacheAttributes.
+ * <p>
+ * @param cattr The new CacheAttributes value
+ */
+ @Override
+ public void setCacheAttributes( ICompositeCacheAttributes cattr )
+ {
+ this.cacheAttributes = cattr;
+ }
+
+ /**
+ * Gets the cache hub / region that the MemoryCache is used by
+ * <p>
+ * @return The cache value
+ */
+ @Override
+ public CompositeCache<K, V> getCompositeCache()
+ {
+ return this.cache;
+ }
+
+ /**
+ * Remove all keys of the same group hierarchy.
+ * @param key the key
+ * @return true if something has been removed
+ */
+ protected boolean removeByGroup(K key)
+ {
+ GroupId groupId = ((GroupAttrName<?>) key).groupId;
+
+ // remove all keys of the same group hierarchy.
+ return map.entrySet().removeIf(entry -> {
+ K k = entry.getKey();
+
+ if (k instanceof GroupAttrName && ((GroupAttrName<?>) k).groupId.equals(groupId))
+ {
+ lock.lock();
+ try
+ {
+ lockedRemoveElement(entry.getValue());
+ return true;
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+
+ return false;
+ });
+ }
+
+ /**
+ * Remove all keys of the same name hierarchy.
+ *
+ * @param key the key
+ * @return true if something has been removed
+ */
+ protected boolean removeByHierarchy(K key)
+ {
+ String keyString = key.toString();
+
+ // remove all keys of the same name hierarchy.
+ return map.entrySet().removeIf(entry -> {
+ K k = entry.getKey();
+
+ if (k instanceof String && ((String) k).startsWith(keyString))
+ {
+ lock.lock();
+ try
+ {
+ lockedRemoveElement(entry.getValue());
+ return true;
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+
+ return false;
+ });
+ }
+
+ /**
+ * Remove element from control structure
+ * (guarded by the lock)
+ *
+ * @param me the memory element descriptor
+ */
+ protected abstract void lockedRemoveElement(MemoryElementDescriptor<K, V> me);
+
+ /**
+ * Removes an item from the cache. This method handles hierarchical removal. If the key is a
+ * String and ends with the CacheConstants.NAME_COMPONENT_DELIMITER, then all items with keys
+ * starting with the argument String will be removed.
+ * <p>
+ *
+ * @param key
+ * @return true if the removal was successful
+ * @throws IOException
+ */
+ @Override
+ public boolean remove(K key) throws IOException
+ {
+ log.debug("removing item for key: {0}", key);
+
+ boolean removed = false;
+
+ // handle partial removal
+ if (key instanceof String && ((String) key).endsWith(ICache.NAME_COMPONENT_DELIMITER))
+ {
+ removed = removeByHierarchy(key);
+ }
+ else if (key instanceof GroupAttrName && ((GroupAttrName<?>) key).attrName == null)
+ {
+ removed = removeByGroup(key);
+ }
+ else
+ {
+ // remove single item.
+ lock.lock();
+ try
+ {
+ MemoryElementDescriptor<K, V> me = map.remove(key);
+ if (me != null)
+ {
+ lockedRemoveElement(me);
+ removed = true;
+ }
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+
+ return removed;
+ }
+
+ /**
+ * Get an Array of the keys for all elements in the memory cache
+ *
+ * @return An Object[]
+ */
+ @Override
+ public Set<K> getKeySet()
+ {
+ return new LinkedHashSet<>(map.keySet());
+ }
+
+ /**
+ * Get an item from the cache.
+ * <p>
+ *
+ * @param key Identifies item to find
+ * @return ICacheElement<K, V> if found, else null
+ * @throws IOException
+ */
+ @Override
+ public ICacheElement<K, V> get(K key) throws IOException
+ {
+ ICacheElement<K, V> ce = null;
+
+ log.debug("{0}: getting item for key {1}", () -> getCacheName(),
+ () -> key);
+
+ MemoryElementDescriptor<K, V> me = map.get(key);
+
+ if (me != null)
+ {
+ hitCnt.incrementAndGet();
+ ce = me.getCacheElement();
+
+ lock.lock();
+ try
+ {
+ lockedGetElement(me);
+ }
+ finally
+ {
+ lock.unlock();
+ }
+
+ log.debug("{0}: MemoryCache hit for {1}", () -> getCacheName(),
+ () -> key);
+ }
+ else
+ {
+ missCnt.incrementAndGet();
+
+ log.debug("{0}: MemoryCache miss for {1}", () -> getCacheName(),
+ () -> key);
+ }
+
+ return ce;
+ }
+
+ /**
+ * Update control structures after get
+ * (guarded by the lock)
+ *
+ * @param me the memory element descriptor
+ */
+ protected abstract void lockedGetElement(MemoryElementDescriptor<K, V> me);
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/behavior/IMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/behavior/IMemoryCache.java
new file mode 100644
index 0000000..fa5b2fe
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/behavior/IMemoryCache.java
@@ -0,0 +1,187 @@
+package org.apache.commons.jcs3.engine.memory.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+
+/** For the framework. Insures methods a MemoryCache needs to access. */
+public interface IMemoryCache<K, V>
+{
+ /**
+ * Initialize the memory cache
+ * <p>
+ * @param cache The cache (region) this memory store is attached to.
+ */
+ void initialize( CompositeCache<K, V> cache );
+
+ /**
+ * Destroy the memory cache
+ * <p>
+ * @throws IOException
+ */
+ void dispose()
+ throws IOException;
+
+ /**
+ * Get the number of elements contained in the memory store
+ * <p>
+ * @return Element count
+ */
+ int getSize();
+
+ /**
+ * Returns the historical and statistical data for a region's memory cache.
+ * <p>
+ * @return Statistics and Info for the Memory Cache.
+ */
+ IStats getStatistics();
+
+ /**
+ * Get a set of the keys for all elements in the memory cache.
+ * <p>
+ * @return a set of the key type
+ * TODO This should probably be done in chunks with a range passed in. This
+ * will be a problem if someone puts a 1,000,000 or so items in a
+ * region.
+ */
+ Set<K> getKeySet();
+
+ /**
+ * Removes an item from the cache
+ * <p>
+ * @param key
+ * Identifies item to be removed
+ * @return Description of the Return Value
+ * @throws IOException
+ * Description of the Exception
+ */
+ boolean remove( K key )
+ throws IOException;
+
+ /**
+ * Removes all cached items from the cache.
+ * <p>
+ * @throws IOException
+ * Description of the Exception
+ */
+ void removeAll()
+ throws IOException;
+
+ /**
+ * This instructs the memory cache to remove the <i>numberToFree</i>
+ * according to its eviction policy. For example, the LRUMemoryCache will
+ * remove the <i>numberToFree</i> least recently used items. These will be
+ * spooled to disk if a disk auxiliary is available.
+ * <p>
+ * @param numberToFree
+ * @return the number that were removed. if you ask to free 5, but there are
+ * only 3, you will get 3.
+ * @throws IOException
+ */
+ int freeElements( int numberToFree )
+ throws IOException;
+
+ /**
+ * Get an item from the cache
+ * <p>
+ * @param key
+ * Description of the Parameter
+ * @return Description of the Return Value
+ * @throws IOException
+ * Description of the Exception
+ */
+ ICacheElement<K, V> get( K key )
+ throws IOException;
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map
+ * if there is no data in cache for any of these keys
+ * @throws IOException
+ */
+ Map<K, ICacheElement<K, V>> getMultiple( Set<K> keys )
+ throws IOException;
+
+ /**
+ * Get an item from the cache without effecting its order or last access
+ * time
+ * <p>
+ * @param key
+ * Description of the Parameter
+ * @return The quiet value
+ * @throws IOException
+ * Description of the Exception
+ */
+ ICacheElement<K, V> getQuiet( K key )
+ throws IOException;
+
+ /**
+ * Spools the item contained in the provided element to disk
+ * <p>
+ * @param ce
+ * Description of the Parameter
+ * @throws IOException
+ * Description of the Exception
+ */
+ void waterfal( ICacheElement<K, V> ce )
+ throws IOException;
+
+ /**
+ * Puts an item to the cache.
+ * <p>
+ * @param ce
+ * Description of the Parameter
+ * @throws IOException
+ * Description of the Exception
+ */
+ void update( ICacheElement<K, V> ce )
+ throws IOException;
+
+ /**
+ * Returns the CacheAttributes for the region.
+ * <p>
+ * @return The cacheAttributes value
+ */
+ ICompositeCacheAttributes getCacheAttributes();
+
+ /**
+ * Sets the CacheAttributes of the region.
+ * <p>
+ * @param cattr
+ * The new cacheAttributes value
+ */
+ void setCacheAttributes( ICompositeCacheAttributes cattr );
+
+ /**
+ * Gets the cache hub / region that uses the MemoryCache.
+ * <p>
+ * @return The cache value
+ */
+ CompositeCache<K, V> getCompositeCache();
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/fifo/FIFOMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/fifo/FIFOMemoryCache.java
new file mode 100644
index 0000000..33621c4
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/fifo/FIFOMemoryCache.java
@@ -0,0 +1,59 @@
+package org.apache.commons.jcs3.engine.memory.fifo;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.memory.AbstractDoubleLinkedListMemoryCache;
+import org.apache.commons.jcs3.engine.memory.util.MemoryElementDescriptor;
+
+/**
+ * The items are spooled in the order they are added. No adjustments to the list are made on get.
+ */
+public class FIFOMemoryCache<K, V>
+ extends AbstractDoubleLinkedListMemoryCache<K, V>
+{
+ /**
+ * Puts an item to the cache. Removes any pre-existing entries of the same key from the linked
+ * list and adds this one first.
+ * <p>
+ * @param ce The cache element, or entry wrapper
+ * @return MemoryElementDescriptor the new node
+ * @throws IOException
+ */
+ @Override
+ protected MemoryElementDescriptor<K, V> adjustListForUpdate( ICacheElement<K, V> ce )
+ throws IOException
+ {
+ return addFirst( ce );
+ }
+
+ /**
+ * Does nothing.
+ * <p>
+ * @param me
+ */
+ @Override
+ protected void adjustListForGet( MemoryElementDescriptor<K, V> me )
+ {
+ // DO NOTHING
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/lru/LHMLRUMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/lru/LHMLRUMemoryCache.java
new file mode 100644
index 0000000..8d9fa7b
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/lru/LHMLRUMemoryCache.java
@@ -0,0 +1,202 @@
+package org.apache.commons.jcs3.engine.memory.lru;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.memory.AbstractMemoryCache;
+import org.apache.commons.jcs3.engine.memory.util.MemoryElementDescriptor;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This is a test memory manager using the jdk1.4 LinkedHashMap.
+ */
+public class LHMLRUMemoryCache<K, V>
+ extends AbstractMemoryCache<K, V>
+{
+ /** The Logger. */
+ private static final Log log = LogManager.getLog( LRUMemoryCache.class );
+
+ /**
+ * For post reflection creation initialization
+ * <p>
+ * @param hub
+ */
+ @Override
+ public void initialize( CompositeCache<K, V> hub )
+ {
+ super.initialize( hub );
+ log.info( "initialized LHMLRUMemoryCache for {0}", () -> getCacheName() );
+ }
+
+ /**
+ * Returns a synchronized LHMSpooler
+ * <p>
+ * @return Collections.synchronizedMap( new LHMSpooler() )
+ */
+ @Override
+ public Map<K, MemoryElementDescriptor<K, V>> createMap()
+ {
+ return Collections.synchronizedMap( new LHMSpooler() );
+ }
+
+ /**
+ * Puts an item to the cache.
+ * <p>
+ * @param ce Description of the Parameter
+ * @throws IOException
+ */
+ @Override
+ public void update( ICacheElement<K, V> ce )
+ throws IOException
+ {
+ putCnt.incrementAndGet();
+ map.put( ce.getKey(), new MemoryElementDescriptor<>(ce) );
+ }
+
+ /**
+ * Update control structures after get
+ * (guarded by the lock)
+ *
+ * @param me the memory element descriptor
+ */
+ @Override
+ protected void lockedGetElement(MemoryElementDescriptor<K, V> me)
+ {
+ // empty
+ }
+
+ /**
+ * Remove element from control structure
+ * (guarded by the lock)
+ *
+ * @param me the memory element descriptor
+ */
+ @Override
+ protected void lockedRemoveElement(MemoryElementDescriptor<K, V> me)
+ {
+ // empty
+ }
+
+ /**
+ * Removes all cached items from the cache control structures.
+ * (guarded by the lock)
+ */
+ @Override
+ protected void lockedRemoveAll()
+ {
+ // empty
+ }
+
+ /**
+ * This returns semi-structured information on the memory cache, such as the size, put count,
+ * hit count, and miss count.
+ * <p>
+ * @return IStats
+ */
+ @Override
+ public IStats getStatistics()
+ {
+ IStats stats = super.getStatistics();
+ stats.setTypeName( "LHMLRU Memory Cache" );
+
+ return stats;
+ }
+
+ // ---------------------------------------------------------- debug methods
+
+ /**
+ * Dump the cache entries from first to last for debugging.
+ */
+ public void dumpCacheEntries()
+ {
+ dumpMap();
+ }
+
+ /**
+ * This can't be implemented.
+ * <p>
+ * @param numberToFree
+ * @return 0
+ * @throws IOException
+ */
+ @Override
+ public int freeElements( int numberToFree )
+ throws IOException
+ {
+ // can't be implemented using the LHM
+ return 0;
+ }
+
+ // ---------------------------------------------------------- extended map
+
+ /**
+ * Implementation of removeEldestEntry in LinkedHashMap
+ */
+ protected class LHMSpooler
+ extends java.util.LinkedHashMap<K, MemoryElementDescriptor<K, V>>
+ {
+ /** Don't change. */
+ private static final long serialVersionUID = -1255907868906762484L;
+
+ /**
+ * Initialize to a small size--for now, 1/2 of max 3rd variable "true" indicates that it
+ * should be access and not time governed. This could be configurable.
+ */
+ public LHMSpooler()
+ {
+ super( (int) ( getCacheAttributes().getMaxObjects() * .5 ), .75F, true );
+ }
+
+ /**
+ * Remove eldest. Automatically called by LinkedHashMap.
+ * <p>
+ * @param eldest
+ * @return true if removed
+ */
+ @SuppressWarnings("synthetic-access")
+ @Override
+ protected boolean removeEldestEntry( Map.Entry<K, MemoryElementDescriptor<K, V>> eldest )
+ {
+ ICacheElement<K, V> element = eldest.getValue().getCacheElement();
+
+ if ( size() <= getCacheAttributes().getMaxObjects() )
+ {
+ return false;
+ }
+ else
+ {
+ log.debug( "LHMLRU max size: {0}. Spooling element, key: {1}",
+ () -> getCacheAttributes().getMaxObjects(), () -> element.getKey() );
+
+ waterfal( element );
+
+ log.debug( "LHMLRU size: {0}", () -> map.size() );
+ }
+ return true;
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/lru/LRUMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/lru/LRUMemoryCache.java
new file mode 100644
index 0000000..ac40202
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/lru/LRUMemoryCache.java
@@ -0,0 +1,67 @@
+package org.apache.commons.jcs3.engine.memory.lru;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.memory.AbstractDoubleLinkedListMemoryCache;
+import org.apache.commons.jcs3.engine.memory.util.MemoryElementDescriptor;
+
+/**
+ * A fast reference management system. The least recently used items move to the end of the list and
+ * get spooled to disk if the cache hub is configured to use a disk cache. Most of the cache
+ * bottlenecks are in IO. There are no io bottlenecks here, it's all about processing power.
+ * <p>
+ * Even though there are only a few adjustments necessary to maintain the double linked list, we
+ * might want to find a more efficient memory manager for large cache regions.
+ * <p>
+ * The LRUMemoryCache is most efficient when the first element is selected. The smaller the region,
+ * the better the chance that this will be the case. < .04 ms per put, p3 866, 1/10 of that per get
+ */
+public class LRUMemoryCache<K, V>
+ extends AbstractDoubleLinkedListMemoryCache<K, V>
+{
+ /**
+ * Puts an item to the cache. Removes any pre-existing entries of the same key from the linked
+ * list and adds this one first.
+ * <p>
+ * @param ce The cache element, or entry wrapper
+ * @return MemoryElementDescriptor the new node
+ * @throws IOException
+ */
+ @Override
+ protected MemoryElementDescriptor<K, V> adjustListForUpdate( ICacheElement<K, V> ce )
+ throws IOException
+ {
+ return addFirst( ce );
+ }
+
+ /**
+ * Makes the item the first in the list.
+ * <p>
+ * @param me
+ */
+ @Override
+ protected void adjustListForGet( MemoryElementDescriptor<K, V> me )
+ {
+ list.makeFirst( me );
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/lru/package.html b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/lru/package.html
similarity index 100%
rename from commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/lru/package.html
rename to commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/lru/package.html
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/mru/MRUMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/mru/MRUMemoryCache.java
new file mode 100644
index 0000000..2cf7fcb
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/mru/MRUMemoryCache.java
@@ -0,0 +1,62 @@
+package org.apache.commons.jcs3.engine.memory.mru;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.memory.AbstractDoubleLinkedListMemoryCache;
+import org.apache.commons.jcs3.engine.memory.util.MemoryElementDescriptor;
+
+/**
+ * The most recently used items move to the front of the list and get spooled to disk if the cache
+ * hub is configured to use a disk cache.
+ */
+public class MRUMemoryCache<K, V>
+ extends AbstractDoubleLinkedListMemoryCache<K, V>
+{
+ /**
+ * Adds the item to the front of the list. A put doesn't count as a usage.
+ * <p>
+ * It's not clear if the put operation should be different. Perhaps this should remove the oldest
+ * if full, and then put.
+ * <p>
+ * @param ce
+ * @return MemoryElementDescriptor the new node
+ * @throws IOException
+ */
+ @Override
+ protected MemoryElementDescriptor<K, V> adjustListForUpdate( ICacheElement<K, V> ce )
+ throws IOException
+ {
+ return addFirst( ce );
+ }
+
+ /**
+ * Makes the item the last in the list.
+ * <p>
+ * @param me
+ */
+ @Override
+ protected void adjustListForGet( MemoryElementDescriptor<K, V> me )
+ {
+ list.makeLast( me );
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/mru/package.html b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/mru/package.html
similarity index 100%
rename from commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/mru/package.html
rename to commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/mru/package.html
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/package.html b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/package.html
similarity index 100%
rename from commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/package.html
rename to commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/package.html
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/shrinking/ShrinkerThread.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/shrinking/ShrinkerThread.java
new file mode 100644
index 0000000..ee01831
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/shrinking/ShrinkerThread.java
@@ -0,0 +1,202 @@
+package org.apache.commons.jcs3.engine.memory.shrinking;
+
+/*
+ * 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.
+ */
+
+import java.util.Set;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.control.event.behavior.ElementEventType;
+import org.apache.commons.jcs3.engine.memory.behavior.IMemoryCache;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * A background memory shrinker. Memory problems and concurrent modification exception caused by
+ * acting directly on an iterator of the underlying memory cache should have been solved.
+ * @version $Id$
+ */
+public class ShrinkerThread<K, V>
+ implements Runnable
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( ShrinkerThread.class );
+
+ /** The CompositeCache instance which this shrinker is watching */
+ private final CompositeCache<K, V> cache;
+
+ /** Maximum memory idle time for the whole cache */
+ private final long maxMemoryIdleTime;
+
+ /** Maximum number of items to spool per run. Default is -1, or no limit. */
+ private final int maxSpoolPerRun;
+
+ /** Should we limit the number spooled per run. If so, the maxSpoolPerRun will be used. */
+ private boolean spoolLimit = false;
+
+ /**
+ * Constructor for the ShrinkerThread object.
+ * <p>
+ * @param cache The MemoryCache which the new shrinker should watch.
+ */
+ public ShrinkerThread( CompositeCache<K, V> cache )
+ {
+ super();
+
+ this.cache = cache;
+
+ long maxMemoryIdleTimeSeconds = cache.getCacheAttributes().getMaxMemoryIdleTimeSeconds();
+
+ if ( maxMemoryIdleTimeSeconds < 0 )
+ {
+ this.maxMemoryIdleTime = -1;
+ }
+ else
+ {
+ this.maxMemoryIdleTime = maxMemoryIdleTimeSeconds * 1000;
+ }
+
+ this.maxSpoolPerRun = cache.getCacheAttributes().getMaxSpoolPerRun();
+ if ( this.maxSpoolPerRun != -1 )
+ {
+ this.spoolLimit = true;
+ }
+
+ }
+
+ /**
+ * Main processing method for the ShrinkerThread object
+ */
+ @Override
+ public void run()
+ {
+ shrink();
+ }
+
+ /**
+ * This method is called when the thread wakes up. First the method obtains an array of keys for
+ * the cache region. It iterates through the keys and tries to get the item from the cache
+ * without affecting the last access or position of the item. The item is checked for
+ * expiration, the expiration check has 3 parts:
+ * <ol>
+ * <li>Has the cacheattributes.MaxMemoryIdleTimeSeconds defined for the region been exceeded? If
+ * so, the item should be move to disk.</li> <li>Has the item exceeded MaxLifeSeconds defined in
+ * the element attributes? If so, remove it.</li> <li>Has the item exceeded IdleTime defined in
+ * the element attributes? If so, remove it. If there are event listeners registered for the
+ * cache element, they will be called.</li>
+ * </ol>
+ * TODO Change element event handling to use the queue, then move the queue to the region and
+ * access via the Cache.
+ */
+ protected void shrink()
+ {
+ log.debug( "Shrinking memory cache for: {0}", () -> this.cache.getCacheName() );
+
+ IMemoryCache<K, V> memCache = cache.getMemoryCache();
+
+ try
+ {
+ Set<K> keys = memCache.getKeySet();
+ int size = keys.size();
+ log.debug( "Keys size: {0}", size );
+
+ int spoolCount = 0;
+
+ for (K key : keys)
+ {
+ final ICacheElement<K, V> cacheElement = memCache.getQuiet( key );
+
+ if ( cacheElement == null )
+ {
+ continue;
+ }
+
+ IElementAttributes attributes = cacheElement.getElementAttributes();
+
+ boolean remove = false;
+
+ long now = System.currentTimeMillis();
+
+ // If the element is not eternal, check if it should be
+ // removed and remove it if so.
+ if ( !attributes.getIsEternal() )
+ {
+ remove = cache.isExpired( cacheElement, now,
+ ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND,
+ ElementEventType.EXCEEDED_IDLETIME_BACKGROUND );
+
+ if ( remove )
+ {
+ memCache.remove( key );
+ }
+ }
+
+ // If the item is not removed, check is it has been idle
+ // long enough to be spooled.
+
+ if ( !remove && maxMemoryIdleTime != -1 )
+ {
+ if ( !spoolLimit || spoolCount < this.maxSpoolPerRun )
+ {
+ final long lastAccessTime = attributes.getLastAccessTime();
+
+ if ( lastAccessTime + maxMemoryIdleTime < now )
+ {
+ log.debug( "Exceeded memory idle time: {0}", key );
+
+ // Shouldn't we ensure that the element is
+ // spooled before removing it from memory?
+ // No the disk caches have a purgatory. If it fails
+ // to spool that does not affect the
+ // responsibilities of the memory cache.
+
+ spoolCount++;
+
+ memCache.remove( key );
+ memCache.waterfal( cacheElement );
+ }
+ }
+ else
+ {
+ log.debug( "spoolCount = \"{0}\"; maxSpoolPerRun = \"{1}\"",
+ spoolCount, maxSpoolPerRun );
+
+ // stop processing if limit has been reached.
+ if ( spoolLimit && spoolCount >= this.maxSpoolPerRun )
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
+ catch ( Throwable t )
+ {
+ log.info( "Unexpected trouble in shrink cycle", t );
+
+ // concurrent modifications should no longer be a problem
+ // It is up to the IMemoryCache to return an array of keys
+
+ // stop for now
+ return;
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/soft/SoftReferenceMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/soft/SoftReferenceMemoryCache.java
new file mode 100644
index 0000000..9776ac2
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/soft/SoftReferenceMemoryCache.java
@@ -0,0 +1,240 @@
+package org.apache.commons.jcs3.engine.memory.soft;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.lang.ref.SoftReference;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.memory.AbstractMemoryCache;
+import org.apache.commons.jcs3.engine.memory.util.MemoryElementDescriptor;
+import org.apache.commons.jcs3.engine.memory.util.SoftReferenceElementDescriptor;
+import org.apache.commons.jcs3.engine.stats.StatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * A JCS IMemoryCache that has {@link SoftReference} to all its values.
+ * This cache does not respect {@link ICompositeCacheAttributes#getMaxObjects()}
+ * as overflowing is handled by Java GC.
+ * <p>
+ * The cache also has strong references to a maximum number of objects given by
+ * the maxObjects parameter
+ *
+ * @author halset
+ */
+public class SoftReferenceMemoryCache<K, V> extends AbstractMemoryCache<K, V>
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog(SoftReferenceMemoryCache.class);
+
+ /**
+ * Strong references to the maxObjects number of newest objects.
+ * <p>
+ * Trimming is done by {@link #trimStrongReferences()} instead of by
+ * overriding removeEldestEntry to be able to control waterfalling as easy
+ * as possible
+ */
+ private LinkedBlockingQueue<ICacheElement<K, V>> strongReferences;
+
+ /**
+ * For post reflection creation initialization
+ * <p>
+ * @param hub
+ */
+ @Override
+ public synchronized void initialize( CompositeCache<K, V> hub )
+ {
+ super.initialize( hub );
+ strongReferences = new LinkedBlockingQueue<>();
+ log.info( "initialized Soft Reference Memory Cache for {0}",
+ () -> getCacheName() );
+ }
+
+ /**
+ * @see org.apache.commons.jcs3.engine.memory.AbstractMemoryCache#createMap()
+ */
+ @Override
+ public ConcurrentMap<K, MemoryElementDescriptor<K, V>> createMap()
+ {
+ return new ConcurrentHashMap<>();
+ }
+
+ /**
+ * @see org.apache.commons.jcs3.engine.memory.behavior.IMemoryCache#getKeySet()
+ */
+ @Override
+ public Set<K> getKeySet()
+ {
+ Set<K> keys = new HashSet<>();
+ for (Map.Entry<K, MemoryElementDescriptor<K, V>> e : map.entrySet())
+ {
+ SoftReferenceElementDescriptor<K, V> sred = (SoftReferenceElementDescriptor<K, V>) e.getValue();
+ if (sred.getCacheElement() != null)
+ {
+ keys.add(e.getKey());
+ }
+ }
+
+ return keys;
+ }
+
+ /**
+ * Returns the current cache size.
+ * <p>
+ * @return The size value
+ */
+ @Override
+ public int getSize()
+ {
+ int size = 0;
+ for (MemoryElementDescriptor<K, V> me : map.values())
+ {
+ SoftReferenceElementDescriptor<K, V> sred = (SoftReferenceElementDescriptor<K, V>) me;
+ if (sred.getCacheElement() != null)
+ {
+ size++;
+ }
+ }
+ return size;
+ }
+
+ /**
+ * @return statistics about the cache
+ */
+ @Override
+ public IStats getStatistics()
+ {
+ IStats stats = super.getStatistics();
+ stats.setTypeName("Soft Reference Memory Cache");
+
+ List<IStatElement<?>> elems = stats.getStatElements();
+ int emptyrefs = map.size() - getSize();
+ elems.add(new StatElement<>("Empty References", Integer.valueOf(emptyrefs)));
+ elems.add(new StatElement<>("Strong References", Integer.valueOf(strongReferences.size())));
+
+ return stats;
+ }
+
+ /**
+ * Update control structures after get
+ * (guarded by the lock)
+ *
+ * @param me the memory element descriptor
+ */
+ @Override
+ protected void lockedGetElement(MemoryElementDescriptor<K, V> me)
+ {
+ ICacheElement<K, V> val = me.getCacheElement();
+ val.getElementAttributes().setLastAccessTimeNow();
+
+ // update the ordering of the strong references
+ strongReferences.add(val);
+ trimStrongReferences();
+ }
+
+ /**
+ * Remove element from control structure
+ * (guarded by the lock)
+ *
+ * @param me the memory element descriptor
+ */
+ @Override
+ protected void lockedRemoveElement(MemoryElementDescriptor<K, V> me)
+ {
+ strongReferences.remove(me.getCacheElement());
+ }
+
+ /**
+ * Removes all cached items from the cache control structures.
+ * (guarded by the lock)
+ */
+ @Override
+ protected void lockedRemoveAll()
+ {
+ strongReferences.clear();
+ }
+
+ /**
+ * Puts an item to the cache.
+ * <p>
+ * @param ce Description of the Parameter
+ * @throws IOException Description of the Exception
+ */
+ @Override
+ public void update(ICacheElement<K, V> ce) throws IOException
+ {
+ putCnt.incrementAndGet();
+ ce.getElementAttributes().setLastAccessTimeNow();
+
+ lock.lock();
+
+ try
+ {
+ map.put(ce.getKey(), new SoftReferenceElementDescriptor<>(ce));
+ strongReferences.add(ce);
+ trimStrongReferences();
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Trim the number of strong references to equal or below the number given
+ * by the maxObjects parameter.
+ */
+ private void trimStrongReferences()
+ {
+ int max = getCacheAttributes().getMaxObjects();
+ int startsize = strongReferences.size();
+
+ for (int cursize = startsize; cursize > max; cursize--)
+ {
+ ICacheElement<K, V> ce = strongReferences.poll();
+ waterfal(ce);
+ }
+ }
+
+ /**
+ * This can't be implemented.
+ * <p>
+ * @param numberToFree
+ * @return 0
+ * @throws IOException
+ */
+ @Override
+ public int freeElements(int numberToFree) throws IOException
+ {
+ return 0;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/soft/package.html b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/soft/package.html
similarity index 100%
rename from commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/soft/package.html
rename to commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/soft/package.html
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/util/MemoryElementDescriptor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/util/MemoryElementDescriptor.java
new file mode 100644
index 0000000..7577016
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/util/MemoryElementDescriptor.java
@@ -0,0 +1,53 @@
+package org.apache.commons.jcs3.engine.memory.util;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.utils.struct.DoubleLinkedListNode;
+
+/**
+ * This wrapper is needed for double linked lists.
+ */
+public class MemoryElementDescriptor<K, V>
+ extends DoubleLinkedListNode<ICacheElement<K, V>>
+{
+ /** Don't change */
+ private static final long serialVersionUID = -1905161209035522460L;
+
+ /**
+ * Constructs a usable MemoryElementDescriptor.
+ * <p>
+ * @param ce
+ */
+ public MemoryElementDescriptor( ICacheElement<K, V> ce )
+ {
+ super( ce );
+ }
+
+ /**
+ * Get the cache element
+ *
+ * @return the ce
+ */
+ public ICacheElement<K, V> getCacheElement()
+ {
+ return getPayload();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/util/SoftReferenceElementDescriptor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/util/SoftReferenceElementDescriptor.java
new file mode 100644
index 0000000..4b001ec
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/memory/util/SoftReferenceElementDescriptor.java
@@ -0,0 +1,62 @@
+package org.apache.commons.jcs3.engine.memory.util;
+
+/*
+ * 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.
+ */
+
+import java.lang.ref.SoftReference;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/**
+ * This wrapper is needed for double linked lists.
+ */
+public class SoftReferenceElementDescriptor<K, V>
+ extends MemoryElementDescriptor<K, V>
+{
+ /** Don't change */
+ private static final long serialVersionUID = -1905161209035522460L;
+
+ /** The CacheElement wrapped by this descriptor */
+ private final SoftReference<ICacheElement<K, V>> srce;
+
+ /**
+ * Constructs a usable MemoryElementDescriptor.
+ * <p>
+ * @param ce
+ */
+ public SoftReferenceElementDescriptor( ICacheElement<K, V> ce )
+ {
+ super( null );
+ this.srce = new SoftReference<>(ce);
+ }
+
+ /**
+ * @return the ce
+ */
+ @Override
+ public ICacheElement<K, V> getCacheElement()
+ {
+ if (srce != null)
+ {
+ return srce.get();
+ }
+
+ return null;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/package.html b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/package.html
similarity index 100%
rename from commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/package.html
rename to commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/package.html
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/stats/CacheStats.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/stats/CacheStats.java
new file mode 100644
index 0000000..6f6c9d5
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/stats/CacheStats.java
@@ -0,0 +1,116 @@
+package org.apache.commons.jcs3.engine.stats;
+
+/*
+ * 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.
+ */
+
+import java.util.List;
+
+import org.apache.commons.jcs3.engine.stats.behavior.ICacheStats;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+
+/**
+ * This class stores cache historical and statistics data for a region.
+ * <p>
+ * Only the composite cache knows what the hit count across all auxiliaries is.
+ */
+public class CacheStats
+ extends Stats
+ implements ICacheStats
+{
+ /** Don't change. */
+ private static final long serialVersionUID = 529914708798168590L;
+
+ /** The region */
+ private String regionName = null;
+
+ /** What that auxiliaries are reporting. */
+ private List<IStats> auxStats = null;
+
+ /**
+ * Stats are for a region, though auxiliary data may be for more.
+ * <p>
+ * @return The region name
+ */
+ @Override
+ public String getRegionName()
+ {
+ return regionName;
+ }
+
+ /**
+ * Stats are for a region, though auxiliary data may be for more.
+ * <p>
+ * @param name - The region name
+ */
+ @Override
+ public void setRegionName( String name )
+ {
+ regionName = name;
+ }
+
+ /**
+ * @return IStats[]
+ */
+ @Override
+ public List<IStats> getAuxiliaryCacheStats()
+ {
+ return auxStats;
+ }
+
+ /**
+ * @param stats
+ */
+ @Override
+ public void setAuxiliaryCacheStats( List<IStats> stats )
+ {
+ auxStats = stats;
+ }
+
+ /**
+ * @return readable string that can be logged.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append( "Region Name = " + regionName );
+
+ if ( getStatElements() != null )
+ {
+ for ( Object stat : getStatElements() )
+ {
+ buf.append( "\n" );
+ buf.append( stat );
+ }
+ }
+
+ if ( auxStats != null )
+ {
+ for ( Object auxStat : auxStats )
+ {
+ buf.append( "\n" );
+ buf.append( "---------------------------" );
+ buf.append( auxStat );
+ }
+ }
+
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/stats/StatElement.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/stats/StatElement.java
new file mode 100644
index 0000000..53b997c
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/stats/StatElement.java
@@ -0,0 +1,104 @@
+package org.apache.commons.jcs3.engine.stats;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+
+/**
+ * This is a stat data holder.
+ */
+public class StatElement<V>
+ implements IStatElement<V>
+{
+ /** Don't change */
+ private static final long serialVersionUID = -2982373725267618092L;
+
+ /** name of the stat */
+ private String name = null;
+
+ /** the data */
+ private V data = null;
+
+ /**
+ * Constructor
+ *
+ * @param name
+ * @param data
+ */
+ public StatElement(String name, V data)
+ {
+ super();
+ this.name = name;
+ this.data = data;
+ }
+
+ /**
+ * Get the name of the stat element, ex. HitCount
+ * <p>
+ * @return the stat element name
+ */
+ @Override
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * @param name
+ */
+ @Override
+ public void setName( String name )
+ {
+ this.name = name;
+ }
+
+ /**
+ * Get the data, ex. for hit count you would get a value for some number.
+ * <p>
+ * @return data
+ */
+ @Override
+ public V getData()
+ {
+ return data;
+ }
+
+ /**
+ * Set the data for this element.
+ * <p>
+ * @param data
+ */
+ @Override
+ public void setData( V data )
+ {
+ this.data = data;
+ }
+
+ /**
+ * @return a readable string.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( name ).append(" = ").append( data );
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/stats/Stats.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/stats/Stats.java
new file mode 100644
index 0000000..db420a8
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/stats/Stats.java
@@ -0,0 +1,99 @@
+package org.apache.commons.jcs3.engine.stats;
+
+/*
+ * 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.
+ */
+
+import java.util.List;
+
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+
+/**
+ * @author aaronsm
+ */
+public class Stats
+ implements IStats
+{
+ /** Don't change */
+ private static final long serialVersionUID = 227327902875154010L;
+
+ /** The stats */
+ private List<IStatElement<?>> stats = null;
+
+ /** The type of stat */
+ private String typeName = null;
+
+ /**
+ * @return IStatElement[]
+ */
+ @Override
+ public List<IStatElement<?>> getStatElements()
+ {
+ return stats;
+ }
+
+ /**
+ * @param stats
+ */
+ @Override
+ public void setStatElements( List<IStatElement<?>> stats )
+ {
+ this.stats = stats;
+ }
+
+ /**
+ * @return typeName
+ */
+ @Override
+ public String getTypeName()
+ {
+ return typeName;
+ }
+
+ /**
+ * @param name
+ */
+ @Override
+ public void setTypeName( String name )
+ {
+ typeName = name;
+ }
+
+ /**
+ * @return the stats in a readable string
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append( typeName );
+
+ if ( stats != null )
+ {
+ for (Object stat : stats)
+ {
+ buf.append( "\n" );
+ buf.append( stat );
+ }
+ }
+
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/stats/behavior/ICacheStats.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/stats/behavior/ICacheStats.java
new file mode 100644
index 0000000..8914e5c
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/stats/behavior/ICacheStats.java
@@ -0,0 +1,51 @@
+package org.apache.commons.jcs3.engine.stats.behavior;
+
+import java.util.List;
+
+/*
+ * 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.
+ */
+
+/**
+ * This holds stat information on a region. It contains both auxiliary and core stats.
+ */
+public interface ICacheStats
+ extends IStats
+{
+ /**
+ * Stats are for a region, though auxiliary data may be for more.
+ * <p>
+ * @return The region name
+ */
+ String getRegionName();
+
+ /**
+ * @param name
+ */
+ void setRegionName( String name );
+
+ /**
+ * @return IStats[]
+ */
+ List<IStats> getAuxiliaryCacheStats();
+
+ /**
+ * @param stats
+ */
+ void setAuxiliaryCacheStats( List<IStats> stats );
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/stats/behavior/IStatElement.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/stats/behavior/IStatElement.java
new file mode 100644
index 0000000..a542477
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/stats/behavior/IStatElement.java
@@ -0,0 +1,54 @@
+package org.apache.commons.jcs3.engine.stats.behavior;
+
+import java.io.Serializable;
+
+/*
+ * 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.
+ */
+
+/**
+ * IAuxiliaryCacheStats will hold these IStatElements.
+ */
+public interface IStatElement<V> extends Serializable
+{
+ /**
+ * Get the name of the stat element, ex. HitCount
+ * <p>
+ * @return the stat element name
+ */
+ String getName();
+
+ /**
+ * @param name
+ */
+ void setName( String name );
+
+ /**
+ * Get the data, ex. for hit count you would get a value for some number.
+ * <p>
+ * @return data
+ */
+ V getData();
+
+ /**
+ * Set the data for this element.
+ * <p>
+ * @param data
+ */
+ void setData( V data );
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/stats/behavior/IStats.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/stats/behavior/IStats.java
new file mode 100644
index 0000000..ce6358e
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/engine/stats/behavior/IStats.java
@@ -0,0 +1,63 @@
+package org.apache.commons.jcs3.engine.stats.behavior;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * This interface defines the common behavior for a stats holder.
+ *
+ * @author aaronsm
+ *
+ */
+public interface IStats
+ extends Serializable
+{
+
+ /**
+ * Return generic statistical or historical data.
+ *
+ * @return list of IStatElements
+ */
+ List<IStatElement<?>> getStatElements();
+
+ /**
+ * Set the generic statistical or historical data.
+ *
+ * @param stats
+ */
+ void setStatElements( List<IStatElement<?>> stats );
+
+ /**
+ * Get the type name, such as "LRU Memory Cache." No formal type is defined.
+ *
+ * @return String
+ */
+ String getTypeName();
+
+ /**
+ * Set the type name, such as "LRU Memory Cache." No formal type is defined.
+ * If we need formal types, we can use the cachetype param
+ *
+ * @param name
+ */
+ void setTypeName( String name );
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/io/ObjectInputStreamClassLoaderAware.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/io/ObjectInputStreamClassLoaderAware.java
new file mode 100644
index 0000000..757024b
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/io/ObjectInputStreamClassLoaderAware.java
@@ -0,0 +1,95 @@
+/*
+ * 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.apache.commons.jcs3.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
+import java.lang.reflect.Proxy;
+
+public class ObjectInputStreamClassLoaderAware extends ObjectInputStream {
+ private final ClassLoader classLoader;
+
+ public ObjectInputStreamClassLoaderAware(final InputStream in, final ClassLoader classLoader) throws IOException {
+ super(in);
+ this.classLoader = classLoader != null ? classLoader : Thread.currentThread().getContextClassLoader();
+ }
+
+ @Override
+ protected Class<?> resolveClass(final ObjectStreamClass desc) throws ClassNotFoundException {
+ return Class.forName(BlacklistClassResolver.DEFAULT.check(desc.getName()), false, classLoader);
+ }
+
+ @Override
+ protected Class<?> resolveProxyClass(final String[] interfaces) throws IOException, ClassNotFoundException {
+ final Class<?>[] cinterfaces = new Class[interfaces.length];
+ for (int i = 0; i < interfaces.length; i++) {
+ cinterfaces[i] = Class.forName(interfaces[i], false, classLoader);
+ }
+
+ try {
+ return Proxy.getProxyClass(classLoader, cinterfaces);
+ } catch (IllegalArgumentException e) {
+ throw new ClassNotFoundException(null, e);
+ }
+ }
+
+ private static class BlacklistClassResolver {
+ private static final BlacklistClassResolver DEFAULT = new BlacklistClassResolver(
+ toArray(System.getProperty(
+ "jcs.serialization.class.blacklist",
+ "org.codehaus.groovy.runtime.,org.apache.commons.collections.functors.,org.apache.xalan")),
+ toArray(System.getProperty("jcs.serialization.class.whitelist")));
+
+ private final String[] blacklist;
+ private final String[] whitelist;
+
+ protected BlacklistClassResolver(final String[] blacklist, final String[] whitelist) {
+ this.whitelist = whitelist;
+ this.blacklist = blacklist;
+ }
+
+ protected boolean isBlacklisted(final String name) {
+ return (whitelist != null && !contains(whitelist, name)) || contains(blacklist, name);
+ }
+
+ public final String check(final String name) {
+ if (isBlacklisted(name)) {
+ throw new SecurityException(name + " is not whitelisted as deserialisable, prevented before loading.");
+ }
+ return name;
+ }
+
+ private static String[] toArray(final String property) {
+ return property == null ? null : property.split(" *, *");
+ }
+
+ private static boolean contains(final String[] list, String name) {
+ if (list != null) {
+ for (final String white : list) {
+ if (name.startsWith(white)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/JulLogAdapter.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/JulLogAdapter.java
new file mode 100644
index 0000000..bf52400
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/JulLogAdapter.java
@@ -0,0 +1,574 @@
+package org.apache.commons.jcs3.log;
+
+import java.util.function.Supplier;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/*
+ * 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.
+ */
+
+/**
+ * This is a wrapper around the <code>java.util.logging.Logger</code> implementing our own
+ * <code>Log</code> interface.
+ * <p>
+ * This is the mapping of the log levels
+ * </p>
+ * <pre>
+ * Java Level Log Level
+ * SEVERE FATAL
+ * SEVERE ERROR
+ * WARNING WARN
+ * INFO INFO
+ * FINE DEBUG
+ * FINER TRACE
+ * </pre>
+ */
+public class JulLogAdapter implements Log
+{
+ private final Logger logger;
+
+ /**
+ * Construct a JUL Logger wrapper
+ *
+ * @param logger the JUL Logger
+ */
+ public JulLogAdapter(Logger logger)
+ {
+ super();
+ this.logger = logger;
+ }
+
+ private void log(Level level, String message)
+ {
+ if (logger.isLoggable(level))
+ {
+ logger.logp(level, logger.getName(), "", message);
+ }
+ }
+
+ private void log(Level level, Object message)
+ {
+ if (logger.isLoggable(level))
+ {
+ if (message instanceof Throwable)
+ {
+ logger.logp(level, logger.getName(), "", "Exception:", (Throwable) message);
+ }
+ else
+ {
+ logger.logp(level, logger.getName(), "",
+ message == null ? null : message.toString());
+ }
+ }
+ }
+
+ private void log(Level level, String message, Throwable t)
+ {
+ if (logger.isLoggable(level))
+ {
+ logger.logp(level, logger.getName(), "", message, t);
+ }
+ }
+
+ private void log(Level level, String message, Object... params)
+ {
+ if (logger.isLoggable(level))
+ {
+ MessageFormatter formatter = new MessageFormatter(message, params);
+ if (formatter.hasThrowable())
+ {
+ logger.logp(level, logger.getName(), "",
+ formatter.getFormattedMessage(), formatter.getThrowable());
+ }
+ else
+ {
+ logger.logp(level, logger.getName(), "",
+ formatter.getFormattedMessage());
+ }
+ }
+ }
+
+ private void log(Level level, String message, Supplier<?>... paramSuppliers)
+ {
+ if (logger.isLoggable(level))
+ {
+ MessageFormatter formatter = new MessageFormatter(message, paramSuppliers);
+ if (formatter.hasThrowable())
+ {
+ logger.logp(level, logger.getName(), "",
+ formatter.getFormattedMessage(), formatter.getThrowable());
+ }
+ else
+ {
+ logger.logp(level, logger.getName(), "",
+ formatter.getFormattedMessage());
+ }
+ }
+ }
+
+ /**
+ * Logs a message object with the DEBUG level.
+ *
+ * @param message the message string to log.
+ */
+ @Override
+ public void debug(String message)
+ {
+ log(Level.FINE, message);
+ }
+
+ /**
+ * Logs a message object with the DEBUG level.
+ *
+ * @param message the message object to log.
+ */
+ @Override
+ public void debug(Object message)
+ {
+ log(Level.FINE, message);
+ }
+
+ /**
+ * Logs a message with parameters at the DEBUG level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param params parameters to the message.
+ * @see #getMessageFactory()
+ */
+ @Override
+ public void debug(String message, Object... params)
+ {
+ log(Level.FINE, message, params);
+ }
+
+ /**
+ * Logs a message with parameters which are only to be constructed if the
+ * logging level is the DEBUG level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param paramSuppliers An array of functions, which when called,
+ * produce the desired log message parameters.
+ */
+ @Override
+ public void debug(String message, Supplier<?>... paramSuppliers)
+ {
+ log(Level.FINE, message, paramSuppliers);
+ }
+
+ /**
+ * Logs a message at the DEBUG level including the stack trace of the {@link Throwable}
+ * <code>t</code> passed as parameter.
+ *
+ * @param message the message to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ @Override
+ public void debug(String message, Throwable t)
+ {
+ log(Level.FINE, message, t);
+ }
+
+ /**
+ * Logs a message object with the ERROR level.
+ *
+ * @param message the message string to log.
+ */
+ @Override
+ public void error(String message)
+ {
+ log(Level.SEVERE, message);
+ }
+
+ /**
+ * Logs a message object with the ERROR level.
+ *
+ * @param message the message object to log.
+ */
+ @Override
+ public void error(Object message)
+ {
+ log(Level.SEVERE, message);
+ }
+
+ /**
+ * Logs a message with parameters at the ERROR level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param params parameters to the message.
+ */
+ @Override
+ public void error(String message, Object... params)
+ {
+ log(Level.SEVERE, message, params);
+ }
+
+ /**
+ * Logs a message with parameters which are only to be constructed if the
+ * logging level is the ERROR level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param paramSuppliers An array of functions, which when called, produce
+ * the desired log message parameters.
+ * @since 2.4
+ */
+ @Override
+ public void error(String message, Supplier<?>... paramSuppliers)
+ {
+ log(Level.SEVERE, message, paramSuppliers);
+ }
+
+ /**
+ * Logs a message at the ERROR level including the stack trace of the {@link Throwable}
+ * <code>t</code> passed as parameter.
+ *
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ @Override
+ public void error(String message, Throwable t)
+ {
+ log(Level.SEVERE, message, t);
+ }
+
+ /**
+ * Logs a message object with the FATAL level.
+ *
+ * @param message the message string to log.
+ */
+ @Override
+ public void fatal(String message)
+ {
+ log(Level.SEVERE, message);
+ }
+
+ /**
+ * Logs a message object with the FATAL level.
+ *
+ * @param message the message object to log.
+ */
+ @Override
+ public void fatal(Object message)
+ {
+ log(Level.SEVERE, message);
+ }
+
+ /**
+ * Logs a message with parameters at the FATAL level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param params parameters to the message.
+ */
+ @Override
+ public void fatal(String message, Object... params)
+ {
+ log(Level.SEVERE, message, params);
+ }
+
+ /**
+ * Logs a message with parameters which are only to be constructed if the
+ * logging level is the FATAL level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param paramSuppliers An array of functions, which when called, produce the
+ * desired log message parameters.
+ */
+ @Override
+ public void fatal(String message, Supplier<?>... paramSuppliers)
+ {
+ log(Level.SEVERE, message, paramSuppliers);
+ }
+
+ /**
+ * Logs a message at the FATAL level including the stack trace of the {@link Throwable}
+ * <code>t</code> passed as parameter.
+ *
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ @Override
+ public void fatal(String message, Throwable t)
+ {
+ log(Level.SEVERE, message, t);
+ }
+
+ /**
+ * Gets the logger name.
+ *
+ * @return the logger name.
+ */
+ @Override
+ public String getName()
+ {
+ return logger.getName();
+ }
+
+ /**
+ * Logs a message object with the INFO level.
+ *
+ * @param message the message string to log.
+ */
+ @Override
+ public void info(String message)
+ {
+ log(Level.INFO, message);
+ }
+
+ /**
+ * Logs a message object with the INFO level.
+ *
+ * @param message the message object to log.
+ */
+ @Override
+ public void info(Object message)
+ {
+ log(Level.INFO, message);
+ }
+
+ /**
+ * Logs a message with parameters at the INFO level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param params parameters to the message.
+ */
+ @Override
+ public void info(String message, Object... params)
+ {
+ log(Level.INFO, message, params);
+ }
+
+ /**
+ * Logs a message with parameters which are only to be constructed if the
+ * logging level is the INFO level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param paramSuppliers An array of functions, which when called, produce
+ * the desired log message parameters.
+ */
+ @Override
+ public void info(String message, Supplier<?>... paramSuppliers)
+ {
+ log(Level.INFO, message, paramSuppliers);
+ }
+
+ /**
+ * Logs a message at the INFO level including the stack trace of the {@link Throwable}
+ * <code>t</code> passed as parameter.
+ *
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ @Override
+ public void info(String message, Throwable t)
+ {
+ log(Level.INFO, message, t);
+ }
+
+ /**
+ * Checks whether this Logger is enabled for the DEBUG Level.
+ *
+ * @return boolean - {@code true} if this Logger is enabled for level DEBUG, {@code false}
+ * otherwise.
+ */
+ @Override
+ public boolean isDebugEnabled()
+ {
+ return logger.isLoggable(Level.FINE);
+ }
+
+ /**
+ * Checks whether this Logger is enabled for the ERROR Level.
+ *
+ * @return boolean - {@code true} if this Logger is enabled for level ERROR, {@code false}
+ * otherwise.
+ */
+ @Override
+ public boolean isErrorEnabled()
+ {
+ return logger.isLoggable(Level.SEVERE);
+ }
+
+ /**
+ * Checks whether this Logger is enabled for the FATAL Level.
+ *
+ * @return boolean - {@code true} if this Logger is enabled for level FATAL, {@code false}
+ * otherwise.
+ */
+ @Override
+ public boolean isFatalEnabled()
+ {
+ return logger.isLoggable(Level.SEVERE);
+ }
+
+ /**
+ * Checks whether this Logger is enabled for the INFO Level.
+ *
+ * @return boolean - {@code true} if this Logger is enabled for level INFO, {@code false}
+ * otherwise.
+ */
+ @Override
+ public boolean isInfoEnabled()
+ {
+ return logger.isLoggable(Level.INFO);
+ }
+
+ /**
+ * Checks whether this Logger is enabled for the TRACE level.
+ *
+ * @return boolean - {@code true} if this Logger is enabled for level TRACE, {@code false}
+ * otherwise.
+ */
+ @Override
+ public boolean isTraceEnabled()
+ {
+ return logger.isLoggable(Level.FINER);
+ }
+
+ /**
+ * Checks whether this Logger is enabled for the WARN Level.
+ *
+ * @return boolean - {@code true} if this Logger is enabled for level WARN, {@code false}
+ * otherwise.
+ */
+ @Override
+ public boolean isWarnEnabled()
+ {
+ return logger.isLoggable(Level.WARNING);
+ }
+
+ /**
+ * Logs a message object with the TRACE level.
+ *
+ * @param message the message string to log.
+ */
+ @Override
+ public void trace(String message)
+ {
+ log(Level.FINER, message);
+ }
+
+ /**
+ * Logs a message object with the TRACE level.
+ *
+ * @param message the message object to log.
+ */
+ @Override
+ public void trace(Object message)
+ {
+ log(Level.FINER, message);
+ }
+
+ /**
+ * Logs a message with parameters at the TRACE level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param params parameters to the message.
+ */
+ @Override
+ public void trace(String message, Object... params)
+ {
+ log(Level.FINER, message, params);
+ }
+
+ /**
+ * Logs a message with parameters which are only to be constructed if the
+ * logging level is the TRACE level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param paramSuppliers An array of functions, which when called, produce
+ * the desired log message parameters.
+ */
+ @Override
+ public void trace(String message, Supplier<?>... paramSuppliers)
+ {
+ log(Level.FINER, message, paramSuppliers);
+ }
+
+ /**
+ * Logs a message at the TRACE level including the stack trace of the {@link Throwable}
+ * <code>t</code> passed as parameter.
+ *
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ * @see #debug(String)
+ */
+ @Override
+ public void trace(String message, Throwable t)
+ {
+ log(Level.FINER, message, t);
+ }
+
+ /**
+ * Logs a message object with the WARN level.
+ *
+ * @param message the message string to log.
+ */
+ @Override
+ public void warn(String message)
+ {
+ log(Level.WARNING, message);
+ }
+
+ /**
+ * Logs a message object with the WARN level.
+ *
+ * @param message the message object to log.
+ */
+ @Override
+ public void warn(Object message)
+ {
+ log(Level.WARNING, message);
+ }
+
+ /**
+ * Logs a message with parameters at the WARN level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param params parameters to the message.
+ */
+ @Override
+ public void warn(String message, Object... params)
+ {
+ log(Level.WARNING, message, params);
+ }
+
+ /**
+ * Logs a message with parameters which are only to be constructed if the
+ * logging level is the WARN level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param paramSuppliers An array of functions, which when called, produce
+ * the desired log message parameters.
+ */
+ @Override
+ public void warn(String message, Supplier<?>... paramSuppliers)
+ {
+ log(Level.WARNING, message, paramSuppliers);
+ }
+
+ /**
+ * Logs a message at the WARN level including the stack trace of the {@link Throwable}
+ * <code>t</code> passed as parameter.
+ *
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ @Override
+ public void warn(String message, Throwable t)
+ {
+ log(Level.WARNING, message, t);
+ }
+}
\ No newline at end of file
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/JulLogFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/JulLogFactory.java
new file mode 100644
index 0000000..2edfb1c
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/JulLogFactory.java
@@ -0,0 +1,76 @@
+package org.apache.commons.jcs3.log;
+
+import java.util.logging.Logger;
+
+/*
+ * 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.
+ */
+
+/**
+ * This is a SPI factory implementation for java.util.logging
+ */
+public class JulLogFactory implements LogFactory
+{
+ /**
+ * Return the name of the Log subsystem managed by this factory
+ *
+ * @return the name of the log subsystem
+ */
+ @Override
+ public String getName()
+ {
+ return "jul";
+ }
+
+ /**
+ * Shutdown the logging system if the logging system supports it.
+ */
+ @Override
+ public void shutdown()
+ {
+ // do nothing
+ }
+
+ /**
+ * Returns a Log using the fully qualified name of the Class as the Log
+ * name.
+ *
+ * @param clazz
+ * The Class whose name should be used as the Log name.
+ *
+ * @return The Log.
+ */
+ @Override
+ public Log getLog(final Class<?> clazz)
+ {
+ Logger logger = Logger.getLogger(clazz.getName());
+ return new JulLogAdapter(logger);
+ }
+
+ /**
+ * Returns a Log with the specified name.
+ *
+ * @param name
+ * The logger name.
+ * @return The Log.
+ */
+ @Override
+ public Log getLog(final String name)
+ {
+ Logger logger = Logger.getLogger(name);
+ return new JulLogAdapter(logger);
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/Log.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/Log.java
new file mode 100644
index 0000000..649a0e3
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/Log.java
@@ -0,0 +1,343 @@
+package org.apache.commons.jcs3.log;
+
+/*
+ * 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.
+ */
+
+import java.util.function.Supplier;
+
+/**
+ * This is a borrowed and stripped-down version of the log4j2 Logger interface.
+ * All logging operations, except configuration, are done through this interface.
+ *
+ * <p>
+ * The canonical way to obtain a Logger for a class is through {@link LogManager#getLog()}.
+ * Typically, each class should get its own Log named after its fully qualified class name
+ * </p>
+ *
+ * <pre>
+ * public class MyClass {
+ * private static final Log log = LogManager.getLog(MyClass.class);
+ * // ...
+ * }
+ * </pre>
+ */
+public interface Log
+{
+ /**
+ * Logs a message object with the DEBUG level.
+ *
+ * @param message the message string to log.
+ */
+ void debug(String message);
+
+ /**
+ * Logs a message object with the DEBUG level.
+ *
+ * @param message the message object to log.
+ */
+ void debug(Object message);
+
+ /**
+ * Logs a message with parameters at the DEBUG level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param params parameters to the message.
+ */
+ void debug(String message, Object... params);
+
+ /**
+ * Logs a message with parameters which are only to be constructed if the
+ * logging level is the DEBUG level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param paramSuppliers An array of functions, which when called, produce
+ * the desired log message parameters.
+ */
+ void debug(String message, Supplier<?>... paramSuppliers);
+
+ /**
+ * Logs a message at the DEBUG level including the stack trace of the {@link Throwable}
+ * <code>t</code> passed as parameter.
+ *
+ * @param message the message to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ void debug(String message, Throwable t);
+
+ /**
+ * Logs a message object with the ERROR level.
+ *
+ * @param message the message string to log.
+ */
+ void error(String message);
+
+ /**
+ * Logs a message object with the ERROR level.
+ *
+ * @param message the message object to log.
+ */
+ void error(Object message);
+
+ /**
+ * Logs a message with parameters at the ERROR level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param params parameters to the message.
+ */
+ void error(String message, Object... params);
+
+ /**
+ * Logs a message with parameters which are only to be constructed if the
+ * logging level is the ERROR level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param paramSuppliers An array of functions, which when called, produce
+ * the desired log message parameters.
+ */
+ void error(String message, Supplier<?>... paramSuppliers);
+
+ /**
+ * Logs a message at the ERROR level including the stack trace of the {@link Throwable}
+ * <code>t</code> passed as parameter.
+ *
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ void error(String message, Throwable t);
+
+ /**
+ * Logs a message object with the FATAL level.
+ *
+ * @param message the message string to log.
+ */
+ void fatal(String message);
+
+ /**
+ * Logs a message object with the FATAL level.
+ *
+ * @param message the message object to log.
+ */
+ void fatal(Object message);
+
+ /**
+ * Logs a message with parameters at the FATAL level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param params parameters to the message.
+ */
+ void fatal(String message, Object... params);
+
+ /**
+ * Logs a message with parameters which are only to be constructed if the
+ * logging level is the FATAL level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param paramSuppliers An array of functions, which when called, produce
+ * the desired log message parameters.
+ */
+ void fatal(String message, Supplier<?>... paramSuppliers);
+
+ /**
+ * Logs a message at the FATAL level including the stack trace of the {@link Throwable}
+ * <code>t</code> passed as parameter.
+ *
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ void fatal(String message, Throwable t);
+
+ /**
+ * Gets the logger name.
+ *
+ * @return the logger name.
+ */
+ String getName();
+
+ /**
+ * Logs a message object with the INFO level.
+ *
+ * @param message the message string to log.
+ */
+ void info(String message);
+
+ /**
+ * Logs a message object with the INFO level.
+ *
+ * @param message the message object to log.
+ */
+ void info(Object message);
+
+ /**
+ * Logs a message with parameters at the INFO level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param params parameters to the message.
+ */
+ void info(String message, Object... params);
+
+ /**
+ * Logs a message with parameters which are only to be constructed if the
+ * logging level is the INFO level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param paramSuppliers An array of functions, which when called, produce
+ * the desired log message parameters.
+ */
+ void info(String message, Supplier<?>... paramSuppliers);
+
+ /**
+ * Logs a message at the INFO level including the stack trace of the {@link Throwable}
+ * <code>t</code> passed as parameter.
+ *
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ void info(String message, Throwable t);
+
+ /**
+ * Checks whether this Logger is enabled for the DEBUG Level.
+ *
+ * @return boolean - {@code true} if this Logger is enabled for level DEBUG, {@code false}
+ * otherwise.
+ */
+ boolean isDebugEnabled();
+
+ /**
+ * Checks whether this Logger is enabled for the ERROR Level.
+ *
+ * @return boolean - {@code true} if this Logger is enabled for level ERROR, {@code false}
+ * otherwise.
+ */
+ boolean isErrorEnabled();
+
+ /**
+ * Checks whether this Logger is enabled for the FATAL Level.
+ *
+ * @return boolean - {@code true} if this Logger is enabled for level FATAL, {@code false}
+ * otherwise.
+ */
+ boolean isFatalEnabled();
+
+ /**
+ * Checks whether this Logger is enabled for the INFO Level.
+ *
+ * @return boolean - {@code true} if this Logger is enabled for level INFO, {@code false}
+ * otherwise.
+ */
+ boolean isInfoEnabled();
+
+ /**
+ * Checks whether this Logger is enabled for the TRACE level.
+ *
+ * @return boolean - {@code true} if this Logger is enabled for level TRACE, {@code false}
+ * otherwise.
+ */
+ boolean isTraceEnabled();
+
+ /**
+ * Checks whether this Logger is enabled for the WARN Level.
+ *
+ * @return boolean - {@code true} if this Logger is enabled for level WARN, {@code false}
+ * otherwise.
+ */
+ boolean isWarnEnabled();
+
+ /**
+ * Logs a message object with the TRACE level.
+ *
+ * @param message the message string to log.
+ */
+ void trace(String message);
+
+ /**
+ * Logs a message object with the TRACE level.
+ *
+ * @param message the message object to log.
+ */
+ void trace(Object message);
+
+ /**
+ * Logs a message with parameters at the TRACE level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param params parameters to the message.
+ * @see #getMessageFactory()
+ */
+ void trace(String message, Object... params);
+
+ /**
+ * Logs a message with parameters which are only to be constructed if the
+ * logging level is the TRACE level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param paramSuppliers An array of functions, which when called, produce
+ * the desired log message parameters.
+ */
+ void trace(String message, Supplier<?>... paramSuppliers);
+
+ /**
+ * Logs a message at the TRACE level including the stack trace of the {@link Throwable}
+ * <code>t</code> passed as parameter.
+ *
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ * @see #debug(String)
+ */
+ void trace(String message, Throwable t);
+
+ /**
+ * Logs a message object with the WARN level.
+ *
+ * @param message the message string to log.
+ */
+ void warn(String message);
+
+ /**
+ * Logs a message object with the WARN level.
+ *
+ * @param message the message object to log.
+ */
+ void warn(Object message);
+
+ /**
+ * Logs a message with parameters at the WARN level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param params parameters to the message.
+ * @see #getMessageFactory()
+ */
+ void warn(String message, Object... params);
+
+ /**
+ * Logs a message with parameters which are only to be constructed if the
+ * logging level is the WARN level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param paramSuppliers An array of functions, which when called, produce
+ * the desired log message parameters.
+ */
+ void warn(String message, Supplier<?>... paramSuppliers);
+
+ /**
+ * Logs a message at the WARN level including the stack trace of the {@link Throwable}
+ * <code>t</code> passed as parameter.
+ *
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ void warn(String message, Throwable t);
+}
\ No newline at end of file
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/Log4j2Factory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/Log4j2Factory.java
new file mode 100644
index 0000000..ef6fdbc
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/Log4j2Factory.java
@@ -0,0 +1,88 @@
+package org.apache.commons.jcs3.log;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.message.MessageFactory;
+import org.apache.logging.log4j.message.MessageFormatMessageFactory;
+
+/*
+ * 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.
+ */
+
+/**
+ * This is a SPI factory implementation for log4j2
+ */
+public class Log4j2Factory implements LogFactory
+{
+ /** Use java.text.MessageFormat for log messages */
+ private final MessageFactory messageFactory = new MessageFormatMessageFactory();
+
+ /**
+ * Return the name of the Log subsystem managed by this factory
+ *
+ * @return the name of the log subsystem
+ */
+ @Override
+ public String getName()
+ {
+ return "log4j2";
+ }
+
+ /**
+ * Shutdown the logging system if the logging system supports it.
+ */
+ @Override
+ public void shutdown()
+ {
+ org.apache.logging.log4j.LogManager.shutdown();
+ }
+
+ /**
+ * Returns a Log using the fully qualified name of the Class as the Log
+ * name.
+ *
+ * @param clazz
+ * The Class whose name should be used as the Log name. If null
+ * it will default to the calling class.
+ * @return The Log.
+ * @throws UnsupportedOperationException
+ * if {@code clazz} is {@code null} and the calling class cannot
+ * be determined.
+ */
+ @Override
+ public Log getLog(final Class<?> clazz)
+ {
+ Logger logger = org.apache.logging.log4j.LogManager.getLogger(clazz, messageFactory);
+ return new Log4j2LogAdapter(logger);
+ }
+
+ /**
+ * Returns a Log with the specified name.
+ *
+ * @param name
+ * The logger name. If null the name of the calling class will be
+ * used.
+ * @return The Log.
+ * @throws UnsupportedOperationException
+ * if {@code name} is {@code null} and the calling class cannot
+ * be determined.
+ */
+ @Override
+ public Log getLog(final String name)
+ {
+ Logger logger = org.apache.logging.log4j.LogManager.getLogger(name, messageFactory);
+ return new Log4j2LogAdapter(logger);
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/Log4j2LogAdapter.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/Log4j2LogAdapter.java
new file mode 100644
index 0000000..60239b7
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/Log4j2LogAdapter.java
@@ -0,0 +1,531 @@
+package org.apache.commons.jcs3.log;
+
+/*
+ * 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.
+ */
+
+import java.util.function.Supplier;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+
+/**
+ * This is a wrapper around the <code>org.apache.logging.log4j.Logger</code> implementing our own
+ * <code>Log</code> interface.
+ */
+public class Log4j2LogAdapter implements Log
+{
+ private final Logger logger;
+
+ /**
+ * Construct a Log4j Logger wrapper
+ *
+ * @param logger the log4j Logger
+ */
+ public Log4j2LogAdapter(Logger logger)
+ {
+ super();
+ this.logger = logger;
+ }
+
+ private void log(Level level, String message, Supplier<?>... paramSuppliers)
+ {
+ if (logger.isEnabled(level))
+ {
+ if (paramSuppliers == null)
+ {
+ logger.log(level, message);
+ }
+ else
+ {
+ switch (paramSuppliers.length)
+ {
+ case 1: logger.log(level, message, paramSuppliers[0].get());
+ break;
+ case 2: logger.log(level, message, paramSuppliers[0].get(),
+ paramSuppliers[1].get());
+ break;
+ case 3: logger.log(level, message, paramSuppliers[0].get(),
+ paramSuppliers[1].get(), paramSuppliers[2].get());
+ break;
+ case 4: logger.log(level, message, paramSuppliers[0].get(),
+ paramSuppliers[1].get(), paramSuppliers[2].get(),
+ paramSuppliers[3].get());
+ break;
+ case 5: logger.log(level, message, paramSuppliers[0].get(),
+ paramSuppliers[1].get(), paramSuppliers[2].get(),
+ paramSuppliers[3].get(), paramSuppliers[4].get());
+ break;
+ default: logger.log(level, message, paramSuppliers[0].get(),
+ paramSuppliers[1].get(), paramSuppliers[2].get(),
+ paramSuppliers[3].get(), paramSuppliers[4].get(),
+ paramSuppliers[5].get());
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Logs a message object with the DEBUG level.
+ *
+ * @param message the message string to log.
+ */
+ @Override
+ public void debug(String message)
+ {
+ logger.debug(message);
+ }
+
+ /**
+ * Logs a message object with the DEBUG level.
+ *
+ * @param message the message object to log.
+ */
+ @Override
+ public void debug(Object message)
+ {
+ logger.debug(message);
+ }
+
+ /**
+ * Logs a message with parameters at the DEBUG level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param params parameters to the message.
+ */
+ @Override
+ public void debug(String message, Object... params)
+ {
+ logger.debug(message, params);
+ }
+
+ /**
+ * Logs a message with parameters which are only to be constructed if the
+ * logging level is the DEBUG level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param paramSuppliers An array of functions, which when called, produce
+ * the desired log message parameters.
+ */
+ @Override
+ public void debug(String message, Supplier<?>... paramSuppliers)
+ {
+ log(Level.DEBUG, message, paramSuppliers);
+ }
+
+ /**
+ * Logs a message at the DEBUG level including the stack trace of the {@link Throwable}
+ * <code>t</code> passed as parameter.
+ *
+ * @param message the message to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ @Override
+ public void debug(String message, Throwable t)
+ {
+ logger.debug(message, t);
+ }
+
+ /**
+ * Logs a message object with the ERROR level.
+ *
+ * @param message the message string to log.
+ */
+ @Override
+ public void error(String message)
+ {
+ logger.error(message);
+ }
+
+ /**
+ * Logs a message object with the ERROR level.
+ *
+ * @param message the message object to log.
+ */
+ @Override
+ public void error(Object message)
+ {
+ logger.error(message);
+ }
+
+ /**
+ * Logs a message with parameters at the ERROR level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param params parameters to the message.
+ */
+ @Override
+ public void error(String message, Object... params)
+ {
+ logger.error(message, params);
+ }
+
+ /**
+ * Logs a message with parameters which are only to be constructed if the
+ * logging level is the ERROR level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param paramSuppliers An array of functions, which when called, produce
+ * the desired log message parameters.
+ */
+ @Override
+ public void error(String message, Supplier<?>... paramSuppliers)
+ {
+ log(Level.ERROR, message, paramSuppliers);
+ }
+
+ /**
+ * Logs a message at the ERROR level including the stack trace of the {@link Throwable}
+ * <code>t</code> passed as parameter.
+ *
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ @Override
+ public void error(String message, Throwable t)
+ {
+ logger.error(message, t);
+ }
+
+ /**
+ * Logs a message object with the FATAL level.
+ *
+ * @param message the message string to log.
+ */
+ @Override
+ public void fatal(String message)
+ {
+ logger.fatal(message);
+ }
+
+ /**
+ * Logs a message object with the FATAL level.
+ *
+ * @param message the message object to log.
+ */
+ @Override
+ public void fatal(Object message)
+ {
+ logger.fatal(message);
+ }
+
+ /**
+ * Logs a message with parameters at the FATAL level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param params parameters to the message.
+ */
+ @Override
+ public void fatal(String message, Object... params)
+ {
+ logger.fatal(message, params);
+ }
+
+ /**
+ * Logs a message with parameters which are only to be constructed if the
+ * logging level is the FATAL level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param paramSuppliers An array of functions, which when called, produce
+ * the desired log message parameters.
+ */
+ @Override
+ public void fatal(String message, Supplier<?>... paramSuppliers)
+ {
+ log(Level.FATAL, message, paramSuppliers);
+ }
+
+ /**
+ * Logs a message at the FATAL level including the stack trace of the {@link Throwable}
+ * <code>t</code> passed as parameter.
+ *
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ @Override
+ public void fatal(String message, Throwable t)
+ {
+ logger.fatal(message, t);
+ }
+
+ /**
+ * Gets the logger name.
+ *
+ * @return the logger name.
+ */
+ @Override
+ public String getName()
+ {
+ return logger.getName();
+ }
+
+ /**
+ * Logs a message object with the INFO level.
+ *
+ * @param message the message string to log.
+ */
+ @Override
+ public void info(String message)
+ {
+ logger.info(message);
+ }
+
+ /**
+ * Logs a message object with the INFO level.
+ *
+ * @param message the message object to log.
+ */
+ @Override
+ public void info(Object message)
+ {
+ logger.info(message);
+ }
+
+ /**
+ * Logs a message with parameters at the INFO level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param params parameters to the message.
+ */
+ @Override
+ public void info(String message, Object... params)
+ {
+ logger.info(message, params);
+ }
+
+ /**
+ * Logs a message with parameters which are only to be constructed if the
+ * logging level is the INFO level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param paramSuppliers An array of functions, which when called, produce
+ * the desired log message parameters.
+ */
+ @Override
+ public void info(String message, Supplier<?>... paramSuppliers)
+ {
+ log(Level.INFO, message, paramSuppliers);
+ }
+
+ /**
+ * Logs a message at the INFO level including the stack trace of the {@link Throwable}
+ * <code>t</code> passed as parameter.
+ *
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ @Override
+ public void info(String message, Throwable t)
+ {
+ logger.info(message, t);
+ }
+
+ /**
+ * Checks whether this Logger is enabled for the DEBUG Level.
+ *
+ * @return boolean - {@code true} if this Logger is enabled for level DEBUG, {@code false}
+ * otherwise.
+ */
+ @Override
+ public boolean isDebugEnabled()
+ {
+ return logger.isDebugEnabled();
+ }
+
+ /**
+ * Checks whether this Logger is enabled for the ERROR Level.
+ *
+ * @return boolean - {@code true} if this Logger is enabled for level ERROR, {@code false}
+ * otherwise.
+ */
+ @Override
+ public boolean isErrorEnabled()
+ {
+ return logger.isErrorEnabled();
+ }
+
+ /**
+ * Checks whether this Logger is enabled for the FATAL Level.
+ *
+ * @return boolean - {@code true} if this Logger is enabled for level FATAL, {@code false}
+ * otherwise.
+ */
+ @Override
+ public boolean isFatalEnabled()
+ {
+ return logger.isFatalEnabled();
+ }
+
+ /**
+ * Checks whether this Logger is enabled for the INFO Level.
+ *
+ * @return boolean - {@code true} if this Logger is enabled for level INFO, {@code false}
+ * otherwise.
+ */
+ @Override
+ public boolean isInfoEnabled()
+ {
+ return logger.isInfoEnabled();
+ }
+
+ /**
+ * Checks whether this Logger is enabled for the TRACE level.
+ *
+ * @return boolean - {@code true} if this Logger is enabled for level TRACE, {@code false}
+ * otherwise.
+ */
+ @Override
+ public boolean isTraceEnabled()
+ {
+ return logger.isTraceEnabled();
+ }
+
+ /**
+ * Checks whether this Logger is enabled for the WARN Level.
+ *
+ * @return boolean - {@code true} if this Logger is enabled for level WARN, {@code false}
+ * otherwise.
+ */
+ @Override
+ public boolean isWarnEnabled()
+ {
+ return logger.isWarnEnabled();
+ }
+
+ /**
+ * Logs a message object with the TRACE level.
+ *
+ * @param message the message string to log.
+ */
+ @Override
+ public void trace(String message)
+ {
+ logger.trace(message);
+ }
+
+ /**
+ * Logs a message object with the TRACE level.
+ *
+ * @param message the message object to log.
+ */
+ @Override
+ public void trace(Object message)
+ {
+ logger.trace(message);
+ }
+
+ /**
+ * Logs a message with parameters at the TRACE level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param params parameters to the message.
+ */
+ @Override
+ public void trace(String message, Object... params)
+ {
+ logger.trace(message, params);
+ }
+
+ /**
+ * Logs a message with parameters which are only to be constructed if the
+ * logging level is the TRACE level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param paramSuppliers An array of functions, which when called, produce
+ * the desired log message parameters.
+ */
+ @Override
+ public void trace(String message, Supplier<?>... paramSuppliers)
+ {
+ log(Level.TRACE, message, paramSuppliers);
+ }
+
+ /**
+ * Logs a message at the TRACE level including the stack trace of the {@link Throwable}
+ * <code>t</code> passed as parameter.
+ *
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ * @see #debug(String)
+ */
+ @Override
+ public void trace(String message, Throwable t)
+ {
+ logger.trace(message, t);
+ }
+
+ /**
+ * Logs a message object with the WARN level.
+ *
+ * @param message the message string to log.
+ */
+ @Override
+ public void warn(String message)
+ {
+ logger.warn(message);
+ }
+
+ /**
+ * Logs a message object with the WARN level.
+ *
+ * @param message the message object to log.
+ */
+ @Override
+ public void warn(Object message)
+ {
+ logger.warn(message);
+ }
+
+ /**
+ * Logs a message with parameters at the WARN level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param params parameters to the message.
+ */
+ @Override
+ public void warn(String message, Object... params)
+ {
+ logger.warn(message, params);
+ }
+
+ /**
+ * Logs a message with parameters which are only to be constructed if the
+ * logging level is the WARN level.
+ *
+ * @param message the message to log; the format depends on the message factory.
+ * @param paramSuppliers An array of functions, which when called, produce
+ * the desired log message parameters.
+ */
+ @Override
+ public void warn(String message, Supplier<?>... paramSuppliers)
+ {
+ log(Level.WARN, message, paramSuppliers);
+ }
+
+ /**
+ * Logs a message at the WARN level including the stack trace of the {@link Throwable}
+ * <code>t</code> passed as parameter.
+ *
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ @Override
+ public void warn(String message, Throwable t)
+ {
+ logger.warn(message, t);
+ }
+}
\ No newline at end of file
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/LogFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/LogFactory.java
new file mode 100644
index 0000000..fbecd24
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/LogFactory.java
@@ -0,0 +1,68 @@
+package org.apache.commons.jcs3.log;
+
+/*
+ * 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.
+ */
+
+/**
+ * This is a SPI factory interface for specialized Log objects
+ */
+public interface LogFactory
+{
+ /**
+ * The name of the root Log.
+ */
+ String ROOT_LOGGER_NAME = "";
+
+ /**
+ * Return the name of the Log subsystem managed by this factory
+ *
+ * @return the name of the log subsystem
+ */
+ String getName();
+
+ /**
+ * Shutdown the logging system if the logging system supports it.
+ */
+ void shutdown();
+
+ /**
+ * Returns a Log using the fully qualified name of the Class as the Log
+ * name.
+ *
+ * @param clazz
+ * The Class whose name should be used as the Log name. If null
+ * it will default to the calling class.
+ * @return The Log.
+ * @throws UnsupportedOperationException
+ * if {@code clazz} is {@code null} and the calling class cannot
+ * be determined.
+ */
+ Log getLog(final Class<?> clazz);
+
+ /**
+ * Returns a Log with the specified name.
+ *
+ * @param name
+ * The logger name. If null the name of the calling class will be
+ * used.
+ * @return The Log.
+ * @throws UnsupportedOperationException
+ * if {@code name} is {@code null} and the calling class cannot
+ * be determined.
+ */
+ Log getLog(final String name);
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/LogManager.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/LogManager.java
new file mode 100644
index 0000000..c5875f3
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/LogManager.java
@@ -0,0 +1,139 @@
+package org.apache.commons.jcs3.log;
+
+/*
+ * 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.
+ */
+
+import java.util.ServiceLoader;
+
+/**
+ * This is a borrowed and stripped-down version of the log4j2 LogManager class.
+ *
+ * The anchor point for the JCS logging system. The most common usage of this
+ * class is to obtain a named {@link Log}.
+ */
+public class LogManager
+{
+ /**
+ * The name of log subsystem
+ */
+ private static String logSystem = null;
+
+ /**
+ * The SPI LogFactory
+ */
+ private static class LogFactoryHolder
+ {
+ static final LogFactory INSTANCE = createLogFactory();
+
+ /**
+ * Scans the classpath to find a logging implementation.
+ *
+ * @return the LogFactory
+ * @throws RuntimeException, if no factory implementation could be found
+ */
+ private static LogFactory createLogFactory()
+ {
+ ServiceLoader<LogFactory> factories = ServiceLoader.load(LogFactory.class);
+ if (LogManager.logSystem == null)
+ {
+ LogManager.logSystem = System.getProperty("jcs.logSystem", "jul");
+ }
+
+ for (LogFactory factory : factories)
+ {
+ if (logSystem.equalsIgnoreCase(factory.getName()))
+ {
+ return factory;
+ }
+ }
+
+ throw new RuntimeException("Could not find factory implementation for log subsystem " + logSystem);
+ }
+ }
+
+ /**
+ * Set the log system. Must be called before getLog is called
+ *
+ * @param logSystem the logSystem to set
+ */
+ public static void setLogSystem(String logSystem)
+ {
+ LogManager.logSystem = logSystem;
+ }
+
+ /**
+ * Return the LogFactory
+ */
+ private static LogFactory getLogFactory()
+ {
+ return LogFactoryHolder.INSTANCE;
+ }
+
+ /**
+ * Prevents instantiation
+ */
+ protected LogManager()
+ {
+ }
+
+ /**
+ * Shutdown the logging system if the logging system supports it.
+ */
+ public static void shutdown()
+ {
+ getLogFactory().shutdown();
+ }
+
+ /**
+ * Returns a Log using the fully qualified name of the Class as the Log
+ * name.
+ *
+ * @param clazz
+ * The Class whose name should be used as the Log name.
+ * @return The Log.
+ * @throws UnsupportedOperationException
+ * if {@code clazz} is {@code null}
+ */
+ public static Log getLog(final Class<?> clazz)
+ {
+ return getLogFactory().getLog(clazz);
+ }
+
+ /**
+ * Returns a Log with the specified name.
+ *
+ * @param name
+ * The logger name.
+ * @return The Log.
+ * @throws UnsupportedOperationException
+ * if {@code name} is {@code null}
+ */
+ public static Log getLog(final String name)
+ {
+ return getLogFactory().getLog(name);
+ }
+
+ /**
+ * Returns the root logger.
+ *
+ * @return the root logger, named {@link LogFactory.ROOT_LOGGER_NAME}.
+ */
+ public static Log getRootLogger()
+ {
+ return getLog(LogFactory.ROOT_LOGGER_NAME);
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/MessageFormatter.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/MessageFormatter.java
new file mode 100644
index 0000000..fbabfa9
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/log/MessageFormatter.java
@@ -0,0 +1,130 @@
+package org.apache.commons.jcs3.log;
+
+/*
+ * 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.
+ */
+
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.IllegalFormatException;
+import java.util.function.Supplier;
+
+/**
+ * Handles messages that consist of a format string conforming to
+ * java.text.MessageFormat. (Borrowed from log4j2)
+ */
+public class MessageFormatter
+{
+ private final String messagePattern;
+ private transient Object[] parameters;
+ private transient String formattedMessage;
+ private transient Throwable throwable;
+
+ /**
+ * Constructs a message formatter.
+ *
+ * @param messagePattern
+ * the pattern for this message format
+ * @param parameters
+ * The objects to format
+ */
+ public MessageFormatter(final String messagePattern, final Object... parameters)
+ {
+ this.messagePattern = messagePattern;
+ this.parameters = parameters;
+ final int length = parameters == null ? 0 : parameters.length;
+ if (length > 0 && parameters[length - 1] instanceof Throwable)
+ {
+ this.throwable = (Throwable) parameters[length - 1];
+ }
+ }
+
+ /**
+ * Constructs a message formatter.
+ *
+ * @param messagePattern
+ * the pattern for this message format
+ * @param paramSuppliers
+ * An array of functions, which when called, produce the desired
+ * log message parameters.
+ */
+ public MessageFormatter(final String messagePattern, final Supplier<?>... paramSuppliers)
+ {
+ this.messagePattern = messagePattern;
+ this.parameters = Arrays.stream(paramSuppliers)
+ .map(s -> s.get())
+ .toArray();
+
+ final int length = parameters == null ? 0 : parameters.length;
+ if (length > 0 && parameters[length - 1] instanceof Throwable)
+ {
+ this.throwable = (Throwable) parameters[length - 1];
+ }
+ }
+
+ /**
+ * Returns the formatted message.
+ *
+ * @return the formatted message.
+ */
+ public String getFormattedMessage()
+ {
+ if (formattedMessage == null)
+ {
+ formattedMessage = formatMessage(messagePattern, parameters);
+ }
+ return formattedMessage;
+ }
+
+ protected String formatMessage(final String msgPattern, final Object... args)
+ {
+ try
+ {
+ final MessageFormat temp = new MessageFormat(msgPattern);
+ return temp.format(args);
+ }
+ catch (final IllegalFormatException ife)
+ {
+ return msgPattern;
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return getFormattedMessage();
+ }
+
+ /**
+ * Return the throwable passed to the Message.
+ *
+ * @return the Throwable.
+ */
+ public Throwable getThrowable()
+ {
+ return throwable;
+ }
+
+ /**
+ * Return true, if the parameters list contains a Throwable.
+ *
+ * @return true, if the parameters list contains a Throwable.
+ */
+ public boolean hasThrowable()
+ {
+ return throwable != null;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/package.html b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/package.html
similarity index 100%
rename from commons-jcs-core/src/main/java/org/apache/commons/jcs/package.html
rename to commons-jcs-core/src/main/java/org/apache/commons/jcs3/package.html
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/access/AbstractJCSWorkerHelper.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/access/AbstractJCSWorkerHelper.java
new file mode 100644
index 0000000..f27a43a
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/access/AbstractJCSWorkerHelper.java
@@ -0,0 +1,60 @@
+package org.apache.commons.jcs3.utils.access;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/*
+ * 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.
+ */
+
+/**
+ * This is an abstract template for JCSWorkerHelper implementations. it simple has a convenience
+ * method for setting the finished flag.
+ * <p>
+ * @author tsavo
+ */
+public abstract class AbstractJCSWorkerHelper<V> implements JCSWorkerHelper<V>
+{
+ /** finished flag. Can't we use wait notify? */
+ private final AtomicBoolean finished = new AtomicBoolean(false);
+
+ /**
+ * Default
+ */
+ public AbstractJCSWorkerHelper()
+ {
+ super();
+ }
+
+ /**
+ * @return finished
+ */
+ @Override
+ public boolean isFinished()
+ {
+ return finished.get();
+ }
+
+ /**
+ * @param isFinished
+ */
+ @Override
+ public void setFinished( boolean isFinished )
+ {
+ finished.set(isFinished);
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/access/JCSWorker.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/access/JCSWorker.java
new file mode 100644
index 0000000..f0caba8
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/access/JCSWorker.java
@@ -0,0 +1,286 @@
+package org.apache.commons.jcs3.utils.access;
+
+/*
+ * 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.
+ */
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.access.GroupCacheAccess;
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * Utility class to encapsulate doing a piece of work, and caching the results
+ * in JCS. Simply construct this class with the region name for the Cache and
+ * keep a static reference to it instead of the JCS itself. Then make a new
+ * org.apache.commons.jcs3.utils.access.AbstractJCSWorkerHelper and implement Object
+ * doWork() and do the work in there, returning the object to be cached. Then
+ * call .getResult() with the key and the AbstractJCSWorkerHelper to get the
+ * result of the work. If the object isn't already in the Cache,
+ * AbstractJCSWorkerHelper.doWork() will get called, and the result will be put
+ * into the cache. If the object is already in cache, the cached result will be
+ * returned instead.
+ * <p>
+ * As an added bonus, multiple JCSWorkers with the same region, and key won't do
+ * the work multiple times: The first JCSWorker to get started will do the work,
+ * and all subsequent workers with the same region, group, and key will wait on
+ * the first one and use his resulting work instead of doing the work
+ * themselves.
+ * <p>
+ * This is ideal when the work being done is a query to the database where the
+ * results may take time to be retrieved.
+ * <p>
+ * For example:
+ *
+ * <pre>
+ * public static JCSWorker cachingWorker = new JCSWorker("example region");
+ * public Object getSomething(Serializable aKey){
+ * JCSWorkerHelper helper = new AbstractJCSWorkerHelper(){
+ * public Object doWork(){
+ * // Do some (DB?) work here which results in a list
+ * // This only happens if the cache dosn't have a item in this region for aKey
+ * // Note this is especially useful with Hibernate, which will cache indiviual
+ * // Objects, but not entire query result sets.
+ * List results = query.list();
+ * // Whatever we return here get's cached with aKey, and future calls to
+ * // getResult() on a CachedWorker with the same region and key will return that instead.
+ * return results;
+ * };
+ * List result = worker.getResult(aKey, helper);
+ * }
+ * </pre>
+ *
+ * This is essentially the same as doing:
+ *
+ * <pre>
+ * JCS jcs = JCS.getInstance( "exampleregion" );
+ * List results = (List) jcs.get( aKey );
+ * if ( results != null )
+ * {
+ * //do the work here
+ * results = query.list();
+ * jcs.put( aKey, results );
+ * }
+ * </pre>
+ *
+ * <p>
+ * But has the added benefit of the work-load sharing; under normal
+ * circumstances if multiple threads all tried to do the same query at the same
+ * time, the same query would happen multiple times on the database, and the
+ * resulting object would get put into JCS multiple times.
+ * <p>
+ * @author Travis Savo
+ */
+public class JCSWorker<K, V>
+{
+ /** The logger */
+ private static final Log logger = LogManager.getLog( JCSWorker.class );
+
+ /** The cache we are working with */
+ private CacheAccess<K, V> cache;
+
+ /** The cache we are working with */
+ private GroupCacheAccess<K, V> groupCache;
+
+ /**
+ * Map to hold who's doing work presently.
+ */
+ private volatile ConcurrentMap<String, JCSWorkerHelper<V>> map = new ConcurrentHashMap<>();
+
+ /**
+ * Region for the JCS cache.
+ */
+ private final String region;
+
+ /**
+ * Constructor which takes a region for the JCS cache.
+ * @param aRegion
+ * The Region to use for the JCS cache.
+ */
+ public JCSWorker( final String aRegion )
+ {
+ region = aRegion;
+ try
+ {
+ cache = JCS.getInstance( aRegion );
+ groupCache = JCS.getGroupCacheInstance( aRegion );
+ }
+ catch ( CacheException e )
+ {
+ throw new RuntimeException( e.getMessage() );
+ }
+ }
+
+ /**
+ * Getter for the region of the JCS Cache.
+ * @return The JCS region in which the result will be cached.
+ */
+ public String getRegion()
+ {
+ return region;
+ }
+
+ /**
+ * Gets the cached result for this region/key OR does the work and caches
+ * the result, returning the result. If the result has not been cached yet,
+ * this calls doWork() on the JCSWorkerHelper to do the work and cache the
+ * result. This is also an opportunity to do any post processing of the
+ * result in your CachedWorker implementation.
+ * @param aKey
+ * The key to get/put with on the Cache.
+ * @param aWorker
+ * The JCSWorkerHelper implementing Object doWork(). This gets
+ * called if the cache get misses, and the result is put into
+ * cache.
+ * @return The result of doing the work, or the cached result.
+ * @throws Exception
+ * Throws an exception if anything goes wrong while doing the
+ * work.
+ */
+ public V getResult( K aKey, JCSWorkerHelper<V> aWorker )
+ throws Exception
+ {
+ return run( aKey, null, aWorker );
+ }
+
+ /**
+ * Gets the cached result for this region/key OR does the work and caches
+ * the result, returning the result. If the result has not been cached yet,
+ * this calls doWork() on the JCSWorkerHelper to do the work and cache the
+ * result. This is also an opportunity to do any post processing of the
+ * result in your CachedWorker implementation.
+ * @param aKey
+ * The key to get/put with on the Cache.
+ * @param aGroup
+ * The cache group to put the result in.
+ * @param aWorker
+ * The JCSWorkerHelper implementing Object doWork(). This gets
+ * called if the cache get misses, and the result is put into
+ * cache.
+ * @return The result of doing the work, or the cached result.
+ * @throws Exception
+ * Throws an exception if anything goes wrong while doing the
+ * work.
+ */
+ public V getResult( K aKey, String aGroup, JCSWorkerHelper<V> aWorker )
+ throws Exception
+ {
+ return run( aKey, aGroup, aWorker );
+ }
+
+ /**
+ * Try and get the object from the cache, and if it's not there, do the work
+ * and cache it. This also ensures that only one CachedWorker is doing the
+ * work and subsequent calls to a CachedWorker with identical
+ * region/key/group will wait on the results of this call. It will call the
+ * JCSWorkerHelper.doWork() if the cache misses, and will put the result.
+ * @param aKey
+ * @param aGroup
+ * @param aHelper
+ * @return Either the result of doing the work, or the cached result.
+ * @throws Exception
+ * If something goes wrong while doing the work, throw an
+ * exception.
+ */
+ private V run( K aKey, String aGroup, JCSWorkerHelper<V> aHelper )
+ throws Exception
+ {
+ V result = null;
+ // long start = 0;
+ // long dbTime = 0;
+ JCSWorkerHelper<V> helper = map.putIfAbsent(getRegion() + aKey, aHelper);
+
+ if ( helper != null )
+ {
+ synchronized ( helper )
+ {
+ logger.debug( "Found a worker already doing this work ({0}:{1}).",
+ () -> getRegion(), () -> aKey );
+ while ( !helper.isFinished() )
+ {
+ try
+ {
+ helper.wait();
+ }
+ catch (InterruptedException e)
+ {
+ // expected
+ }
+ }
+ logger.debug( "Another thread finished our work for us. Using "
+ + "those results instead. ({0}:{1}).",
+ () -> getRegion(), () -> aKey );
+ }
+ }
+ // Do the work
+ try
+ {
+ logger.debug( "{0} is doing the work.", () -> getRegion() );
+
+ // Try to get the item from the cache
+ if ( aGroup != null )
+ {
+ result = groupCache.getFromGroup( aKey, aGroup );
+ }
+ else
+ {
+ result = cache.get( aKey );
+ }
+ // If the cache dosn't have it, do the work.
+ if ( result == null )
+ {
+ result = aHelper.doWork();
+ logger.debug( "Work Done, caching: key:{0}, group:{1}, result:{2}.",
+ aKey, aGroup, result );
+ // Stick the result of the work in the cache.
+ if ( aGroup != null )
+ {
+ groupCache.putInGroup( aKey, aGroup, result );
+ }
+ else
+ {
+ cache.put( aKey, result );
+ }
+ }
+ // return the result
+ return result;
+ }
+ finally
+ {
+ logger.debug( "{0}:{1} entered finally.", () -> getRegion(),
+ () -> aKey );
+
+ // Remove ourselves as the worker.
+ if ( helper == null )
+ {
+ map.remove( getRegion() + aKey );
+ }
+ synchronized ( aHelper )
+ {
+ aHelper.setFinished( true );
+ // Wake everyone waiting on us
+ aHelper.notifyAll();
+ }
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/access/JCSWorkerHelper.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/access/JCSWorkerHelper.java
new file mode 100644
index 0000000..12d62d4
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/access/JCSWorkerHelper.java
@@ -0,0 +1,60 @@
+package org.apache.commons.jcs3.utils.access;
+
+/*
+ * 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.
+ */
+
+/**
+ * Interface for doing a piece of work which is expected to be cached. This is
+ * meant to be used in conjunction with JCSWorker.
+ * <p>
+ * Implement doWork() to return the work being done. isFinished() should return
+ * false until setFinished(true) is called, after which time it should return
+ * true.
+ * <p>
+ * @author tsavo
+ */
+public interface JCSWorkerHelper<V>
+{
+ /**
+ * Tells us whether or not the work has been completed. This will be called
+ * automatically by JCSWorker. You should not call it yourself.
+ * <p>
+ * @return True if the work has already been done, otherwise false.
+ */
+ boolean isFinished();
+
+ /**
+ * Sets whether or not the work has been done.
+ * <p>
+ * @param isFinished
+ * True if the work has already been done, otherwise false.
+ */
+ void setFinished( boolean isFinished );
+
+ /**
+ * The method to implement to do the work that should be cached. JCSWorker
+ * will call this itself! You should not call this directly.
+ * <p>
+ * @return The result of doing the work to be cached.
+ * @throws Exception
+ * If anything goes wrong while doing the work, an Exception
+ * should be thrown.
+ */
+ V doWork() throws Exception;
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/config/OptionConverter.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/config/OptionConverter.java
new file mode 100644
index 0000000..36f35f8
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/config/OptionConverter.java
@@ -0,0 +1,423 @@
+package org.apache.commons.jcs3.utils.config;
+
+/*
+ * 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.
+ */
+
+import java.util.Properties;
+
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This class is based on the log4j class org.apache.log4j.helpers.OptionConverter that was made by
+ * Ceki Gülcü Simon Kitching; Avy Sharell (sharell@online.fr) Anders Kristensen Matthieu
+ * Verbert (mve@zurich.ibm.com) A convenience class to convert property values to specific types.
+ */
+public class OptionConverter
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( OptionConverter.class );
+
+ /** System property delimter */
+ private static final String DELIM_START = "${";
+
+ /** System property delimter */
+ private static final char DELIM_STOP = '}';
+
+ /** System property delimter start length */
+ private static final int DELIM_START_LEN = 2;
+
+ /** System property delimter end length */
+ private static final int DELIM_STOP_LEN = 1;
+
+ /** No instances please. */
+ private OptionConverter()
+ {
+ super();
+ }
+
+ /**
+ * Combines two arrays.
+ * @param l
+ * @param r
+ * @return String[]
+ */
+ public static String[] concatanateArrays( String[] l, String[] r )
+ {
+ int len = l.length + r.length;
+ String[] a = new String[len];
+
+ System.arraycopy( l, 0, a, 0, l.length );
+ System.arraycopy( r, 0, a, l.length, r.length );
+
+ return a;
+ }
+
+ /**
+ * Escapes special characters.
+ *
+ * @param s
+ * @return String
+ */
+ public static String convertSpecialChars( String s )
+ {
+ char c;
+ int len = s.length();
+ StringBuilder sb = new StringBuilder( len );
+
+ int i = 0;
+ while ( i < len )
+ {
+ c = s.charAt( i++ );
+ if ( c == '\\' )
+ {
+ c = s.charAt( i++ );
+ if ( c == 'n' )
+ {
+ c = '\n';
+ }
+ else if ( c == 'r' )
+ {
+ c = '\r';
+ }
+ else if ( c == 't' )
+ {
+ c = '\t';
+ }
+ else if ( c == 'f' )
+ {
+ c = '\f';
+ }
+ else if ( c == '\b' )
+ {
+ c = '\b';
+ }
+ else if ( c == '\"' )
+ {
+ c = '\"';
+ }
+ else if ( c == '\'' )
+ {
+ c = '\'';
+ }
+ else if ( c == '\\' )
+ {
+ c = '\\';
+ }
+ }
+ sb.append( c );
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Very similar to <code>System.getProperty</code> except that the {@link SecurityException} is
+ * hidden.
+ * @param key The key to search for.
+ * @param def The default value to return.
+ * @return the string value of the system property, or the default value if there is no property
+ * with that key.
+ * @since 1.1
+ */
+
+ public static String getSystemProperty( String key, String def )
+ {
+ try
+ {
+ return System.getProperty( key, def );
+ }
+ catch ( Throwable e )
+ {
+ // MS-Java throws com.ms.security.SecurityExceptionEx
+ log.debug( "Was not allowed to read system property \"{0}\".", key );
+ return def;
+ }
+ }
+
+ /**
+ * Creates an object for the className value of the key.
+ *
+ * @param props
+ * @param key
+ * @param defaultValue
+ * @return Object that was created
+ */
+ public static <T> T instantiateByKey( Properties props, String key, T defaultValue )
+ {
+
+ // Get the value of the property in string form
+ String className = findAndSubst( key, props );
+ if ( className == null )
+ {
+ log.trace( "Could not find value for key {0}", key );
+ return defaultValue;
+ }
+ // Trim className to avoid trailing spaces that cause problems.
+ return OptionConverter.instantiateByClassName( className.trim(), defaultValue );
+ }
+
+ /**
+ * If <code>value</code> is "true", then <code>true</code> is returned. If <code>value</code> is
+ * "false", then <code>true</code> is returned. Otherwise, <code>default</code> is returned.
+ *
+ * Case of value is unimportant.
+ * @param value
+ * @param defaultValue
+ * @return Object
+ */
+ public static boolean toBoolean( String value, boolean defaultValue )
+ {
+ if ( value == null )
+ {
+ return defaultValue;
+ }
+ String trimmedVal = value.trim();
+ if ( "true".equalsIgnoreCase( trimmedVal ) )
+ {
+ return true;
+ }
+ if ( "false".equalsIgnoreCase( trimmedVal ) )
+ {
+ return false;
+ }
+ return defaultValue;
+ }
+
+ /**
+ * Converts to int.
+ *
+ * @param value
+ * @param defaultValue
+ * @return int
+ */
+ public static int toInt( String value, int defaultValue )
+ {
+ if ( value != null )
+ {
+ String s = value.trim();
+ try
+ {
+ return Integer.parseInt(s);
+ }
+ catch ( NumberFormatException e )
+ {
+ log.error( "[{0}] is not in proper int form.", s, e );
+ }
+ }
+ return defaultValue;
+ }
+
+ /**
+ * @param value
+ * @param defaultValue
+ * @return long
+ */
+ public static long toFileSize( String value, long defaultValue )
+ {
+ if ( value == null )
+ {
+ return defaultValue;
+ }
+
+ String s = value.trim().toUpperCase();
+ long multiplier = 1;
+ int index;
+
+ if ( ( index = s.indexOf( "KB" ) ) != -1 )
+ {
+ multiplier = 1024;
+ s = s.substring( 0, index );
+ }
+ else if ( ( index = s.indexOf( "MB" ) ) != -1 )
+ {
+ multiplier = 1024 * 1024;
+ s = s.substring( 0, index );
+ }
+ else if ( ( index = s.indexOf( "GB" ) ) != -1 )
+ {
+ multiplier = 1024 * 1024 * 1024;
+ s = s.substring( 0, index );
+ }
+ if ( s != null )
+ {
+ try
+ {
+ return Long.parseLong(s) * multiplier;
+ }
+ catch ( NumberFormatException e )
+ {
+ log.error( "[{0}] is not in proper int form.", s);
+ log.error( "[{0}] not in expected format", value, e );
+ }
+ }
+ return defaultValue;
+ }
+
+ /**
+ * Find the value corresponding to <code>key</code> in <code>props</code>. Then perform variable
+ * substitution on the found value.
+ *
+ * @param key
+ * @param props
+ * @return substituted string
+ */
+
+ public static String findAndSubst( String key, Properties props )
+ {
+ String value = props.getProperty( key );
+ if ( value == null )
+ {
+ return null;
+ }
+
+ try
+ {
+ return substVars( value, props );
+ }
+ catch ( IllegalArgumentException e )
+ {
+ log.error( "Bad option value [{0}]", value, e );
+ return value;
+ }
+ }
+
+ /**
+ * Instantiate an object given a class name. Check that the <code>className</code> is a subclass
+ * of <code>superClass</code>. If that test fails or the object could not be instantiated, then
+ * <code>defaultValue</code> is returned.
+ *
+ * @param className The fully qualified class name of the object to instantiate.
+ * @param defaultValue The object to return in case of non-fulfillment
+ * @return instantiated object
+ */
+
+ public static <T> T instantiateByClassName( String className, T defaultValue )
+ {
+ if ( className != null )
+ {
+ try
+ {
+ Class<?> classObj = Class.forName( className );
+ Object o = classObj.newInstance();
+
+ try
+ {
+ @SuppressWarnings("unchecked") // CCE catched
+ T t = (T) o;
+ return t;
+ }
+ catch (ClassCastException e)
+ {
+ log.error( "A \"{0}\" object is not assignable to the "
+ + "generic variable.", className );
+ return defaultValue;
+ }
+ }
+ catch ( ClassNotFoundException | InstantiationException | IllegalAccessException e )
+ {
+ log.error( "Could not instantiate class [{0}]", className, e );
+ }
+ }
+ return defaultValue;
+ }
+
+ /**
+ * Perform variable substitution in string <code>val</code> from the values of keys found in the
+ * system properties.
+ *
+ * The variable substitution delimiters are <b>${ </b> and <b>} </b>.
+ *
+ * For example, if the System properties contains "key=value", then the call
+ *
+ * <pre>
+ * String s = OptionConverter.substituteVars( "Value of key is ${key}." );
+ * </pre>
+ *
+ * will set the variable <code>s</code> to "Value of key is value.".
+ *
+ * If no value could be found for the specified key, then the <code>props</code> parameter is
+ * searched, if the value could not be found there, then substitution defaults to the empty
+ * string.
+ *
+ * For example, if system properties contains no value for the key "inexistentKey", then the call
+ *
+ * <pre>
+ * String s = OptionConverter.subsVars( "Value of inexistentKey is [${inexistentKey}]" );
+ * </pre>
+ *
+ * will set <code>s</code> to "Value of inexistentKey is []"
+ * <p>
+ * An {@link java.lang.IllegalArgumentException}is thrown if <code>val</code> contains a start
+ * delimiter "${" which is not balanced by a stop delimiter "}".
+ * </p>
+ * <p>
+ * <b>Author </b> Avy Sharell
+ * </p>
+ * @param val The string on which variable substitution is performed.
+ * @param props
+ * @return String
+ * @throws IllegalArgumentException if <code>val</code> is malformed.
+ */
+
+ public static String substVars( String val, Properties props )
+ throws IllegalArgumentException
+ {
+ StringBuilder sbuf = new StringBuilder();
+
+ int i = 0;
+ int j;
+ int k;
+
+ while ( true )
+ {
+ j = val.indexOf( DELIM_START, i );
+ if ( j == -1 )
+ {
+ if ( i == 0 )
+ {
+ return val;
+ }
+ sbuf.append( val.substring( i, val.length() ) );
+ return sbuf.toString();
+ }
+ sbuf.append( val.substring( i, j ) );
+ k = val.indexOf( DELIM_STOP, j );
+ if ( k == -1 )
+ {
+ throw new IllegalArgumentException( '"' + val + "\" has no closing brace. Opening brace at position "
+ + j + '.' );
+ }
+ j += DELIM_START_LEN;
+ String key = val.substring( j, k );
+ // first try in System properties
+ String replacement = getSystemProperty( key, null );
+ // then try props parameter
+ if ( replacement == null && props != null )
+ {
+ replacement = props.getProperty( key );
+ }
+
+ if ( replacement != null )
+ {
+ sbuf.append( replacement );
+ }
+ i = k + DELIM_STOP_LEN;
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/config/PropertySetter.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/config/PropertySetter.java
new file mode 100644
index 0000000..e91ec93
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/config/PropertySetter.java
@@ -0,0 +1,299 @@
+package org.apache.commons.jcs3.utils.config;
+
+/*
+ * 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.
+ */
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.Enumeration;
+import java.util.Properties;
+
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This class is based on the log4j class org.apache.log4j.config.PropertySetter that was made by
+ * Anders Kristensen
+ * <p>
+ * General purpose Object property setter. Clients repeatedly invokes {@link #setProperty
+ * setProperty(name,value)} in order to invoke setters on the Object specified in the constructor.
+ * This class relies on the JavaBeans {@link Introspector}to analyze the given Object Class using
+ * reflection.
+ * <p>
+ * Usage:
+ *
+ * <pre>
+ * PropertySetter ps = new PropertySetter( anObject );
+ * ps.set( "name", "Joe" );
+ * ps.set( "age", "32" );
+ * ps.set( "isMale", "true" );
+ * </pre>
+ *
+ * will cause the invocations anObject.setName("Joe"), anObject.setAge(32), and setMale(true) if
+ * such methods exist with those signatures. Otherwise an {@link IntrospectionException}are thrown.
+ */
+public class PropertySetter
+{
+ /** Logger */
+ private static final Log log = LogManager.getLog( PropertySetter.class );
+
+ /** Description of the Field */
+ private final Object obj;
+
+ /** Description of the Field */
+ private PropertyDescriptor[] props;
+
+ /**
+ * Create a new PropertySetter for the specified Object. This is done in preparation for invoking
+ * {@link #setProperty}one or more times.
+ * @param obj the object for which to set properties
+ */
+ public PropertySetter( Object obj )
+ {
+ this.obj = obj;
+ }
+
+ /**
+ * Uses JavaBeans {@link Introspector}to compute setters of object to be configured.
+ */
+ protected void introspect()
+ {
+ try
+ {
+ BeanInfo bi = Introspector.getBeanInfo( obj.getClass() );
+ props = bi.getPropertyDescriptors();
+ }
+ catch ( IntrospectionException ex )
+ {
+ log.error( "Failed to introspect {0}", obj, ex );
+ props = new PropertyDescriptor[0];
+ }
+ }
+
+ /**
+ * Set the properties of an object passed as a parameter in one go. The <code>properties</code>
+ * are parsed relative to a <code>prefix</code>.
+ * <p>
+ * @param obj The object to configure.
+ * @param properties A java.util.Properties containing keys and values.
+ * @param prefix Only keys having the specified prefix will be set.
+ */
+ public static void setProperties( Object obj, Properties properties, String prefix )
+ {
+ new PropertySetter( obj ).setProperties( properties, prefix );
+ }
+
+ /**
+ * Set the properties for the object that match the <code>prefix</code> passed as parameter.
+ * <p>
+ * @param properties The new properties value
+ * @param prefix The new properties value
+ */
+ public void setProperties( Properties properties, String prefix )
+ {
+ int len = prefix.length();
+
+ for ( Enumeration<?> e = properties.propertyNames(); e.hasMoreElements(); )
+ {
+ String key = (String) e.nextElement();
+
+ // handle only properties that start with the desired prefix.
+ if ( key.startsWith( prefix ) )
+ {
+
+ // ignore key if it contains dots after the prefix
+ if ( key.indexOf( '.', len + 1 ) > 0 )
+ {
+ //System.err.println("----------Ignoring---["+key
+ // +"], prefix=["+prefix+"].");
+ continue;
+ }
+
+ String value = OptionConverter.findAndSubst( key, properties );
+ key = key.substring( len );
+
+ setProperty( key, value );
+ }
+ }
+
+ }
+
+ /**
+ * Set a property on this PropertySetter's Object. If successful, this method will invoke a
+ * setter method on the underlying Object. The setter is the one for the specified property name
+ * and the value is determined partly from the setter argument type and partly from the value
+ * specified in the call to this method.
+ * <p>
+ * If the setter expects a String no conversion is necessary. If it expects an int, then an
+ * attempt is made to convert 'value' to an int using Integer.valueOf(value). If the setter expects
+ * a boolean, the conversion is by Boolean.valueOf(value).
+ * @param name name of the property
+ * @param value String value of the property
+ */
+
+ public void setProperty( String name, String value )
+ {
+ if ( value == null )
+ {
+ return;
+ }
+
+ name = Introspector.decapitalize( name );
+ PropertyDescriptor prop = getPropertyDescriptor( name );
+
+ //log.debug("---------Key: "+name+", type="+prop.getPropertyType());
+
+ if ( prop == null )
+ {
+ log.warn( "No such property [{0}] in {1}.", name, obj.getClass().getName() );
+ }
+ else
+ {
+ try
+ {
+ setProperty( prop, name, value );
+ }
+ catch ( PropertySetterException ex )
+ {
+ log.warn( "Failed to set property {0} to value \"{1}\".", name, value, ex );
+ }
+ }
+ }
+
+ /**
+ * Set the named property given a {@link PropertyDescriptor}.
+ * @param prop A PropertyDescriptor describing the characteristics of the property to set.
+ * @param name The named of the property to set.
+ * @param value The value of the property.
+ * @throws PropertySetterException
+ */
+
+ public void setProperty( PropertyDescriptor prop, String name, String value )
+ throws PropertySetterException
+ {
+ Method setter = prop.getWriteMethod();
+ if ( setter == null )
+ {
+ throw new PropertySetterException( "No setter for property" );
+ }
+ Class<?>[] paramTypes = setter.getParameterTypes();
+ if ( paramTypes.length != 1 )
+ {
+ throw new PropertySetterException( "#params for setter != 1" );
+ }
+
+ Object arg;
+ try
+ {
+ arg = convertArg( value, paramTypes[0] );
+ }
+ catch ( Throwable t )
+ {
+ throw new PropertySetterException( "Conversion to type [" + paramTypes[0] + "] failed. Reason: " + t );
+ }
+ if ( arg == null )
+ {
+ throw new PropertySetterException( "Conversion to type [" + paramTypes[0] + "] failed." );
+ }
+ log.debug( "Setting property [{0}] to [{1}].", name, arg );
+ try
+ {
+ setter.invoke( obj, new Object[] { arg } );
+ }
+ catch ( Exception ex )
+ {
+ throw new PropertySetterException( ex );
+ }
+ }
+
+ /**
+ * Convert <code>val</code> a String parameter to an object of a given type.
+ * @param val
+ * @param type
+ * @return Object
+ */
+ protected Object convertArg( String val, Class<?> type )
+ {
+ if ( val == null )
+ {
+ return null;
+ }
+
+ String v = val.trim();
+ if ( String.class.isAssignableFrom( type ) )
+ {
+ return val;
+ }
+ else if ( Integer.TYPE.isAssignableFrom( type ) )
+ {
+ return Integer.valueOf( v );
+ }
+ else if ( Long.TYPE.isAssignableFrom( type ) )
+ {
+ return Long.valueOf( v );
+ }
+ else if ( Boolean.TYPE.isAssignableFrom( type ) )
+ {
+ if ( "true".equalsIgnoreCase( v ) )
+ {
+ return Boolean.TRUE;
+ }
+ else if ( "false".equalsIgnoreCase( v ) )
+ {
+ return Boolean.FALSE;
+ }
+ }
+ else if( type.isEnum() )
+ {
+ Enum<?> en = Enum.valueOf(type.asSubclass(Enum.class), v );
+ return en;
+ }
+ else if ( File.class.isAssignableFrom( type ) )
+ {
+ return new File( v );
+ }
+ return null;
+ }
+
+ /**
+ * Gets the propertyDescriptor attribute of the PropertySetter object
+ * @param name
+ * @return The propertyDescriptor value
+ */
+ protected PropertyDescriptor getPropertyDescriptor( String name )
+ {
+ if ( props == null )
+ {
+ introspect();
+ }
+
+ for ( int i = 0; i < props.length; i++ )
+ {
+ if ( name.equals( props[i].getName() ) )
+ {
+ return props[i];
+ }
+ }
+ return null;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/config/PropertySetterException.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/config/PropertySetterException.java
new file mode 100644
index 0000000..633f20c
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/config/PropertySetterException.java
@@ -0,0 +1,75 @@
+package org.apache.commons.jcs3.utils.config;
+
+/*
+ * 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.
+ */
+
+/**
+ * This class is based on the log4j class org.apache.log4j.config.PropertySetter that was made by
+ * Anders Kristensen
+ * <p>
+ * Thrown when an error is encountered whilst attempting to set a property using the
+ * {@link PropertySetter}utility class.
+ */
+public class PropertySetterException
+ extends Exception
+{
+ /** DOn't change */
+ private static final long serialVersionUID = -210271658004609028L;
+
+ /** Description of the Field */
+ private final Throwable rootCause;
+
+ /**
+ * Constructor for the PropertySetterException object
+ * <p>
+ * @param msg
+ */
+ public PropertySetterException( String msg )
+ {
+ super( msg );
+ this.rootCause = null;
+ }
+
+ /**
+ * Constructor for the PropertySetterException object
+ * <p>
+ * @param rootCause
+ */
+ public PropertySetterException( Throwable rootCause )
+ {
+ super();
+ this.rootCause = rootCause;
+ }
+
+ /**
+ * Returns descriptive text on the cause of this exception.
+ * <p>
+ * @return The message value
+ */
+ @Override
+ public String getMessage()
+ {
+ String msg = super.getMessage();
+ if ( msg == null && rootCause != null )
+ {
+ msg = rootCause.getMessage();
+ }
+ return msg;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/config/package.html b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/config/package.html
similarity index 100%
rename from commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/config/package.html
rename to commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/config/package.html
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/DiscoveredService.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/DiscoveredService.java
new file mode 100644
index 0000000..d2f252c
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/DiscoveredService.java
@@ -0,0 +1,183 @@
+package org.apache.commons.jcs3.utils.discovery;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+import java.util.ArrayList;
+
+/**
+ * This contains info about a discovered service. These objects are stored in a set in the
+ * UDPDiscoveryService.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class DiscoveredService
+ implements Serializable
+{
+ /** For serialization. Don't change. */
+ private static final long serialVersionUID = -7810164772089509751L;
+
+ /** region names */
+ private ArrayList<String> cacheNames;
+
+ /** service address */
+ private String serviceAddress;
+
+ /** service port */
+ private int servicePort;
+
+ /** last time we heard from this service? */
+ private long lastHearFromTime = 0;
+
+ /**
+ * @param cacheNames the cacheNames to set
+ */
+ public void setCacheNames( ArrayList<String> cacheNames )
+ {
+ this.cacheNames = cacheNames;
+ }
+
+ /**
+ * @return the cacheNames
+ */
+ public ArrayList<String> getCacheNames()
+ {
+ return cacheNames;
+ }
+
+ /**
+ * @param serviceAddress The serviceAddress to set.
+ */
+ public void setServiceAddress( String serviceAddress )
+ {
+ this.serviceAddress = serviceAddress;
+ }
+
+ /**
+ * @return Returns the serviceAddress.
+ */
+ public String getServiceAddress()
+ {
+ return serviceAddress;
+ }
+
+ /**
+ * @param servicePort The servicePort to set.
+ */
+ public void setServicePort( int servicePort )
+ {
+ this.servicePort = servicePort;
+ }
+
+ /**
+ * @return Returns the servicePort.
+ */
+ public int getServicePort()
+ {
+ return servicePort;
+ }
+
+ /**
+ * @param lastHearFromTime The lastHearFromTime to set.
+ */
+ public void setLastHearFromTime( long lastHearFromTime )
+ {
+ this.lastHearFromTime = lastHearFromTime;
+ }
+
+ /**
+ * @return Returns the lastHearFromTime.
+ */
+ public long getLastHearFromTime()
+ {
+ return lastHearFromTime;
+ }
+
+ /** @return hashcode based on address/port */
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + ((serviceAddress == null) ? 0 : serviceAddress.hashCode());
+ result = prime * result + servicePort;
+ return result;
+ }
+
+ /**
+ * NOTE - this object is often put into sets, so equals needs to be overridden.
+ * <p>
+ * We can't use cache names as part of the equals unless we manually only use the address and
+ * port in a contains check. So that we can use normal set functionality, I've kept the cache
+ * names out.
+ * <p>
+ * @param otherArg other
+ * @return equality based on the address/port
+ */
+ @Override
+ public boolean equals(Object otherArg)
+ {
+ if (this == otherArg)
+ {
+ return true;
+ }
+ if (otherArg == null)
+ {
+ return false;
+ }
+ if (!(otherArg instanceof DiscoveredService))
+ {
+ return false;
+ }
+ DiscoveredService other = (DiscoveredService) otherArg;
+ if (serviceAddress == null)
+ {
+ if (other.serviceAddress != null)
+ {
+ return false;
+ }
+ } else if (!serviceAddress.equals(other.serviceAddress))
+ {
+ return false;
+ }
+ if (servicePort != other.servicePort)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @return string for debugging purposes.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\n DiscoveredService" );
+ buf.append( "\n CacheNames = [" + getCacheNames() + "]" );
+ buf.append( "\n ServiceAddress = [" + getServiceAddress() + "]" );
+ buf.append( "\n ServicePort = [" + getServicePort() + "]" );
+ buf.append( "\n LastHearFromTime = [" + getLastHearFromTime() + "]" );
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPCleanupRunner.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPCleanupRunner.java
new file mode 100644
index 0000000..f07b822
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPCleanupRunner.java
@@ -0,0 +1,92 @@
+package org.apache.commons.jcs3.utils.discovery;
+
+/*
+ * 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.
+ */
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This class periodically check the lastHeardFrom time on the services.
+ * <p>
+ * If they exceed the configurable limit, it removes them from the set.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class UDPCleanupRunner
+ implements Runnable
+{
+ /** log instance */
+ private static final Log log = LogManager.getLog( UDPCleanupRunner.class );
+
+ /** UDP discovery service */
+ private final UDPDiscoveryService discoveryService;
+
+ /** default for max idle time, in seconds */
+ private static final long DEFAULT_MAX_IDLE_TIME_SECONDS = 180;
+
+ /** The configured max idle time, in seconds */
+ private final long maxIdleTimeSeconds = DEFAULT_MAX_IDLE_TIME_SECONDS;
+
+ /**
+ * @param service UDPDiscoveryService
+ */
+ public UDPCleanupRunner( UDPDiscoveryService service )
+ {
+ this.discoveryService = service;
+ }
+
+ /**
+ * This goes through the list of services and removes those that we haven't heard from in longer
+ * than the max idle time.
+ * <p>
+ * @see java.lang.Runnable#run()
+ */
+ @Override
+ public void run()
+ {
+ long now = System.currentTimeMillis();
+
+ // iterate through the set
+ // it is thread safe
+ // TODO this should get a copy. you can't simply remove from this.
+ // the listeners need to be notified.
+ Set<DiscoveredService> toRemove = new HashSet<>();
+ // can't remove via the iterator. must remove directly
+ for (DiscoveredService service : discoveryService.getDiscoveredServices())
+ {
+ if ( ( now - service.getLastHearFromTime() ) > ( maxIdleTimeSeconds * 1000 ) )
+ {
+ log.info( "Removing service, since we haven't heard from it in "
+ + "{0} seconds. service = {1}", maxIdleTimeSeconds, service );
+ toRemove.add( service );
+ }
+ }
+
+ // remove the bad ones
+ for (DiscoveredService service : toRemove)
+ {
+ // call this so the listeners get notified
+ discoveryService.removeDiscoveredService( service );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryAttributes.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryAttributes.java
new file mode 100644
index 0000000..d0d8c04
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryAttributes.java
@@ -0,0 +1,269 @@
+package org.apache.commons.jcs3.utils.discovery;
+
+/*
+ * 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.
+ */
+
+/**
+ * Configuration properties for UDP discover service.
+ * <p>
+ * The service will allow out applications to find each other.
+ * <p>
+ * @author Aaron Smuts
+ */
+public final class UDPDiscoveryAttributes
+ implements Cloneable
+{
+ /** service name */
+ private String serviceName;
+
+ /** service address */
+ private String serviceAddress;
+
+ /** service port */
+ private int servicePort;
+
+ /**
+ * false -> this service instance is not ready to receive requests. true -> ready for use
+ */
+ private boolean isDark;
+
+ /** default udp discovery address */
+ private static final String DEFAULT_UDP_DISCOVERY_ADDRESS = "228.4.5.6";
+
+ /** default udp discovery port */
+ private static final int DEFAULT_UDP_DISCOVERY_PORT = 5678;
+
+ /** udp discovery address */
+ private String udpDiscoveryAddr = DEFAULT_UDP_DISCOVERY_ADDRESS;
+
+ /** udp discovery network interface */
+ private String udpDiscoveryInterface = null;
+
+ /** udp discovery port */
+ private int udpDiscoveryPort = DEFAULT_UDP_DISCOVERY_PORT;
+
+ /** udp datagram TTL */
+ private int udpTTL = 0;
+
+ /** default delay between sending passive broadcasts */
+ private static final int DEFAULT_SEND_DELAY_SEC = 60;
+
+ /** delay between sending passive broadcasts */
+ private int sendDelaySec = DEFAULT_SEND_DELAY_SEC;
+
+ /** default amount of time before we remove services that we haven't heard from */
+ private static final int DEFAULT_MAX_IDLE_TIME_SEC = 180;
+
+ /** amount of time before we remove services that we haven't heard from */
+ private int maxIdleTimeSec = DEFAULT_MAX_IDLE_TIME_SEC;
+
+ /**
+ * @param serviceName The serviceName to set.
+ */
+ public void setServiceName( String serviceName )
+ {
+ this.serviceName = serviceName;
+ }
+
+ /**
+ * @return Returns the serviceName.
+ */
+ public String getServiceName()
+ {
+ return serviceName;
+ }
+
+ /**
+ * @param serviceAddress The serviceAddress to set.
+ */
+ public void setServiceAddress( String serviceAddress )
+ {
+ this.serviceAddress = serviceAddress;
+ }
+
+ /**
+ * @return Returns the serviceAddress.
+ */
+ public String getServiceAddress()
+ {
+ return serviceAddress;
+ }
+
+ /**
+ * @param servicePort The servicePort to set.
+ */
+ public void setServicePort( int servicePort )
+ {
+ this.servicePort = servicePort;
+ }
+
+ /**
+ * @return Returns the servicePort.
+ */
+ public int getServicePort()
+ {
+ return servicePort;
+ }
+
+ /**
+ * @param udpDiscoveryAddr The udpDiscoveryAddr to set.
+ */
+ public void setUdpDiscoveryAddr( String udpDiscoveryAddr )
+ {
+ this.udpDiscoveryAddr = udpDiscoveryAddr;
+ }
+
+ /**
+ * @return Returns the udpDiscoveryAddr.
+ */
+ public String getUdpDiscoveryAddr()
+ {
+ return udpDiscoveryAddr;
+ }
+
+ /**
+ * @param udpDiscoveryInterface The udpDiscoveryInterface to set.
+ */
+ public void setUdpDiscoveryInterface( String udpDiscoveryInterface )
+ {
+ this.udpDiscoveryInterface = udpDiscoveryInterface;
+ }
+
+ /**
+ * @return Returns the udpDiscoveryInterface.
+ */
+ public String getUdpDiscoveryInterface()
+ {
+ return udpDiscoveryInterface;
+ }
+
+ /**
+ * @param udpDiscoveryPort The udpDiscoveryPort to set.
+ */
+ public void setUdpDiscoveryPort( int udpDiscoveryPort )
+ {
+ this.udpDiscoveryPort = udpDiscoveryPort;
+ }
+
+ /**
+ * @return Returns the udpTTL.
+ */
+ public int getUdpTTL()
+ {
+ return udpTTL;
+ }
+
+ /**
+ * @param udpTTL The udpTTL to set.
+ */
+ public void setUdpTTL( int udpTTL )
+ {
+ this.udpTTL = udpTTL;
+ }
+
+ /**
+ * @return Returns the udpDiscoveryPort.
+ */
+ public int getUdpDiscoveryPort()
+ {
+ return udpDiscoveryPort;
+ }
+
+ /**
+ * @param sendDelaySec The sendDelaySec to set.
+ */
+ public void setSendDelaySec( int sendDelaySec )
+ {
+ this.sendDelaySec = sendDelaySec;
+ }
+
+ /**
+ * @return Returns the sendDelaySec.
+ */
+ public int getSendDelaySec()
+ {
+ return sendDelaySec;
+ }
+
+ /**
+ * @param maxIdleTimeSec The maxIdleTimeSec to set.
+ */
+ public void setMaxIdleTimeSec( int maxIdleTimeSec )
+ {
+ this.maxIdleTimeSec = maxIdleTimeSec;
+ }
+
+ /**
+ * @return Returns the maxIdleTimeSec.
+ */
+ public int getMaxIdleTimeSec()
+ {
+ return maxIdleTimeSec;
+ }
+
+ /**
+ * @return Returns the isDark.
+ */
+ public boolean isDark()
+ {
+ return isDark;
+ }
+
+ /**
+ * @param isDark The isDark to set.
+ */
+ public void setDark( boolean isDark )
+ {
+ this.isDark = isDark;
+ }
+
+ /** @return a clone of this object */
+ @Override
+ public UDPDiscoveryAttributes clone()
+ {
+ UDPDiscoveryAttributes attributes = new UDPDiscoveryAttributes();
+ attributes.setSendDelaySec( this.getSendDelaySec() );
+ attributes.setMaxIdleTimeSec( this.getMaxIdleTimeSec() );
+ attributes.setServiceName( this.getServiceName() );
+ attributes.setServicePort( this.getServicePort() );
+ attributes.setUdpDiscoveryAddr( this.getUdpDiscoveryAddr() );
+ attributes.setUdpDiscoveryPort( this.getUdpDiscoveryPort() );
+ attributes.setDark( this.isDark() );
+ return attributes;
+ }
+
+ /**
+ * @return string for debugging purposes.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\n UDPDiscoveryAttributes" );
+ buf.append( "\n ServiceName = [" + getServiceName() + "]" );
+ buf.append( "\n ServiceAddress = [" + getServiceAddress() + "]" );
+ buf.append( "\n ServicePort = [" + getServicePort() + "]" );
+ buf.append( "\n UdpDiscoveryAddr = [" + getUdpDiscoveryAddr() + "]" );
+ buf.append( "\n UdpDiscoveryPort = [" + getUdpDiscoveryPort() + "]" );
+ buf.append( "\n SendDelaySec = [" + getSendDelaySec() + "]" );
+ buf.append( "\n MaxIdleTimeSec = [" + getMaxIdleTimeSec() + "]" );
+ buf.append( "\n IsDark = [" + isDark() + "]" );
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryManager.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryManager.java
new file mode 100644
index 0000000..40f7a44
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryManager.java
@@ -0,0 +1,108 @@
+package org.apache.commons.jcs3.utils.discovery;
+
+/*
+ * 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.
+ */
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IProvideScheduler;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This manages UDPDiscovery Services. We should end up with one service per Lateral Cache Manager
+ * Instance. One service works for multiple regions. We don't want a connection for each region.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class UDPDiscoveryManager
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( UDPDiscoveryManager.class );
+
+ /** Singleton instance */
+ private static UDPDiscoveryManager INSTANCE = new UDPDiscoveryManager();
+
+ /** Known services */
+ private final ConcurrentMap<String, UDPDiscoveryService> services = new ConcurrentHashMap<>();
+
+ /** private for singleton */
+ private UDPDiscoveryManager()
+ {
+ // noopt
+ }
+
+ /**
+ * Singleton
+ * <p>
+ * @return UDPDiscoveryManager
+ */
+ public static UDPDiscoveryManager getInstance()
+ {
+ return INSTANCE;
+ }
+
+ /**
+ * Creates a service for the address and port if one doesn't exist already.
+ * <p>
+ * We need to key this using the listener port too. TODO think of making one discovery service
+ * work for multiple types of clients.
+ * <p>
+ * @param discoveryAddress
+ * @param discoveryPort
+ * @param servicePort
+ * @param cacheMgr
+ * @return UDPDiscoveryService
+ */
+ public UDPDiscoveryService getService( String discoveryAddress, int discoveryPort, int servicePort,
+ ICompositeCacheManager cacheMgr )
+ {
+ String key = discoveryAddress + ":" + discoveryPort + ":" + servicePort;
+
+ UDPDiscoveryService service = services.computeIfAbsent(key, k -> {
+ log.info( "Creating service for address:port:servicePort [{0}]", key );
+
+ UDPDiscoveryAttributes attributes = new UDPDiscoveryAttributes();
+ attributes.setUdpDiscoveryAddr( discoveryAddress );
+ attributes.setUdpDiscoveryPort( discoveryPort );
+ attributes.setServicePort( servicePort );
+
+ UDPDiscoveryService newService = new UDPDiscoveryService( attributes );
+
+ // register for shutdown notification
+ cacheMgr.registerShutdownObserver( newService );
+
+ // inject scheduler
+ if ( cacheMgr instanceof IProvideScheduler)
+ {
+ newService.setScheduledExecutorService(((IProvideScheduler)cacheMgr)
+ .getScheduledExecutorService());
+ }
+
+ newService.startup();
+ return newService;
+ });
+
+ log.debug( "Returning service [{0}] for key [{1}]", service, key );
+
+ return service;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryMessage.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryMessage.java
new file mode 100644
index 0000000..70eeb1e
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryMessage.java
@@ -0,0 +1,166 @@
+package org.apache.commons.jcs3.utils.discovery;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+import java.util.ArrayList;
+
+/**
+ * The message sent by the discovery mechanism.
+ */
+public class UDPDiscoveryMessage
+ implements Serializable
+{
+ /** Don't change */
+ private static final long serialVersionUID = -5332377899560951793L;
+
+ public enum BroadcastType
+ {
+ /**
+ * This is the periodic broadcast of a servers location. This type of message is also sent in
+ * response to a REQUEST_BROADCAST.
+ */
+ PASSIVE,
+
+ /**
+ * This asks recipients to broadcast their location. This is used on startup.
+ */
+ REQUEST,
+
+ /**
+ * This message instructs the receiver to remove this service from its list.
+ */
+ REMOVE
+ }
+
+ /** The message type */
+ private BroadcastType messageType = BroadcastType.PASSIVE;
+
+ /** udp port */
+ private int port = 6789;
+
+ /** UDP host */
+ private String host = "228.5.6.7";
+
+ /** Id of the requester, allows self-filtration */
+ private long requesterId;
+
+ /** Names of regions */
+ private ArrayList<String> cacheNames = new ArrayList<>();
+
+ /**
+ * @param port The port to set.
+ */
+ public void setPort( int port )
+ {
+ this.port = port;
+ }
+
+ /**
+ * @return Returns the port.
+ */
+ public int getPort()
+ {
+ return port;
+ }
+
+ /**
+ * @param host The host to set.
+ */
+ public void setHost( String host )
+ {
+ this.host = host;
+ }
+
+ /**
+ * @return Returns the host.
+ */
+ public String getHost()
+ {
+ return host;
+ }
+
+ /**
+ * @param requesterId The requesterId to set.
+ */
+ public void setRequesterId( long requesterId )
+ {
+ this.requesterId = requesterId;
+ }
+
+ /**
+ * @return Returns the requesterId.
+ */
+ public long getRequesterId()
+ {
+ return requesterId;
+ }
+
+ /**
+ * @param messageType The messageType to set.
+ */
+ public void setMessageType( BroadcastType messageType )
+ {
+ this.messageType = messageType;
+ }
+
+ /**
+ * @return Returns the messageType.
+ */
+ public BroadcastType getMessageType()
+ {
+ return messageType;
+ }
+
+ /**
+ * @param cacheNames The cacheNames to set.
+ */
+ public void setCacheNames( ArrayList<String> cacheNames )
+ {
+ this.cacheNames = cacheNames;
+ }
+
+ /**
+ * @return Returns the cacheNames.
+ */
+ public ArrayList<String> getCacheNames()
+ {
+ return cacheNames;
+ }
+
+ /**
+ * @return debugging string
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\n host = [" + host + "]" );
+ buf.append( "\n port = [" + port + "]" );
+ buf.append( "\n requesterId = [" + requesterId + "]" );
+ buf.append( "\n messageType = [" + messageType + "]" );
+ buf.append( "\n Cache Names" );
+ for (String name : cacheNames)
+ {
+ buf.append( " cacheName = [" + name + "]" );
+ }
+ return buf.toString();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryReceiver.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryReceiver.java
new file mode 100644
index 0000000..361b90a
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryReceiver.java
@@ -0,0 +1,366 @@
+package org.apache.commons.jcs3.utils.discovery;
+
+/*
+ * 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.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+import java.net.MulticastSocket;
+import java.net.NetworkInterface;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.commons.jcs3.engine.CacheInfo;
+import org.apache.commons.jcs3.engine.behavior.IShutdownObserver;
+import org.apache.commons.jcs3.io.ObjectInputStreamClassLoaderAware;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.discovery.UDPDiscoveryMessage.BroadcastType;
+import org.apache.commons.jcs3.utils.net.HostNameUtil;
+import org.apache.commons.jcs3.utils.threadpool.PoolConfiguration;
+import org.apache.commons.jcs3.utils.threadpool.ThreadPoolManager;
+import org.apache.commons.jcs3.utils.threadpool.PoolConfiguration.WhenBlockedPolicy;
+
+/** Receives UDP Discovery messages. */
+public class UDPDiscoveryReceiver
+ implements Runnable, IShutdownObserver
+{
+ /** The log factory */
+ private static final Log log = LogManager.getLog( UDPDiscoveryReceiver.class );
+
+ /** buffer */
+ private final byte[] mBuffer = new byte[65536];
+
+ /** The socket used for communication. */
+ private MulticastSocket mSocket;
+
+ /**
+ * TODO: Consider using the threadpool manager to get this thread pool. For now place a tight
+ * restriction on the pool size
+ */
+ private static final int maxPoolSize = 2;
+
+ /** The processor */
+ private final ExecutorService pooledExecutor;
+
+ /** number of messages received. For debugging and testing. */
+ private final AtomicInteger cnt = new AtomicInteger(0);
+
+ /** Service to get cache names and handle request broadcasts */
+ private final UDPDiscoveryService service;
+
+ /** Multicast address */
+ private final InetAddress multicastAddress;
+
+ /** Is it shutdown. */
+ private boolean shutdown = false;
+
+ /**
+ * Constructor for the LateralUDPReceiver object.
+ * <p>
+ * We determine out own host using InetAddress
+ *<p>
+ * @param service
+ * @param multicastInterfaceString
+ * @param multicastAddressString
+ * @param multicastPort
+ * @throws IOException
+ */
+ public UDPDiscoveryReceiver( UDPDiscoveryService service, String multicastInterfaceString,
+ String multicastAddressString, int multicastPort )
+ throws IOException
+ {
+ this.service = service;
+ this.multicastAddress = InetAddress.getByName( multicastAddressString );
+
+ // create a small thread pool to handle a barrage
+ this.pooledExecutor = ThreadPoolManager.getInstance().createPool(
+ new PoolConfiguration(false, 0, maxPoolSize, maxPoolSize, 0,
+ WhenBlockedPolicy.DISCARDOLDEST, maxPoolSize),
+ "JCS-UDPDiscoveryReceiver-", Thread.MIN_PRIORITY);
+
+ log.info( "Constructing listener, [{0}:{1}]", multicastAddress, multicastPort );
+
+ createSocket( multicastInterfaceString, multicastAddress, multicastPort );
+ }
+
+ /**
+ * Creates the socket for this class.
+ * <p>
+ * @param multicastInterfaceString
+ * @param multicastAddress
+ * @param multicastPort
+ * @throws IOException
+ */
+ private void createSocket( String multicastInterfaceString, InetAddress multicastAddress,
+ int multicastPort )
+ throws IOException
+ {
+ try
+ {
+ mSocket = new MulticastSocket( multicastPort );
+ if (log.isInfoEnabled())
+ {
+ log.info( "Joining Group: [{0}]", multicastAddress );
+ }
+
+ // Use dedicated interface if specified
+ NetworkInterface multicastInterface = null;
+ if (multicastInterfaceString != null)
+ {
+ multicastInterface = NetworkInterface.getByName(multicastInterfaceString);
+ }
+ else
+ {
+ multicastInterface = HostNameUtil.getMulticastNetworkInterface();
+ }
+ if (multicastInterface != null)
+ {
+ log.info("Using network interface {0}", multicastInterface.getDisplayName());
+ mSocket.setNetworkInterface(multicastInterface);
+ }
+
+ mSocket.joinGroup( multicastAddress );
+ }
+ catch ( IOException e )
+ {
+ log.error( "Could not bind to multicast address [{0}:{1}]", multicastAddress,
+ multicastPort, e );
+ throw e;
+ }
+ }
+
+ /**
+ * Highly unreliable. If it is processing one message while another comes in, the second
+ * message is lost. This is for low concurrency peppering.
+ * <p>
+ * @return the object message
+ * @throws IOException
+ */
+ public Object waitForMessage()
+ throws IOException
+ {
+ final DatagramPacket packet = new DatagramPacket( mBuffer, mBuffer.length );
+ Object obj = null;
+ try
+ {
+ log.debug( "Waiting for message." );
+
+ mSocket.receive( packet );
+
+ log.debug( "Received packet from address [{0}]",
+ () -> packet.getSocketAddress() );
+
+ try (ByteArrayInputStream byteStream = new ByteArrayInputStream(mBuffer, 0, packet.getLength());
+ ObjectInputStream objectStream = new ObjectInputStreamClassLoaderAware(byteStream, null))
+ {
+ obj = objectStream.readObject();
+ }
+
+ if ( obj instanceof UDPDiscoveryMessage )
+ {
+ // Ensure that the address we're supposed to send to is, indeed, the address
+ // of the machine on the other end of this connection. This guards against
+ // instances where we don't exactly get the right local host address
+ UDPDiscoveryMessage msg = (UDPDiscoveryMessage) obj;
+ msg.setHost(packet.getAddress().getHostAddress());
+
+ log.debug( "Read object from address [{0}], object=[{1}]",
+ packet.getSocketAddress(), obj );
+ }
+ }
+ catch ( Exception e )
+ {
+ log.error( "Error receiving multicast packet", e );
+ }
+
+ return obj;
+ }
+
+ /** Main processing method for the LateralUDPReceiver object */
+ @Override
+ public void run()
+ {
+ try
+ {
+ while ( !shutdown )
+ {
+ Object obj = waitForMessage();
+
+ cnt.incrementAndGet();
+
+ log.debug( "{0} messages received.", () -> getCnt() );
+
+ UDPDiscoveryMessage message = null;
+
+ try
+ {
+ message = (UDPDiscoveryMessage) obj;
+ // check for null
+ if ( message != null )
+ {
+ MessageHandler handler = new MessageHandler( message );
+
+ pooledExecutor.execute( handler );
+
+ log.debug( "Passed handler to executor." );
+ }
+ else
+ {
+ log.warn( "message is null" );
+ }
+ }
+ catch ( ClassCastException cce )
+ {
+ log.warn( "Received unknown message type", cce.getMessage() );
+ }
+ } // end while
+ }
+ catch ( IOException e )
+ {
+ log.error( "Unexpected exception in UDP receiver.", e );
+ try
+ {
+ Thread.sleep( 100 );
+ // TODO consider some failure count so we don't do this
+ // forever.
+ }
+ catch ( InterruptedException e2 )
+ {
+ log.error( "Problem sleeping", e2 );
+ }
+ }
+ }
+
+ /**
+ * @param cnt The cnt to set.
+ */
+ public void setCnt( int cnt )
+ {
+ this.cnt.set(cnt);
+ }
+
+ /**
+ * @return Returns the cnt.
+ */
+ public int getCnt()
+ {
+ return cnt.get();
+ }
+
+ /**
+ * Separate thread run when a command comes into the UDPDiscoveryReceiver.
+ */
+ public class MessageHandler
+ implements Runnable
+ {
+ /** The message to handle. Passed in during construction. */
+ private UDPDiscoveryMessage message = null;
+
+ /**
+ * @param message
+ */
+ public MessageHandler( UDPDiscoveryMessage message )
+ {
+ this.message = message;
+ }
+
+ /**
+ * Process the message.
+ */
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public void run()
+ {
+ // consider comparing ports here instead.
+ if ( message.getRequesterId() == CacheInfo.listenerId )
+ {
+ log.debug( "Ignoring message sent from self" );
+ }
+ else
+ {
+ log.debug( "Process message sent from another" );
+ log.debug( "Message = {0}", message );
+
+ if ( message.getHost() == null || message.getCacheNames() == null || message.getCacheNames().isEmpty() )
+ {
+ log.debug( "Ignoring invalid message: {0}", message );
+ }
+ else
+ {
+ processMessage();
+ }
+ }
+ }
+
+ /**
+ * Process the incoming message.
+ */
+ @SuppressWarnings("synthetic-access")
+ private void processMessage()
+ {
+ DiscoveredService discoveredService = new DiscoveredService();
+ discoveredService.setServiceAddress( message.getHost() );
+ discoveredService.setCacheNames( message.getCacheNames() );
+ discoveredService.setServicePort( message.getPort() );
+ discoveredService.setLastHearFromTime( System.currentTimeMillis() );
+
+ // if this is a request message, have the service handle it and
+ // return
+ if ( message.getMessageType() == BroadcastType.REQUEST )
+ {
+ log.debug( "Message is a Request Broadcast, will have the service handle it." );
+ service.serviceRequestBroadcast();
+ return;
+ }
+ else if ( message.getMessageType() == BroadcastType.REMOVE )
+ {
+ log.debug( "Removing service from set {0}", discoveredService );
+ service.removeDiscoveredService( discoveredService );
+ }
+ else
+ {
+ service.addOrUpdateService( discoveredService );
+ }
+ }
+ }
+
+ /** Shuts down the socket. */
+ @Override
+ public void shutdown()
+ {
+ if (!shutdown)
+ {
+ try
+ {
+ shutdown = true;
+ mSocket.leaveGroup( multicastAddress );
+ mSocket.close();
+ pooledExecutor.shutdownNow();
+ }
+ catch ( IOException e )
+ {
+ log.error( "Problem closing socket" );
+ }
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoverySender.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoverySender.java
new file mode 100644
index 0000000..0710bdc
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoverySender.java
@@ -0,0 +1,260 @@
+package org.apache.commons.jcs3.utils.discovery;
+
+/*
+ * 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.
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+import java.net.MulticastSocket;
+import java.util.ArrayList;
+
+import org.apache.commons.jcs3.engine.CacheInfo;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.discovery.UDPDiscoveryMessage.BroadcastType;
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+
+/**
+ * This is a generic sender for the UDPDiscovery process.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class UDPDiscoverySender implements AutoCloseable
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog( UDPDiscoverySender.class );
+
+ /** The socket */
+ private final MulticastSocket localSocket;
+
+ /** The address */
+ private final InetAddress multicastAddress;
+
+ /** The port */
+ private final int multicastPort;
+
+ /** Used to serialize messages */
+ private final StandardSerializer serializer = new StandardSerializer();
+
+ /**
+ * Constructor for the UDPDiscoverySender object
+ * <p>
+ * This sender can be used to send multiple messages.
+ * <p>
+ * When you are done sending, you should destroy the socket sender.
+ * <p>
+ * @param host
+ * @param port
+ * @param udpTTL the Datagram packet time-to-live
+ * @throws IOException
+ */
+ public UDPDiscoverySender( String host, int port, int udpTTL )
+ throws IOException
+ {
+ try
+ {
+ log.debug( "Constructing socket for sender on port [{0}]", port );
+ localSocket = new MulticastSocket( port );
+ if (udpTTL > 0)
+ {
+ log.debug( "Setting datagram TTL to [{0}]", udpTTL );
+ localSocket.setTimeToLive(udpTTL);
+ }
+
+ // Remote address.
+ multicastAddress = InetAddress.getByName( host );
+ }
+ catch ( IOException e )
+ {
+ log.error( "Could not bind to multicast address [{0}]", host, e );
+ throw e;
+ }
+
+ this.multicastPort = port;
+ }
+
+ /**
+ * Closes the socket connection.
+ */
+ @Override
+ public void close()
+ {
+ if ( this.localSocket != null && !this.localSocket.isClosed() )
+ {
+ this.localSocket.close();
+ }
+ }
+
+ /**
+ * Send messages.
+ * <p>
+ * @param message
+ * @throws IOException
+ */
+ public void send( UDPDiscoveryMessage message )
+ throws IOException
+ {
+ if ( this.localSocket == null )
+ {
+ throw new IOException( "Socket is null, cannot send message." );
+ }
+
+ if ( this.localSocket.isClosed() )
+ {
+ throw new IOException( "Socket is closed, cannot send message." );
+ }
+
+ log.debug( "sending UDPDiscoveryMessage, address [{0}], port [{1}], "
+ + "message = {2}", multicastAddress, multicastPort, message );
+
+ try
+ {
+ final byte[] bytes = serializer.serialize( message );
+
+ // put the byte array in a packet
+ final DatagramPacket packet = new DatagramPacket( bytes, bytes.length, multicastAddress, multicastPort );
+
+ log.debug( "Sending DatagramPacket. bytes.length [{0}] to {1}:{2}",
+ bytes.length, multicastAddress, multicastPort );
+
+ localSocket.send( packet );
+ }
+ catch ( IOException e )
+ {
+ log.error( "Error sending message", e );
+ throw e;
+ }
+ }
+
+ /**
+ * Ask other to broadcast their info the the multicast address. If a lateral is non receiving it
+ * can use this. This is also called on startup so we can get info.
+ * <p>
+ * @throws IOException
+ */
+ public void requestBroadcast()
+ throws IOException
+ {
+ log.debug( "sending requestBroadcast" );
+
+ UDPDiscoveryMessage message = new UDPDiscoveryMessage();
+ message.setRequesterId( CacheInfo.listenerId );
+ message.setMessageType( BroadcastType.REQUEST );
+ send( message );
+ }
+
+ /**
+ * This sends a message broadcasting out that the host and port is available for connections.
+ * <p>
+ * It uses the vmid as the requesterDI
+ * @param host
+ * @param port
+ * @param cacheNames
+ * @throws IOException
+ */
+ public void passiveBroadcast( String host, int port, ArrayList<String> cacheNames )
+ throws IOException
+ {
+ passiveBroadcast( host, port, cacheNames, CacheInfo.listenerId );
+ }
+
+ /**
+ * This allows you to set the sender id. This is mainly for testing.
+ * <p>
+ * @param host
+ * @param port
+ * @param cacheNames names of the cache regions
+ * @param listenerId
+ * @throws IOException
+ */
+ protected void passiveBroadcast( String host, int port, ArrayList<String> cacheNames, long listenerId )
+ throws IOException
+ {
+ log.debug( "sending passiveBroadcast" );
+
+ UDPDiscoveryMessage message = new UDPDiscoveryMessage();
+ message.setHost( host );
+ message.setPort( port );
+ message.setCacheNames( cacheNames );
+ message.setRequesterId( listenerId );
+ message.setMessageType( BroadcastType.PASSIVE );
+ send( message );
+ }
+
+ /**
+ * This sends a message broadcasting our that the host and port is no longer available.
+ * <p>
+ * It uses the vmid as the requesterID
+ * <p>
+ * @param host host
+ * @param port port
+ * @param cacheNames names of the cache regions
+ * @throws IOException on error
+ */
+ public void removeBroadcast( String host, int port, ArrayList<String> cacheNames )
+ throws IOException
+ {
+ removeBroadcast( host, port, cacheNames, CacheInfo.listenerId );
+ }
+
+ /**
+ * This allows you to set the sender id. This is mainly for testing.
+ * <p>
+ * @param host host
+ * @param port port
+ * @param cacheNames names of the cache regions
+ * @param listenerId listener ID
+ * @throws IOException on error
+ */
+ protected void removeBroadcast( String host, int port, ArrayList<String> cacheNames, long listenerId )
+ throws IOException
+ {
+ log.debug( "sending removeBroadcast" );
+
+ UDPDiscoveryMessage message = new UDPDiscoveryMessage();
+ message.setHost( host );
+ message.setPort( port );
+ message.setCacheNames( cacheNames );
+ message.setRequesterId( listenerId );
+ message.setMessageType( BroadcastType.REMOVE );
+ send( message );
+ }
+}
+
+/**
+ * This allows us to get the byte array from an output stream.
+ * <p>
+ * @author asmuts
+ * @created January 15, 2002
+ */
+
+class MyByteArrayOutputStream
+ extends ByteArrayOutputStream
+{
+ /**
+ * Gets the bytes attribute of the MyByteArrayOutputStream object
+ * @return The bytes value
+ */
+ public byte[] getBytes()
+ {
+ return buf;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoverySenderThread.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoverySenderThread.java
new file mode 100644
index 0000000..21ba9fc
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoverySenderThread.java
@@ -0,0 +1,147 @@
+package org.apache.commons.jcs3.utils.discovery;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * Used to periodically broadcast our location to other caches that might be listening.
+ */
+public class UDPDiscoverySenderThread
+ implements Runnable
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog( UDPDiscoverySenderThread.class );
+
+ /**
+ * details of the host, port, and service being advertised to listen for TCP socket connections
+ */
+ private final UDPDiscoveryAttributes attributes;
+
+ /** List of known regions. */
+ private ArrayList<String> cacheNames = new ArrayList<>();
+
+ /**
+ * @param cacheNames The cacheNames to set.
+ */
+ protected void setCacheNames( ArrayList<String> cacheNames )
+ {
+ log.info( "Resetting cacheNames = [{0}]", cacheNames );
+ this.cacheNames = cacheNames;
+ }
+
+ /**
+ * @return Returns the cacheNames.
+ */
+ protected ArrayList<String> getCacheNames()
+ {
+ return cacheNames;
+ }
+
+ /**
+ * Constructs the sender with the port to tell others to connect to.
+ * <p>
+ * On construction the sender will request that the other caches let it know their addresses.
+ * @param attributes host, port, etc.
+ * @param cacheNames List of strings of the names of the region participating.
+ */
+ public UDPDiscoverySenderThread( UDPDiscoveryAttributes attributes, ArrayList<String> cacheNames )
+ {
+ this.attributes = attributes;
+
+ this.cacheNames = cacheNames;
+
+ log.debug( "Creating sender thread for discoveryAddress = [{0}] and "
+ + "discoveryPort = [{1}] myHostName = [{2}] and port = [{3}]",
+ () -> attributes.getUdpDiscoveryAddr(),
+ () -> attributes.getUdpDiscoveryPort(),
+ () -> attributes.getServiceAddress(),
+ () -> attributes.getServicePort() );
+
+ try (UDPDiscoverySender sender = new UDPDiscoverySender(
+ attributes.getUdpDiscoveryAddr(),
+ attributes.getUdpDiscoveryPort(),
+ attributes.getUdpTTL()))
+ {
+ // move this to the run method and determine how often to call it.
+ sender.requestBroadcast();
+
+ log.debug( "Sent a request broadcast to the group" );
+ }
+ catch ( IOException e )
+ {
+ log.error( "Problem sending a Request Broadcast", e );
+ }
+ }
+
+ /**
+ * Send a message.
+ */
+ @Override
+ public void run()
+ {
+ // create this connection each time.
+ // more robust
+ try (UDPDiscoverySender sender = new UDPDiscoverySender(
+ attributes.getUdpDiscoveryAddr(),
+ attributes.getUdpDiscoveryPort(),
+ attributes.getUdpTTL()))
+ {
+ sender.passiveBroadcast( attributes.getServiceAddress(), attributes.getServicePort(), cacheNames );
+
+ // todo we should consider sending a request broadcast every so
+ // often.
+
+ log.debug( "Called sender to issue a passive broadcast" );
+ }
+ catch ( IOException e )
+ {
+ log.error( "Problem calling the UDP Discovery Sender [{0}:{1}]",
+ attributes.getUdpDiscoveryAddr(),
+ attributes.getUdpDiscoveryPort(), e );
+ }
+ }
+
+ /**
+ * Issues a remove broadcast to the others.
+ */
+ protected void shutdown()
+ {
+ // create this connection each time.
+ // more robust
+ try (UDPDiscoverySender sender = new UDPDiscoverySender(
+ attributes.getUdpDiscoveryAddr(),
+ attributes.getUdpDiscoveryPort(),
+ attributes.getUdpTTL()))
+ {
+ sender.removeBroadcast( attributes.getServiceAddress(), attributes.getServicePort(), cacheNames );
+
+ log.debug( "Called sender to issue a remove broadcast in shudown." );
+ }
+ catch ( IOException e )
+ {
+ log.error( "Problem calling the UDP Discovery Sender", e );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryService.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryService.java
new file mode 100644
index 0000000..534ef1f
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryService.java
@@ -0,0 +1,372 @@
+package org.apache.commons.jcs3.utils.discovery;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.jcs3.engine.behavior.IRequireScheduler;
+import org.apache.commons.jcs3.engine.behavior.IShutdownObserver;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.discovery.behavior.IDiscoveryListener;
+import org.apache.commons.jcs3.utils.net.HostNameUtil;
+
+/**
+ * This service creates a listener that can create lateral caches and add them to the no wait list.
+ * <p>
+ * It also creates a sender that periodically broadcasts its availability.
+ * <p>
+ * The sender also broadcasts a request for other caches to broadcast their addresses.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class UDPDiscoveryService
+ implements IShutdownObserver, IRequireScheduler
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( UDPDiscoveryService.class );
+
+ /** thread that listens for messages */
+ private Thread udpReceiverThread;
+
+ /** the runnable that the receiver thread runs */
+ private UDPDiscoveryReceiver receiver;
+
+ /** the runnable that sends messages via the clock daemon */
+ private UDPDiscoverySenderThread sender = null;
+
+ /** attributes */
+ private UDPDiscoveryAttributes udpDiscoveryAttributes = null;
+
+ /** is this shut down? */
+ private boolean shutdown = false;
+
+ /** This is a set of services that have been discovered. */
+ private final Set<DiscoveredService> discoveredServices = new CopyOnWriteArraySet<>();
+
+ /** This a list of regions that are configured to use discovery. */
+ private final Set<String> cacheNames = new CopyOnWriteArraySet<>();
+
+ /** Set of listeners. */
+ private final Set<IDiscoveryListener> discoveryListeners = new CopyOnWriteArraySet<>();
+
+ /**
+ * @param attributes
+ */
+ public UDPDiscoveryService( UDPDiscoveryAttributes attributes)
+ {
+ udpDiscoveryAttributes = attributes.clone();
+
+ try
+ {
+ // todo, you should be able to set this
+ udpDiscoveryAttributes.setServiceAddress( HostNameUtil.getLocalHostAddress() );
+ }
+ catch ( UnknownHostException e )
+ {
+ log.error( "Couldn't get localhost address", e );
+ }
+
+ try
+ {
+ // todo need some kind of recovery here.
+ receiver = new UDPDiscoveryReceiver( this,
+ getUdpDiscoveryAttributes().getUdpDiscoveryInterface(),
+ getUdpDiscoveryAttributes().getUdpDiscoveryAddr(),
+ getUdpDiscoveryAttributes().getUdpDiscoveryPort() );
+ }
+ catch ( IOException e )
+ {
+ log.error( "Problem creating UDPDiscoveryReceiver, address [{0}] "
+ + "port [{1}] we won't be able to find any other caches",
+ getUdpDiscoveryAttributes().getUdpDiscoveryAddr(),
+ getUdpDiscoveryAttributes().getUdpDiscoveryPort(), e );
+ }
+
+ // create a sender thread
+ sender = new UDPDiscoverySenderThread( getUdpDiscoveryAttributes(), getCacheNames() );
+ }
+
+ /**
+ * @see org.apache.commons.jcs3.engine.behavior.IRequireScheduler#setScheduledExecutorService(java.util.concurrent.ScheduledExecutorService)
+ */
+ @Override
+ public void setScheduledExecutorService(ScheduledExecutorService scheduledExecutor)
+ {
+ if (sender != null)
+ {
+ scheduledExecutor.scheduleAtFixedRate(sender, 0, 15, TimeUnit.SECONDS);
+ }
+
+ /** removes things that have been idle for too long */
+ UDPCleanupRunner cleanup = new UDPCleanupRunner( this );
+ // I'm going to use this as both, but it could happen
+ // that something could hang around twice the time using this as the
+ // delay and the idle time.
+ scheduledExecutor.scheduleAtFixedRate(cleanup, 0, getUdpDiscoveryAttributes().getMaxIdleTimeSec(), TimeUnit.SECONDS);
+ }
+
+ /**
+ * Send a passive broadcast in response to a request broadcast. Never send a request for a
+ * request. We can respond to our own requests, since a request broadcast is not intended as a
+ * connection request. We might want to only send messages, so we would send a request, but
+ * never a passive broadcast.
+ */
+ protected void serviceRequestBroadcast()
+ {
+ // create this connection each time.
+ // more robust
+ try (UDPDiscoverySender sender = new UDPDiscoverySender(
+ getUdpDiscoveryAttributes().getUdpDiscoveryAddr(),
+ getUdpDiscoveryAttributes().getUdpDiscoveryPort(),
+ getUdpDiscoveryAttributes().getUdpTTL()))
+ {
+ sender.passiveBroadcast( getUdpDiscoveryAttributes().getServiceAddress(), getUdpDiscoveryAttributes()
+ .getServicePort(), this.getCacheNames() );
+
+ // todo we should consider sending a request broadcast every so
+ // often.
+
+ log.debug( "Called sender to issue a passive broadcast" );
+ }
+ catch ( IOException e )
+ {
+ log.error( "Problem calling the UDP Discovery Sender, address [{0}] "
+ + "port [{1}]",
+ getUdpDiscoveryAttributes().getUdpDiscoveryAddr(),
+ getUdpDiscoveryAttributes().getUdpDiscoveryPort(), e );
+ }
+ }
+
+ /**
+ * Adds a region to the list that is participating in discovery.
+ * <p>
+ * @param cacheName
+ */
+ public void addParticipatingCacheName( String cacheName )
+ {
+ cacheNames.add( cacheName );
+ sender.setCacheNames( getCacheNames() );
+ }
+
+ /**
+ * Removes the discovered service from the list and calls the discovery listener.
+ * <p>
+ * @param service
+ */
+ public void removeDiscoveredService( DiscoveredService service )
+ {
+ boolean contained = getDiscoveredServices().remove( service );
+
+ if ( contained )
+ {
+ log.info( "Removing {0}", service );
+ }
+
+ for (IDiscoveryListener listener : getDiscoveryListeners())
+ {
+ listener.removeDiscoveredService( service );
+ }
+ }
+
+ /**
+ * Add a service to the list. Update the held copy if we already know about it.
+ * <p>
+ * @param discoveredService discovered service
+ */
+ protected void addOrUpdateService( DiscoveredService discoveredService )
+ {
+ Set<DiscoveredService> discoveredServices = getDiscoveredServices();
+ // Since this is a set we can add it over an over.
+ // We want to replace the old one, since we may add info that is not part of the equals.
+ // The equals method on the object being added is intentionally restricted.
+ if ( !discoveredServices.contains( discoveredService ) )
+ {
+ log.info( "Set does not contain service. I discovered {0}", discoveredService );
+ log.debug( "Adding service in the set {0}", discoveredService );
+ discoveredServices.add( discoveredService );
+ }
+ else
+ {
+ log.debug( "Set contains service." );
+ log.debug( "Updating service in the set {0}", discoveredService );
+
+ // Update the list of cache names if it has changed.
+ DiscoveredService theOldServiceInformation = null;
+ // need to update the time this sucks. add has no effect convert to a map
+ for (DiscoveredService service1 : discoveredServices)
+ {
+ if ( discoveredService.equals( service1 ) )
+ {
+ theOldServiceInformation = service1;
+ break;
+ }
+ }
+ if ( theOldServiceInformation != null )
+ {
+ if ( !theOldServiceInformation.getCacheNames().equals(
+ discoveredService.getCacheNames() ) )
+ {
+ log.info( "List of cache names changed for service: {0}",
+ discoveredService );
+ }
+ }
+
+ // replace it, we want to reset the payload and the last heard from time.
+ discoveredServices.remove( discoveredService );
+ discoveredServices.add( discoveredService );
+ }
+
+ // Always Notify the listeners
+ // If we don't do this, then if a region using the default config is initialized after notification,
+ // it will never get the service in it's no wait list.
+ // Leave it to the listeners to decide what to do.
+ for (IDiscoveryListener listener : getDiscoveryListeners())
+ {
+ listener.addDiscoveredService( discoveredService );
+ }
+ }
+
+ /**
+ * Get all the cache names we have facades for.
+ * <p>
+ * @return ArrayList
+ */
+ protected ArrayList<String> getCacheNames()
+ {
+ ArrayList<String> names = new ArrayList<>();
+ names.addAll( cacheNames );
+ return names;
+ }
+
+ /**
+ * @param attr The UDPDiscoveryAttributes to set.
+ */
+ public void setUdpDiscoveryAttributes( UDPDiscoveryAttributes attr )
+ {
+ this.udpDiscoveryAttributes = attr;
+ }
+
+ /**
+ * @return Returns the lca.
+ */
+ public UDPDiscoveryAttributes getUdpDiscoveryAttributes()
+ {
+ return this.udpDiscoveryAttributes;
+ }
+
+ /**
+ * Start necessary receiver thread
+ */
+ public void startup()
+ {
+ udpReceiverThread = new Thread(receiver);
+ udpReceiverThread.setDaemon(true);
+ // udpReceiverThread.setName( t.getName() + "--UDPReceiver" );
+ udpReceiverThread.start();
+ }
+
+ /**
+ * Shuts down the receiver.
+ */
+ @Override
+ public void shutdown()
+ {
+ if ( !shutdown )
+ {
+ shutdown = true;
+
+ // no good way to do this right now.
+ if (receiver != null)
+ {
+ log.info( "Shutting down UDP discovery service receiver." );
+ receiver.shutdown();
+ udpReceiverThread.interrupt();
+ }
+
+ if (sender != null)
+ {
+ log.info( "Shutting down UDP discovery service sender." );
+ // also call the shutdown on the sender thread itself, which
+ // will result in a remove command.
+ sender.shutdown();
+ }
+ }
+ else
+ {
+ log.debug( "Shutdown already called." );
+ }
+ }
+
+ /**
+ * @return Returns the discoveredServices.
+ */
+ public Set<DiscoveredService> getDiscoveredServices()
+ {
+ return discoveredServices;
+ }
+
+ /**
+ * @return the discoveryListeners
+ */
+ private Set<IDiscoveryListener> getDiscoveryListeners()
+ {
+ return discoveryListeners;
+ }
+
+ /**
+ * @return the discoveryListeners
+ */
+ public Set<IDiscoveryListener> getCopyOfDiscoveryListeners()
+ {
+ Set<IDiscoveryListener> copy = new HashSet<>();
+ copy.addAll( getDiscoveryListeners() );
+ return copy;
+ }
+
+ /**
+ * Adds a listener.
+ * <p>
+ * @param listener
+ * @return true if it wasn't already in the set
+ */
+ public boolean addDiscoveryListener( IDiscoveryListener listener )
+ {
+ return getDiscoveryListeners().add( listener );
+ }
+
+ /**
+ * Removes a listener.
+ * <p>
+ * @param listener
+ * @return true if it was in the set
+ */
+ public boolean removeDiscoveryListener( IDiscoveryListener listener )
+ {
+ return getDiscoveryListeners().remove( listener );
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/behavior/IDiscoveryListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/behavior/IDiscoveryListener.java
new file mode 100644
index 0000000..0192cd3
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/discovery/behavior/IDiscoveryListener.java
@@ -0,0 +1,44 @@
+package org.apache.commons.jcs3.utils.discovery.behavior;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.utils.discovery.DiscoveredService;
+
+/**
+ * Interface for things that want to listen to discovery events. This will allow discovery to be
+ * used outside of the TCP lateral.
+ */
+public interface IDiscoveryListener
+{
+ /**
+ * Add the service if needed. This does not necessarily mean that the service is not already
+ * added. This can be called if there is a change in service information, such as the cacheNames.
+ * <p>
+ * @param service the service to add
+ */
+ void addDiscoveredService( DiscoveredService service );
+
+ /**
+ * Remove the service from the list.
+ * <p>
+ * @param service the service to remove
+ */
+ void removeDiscoveredService( DiscoveredService service );
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/net/HostNameUtil.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/net/HostNameUtil.java
new file mode 100644
index 0000000..863388b
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/net/HostNameUtil.java
@@ -0,0 +1,195 @@
+package org.apache.commons.jcs3.utils.net;
+
+/*
+ * 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.
+ */
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Enumeration;
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * Simple utility for getting the local host name.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class HostNameUtil
+{
+ /** The logger. */
+ private static final Log log = LogManager.getLog( HostNameUtil.class );
+
+ /**
+ * Gets the address for the local machine.
+ * <p>
+ * @return InetAddress.getLocalHost().getHostAddress()
+ * @throws UnknownHostException
+ */
+ public static String getLocalHostAddress() throws UnknownHostException
+ {
+ try
+ {
+ String hostAddress = getLocalHostLANAddress().getHostAddress();
+ log.debug( "hostAddress = [{0}]", hostAddress );
+ return hostAddress;
+ }
+ catch ( UnknownHostException e1 )
+ {
+ log.error( "Couldn't get localhost address", e1 );
+ throw e1;
+ }
+ }
+
+ /**
+ * Returns an <code>InetAddress</code> object encapsulating what is most likely the machine's
+ * LAN IP address.
+ * <p>
+ * This method is intended for use as a replacement of JDK method
+ * <code>InetAddress.getLocalHost</code>, because that method is ambiguous on Linux systems.
+ * Linux systems enumerate the loopback network interface the same way as regular LAN network
+ * interfaces, but the JDK <code>InetAddress.getLocalHost</code> method does not specify the
+ * algorithm used to select the address returned under such circumstances, and will often return
+ * the loopback address, which is not valid for network communication. Details <a
+ * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4665037">here</a>.
+ * <p>
+ * This method will scan all IP addresses on all network interfaces on the host machine to
+ * determine the IP address most likely to be the machine's LAN address. If the machine has
+ * multiple IP addresses, this method will prefer a site-local IP address (e.g. 192.168.x.x or
+ * 10.10.x.x, usually IPv4) if the machine has one (and will return the first site-local address
+ * if the machine has more than one), but if the machine does not hold a site-local address,
+ * this method will return simply the first non-loopback address found (IPv4 or IPv6).</p>
+ * <p>
+ * If this method cannot find a non-loopback address using this selection algorithm, it will
+ * fall back to calling and returning the result of JDK method
+ * <code>InetAddress.getLocalHost</code>.
+ * <p>
+ * <a href="http://issues.apache.org/jira/browse/JCS-40">JIR ISSUE JCS-40</a>
+ * <p>
+ * @return InetAddress
+ * @throws UnknownHostException If the LAN address of the machine cannot be found.
+ */
+ public static InetAddress getLocalHostLANAddress()
+ throws UnknownHostException
+ {
+ try
+ {
+ InetAddress candidateAddress = null;
+ // Iterate all NICs (network interface cards)...
+ for ( Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); )
+ {
+ NetworkInterface iface = ifaces.nextElement();
+ // Iterate all IP addresses assigned to each card...
+ for ( Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); )
+ {
+ InetAddress inetAddr = inetAddrs.nextElement();
+ if ( !inetAddr.isLoopbackAddress() )
+ {
+ if ( inetAddr.isSiteLocalAddress() )
+ {
+ // Found non-loopback site-local address. Return it immediately...
+ return inetAddr;
+ }
+ else if ( candidateAddress == null )
+ {
+ // Found non-loopback address, but not necessarily site-local.
+ // Store it as a candidate to be returned if site-local address is not subsequently found...
+ candidateAddress = inetAddr;
+ // Note that we don't repeatedly assign non-loopback non-site-local addresses as candidates,
+ // only the first. For subsequent iterations, candidate will be non-null.
+ }
+ }
+ }
+ }
+ if ( candidateAddress != null )
+ {
+ // We did not find a site-local address, but we found some other non-loopback address.
+ // Server might have a non-site-local address assigned to its NIC (or it might be running
+ // IPv6 which deprecates the "site-local" concept).
+ // Return this non-loopback candidate address...
+ return candidateAddress;
+ }
+ // At this point, we did not find a non-loopback address.
+ // Fall back to returning whatever InetAddress.getLocalHost() returns...
+ InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
+ if ( jdkSuppliedAddress == null )
+ {
+ throw new UnknownHostException( "The JDK InetAddress.getLocalHost() method unexpectedly returned null." );
+ }
+ return jdkSuppliedAddress;
+ }
+ catch ( SocketException e )
+ {
+ UnknownHostException unknownHostException = new UnknownHostException( "Failed to determine LAN address: "
+ + e );
+ unknownHostException.initCause( e );
+ throw unknownHostException;
+ }
+ }
+
+ /**
+ * On systems with multiple network interfaces and mixed IPv6/IPv4 get a valid network
+ * interface for binding to multicast
+ *
+ * @return a network interface suitable for multicast
+ * @throws SocketException if a problem occurs while reading the network interfaces
+ */
+ public static NetworkInterface getMulticastNetworkInterface() throws SocketException
+ {
+ Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
+ while (networkInterfaces.hasMoreElements())
+ {
+ NetworkInterface networkInterface = networkInterfaces.nextElement();
+ Enumeration<InetAddress> addressesFromNetworkInterface = networkInterface.getInetAddresses();
+ while (addressesFromNetworkInterface.hasMoreElements())
+ {
+ InetAddress inetAddress = addressesFromNetworkInterface.nextElement();
+ if (inetAddress.isSiteLocalAddress()
+ && !inetAddress.isAnyLocalAddress()
+ && !inetAddress.isLinkLocalAddress()
+ && !inetAddress.isLoopbackAddress()
+ && !inetAddress.isMulticastAddress())
+ {
+ return networkInterface;
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/serialization/CompressingSerializer.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/serialization/CompressingSerializer.java
new file mode 100644
index 0000000..85ec7e5
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/serialization/CompressingSerializer.java
@@ -0,0 +1,69 @@
+package org.apache.commons.jcs3.utils.serialization;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.utils.zip.CompressionUtil;
+
+/**
+ * Performs default serialization and de-serialization. It gzips the value.
+ */
+public class CompressingSerializer extends StandardSerializer
+{
+ /**
+ * Serializes an object using default serialization. Compresses the byte array.
+ * <p>
+ * @param obj object
+ * @return byte[]
+ * @throws IOException on i/o problem
+ */
+ @Override
+ public <T> byte[] serialize( T obj )
+ throws IOException
+ {
+ byte[] uncompressed = super.serialize(obj);
+ byte[] compressed = CompressionUtil.compressByteArray( uncompressed );
+ return compressed;
+ }
+
+ /**
+ * Uses default de-serialization to turn a byte array into an object. Decompresses the value
+ * first. All exceptions are converted into IOExceptions.
+ * <p>
+ * @param data data bytes
+ * @param loader class loader to use
+ * @return Object
+ * @throws IOException on i/o problem
+ * @throws ClassNotFoundException if class is not found during deserialization
+ */
+ @Override
+ public <T> T deSerialize( byte[] data, ClassLoader loader )
+ throws IOException, ClassNotFoundException
+ {
+ if ( data == null )
+ {
+ return null;
+ }
+
+ byte[] decompressedByteArray = CompressionUtil.decompressByteArray( data );
+ return super.deSerialize(decompressedByteArray, loader);
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/serialization/SerializationConversionUtil.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/serialization/SerializationConversionUtil.java
new file mode 100644
index 0000000..f6a1ca4
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/serialization/SerializationConversionUtil.java
@@ -0,0 +1,149 @@
+package org.apache.commons.jcs3.utils.serialization;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.CacheElementSerialized;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElementSerialized;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This uses a supplied Serializer to convert to and from cache elements.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class SerializationConversionUtil
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( SerializationConversionUtil.class );
+
+ /**
+ * This returns a wrapper that has a serialized version of the value instead
+ * of the value.
+ * <p>
+ * @param element
+ * @param elementSerializer
+ * the serializer to be used.
+ * @return null for null;
+ * @throws IOException
+ */
+ public static <K, V> ICacheElementSerialized<K, V> getSerializedCacheElement( ICacheElement<K, V> element,
+ IElementSerializer elementSerializer )
+ throws IOException
+ {
+ if ( element == null )
+ {
+ return null;
+ }
+
+ byte[] serializedValue = null;
+
+ // if it has already been serialized, don't do it again.
+ if ( element instanceof ICacheElementSerialized )
+ {
+ serializedValue = ( (ICacheElementSerialized<K, V>) element ).getSerializedValue();
+ }
+ else
+ {
+ if ( elementSerializer != null )
+ {
+ try
+ {
+ serializedValue = elementSerializer.serialize(element.getVal());
+
+ // update size in bytes
+ element.getElementAttributes().setSize(serializedValue.length);
+ }
+ catch ( IOException e )
+ {
+ log.error( "Problem serializing object.", e );
+ throw e;
+ }
+ }
+ else
+ {
+ // we could just use the default.
+ throw new IOException( "Could not serialize object. The ElementSerializer is null." );
+ }
+ }
+ ICacheElementSerialized<K, V> serialized = new CacheElementSerialized<>(
+ element.getCacheName(), element.getKey(), serializedValue, element.getElementAttributes() );
+
+ return serialized;
+ }
+
+ /**
+ * This returns a wrapper that has a de-serialized version of the value
+ * instead of the serialized value.
+ * <p>
+ * @param serialized
+ * @param elementSerializer
+ * the serializer to be used.
+ * @return null for null;
+ * @throws IOException
+ * @throws ClassNotFoundException
+ */
+ public static <K, V> ICacheElement<K, V> getDeSerializedCacheElement( ICacheElementSerialized<K, V> serialized,
+ IElementSerializer elementSerializer )
+ throws IOException, ClassNotFoundException
+ {
+ if ( serialized == null )
+ {
+ return null;
+ }
+
+ V deSerializedValue = null;
+
+ if ( elementSerializer != null )
+ {
+ try
+ {
+ try
+ {
+ deSerializedValue = elementSerializer.deSerialize( serialized.getSerializedValue(), null );
+ }
+ catch ( ClassNotFoundException e )
+ {
+ log.error( "Problem de-serializing object.", e );
+ throw e;
+ }
+ }
+ catch ( IOException e )
+ {
+ log.error( "Problem de-serializing object.", e );
+ throw e;
+ }
+ }
+ else
+ {
+ // we could just use the default.
+ throw new IOException( "Could not de-serialize object. The ElementSerializer is null." );
+ }
+ ICacheElement<K, V> deSerialized = new CacheElement<>( serialized.getCacheName(), serialized.getKey(), deSerializedValue );
+ deSerialized.setElementAttributes( serialized.getElementAttributes() );
+
+ return deSerialized;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/serialization/StandardSerializer.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/serialization/StandardSerializer.java
new file mode 100644
index 0000000..633a2c3
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/serialization/StandardSerializer.java
@@ -0,0 +1,82 @@
+package org.apache.commons.jcs3.utils.serialization;
+
+/*
+ * 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.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.io.ObjectInputStreamClassLoaderAware;
+
+/**
+ * Performs default serialization and de-serialization.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class StandardSerializer
+ implements IElementSerializer
+{
+ /**
+ * Serializes an object using default serialization.
+ * <p>
+ * @param obj
+ * @return byte[]
+ * @throws IOException
+ */
+ @Override
+ public <T> byte[] serialize(T obj)
+ throws IOException
+ {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ try (ObjectOutputStream oos = new ObjectOutputStream(baos))
+ {
+ oos.writeObject(obj);
+ }
+
+ return baos.toByteArray();
+ }
+
+ /**
+ * Uses default de-serialization to turn a byte array into an object. All exceptions are
+ * converted into IOExceptions.
+ * <p>
+ * @param data data bytes
+ * @param loader class loader to use
+ * @return Object
+ * @throws IOException
+ * @throws ClassNotFoundException
+ */
+ @Override
+ public <T> T deSerialize(byte[] data, ClassLoader loader)
+ throws IOException, ClassNotFoundException
+ {
+ try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
+ ObjectInputStream ois = new ObjectInputStreamClassLoaderAware(bais, loader))
+ {
+ @SuppressWarnings("unchecked") // Need to cast from Object
+ T readObject = (T) ois.readObject();
+ return readObject;
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/servlet/JCSServletContextListener.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/servlet/JCSServletContextListener.java
new file mode 100644
index 0000000..1b9c7f8
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/servlet/JCSServletContextListener.java
@@ -0,0 +1,73 @@
+package org.apache.commons.jcs3.utils.servlet;
+
+/*
+ * 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.
+ */
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * If you add this to the context listeners section of your web.xml file, this will shutdown JCS
+ * gracefully.
+ * <p>
+ * Add the following to the top of your web.xml file.
+ *
+ * <pre>
+ * <listener>
+ * <listener-class>
+ * org.apache.commons.jcs3.utils.servlet.JCSServletContextListener
+ * </listener-class>
+ * </listener>
+ * </pre>
+ * @author Aaron Smuts
+ */
+public class JCSServletContextListener
+ implements ServletContextListener
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( JCSServletContextListener.class );
+
+ /**
+ * This does nothing. We don't want to initialize the cache here.
+ * <p>
+ * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
+ */
+ @Override
+ public void contextInitialized( ServletContextEvent arg0 )
+ {
+ log.debug( "contextInitialized" );
+ }
+
+ /**
+ * Shutdown JCS.
+ * <p>
+ * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
+ */
+ @Override
+ public void contextDestroyed( ServletContextEvent arg0 )
+ {
+ log.debug( "contextDestroyed, shutting down JCS." );
+
+ JCS.shutdown();
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/AbstractLRUMap.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/AbstractLRUMap.java
new file mode 100644
index 0000000..7cfb139
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/AbstractLRUMap.java
@@ -0,0 +1,542 @@
+package org.apache.commons.jcs3.utils.struct;
+
+/*
+ * 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.
+ */
+
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.stream.Collectors;
+
+import org.apache.commons.jcs3.engine.control.group.GroupAttrName;
+import org.apache.commons.jcs3.engine.stats.StatElement;
+import org.apache.commons.jcs3.engine.stats.Stats;
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This is a simple LRUMap. It implements most of the map methods. It is not recommended that you
+ * use any but put, get, remove, and clear.
+ * <p>
+ * Children can implement the processRemovedLRU method if they want to handle the removal of the
+ * least recently used item.
+ * <p>
+ * This class was abstracted out of the LRU Memory cache. Put, remove, and get should be thread
+ * safe. It uses a hashtable and our own double linked list.
+ * <p>
+ * Locking is done on the instance.
+ * <p>
+ * @author aaron smuts
+ */
+public abstract class AbstractLRUMap<K, V>
+ implements Map<K, V>
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( AbstractLRUMap.class );
+
+ /** double linked list for lru */
+ private final DoubleLinkedList<LRUElementDescriptor<K, V>> list;
+
+ /** Map where items are stored by key. */
+ private final Map<K, LRUElementDescriptor<K, V>> map;
+
+ /** lock to keep map and list synchronous */
+ private final Lock lock = new ReentrantLock();
+
+ /** stats */
+ private long hitCnt = 0;
+
+ /** stats */
+ private long missCnt = 0;
+
+ /** stats */
+ private long putCnt = 0;
+
+ /**
+ * This creates an unbounded version. Setting the max objects will result in spooling on
+ * subsequent puts.
+ */
+ public AbstractLRUMap()
+ {
+ list = new DoubleLinkedList<>();
+
+ // normal hashtable is faster for
+ // sequential keys.
+ map = new ConcurrentHashMap<>();
+ }
+
+
+ /**
+ * This simply returns the number of elements in the map.
+ * <p>
+ * @see java.util.Map#size()
+ */
+ @Override
+ public int size()
+ {
+ return map.size();
+ }
+
+ /**
+ * This removes all the items. It clears the map and the double linked list.
+ * <p>
+ * @see java.util.Map#clear()
+ */
+ @Override
+ public void clear()
+ {
+ lock.lock();
+ try
+ {
+ map.clear();
+ list.removeAll();
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns true if the map is empty.
+ * <p>
+ * @see java.util.Map#isEmpty()
+ */
+ @Override
+ public boolean isEmpty()
+ {
+ return map.isEmpty();
+ }
+
+ /**
+ * Returns true if the map contains an element for the supplied key.
+ * <p>
+ * @see java.util.Map#containsKey(java.lang.Object)
+ */
+ @Override
+ public boolean containsKey( Object key )
+ {
+ return map.containsKey( key );
+ }
+
+ /**
+ * This is an expensive operation that determines if the object supplied is mapped to any key.
+ * <p>
+ * @see java.util.Map#containsValue(java.lang.Object)
+ */
+ @Override
+ public boolean containsValue( Object value )
+ {
+ return map.containsValue( value );
+ }
+
+ /**
+ * @return map.values();
+ */
+ @Override
+ public Collection<V> values()
+ {
+ return map.values().stream()
+ .map(value -> value.getPayload())
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * @param source
+ */
+ @Override
+ public void putAll( Map<? extends K, ? extends V> source )
+ {
+ if ( source != null )
+ {
+ source.entrySet()
+ .forEach(entry -> put(entry.getKey(), entry.getValue()));
+ }
+ }
+
+ /**
+ * @param key
+ * @return Object
+ */
+ @Override
+ public V get( Object key )
+ {
+ V retVal;
+
+ log.debug( "getting item for key {0}", key );
+
+ LRUElementDescriptor<K, V> me = map.get( key );
+
+ if ( me == null )
+ {
+ missCnt++;
+ retVal = null;
+ }
+ else
+ {
+ hitCnt++;
+ retVal = me.getPayload();
+ list.makeFirst( me );
+ }
+
+ if ( me == null )
+ {
+ log.debug( "LRUMap miss for {0}", key );
+ }
+ else
+ {
+ log.debug( "LRUMap hit for {0}", key );
+ }
+
+ // verifyCache();
+ return retVal;
+ }
+
+ /**
+ * This gets an element out of the map without adjusting it's position in the LRU. In other
+ * words, this does not count as being used. If the element is the last item in the list, it
+ * will still be the last time in the list.
+ * <p>
+ * @param key
+ * @return Object
+ */
+ public V getQuiet( Object key )
+ {
+ V ce = null;
+ LRUElementDescriptor<K, V> me = map.get( key );
+
+ if ( me != null )
+ {
+ ce = me.getPayload();
+ }
+
+ if ( me == null )
+ {
+ log.debug( "LRUMap quiet miss for {0}", key );
+ }
+ else
+ {
+ log.debug( "LRUMap quiet hit for {0}", key );
+ }
+
+ return ce;
+ }
+
+ /**
+ * @param key
+ * @return Object removed
+ */
+ @Override
+ public V remove( Object key )
+ {
+ log.debug( "removing item for key: {0}", key );
+
+ // remove single item.
+ lock.lock();
+ try
+ {
+ LRUElementDescriptor<K, V> me = map.remove(key);
+
+ if (me != null)
+ {
+ list.remove(me);
+ return me.getPayload();
+ }
+ }
+ finally
+ {
+ lock.unlock();
+ }
+
+ return null;
+ }
+
+ /**
+ * @param key
+ * @param value
+ * @return Object
+ */
+ @Override
+ public V put(K key, V value)
+ {
+ putCnt++;
+
+ LRUElementDescriptor<K, V> old = null;
+ LRUElementDescriptor<K, V> me = new LRUElementDescriptor<>(key, value);
+
+ lock.lock();
+ try
+ {
+ list.addFirst( me );
+ old = map.put(key, me);
+
+ // If the node was the same as an existing node, remove it.
+ if ( old != null && key.equals(old.getKey()))
+ {
+ list.remove( old );
+ }
+ }
+ finally
+ {
+ lock.unlock();
+ }
+
+ // If the element limit is reached, we need to spool
+ if (shouldRemove())
+ {
+ log.debug( "In memory limit reached, removing least recently used." );
+
+ // The spool will put them in a disk event queue, so there is no
+ // need to pre-queue the queuing. This would be a bit wasteful
+ // and wouldn't save much time in this synchronous call.
+ while (shouldRemove())
+ {
+ lock.lock();
+ try
+ {
+ LRUElementDescriptor<K, V> last = list.getLast();
+ if (last != null)
+ {
+ processRemovedLRU(last.getKey(), last.getPayload());
+ if (map.remove(last.getKey()) == null)
+ {
+ log.warn("update: remove failed for key: {0}",
+ () -> last.getKey());
+ verifyCache();
+ }
+ list.removeLast();
+ }
+ else
+ {
+ verifyCache();
+ throw new Error("update: last is null!");
+ }
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+
+ log.debug( "update: After spool map size: {0}", () -> map.size() );
+ if ( map.size() != list.size() )
+ {
+ log.error("update: After spool, size mismatch: map.size() = {0}, "
+ + "linked list size = {1}",
+ () -> map.size(), () -> list.size());
+ }
+ }
+
+ if ( old != null )
+ {
+ return old.getPayload();
+ }
+ return null;
+ }
+
+ protected abstract boolean shouldRemove();
+
+ /**
+ * Dump the cache entries from first to list for debugging.
+ */
+ @SuppressWarnings("unchecked") // No generics for public fields
+ public void dumpCacheEntries()
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("dumpingCacheEntries");
+ for (LRUElementDescriptor<K, V> me = list.getFirst(); me != null; me = (LRUElementDescriptor<K, V>) me.next)
+ {
+ log.trace("dumpCacheEntries> key={0}, val={1}", me.getKey(), me.getPayload());
+ }
+ }
+ }
+
+ /**
+ * Dump the cache map for debugging.
+ */
+ public void dumpMap()
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("dumpingMap");
+ map.entrySet().forEach(e ->
+ log.trace("dumpMap> key={0}, val={1}", e.getKey(), e.getValue().getPayload()));
+ }
+ }
+
+ /**
+ * Checks to see if all the items that should be in the cache are. Checks consistency between
+ * List and map.
+ */
+ @SuppressWarnings("unchecked") // No generics for public fields
+ protected void verifyCache()
+ {
+ if ( !log.isTraceEnabled() )
+ {
+ return;
+ }
+
+ log.trace( "verifycache: mapContains {0} elements, linked list "
+ + "contains {1} elements", map.size(), list.size() );
+ log.trace( "verifycache: checking linked list by key" );
+ for (LRUElementDescriptor<K, V> li = list.getFirst(); li != null; li = (LRUElementDescriptor<K, V>) li.next )
+ {
+ K key = li.getKey();
+ if ( !map.containsKey( key ) )
+ {
+ log.error( "verifycache: map does not contain key : {0}", li.getKey() );
+ log.error( "li.hashcode={0}", li.getKey().hashCode() );
+ log.error( "key class={0}", key.getClass() );
+ log.error( "key hashcode={0}", key.hashCode() );
+ log.error( "key toString={0}", key.toString() );
+ if ( key instanceof GroupAttrName )
+ {
+ GroupAttrName<?> name = (GroupAttrName<?>) key;
+ log.error( "GroupID hashcode={0}", name.groupId.hashCode() );
+ log.error( "GroupID.class={0}", name.groupId.getClass() );
+ log.error( "AttrName hashcode={0}", name.attrName.hashCode() );
+ log.error( "AttrName.class={0}", name.attrName.getClass() );
+ }
+ dumpMap();
+ }
+ else if ( map.get( li.getKey() ) == null )
+ {
+ log.error( "verifycache: linked list retrieval returned null for key: {0}",
+ li.getKey() );
+ }
+ }
+
+ log.trace( "verifycache: checking linked list by value " );
+ for (LRUElementDescriptor<K, V> li3 = list.getFirst(); li3 != null; li3 = (LRUElementDescriptor<K, V>) li3.next )
+ {
+ if ( map.containsValue( li3 ) == false )
+ {
+ log.error( "verifycache: map does not contain value : {0}", li3 );
+ dumpMap();
+ }
+ }
+
+ log.trace( "verifycache: checking via keysets!" );
+ map.forEach((key, value) -> {
+ boolean found = false;
+
+ for (LRUElementDescriptor<K, V> li2 = list.getFirst(); li2 != null; li2 = (LRUElementDescriptor<K, V>) li2.next )
+ {
+ if ( key.equals( li2.getKey() ) )
+ {
+ found = true;
+ break;
+ }
+ }
+ if ( !found )
+ {
+ log.error( "verifycache: key not found in list : {0}", key );
+ dumpCacheEntries();
+ if ( map.containsKey( key ) )
+ {
+ log.error( "verifycache: map contains key" );
+ }
+ else
+ {
+ log.error( "verifycache: map does NOT contain key, what the HECK!" );
+ }
+ }
+ });
+ }
+
+ /**
+ * This is called when an item is removed from the LRU. We just log some information.
+ * <p>
+ * Children can implement this method for special behavior.
+ * @param key
+ * @param value
+ */
+ protected void processRemovedLRU(K key, V value )
+ {
+ log.debug( "Removing key: [{0}] from LRUMap store, value = [{1}]", key, value );
+ log.debug( "LRUMap store size: \"{0}\".", this.size() );
+ }
+
+ /**
+ * @return IStats
+ */
+ public IStats getStatistics()
+ {
+ IStats stats = new Stats();
+ stats.setTypeName( "LRUMap" );
+
+ ArrayList<IStatElement<?>> elems = new ArrayList<>();
+
+ elems.add(new StatElement<>( "List Size", Integer.valueOf(list.size()) ) );
+ elems.add(new StatElement<>( "Map Size", Integer.valueOf(map.size()) ) );
+ elems.add(new StatElement<>( "Put Count", Long.valueOf(putCnt) ) );
+ elems.add(new StatElement<>( "Hit Count", Long.valueOf(hitCnt) ) );
+ elems.add(new StatElement<>( "Miss Count", Long.valueOf(missCnt) ) );
+
+ stats.setStatElements( elems );
+
+ return stats;
+ }
+
+ /**
+ * This returns a set of entries. Our LRUMapEntry is used since the value stored in the
+ * underlying map is a node in the double linked list. We wouldn't want to return this to the
+ * client, so we construct a new entry with the payload of the node.
+ * <p>
+ * TODO we should return out own set wrapper, so we can avoid the extra object creation if it
+ * isn't necessary.
+ * <p>
+ * @see java.util.Map#entrySet()
+ */
+ @Override
+ public Set<Map.Entry<K, V>> entrySet()
+ {
+ lock.lock();
+ try
+ {
+ return map.entrySet().stream()
+ .map(entry -> new AbstractMap.SimpleEntry<>(
+ entry.getKey(), entry.getValue().getPayload()))
+ .collect(Collectors.toSet());
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * @return map.keySet();
+ */
+ @Override
+ public Set<K> keySet()
+ {
+ return map.values().stream()
+ .map(value -> value.getKey())
+ .collect(Collectors.toSet());
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/DoubleLinkedList.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/DoubleLinkedList.java
new file mode 100644
index 0000000..28d119b
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/DoubleLinkedList.java
@@ -0,0 +1,291 @@
+package org.apache.commons.jcs3.utils.struct;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * This is a generic thread safe double linked list. It's very simple and all the operations are so
+ * quick that course grained synchronization is more than acceptable.
+ */
+@SuppressWarnings({ "unchecked", "rawtypes" }) // Don't know how to resolve this with generics
+public class DoubleLinkedList<T extends DoubleLinkedListNode>
+{
+ /** record size to avoid having to iterate */
+ private int size = 0;
+
+ /** The logger */
+ private static final Log log = LogManager.getLog( DoubleLinkedList.class );
+
+ /** LRU double linked list head node */
+ private T first;
+
+ /** LRU double linked list tail node */
+ private T last;
+
+ /**
+ * Default constructor.
+ */
+ public DoubleLinkedList()
+ {
+ super();
+ }
+
+ /**
+ * Adds a new node to the end of the link list.
+ * <p>
+ * @param me The feature to be added to the Last
+ */
+ public synchronized void addLast(T me)
+ {
+ if ( first == null )
+ {
+ // empty list.
+ first = me;
+ }
+ else
+ {
+ last.next = me;
+ me.prev = last;
+ }
+ last = me;
+ size++;
+ }
+
+ /**
+ * Adds a new node to the start of the link list.
+ * <p>
+ * @param me The feature to be added to the First
+ */
+ public synchronized void addFirst(T me)
+ {
+ if ( last == null )
+ {
+ // empty list.
+ last = me;
+ }
+ else
+ {
+ first.prev = me;
+ me.next = first;
+ }
+ first = me;
+ size++;
+ }
+
+ /**
+ * Returns the last node from the link list, if there are any nodes.
+ * <p>
+ * @return The last node.
+ */
+ public synchronized T getLast()
+ {
+ log.debug( "returning last node" );
+ return last;
+ }
+
+ /**
+ * Removes the specified node from the link list.
+ * <p>
+ * @return DoubleLinkedListNode, the first node.
+ */
+ public synchronized T getFirst()
+ {
+ log.debug( "returning first node" );
+ return first;
+ }
+
+ /**
+ * Moves an existing node to the start of the link list.
+ * <p>
+ * @param ln The node to set as the head.
+ */
+ public synchronized void makeFirst(T ln)
+ {
+ if ( ln.prev == null )
+ {
+ // already the first node. or not a node
+ return;
+ }
+ // splice: remove it from the list
+ ln.prev.next = ln.next;
+
+ if ( ln.next == null )
+ {
+ // last but not the first.
+ last = (T) ln.prev;
+ last.next = null;
+ }
+ else
+ {
+ // neither the last nor the first.
+ ln.next.prev = ln.prev;
+ }
+ first.prev = ln;
+ ln.next = first;
+ ln.prev = null;
+ first = ln;
+ }
+
+ /**
+ * Moves an existing node to the end of the link list.
+ * <p>
+ * @param ln The node to set as the head.
+ */
+ public synchronized void makeLast(T ln)
+ {
+ if ( ln.next == null )
+ {
+ // already the last node. or not a node
+ return;
+ }
+ // splice: remove it from the list
+ if ( ln.prev != null )
+ {
+ ln.prev.next = ln.next;
+ }
+ else
+ {
+ // first
+ first = last;
+ }
+
+ if ( last != null )
+ {
+ last.next = ln;
+ }
+ ln.prev = last;
+ ln.next = null;
+ last = ln;
+ }
+
+ /**
+ * Remove all of the elements from the linked list implementation.
+ */
+ public synchronized void removeAll()
+ {
+ for (T me = first; me != null; )
+ {
+ if ( me.prev != null )
+ {
+ me.prev = null;
+ }
+ T next = (T) me.next;
+ me = next;
+ }
+ first = last = null;
+ // make sure this will work, could be add while this is happening.
+ size = 0;
+ }
+
+ /**
+ * Removes the specified node from the link list.
+ * <p>
+ * @param me Description of the Parameter
+ * @return true if an element was removed.
+ */
+ public synchronized boolean remove(T me)
+ {
+ log.debug( "removing node" );
+
+ if ( me.next == null )
+ {
+ if ( me.prev == null )
+ {
+ // Make sure it really is the only node before setting head and
+ // tail to null. It is possible that we will be passed a node
+ // which has already been removed from the list, in which case
+ // we should ignore it
+
+ if ( me == first && me == last )
+ {
+ first = last = null;
+ }
+ }
+ else
+ {
+ // last but not the first.
+ last = (T) me.prev;
+ last.next = null;
+ me.prev = null;
+ }
+ }
+ else if ( me.prev == null )
+ {
+ // first but not the last.
+ first = (T) me.next;
+ first.prev = null;
+ me.next = null;
+ }
+ else
+ {
+ // neither the first nor the last.
+ me.prev.next = me.next;
+ me.next.prev = me.prev;
+ me.prev = me.next = null;
+ }
+ size--;
+
+ return true;
+ }
+
+ /**
+ * Removes the specified node from the link list.
+ * <p>
+ * @return The last node if there was one to remove.
+ */
+ public synchronized T removeLast()
+ {
+ log.debug( "removing last node" );
+ T temp = last;
+ if ( last != null )
+ {
+ remove( last );
+ }
+ return temp;
+ }
+
+ /**
+ * Returns the size of the list.
+ * <p>
+ * @return int
+ */
+ public synchronized int size()
+ {
+ return size;
+ }
+
+ // ///////////////////////////////////////////////////////////////////
+ /**
+ * Dump the cache entries from first to list for debugging.
+ */
+ public synchronized void debugDumpEntries()
+ {
+ if ( log.isDebugEnabled() )
+ {
+ log.debug( "dumping Entries" );
+ for (T me = first; me != null; me = (T) me.next)
+ {
+ log.debug( "dump Entries> payload= \"{0}\"", me.getPayload() );
+ }
+ }
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/DoubleLinkedListNode.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/DoubleLinkedListNode.java
new file mode 100644
index 0000000..3f55041
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/DoubleLinkedListNode.java
@@ -0,0 +1,62 @@
+package org.apache.commons.jcs3.utils.struct;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+
+/**
+ * This serves as a placeholder in a double linked list. You can extend this to
+ * add functionality. This allows you to remove in constant time from a linked
+ * list.
+ * <p>
+ * It simply holds the payload and a reference to the items before and after it
+ * in the list.
+ */
+public class DoubleLinkedListNode<T>
+ implements Serializable
+{
+ /** Dont' change. */
+ private static final long serialVersionUID = -1114934407695836097L;
+
+ /** The object in the node. */
+ private final T payload;
+
+ /** Double Linked list references */
+ public DoubleLinkedListNode<T> prev;
+
+ /** Double Linked list references */
+ public DoubleLinkedListNode<T> next;
+
+ /**
+ * @param payloadP
+ */
+ public DoubleLinkedListNode(T payloadP)
+ {
+ payload = payloadP;
+ }
+
+ /**
+ * @return Object
+ */
+ public T getPayload()
+ {
+ return payload;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/LRUElementDescriptor.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/LRUElementDescriptor.java
new file mode 100644
index 0000000..4a23554
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/LRUElementDescriptor.java
@@ -0,0 +1,60 @@
+package org.apache.commons.jcs3.utils.struct;
+
+/*
+ * 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.
+ */
+
+/**
+ * This is a node in the double linked list. It is stored as the value in the underlying map used by
+ * the LRUMap class.
+ */
+public class LRUElementDescriptor<K, V>
+ extends DoubleLinkedListNode<V>
+{
+ /** Don't change. */
+ private static final long serialVersionUID = 8249555756363020156L;
+
+ /** The key value */
+ private K key;
+
+ /**
+ * @param key
+ * @param payloadP
+ */
+ public LRUElementDescriptor(K key, V payloadP)
+ {
+ super(payloadP);
+ this.setKey(key);
+ }
+
+ /**
+ * @param key The key to set.
+ */
+ public void setKey(K key)
+ {
+ this.key = key;
+ }
+
+ /**
+ * @return Returns the key.
+ */
+ public K getKey()
+ {
+ return key;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/LRUMap.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/LRUMap.java
new file mode 100644
index 0000000..d654c9d
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/struct/LRUMap.java
@@ -0,0 +1,57 @@
+package org.apache.commons.jcs3.utils.struct;
+
+/*
+ * 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.
+ */
+
+/**
+ *
+ * @author Wiktor Niesiobędzki
+ *
+ * Simple LRUMap implementation that keeps the number of the objects below or equal maxObjects
+ *
+ * @param <K>
+ * @param <V>
+ */
+public class LRUMap<K, V> extends AbstractLRUMap<K, V>
+{
+ /** if the max is less than 0, there is no limit! */
+ private int maxObjects = -1;
+
+ public LRUMap()
+ {
+ super();
+ }
+
+ /**
+ *
+ * @param maxObjects
+ * maximum number to keep in the map
+ */
+ public LRUMap(int maxObjects)
+ {
+ this();
+ this.maxObjects = maxObjects;
+ }
+
+ @Override
+ public boolean shouldRemove()
+ {
+ return maxObjects > 0 && this.size() > maxObjects;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/threadpool/DaemonThreadFactory.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/threadpool/DaemonThreadFactory.java
new file mode 100644
index 0000000..c559bee
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/threadpool/DaemonThreadFactory.java
@@ -0,0 +1,74 @@
+package org.apache.commons.jcs3.utils.threadpool;
+
+/*
+ * 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.
+ */
+
+import java.util.concurrent.ThreadFactory;
+
+/**
+ * Allows us to set the daemon status on the threads.
+ * <p>
+ * @author aaronsm
+ */
+public class DaemonThreadFactory
+ implements ThreadFactory
+{
+ private final String prefix;
+ private final boolean threadIsDaemon = true;
+ private int threadPriority = Thread.NORM_PRIORITY;
+
+ /**
+ * Constructor
+ *
+ * @param prefix thread name prefix
+ */
+ public DaemonThreadFactory(String prefix)
+ {
+ this(prefix, Thread.NORM_PRIORITY);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param prefix thread name prefix
+ * @param threadPriority set thread priority
+ */
+ public DaemonThreadFactory(String prefix, int threadPriority)
+ {
+ this.prefix = prefix;
+ this.threadPriority = threadPriority;
+ }
+
+ /**
+ * Sets the thread to daemon.
+ * <p>
+ * @param runner
+ * @return a daemon thread
+ */
+ @Override
+ public Thread newThread( Runnable runner )
+ {
+ Thread t = new Thread( runner );
+ String oldName = t.getName();
+ t.setName( prefix + oldName );
+ t.setDaemon(threadIsDaemon);
+ t.setPriority(threadPriority);
+ return t;
+ }
+}
\ No newline at end of file
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/threadpool/PoolConfiguration.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/threadpool/PoolConfiguration.java
new file mode 100644
index 0000000..c779dc3
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/threadpool/PoolConfiguration.java
@@ -0,0 +1,293 @@
+package org.apache.commons.jcs3.utils.threadpool;
+
+/*
+ * 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.
+ */
+
+/**
+ * This object holds configuration data for a thread pool.
+ * <p>
+ * @author Aaron Smuts
+ */
+public final class PoolConfiguration
+ implements Cloneable
+{
+ /**
+ * DEFAULT SETTINGS
+ */
+ private static final boolean DEFAULT_USE_BOUNDARY = true;
+
+ /** Default queue size limit */
+ private static final int DEFAULT_BOUNDARY_SIZE = 2000;
+
+ /** Default max size */
+ private static final int DEFAULT_MAXIMUM_POOL_SIZE = 150;
+
+ /** Default min */
+ private static final int DEFAULT_MINIMUM_POOL_SIZE = Runtime.getRuntime().availableProcessors();
+
+ /** Default keep alive */
+ private static final int DEFAULT_KEEPALIVE_TIME = 1000 * 60 * 5;
+
+ /** Default when blocked */
+ private static final WhenBlockedPolicy DEFAULT_WHEN_BLOCKED_POLICY = WhenBlockedPolicy.RUN;
+
+ /** Default startup size */
+ private static final int DEFAULT_STARTUP_SIZE = DEFAULT_MINIMUM_POOL_SIZE;
+
+ /** Should we bound the queue */
+ private boolean useBoundary = DEFAULT_USE_BOUNDARY;
+
+ /** If the queue is bounded, how big can it get */
+ private int boundarySize = DEFAULT_BOUNDARY_SIZE;
+
+ /** only has meaning if a boundary is used */
+ private int maximumPoolSize = DEFAULT_MAXIMUM_POOL_SIZE;
+
+ /**
+ * the exact number that will be used in a boundless queue. If the queue has a boundary, more
+ * will be created if the queue fills.
+ */
+ private int minimumPoolSize = DEFAULT_MINIMUM_POOL_SIZE;
+
+ /** How long idle threads above the minimum should be kept alive. */
+ private int keepAliveTime = DEFAULT_KEEPALIVE_TIME;
+
+ public enum WhenBlockedPolicy {
+ /** abort when queue is full and max threads is reached. */
+ ABORT,
+
+ /** block when queue is full and max threads is reached. */
+ BLOCK,
+
+ /** run in current thread when queue is full and max threads is reached. */
+ RUN,
+
+ /** wait when queue is full and max threads is reached. */
+ WAIT,
+
+ /** discard oldest when queue is full and max threads is reached. */
+ DISCARDOLDEST
+ }
+
+ /** should be ABORT, BLOCK, RUN, WAIT, DISCARDOLDEST, */
+ private WhenBlockedPolicy whenBlockedPolicy = DEFAULT_WHEN_BLOCKED_POLICY;
+
+ /** The number of threads to create on startup */
+ private int startUpSize = DEFAULT_MINIMUM_POOL_SIZE;
+
+ /**
+ * @param useBoundary The useBoundary to set.
+ */
+ public void setUseBoundary( boolean useBoundary )
+ {
+ this.useBoundary = useBoundary;
+ }
+
+ /**
+ * @return Returns the useBoundary.
+ */
+ public boolean isUseBoundary()
+ {
+ return useBoundary;
+ }
+
+ /**
+ * Default
+ */
+ public PoolConfiguration()
+ {
+ this( DEFAULT_USE_BOUNDARY, DEFAULT_BOUNDARY_SIZE, DEFAULT_MAXIMUM_POOL_SIZE,
+ DEFAULT_MINIMUM_POOL_SIZE, DEFAULT_KEEPALIVE_TIME,
+ DEFAULT_WHEN_BLOCKED_POLICY, DEFAULT_STARTUP_SIZE );
+ }
+
+ /**
+ * Construct a completely configured instance.
+ * <p>
+ * @param useBoundary
+ * @param boundarySize
+ * @param maximumPoolSize
+ * @param minimumPoolSize
+ * @param keepAliveTime
+ * @param whenBlockedPolicy
+ * @param startUpSize
+ */
+ public PoolConfiguration( boolean useBoundary, int boundarySize, int maximumPoolSize, int minimumPoolSize,
+ int keepAliveTime, WhenBlockedPolicy whenBlockedPolicy, int startUpSize )
+ {
+ setUseBoundary( useBoundary );
+ setBoundarySize( boundarySize );
+ setMaximumPoolSize( maximumPoolSize );
+ setMinimumPoolSize( minimumPoolSize );
+ setKeepAliveTime( keepAliveTime );
+ setWhenBlockedPolicy( whenBlockedPolicy );
+ setStartUpSize( startUpSize );
+ }
+
+ /**
+ * @param boundarySize The boundarySize to set.
+ */
+ public void setBoundarySize( int boundarySize )
+ {
+ this.boundarySize = boundarySize;
+ }
+
+ /**
+ * @return Returns the boundarySize.
+ */
+ public int getBoundarySize()
+ {
+ return boundarySize;
+ }
+
+ /**
+ * @param maximumPoolSize The maximumPoolSize to set.
+ */
+ public void setMaximumPoolSize( int maximumPoolSize )
+ {
+ this.maximumPoolSize = maximumPoolSize;
+ }
+
+ /**
+ * @return Returns the maximumPoolSize.
+ */
+ public int getMaximumPoolSize()
+ {
+ return maximumPoolSize;
+ }
+
+ /**
+ * @param minimumPoolSize The minimumPoolSize to set.
+ */
+ public void setMinimumPoolSize( int minimumPoolSize )
+ {
+ this.minimumPoolSize = minimumPoolSize;
+ }
+
+ /**
+ * @return Returns the minimumPoolSize.
+ */
+ public int getMinimumPoolSize()
+ {
+ return minimumPoolSize;
+ }
+
+ /**
+ * @param keepAliveTime The keepAliveTime to set.
+ */
+ public void setKeepAliveTime( int keepAliveTime )
+ {
+ this.keepAliveTime = keepAliveTime;
+ }
+
+ /**
+ * @return Returns the keepAliveTime.
+ */
+ public int getKeepAliveTime()
+ {
+ return keepAliveTime;
+ }
+
+ /**
+ * @param whenBlockedPolicy The whenBlockedPolicy to set.
+ */
+ public void setWhenBlockedPolicy( String whenBlockedPolicy )
+ {
+ if ( whenBlockedPolicy != null )
+ {
+ WhenBlockedPolicy policy = WhenBlockedPolicy.valueOf(whenBlockedPolicy.trim().toUpperCase());
+ setWhenBlockedPolicy(policy);
+ }
+ else
+ {
+ // the value is null, default to RUN
+ this.whenBlockedPolicy = WhenBlockedPolicy.RUN;
+ }
+ }
+
+ /**
+ * @param whenBlockedPolicy The whenBlockedPolicy to set.
+ */
+ public void setWhenBlockedPolicy( WhenBlockedPolicy whenBlockedPolicy )
+ {
+ if ( whenBlockedPolicy != null )
+ {
+ this.whenBlockedPolicy = whenBlockedPolicy;
+ }
+ else
+ {
+ // the value is null, default to RUN
+ this.whenBlockedPolicy = WhenBlockedPolicy.RUN;
+ }
+ }
+
+ /**
+ * @return Returns the whenBlockedPolicy.
+ */
+ public WhenBlockedPolicy getWhenBlockedPolicy()
+ {
+ return whenBlockedPolicy;
+ }
+
+ /**
+ * @param startUpSize The startUpSize to set.
+ */
+ public void setStartUpSize( int startUpSize )
+ {
+ this.startUpSize = startUpSize;
+ }
+
+ /**
+ * @return Returns the startUpSize.
+ */
+ public int getStartUpSize()
+ {
+ return startUpSize;
+ }
+
+ /**
+ * To string for debugging purposes.
+ * @return String
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "useBoundary = [" + isUseBoundary() + "] " );
+ buf.append( "boundarySize = [" + boundarySize + "] " );
+ buf.append( "maximumPoolSize = [" + maximumPoolSize + "] " );
+ buf.append( "minimumPoolSize = [" + minimumPoolSize + "] " );
+ buf.append( "keepAliveTime = [" + keepAliveTime + "] " );
+ buf.append( "whenBlockedPolicy = [" + getWhenBlockedPolicy() + "] " );
+ buf.append( "startUpSize = [" + startUpSize + "]" );
+ return buf.toString();
+ }
+
+ /**
+ * Copies the instance variables to another instance.
+ * <p>
+ * @return PoolConfiguration
+ */
+ @Override
+ public PoolConfiguration clone()
+ {
+ return new PoolConfiguration( isUseBoundary(), boundarySize, maximumPoolSize, minimumPoolSize, keepAliveTime,
+ getWhenBlockedPolicy(), startUpSize );
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/threadpool/ThreadPoolManager.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/threadpool/ThreadPoolManager.java
new file mode 100644
index 0000000..4552f9a
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/threadpool/ThreadPoolManager.java
@@ -0,0 +1,338 @@
+package org.apache.commons.jcs3.utils.threadpool;
+
+/*
+ * 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.
+ */
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.config.PropertySetter;
+
+/**
+ * This manages threadpools for an application
+ * <p>
+ * It is a singleton since threads need to be managed vm wide.
+ * <p>
+ * This manager forces you to use a bounded queue. By default it uses the current thread for
+ * execution when the buffer is full and no free threads can be created.
+ * <p>
+ * You can specify the props file to use or pass in a properties object prior to configuration.
+ * <p>
+ * If set, the Properties object will take precedence.
+ * <p>
+ * If a value is not set for a particular pool, the hard coded defaults in <code>PoolConfiguration</code> will be used.
+ * You can configure default settings by specifying <code>thread_pool.default</code> in the properties, ie "cache.ccf"
+ * <p>
+ * @author Aaron Smuts
+ */
+public class ThreadPoolManager
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( ThreadPoolManager.class );
+
+ /** The default config, created using property defaults if present, else those above. */
+ private PoolConfiguration defaultConfig;
+
+ /** The default scheduler config, created using property defaults if present, else those above. */
+ private PoolConfiguration defaultSchedulerConfig;
+
+ /** the root property name */
+ private static final String PROP_NAME_ROOT = "thread_pool";
+
+ /** default property file name */
+ private static final String DEFAULT_PROP_NAME_ROOT = "thread_pool.default";
+
+ /** the scheduler root property name */
+ private static final String PROP_NAME_SCHEDULER_ROOT = "scheduler_pool";
+
+ /** default scheduler property file name */
+ private static final String DEFAULT_PROP_NAME_SCHEDULER_ROOT = "scheduler_pool.default";
+
+ /**
+ * You can specify the properties to be used to configure the thread pool. Setting this post
+ * initialization will have no effect.
+ */
+ private static volatile Properties props = null;
+
+ /** Map of names to pools. */
+ private final ConcurrentHashMap<String, ExecutorService> pools;
+
+ /** Map of names to scheduler pools. */
+ private final ConcurrentHashMap<String, ScheduledExecutorService> schedulerPools;
+
+ /**
+ * The ThreadPoolManager instance (holder pattern)
+ */
+ private static class ThreadPoolManagerHolder
+ {
+ static final ThreadPoolManager INSTANCE = new ThreadPoolManager();
+ }
+
+ /**
+ * No instances please. This is a singleton.
+ */
+ private ThreadPoolManager()
+ {
+ this.pools = new ConcurrentHashMap<>();
+ this.schedulerPools = new ConcurrentHashMap<>();
+ configure();
+ }
+
+ /**
+ * Creates a pool based on the configuration info.
+ * <p>
+ * @param config the pool configuration
+ * @param threadNamePrefix prefix for the thread names of the pool
+ * @return A ThreadPool wrapper
+ */
+ public ExecutorService createPool( PoolConfiguration config, String threadNamePrefix)
+ {
+ return createPool(config, threadNamePrefix, Thread.NORM_PRIORITY);
+ }
+
+ /**
+ * Creates a pool based on the configuration info.
+ * <p>
+ * @param config the pool configuration
+ * @param threadNamePrefix prefix for the thread names of the pool
+ * @param threadPriority the priority of the created threads
+ * @return A ThreadPool wrapper
+ */
+ public ExecutorService createPool( PoolConfiguration config, String threadNamePrefix, int threadPriority )
+ {
+ BlockingQueue<Runnable> queue = null;
+ if ( config.isUseBoundary() )
+ {
+ log.debug( "Creating a Bounded Buffer to use for the pool" );
+ queue = new LinkedBlockingQueue<>(config.getBoundarySize());
+ }
+ else
+ {
+ log.debug( "Creating a non bounded Linked Queue to use for the pool" );
+ queue = new LinkedBlockingQueue<>();
+ }
+
+ ThreadPoolExecutor pool = new ThreadPoolExecutor(
+ config.getStartUpSize(),
+ config.getMaximumPoolSize(),
+ config.getKeepAliveTime(),
+ TimeUnit.MILLISECONDS,
+ queue,
+ new DaemonThreadFactory(threadNamePrefix, threadPriority));
+
+ // when blocked policy
+ switch (config.getWhenBlockedPolicy())
+ {
+ case ABORT:
+ pool.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
+ break;
+
+ case RUN:
+ pool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+ break;
+
+ case WAIT:
+ throw new RuntimeException("POLICY_WAIT no longer supported");
+
+ case DISCARDOLDEST:
+ pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
+ break;
+
+ default:
+ break;
+ }
+
+ pool.prestartAllCoreThreads();
+
+ return pool;
+ }
+
+ /**
+ * Creates a scheduler pool based on the configuration info.
+ * <p>
+ * @param config the pool configuration
+ * @param threadNamePrefix prefix for the thread names of the pool
+ * @param threadPriority the priority of the created threads
+ * @return A ScheduledExecutorService
+ */
+ public ScheduledExecutorService createSchedulerPool( PoolConfiguration config, String threadNamePrefix, int threadPriority )
+ {
+ ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(
+ config.getMaximumPoolSize(),
+ new DaemonThreadFactory(threadNamePrefix, threadPriority));
+
+ return scheduler;
+ }
+
+ /**
+ * Returns a configured instance of the ThreadPoolManger To specify a configuration file or
+ * Properties object to use call the appropriate setter prior to calling getInstance.
+ * <p>
+ * @return The single instance of the ThreadPoolManager
+ */
+ public static ThreadPoolManager getInstance()
+ {
+ return ThreadPoolManagerHolder.INSTANCE;
+ }
+
+ /**
+ * Dispose of the instance of the ThreadPoolManger and shut down all thread pools
+ */
+ public static void dispose()
+ {
+ for ( Iterator<Map.Entry<String, ExecutorService>> i =
+ getInstance().pools.entrySet().iterator(); i.hasNext(); )
+ {
+ Map.Entry<String, ExecutorService> entry = i.next();
+ try
+ {
+ entry.getValue().shutdownNow();
+ }
+ catch (Throwable t)
+ {
+ log.warn("Failed to close pool {0}", entry.getKey(), t);
+ }
+ i.remove();
+ }
+
+ for ( Iterator<Map.Entry<String, ScheduledExecutorService>> i =
+ getInstance().schedulerPools.entrySet().iterator(); i.hasNext(); )
+ {
+ Map.Entry<String, ScheduledExecutorService> entry = i.next();
+ try
+ {
+ entry.getValue().shutdownNow();
+ }
+ catch (Throwable t)
+ {
+ log.warn("Failed to close pool {0}", entry.getKey(), t);
+ }
+ i.remove();
+ }
+ }
+
+ /**
+ * Returns an executor service by name. If a service by this name does not exist in the configuration file or
+ * properties, one will be created using the default values.
+ * <p>
+ * Services are lazily created.
+ * <p>
+ * @param name
+ * @return The executor service configured for the name.
+ */
+ public ExecutorService getExecutorService( String name )
+ {
+ ExecutorService pool = pools.computeIfAbsent(name, key -> {
+ log.debug( "Creating pool for name [{0}]", key );
+ PoolConfiguration config = loadConfig( PROP_NAME_ROOT + "." + key, defaultConfig );
+ return createPool( config, "JCS-ThreadPoolManager-" + key + "-" );
+ });
+
+ return pool;
+ }
+
+ /**
+ * Returns a scheduler pool by name. If a pool by this name does not exist in the configuration file or
+ * properties, one will be created using the default values.
+ * <p>
+ * Pools are lazily created.
+ * <p>
+ * @param name
+ * @return The scheduler pool configured for the name.
+ */
+ public ScheduledExecutorService getSchedulerPool( String name )
+ {
+ ScheduledExecutorService pool = schedulerPools.computeIfAbsent(name, key -> {
+ log.debug( "Creating scheduler pool for name [{0}]", key );
+ PoolConfiguration config = loadConfig( PROP_NAME_SCHEDULER_ROOT + "." + key,
+ defaultSchedulerConfig );
+ return createSchedulerPool( config, "JCS-ThreadPoolManager-" + key + "-", Thread.NORM_PRIORITY );
+ });
+
+ return pool;
+ }
+
+ /**
+ * Returns the names of all configured pools.
+ * <p>
+ * @return ArrayList of string names
+ */
+ protected Set<String> getPoolNames()
+ {
+ return pools.keySet();
+ }
+
+ /**
+ * This will be used if it is not null on initialization. Setting this post initialization will
+ * have no effect.
+ * <p>
+ * @param props The props to set.
+ */
+ public static void setProps( Properties props )
+ {
+ ThreadPoolManager.props = props;
+ }
+
+ /**
+ * Initialize the ThreadPoolManager and create all the pools defined in the configuration.
+ */
+ private void configure()
+ {
+ log.debug( "Initializing ThreadPoolManager" );
+
+ if ( props == null )
+ {
+ log.warn( "No configuration settings found. Using hardcoded default values for all pools." );
+ props = new Properties();
+ }
+
+ // set initial default and then override if new settings are available
+ defaultConfig = loadConfig( DEFAULT_PROP_NAME_ROOT, new PoolConfiguration() );
+ defaultSchedulerConfig = loadConfig( DEFAULT_PROP_NAME_SCHEDULER_ROOT, new PoolConfiguration() );
+ }
+
+ /**
+ * Configures the PoolConfiguration settings.
+ * <p>
+ * @param root the configuration key prefix
+ * @param defaultPoolConfiguration the default configuration
+ * @return PoolConfiguration
+ */
+ private PoolConfiguration loadConfig( String root, PoolConfiguration defaultPoolConfiguration )
+ {
+ PoolConfiguration config = defaultPoolConfiguration.clone();
+ PropertySetter.setProperties( config, props, root + "." );
+
+ log.debug( "{0} PoolConfiguration = {1}", root, config );
+
+ return config;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/timing/ElapsedTimer.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/timing/ElapsedTimer.java
new file mode 100644
index 0000000..f9b7fc8
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/timing/ElapsedTimer.java
@@ -0,0 +1,58 @@
+package org.apache.commons.jcs3.utils.timing;
+
+/*
+ * 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.
+ */
+
+/**
+ * This is a simple timer utility.
+ */
+public class ElapsedTimer
+{
+ /** display suffix describing the unit of measure. */
+ private static final String SUFFIX = "ms.";
+
+ /**
+ * Sets the start time when created.
+ */
+ private long timeStamp = System.currentTimeMillis();
+
+ /**
+ * Gets the time elapsed between the start time and now. The start time is reset to now.
+ * Subsequent calls will get the time between then and now.
+ * <p>
+ * @return the elapsed time
+ */
+ public long getElapsedTime()
+ {
+ long now = System.currentTimeMillis();
+ long elapsed = now - timeStamp;
+ timeStamp = now;
+ return elapsed;
+ }
+
+ /**
+ * Returns the elapsed time with the display suffix.
+ * <p>
+ * @return formatted elapsed Time
+ */
+ public String getElapsedTimeString()
+ {
+ return String.valueOf( getElapsedTime() ) + SUFFIX;
+ }
+}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/zip/CompressionUtil.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/zip/CompressionUtil.java
new file mode 100644
index 0000000..9b67c32
--- /dev/null
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs3/utils/zip/CompressionUtil.java
@@ -0,0 +1,203 @@
+package org.apache.commons.jcs3.utils.zip;
+
+/*
+ * 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.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.Inflater;
+
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/** Compress / Decompress. */
+public final class CompressionUtil
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( CompressionUtil.class );
+
+ /**
+ * no instances.
+ */
+ private CompressionUtil()
+ {
+ // NO OP
+ }
+
+ /**
+ * Decompress the byte array passed using a default buffer length of 1024.
+ * <p>
+ * @param input compressed byte array webservice response
+ * @return uncompressed byte array
+ */
+ public static byte[] decompressByteArray( final byte[] input )
+ {
+ return decompressByteArray( input, 1024 );
+ }
+
+ /**
+ * Decompress the byte array passed
+ * <p>
+ * @param input compressed byte array webservice response
+ * @param bufferLength buffer length
+ * @return uncompressed byte array
+ */
+ public static byte[] decompressByteArray( final byte[] input, final int bufferLength )
+ {
+ if ( null == input )
+ {
+ throw new IllegalArgumentException( "Input was null" );
+ }
+
+ // Create the decompressor and give it the data to compress
+ final Inflater decompressor = new Inflater();
+
+ decompressor.setInput( input );
+
+ // Create an expandable byte array to hold the decompressed data
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream( input.length );
+
+ // Decompress the data
+ final byte[] buf = new byte[bufferLength];
+
+ try
+ {
+ while ( !decompressor.finished() )
+ {
+ int count = decompressor.inflate( buf );
+ baos.write( buf, 0, count );
+ }
+ }
+ catch ( DataFormatException ex )
+ {
+ log.error( "Problem decompressing.", ex );
+ }
+
+ decompressor.end();
+
+ try
+ {
+ baos.close();
+ }
+ catch ( IOException ex )
+ {
+ log.error( "Problem closing stream.", ex );
+ }
+
+ return baos.toByteArray();
+ }
+
+ /**
+ * Compress the byte array passed
+ * <p>
+ * @param input byte array
+ * @return compressed byte array
+ * @throws IOException thrown if we can't close the output stream
+ */
+ public static byte[] compressByteArray( byte[] input )
+ throws IOException
+ {
+ return compressByteArray( input, 1024 );
+ }
+
+ /**
+ * Compress the byte array passed
+ * <p>
+ * @param input byte array
+ * @param bufferLength buffer length
+ * @return compressed byte array
+ * @throws IOException thrown if we can't close the output stream
+ */
+ public static byte[] compressByteArray( byte[] input, int bufferLength )
+ throws IOException
+ {
+ // Compressor with highest level of compression
+ Deflater compressor = new Deflater();
+ compressor.setLevel( Deflater.BEST_COMPRESSION );
+
+ // Give the compressor the data to compress
+ compressor.setInput( input );
+ compressor.finish();
+
+ // Create an expandable byte array to hold the compressed data.
+ // It is not necessary that the compressed data will be smaller than
+ // the uncompressed data.
+ ByteArrayOutputStream bos = new ByteArrayOutputStream( input.length );
+
+ // Compress the data
+ byte[] buf = new byte[bufferLength];
+ while ( !compressor.finished() )
+ {
+ int count = compressor.deflate( buf );
+ bos.write( buf, 0, count );
+ }
+
+ // JCS-136 ( Details here : http://www.devguli.com/blog/eng/java-deflater-and-outofmemoryerror/ )
+ compressor.end();
+ bos.close();
+
+ // Get the compressed data
+ return bos.toByteArray();
+
+ }
+
+ /**
+ * decompress a gzip byte array, using a default buffer length of 1024
+ * <p>
+ * @param compressedByteArray gzip-compressed byte array
+ * @return decompressed byte array
+ * @throws IOException thrown if there was a failure to construct the GzipInputStream
+ */
+ public static byte[] decompressGzipByteArray( byte[] compressedByteArray )
+ throws IOException
+ {
+ return decompressGzipByteArray( compressedByteArray, 1024 );
+ }
+
+ /**
+ * decompress a gzip byte array, using a default buffer length of 1024
+ * <p>
+ * @param compressedByteArray gzip-compressed byte array
+ * @param bufferlength size of the buffer in bytes
+ * @return decompressed byte array
+ * @throws IOException thrown if there was a failure to construct the GzipInputStream
+ */
+ public static byte[] decompressGzipByteArray( byte[] compressedByteArray, int bufferlength )
+ throws IOException
+ {
+ ByteArrayOutputStream uncompressedStream = new ByteArrayOutputStream();
+
+ GZIPInputStream compressedStream = new GZIPInputStream( new ByteArrayInputStream( compressedByteArray ) );
+
+ byte[] buffer = new byte[bufferlength];
+
+ int index = -1;
+
+ while ( ( index = compressedStream.read( buffer ) ) != -1 )
+ {
+ uncompressedStream.write( buffer, 0, index );
+ }
+
+ return uncompressedStream.toByteArray();
+ }
+}
diff --git a/commons-jcs-core/src/main/resources/META-INF/services/org.apache.commons.jcs.log.LogFactory b/commons-jcs-core/src/main/resources/META-INF/services/org.apache.commons.jcs.log.LogFactory
deleted file mode 100644
index c34a93d..0000000
--- a/commons-jcs-core/src/main/resources/META-INF/services/org.apache.commons.jcs.log.LogFactory
+++ /dev/null
@@ -1,16 +0,0 @@
-# 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.
-org.apache.commons.jcs.log.JulLogFactory
-org.apache.commons.jcs.log.Log4j2Factory
diff --git a/commons-jcs-core/src/main/resources/META-INF/services/org.apache.commons.jcs3.log.LogFactory b/commons-jcs-core/src/main/resources/META-INF/services/org.apache.commons.jcs3.log.LogFactory
new file mode 100644
index 0000000..2a8bea7
--- /dev/null
+++ b/commons-jcs-core/src/main/resources/META-INF/services/org.apache.commons.jcs3.log.LogFactory
@@ -0,0 +1,16 @@
+# 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.
+org.apache.commons.jcs3.log.JulLogFactory
+org.apache.commons.jcs3.log.Log4j2Factory
diff --git a/commons-jcs-core/src/test/conf/cache.ccf b/commons-jcs-core/src/test/conf/cache.ccf
index bbe3853..239c928 100644
--- a/commons-jcs-core/src/test/conf/cache.ccf
+++ b/commons-jcs-core/src/test/conf/cache.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200001
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
diff --git a/commons-jcs-core/src/test/conf/cache2.ccf b/commons-jcs-core/src/test/conf/cache2.ccf
index 83ed80c..3aeec13 100644
--- a/commons-jcs-core/src/test/conf/cache2.ccf
+++ b/commons-jcs-core/src/test/conf/cache2.ccf
@@ -18,59 +18,59 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# should be defined for the storage of group attribute list
jcs.system.groupIdCache=DC
-jcs.system.groupIdCache.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.system.groupIdCache.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.system.groupIdCache.cacheattributes.MaxObjects=1000
-jcs.system.groupIdCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.system.groupIdCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #############################################################
# ################# CACHE REGIONS AVAILABLE ###################
jcs.region.testCache1=DC,RC
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=10
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
jcs.region.testCache1.elementattributes.IsRemote=true
jcs.region.testCache2=DC
-jcs.region.testCache2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache2.cacheattributes.MaxObjects=1000
-jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# prefered config
jcs.region.test2=DC
-jcs.region.test2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.test2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.test2.cacheattributes.MaxObjects=1000
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
-jcs.auxiliary.HC=org.apache.commons.jcs.auxiliary.disk.hsql.HSQLCacheFactory
-jcs.auxiliary.HC.attributes=org.apache.commons.jcs.auxiliary.disk.hsql.HSQLCacheAttributes
+jcs.auxiliary.HC=org.apache.commons.jcs3.auxiliary.disk.hsql.HSQLCacheFactory
+jcs.auxiliary.HC.attributes=org.apache.commons.jcs3.auxiliary.disk.hsql.HSQLCacheAttributes
jcs.auxiliary.HC.attributes.DiskPath=@project_home@/hsql
# standard disk cache
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=target/test-sandbox
# need to make put or invalidate an option
# just a remove lock to add
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RC.attributes.FailoverServers=localhost:1101
jcs.auxiliary.RC.attributes.LocalPort=1202
jcs.auxiliary.RC.attributes.RemoveUponRemotePut=false
@@ -79,45 +79,45 @@
jcs.auxiliary.RC.attributes.GetOnly=false
# unreliable
-jcs.auxiliary.LUDP=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LUDP.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LUDP=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LUDP.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LUDP.attributes.TransmissionTypeName=UDP
jcs.auxiliary.LUDP.attributes.UdpMulticastAddr=228.5.6.7
jcs.auxiliary.LUDP.attributes.UdpMulticastPort=6789
-jcs.auxiliary.LJG=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LJG.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LJG=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LJG.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LJG.attributes.TransmissionTypeName=JAVAGROUPS
jcs.auxiliary.LJG.attributes.UdpMulticastAddr=228.5.6.7
jcs.auxiliary.LJG.attributes.UdpMulticastPort=6789
jcs.auxiliary.LJG.attributes.PutOnlyMode=true
# almost complete
-jcs.auxiliary.LTCP=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LTCP=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LTCP.attributes.TransmissionTypeName=TCP
jcs.auxiliary.LTCP.attributes.TcpServers=localhost:1111
jcs.auxiliary.LTCP.attributes.TcpListenerPort=1112
jcs.auxiliary.LTCP.attributes.PutOnlyMode=true
-jcs.auxiliary.XMLRPC=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.XMLRPC.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.XMLRPC=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.XMLRPC.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.XMLRPC.attributes.TransmissionTypeName=XMLRPC
jcs.auxiliary.XMLRPC.attributes.HttpServers=localhost:8181
jcs.auxiliary.XMLRPC.attributes.HttpListenerPort=8182
jcs.auxiliary.XMLRPC.attributes.PutOnlyMode=false
-jcs.auxiliary.LTCP2=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LTCP2.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LTCP2=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LTCP2.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LTCP2.attributes.TransmissionTypeName=TCP
jcs.auxiliary.LTCP2.attributes.TcpServers=localhost:1111,localhost2:1112
jcs.auxiliary.LTCP2.attributes.TcpListenerPort=1111
# example of how to configure the http version of the lateral cache
# not converteed to new cache
-jcs.auxiliary.LCHTTP=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LCHTTP.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LCHTTP=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LCHTTP.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LCHTTP.attributes.TransmissionType=HTTP
jcs.auxiliary.LCHTTP.attributes.httpServers=localhost:8080,localhost:7001,localhost:80
jcs.auxiliary.LCHTTP.attributes.httpReceiveServlet=/cache/LateralCacheReceiverServlet
diff --git a/commons-jcs-core/src/test/conf/cache3.ccf b/commons-jcs-core/src/test/conf/cache3.ccf
index 54e4962..412f80c 100644
--- a/commons-jcs-core/src/test/conf/cache3.ccf
+++ b/commons-jcs-core/src/test/conf/cache3.ccf
@@ -18,51 +18,51 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=1000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# should be defined for the storage of group attribute list
jcs.system.groupIdCache=DC
-jcs.system.groupIdCache.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.system.groupIdCache.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.system.groupIdCache.cacheattributes.MaxObjects=1000
-jcs.system.groupIdCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.system.groupIdCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #############################################################
# ################# CACHE REGIONS AVAILABLE ###################
jcs.region.testCache1=RC
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=1000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.elementattributes.IsLateral=true
jcs.region.testCache2=DC
-jcs.region.testCache2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache2.cacheattributes.MaxObjects=1000
-jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# prefered config
jcs.region.test2=DC
-jcs.region.test2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.test2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.test2.cacheattributes.MaxObjects=1000
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
-jcs.auxiliary.HC=org.apache.commons.jcs.auxiliary.disk.hsql.HSQLCacheFactory
-jcs.auxiliary.HC.attributes=org.apache.commons.jcs.auxiliary.disk.hsql.HSQLCacheAttributes
+jcs.auxiliary.HC=org.apache.commons.jcs3.auxiliary.disk.hsql.HSQLCacheFactory
+jcs.auxiliary.HC.attributes=org.apache.commons.jcs3.auxiliary.disk.hsql.HSQLCacheAttributes
jcs.auxiliary.HC.attributes.DiskPath=@project_home@/hsql
# standard disk cache
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=@project_home@/raf
# need to make put or invalidate an option
# just a remove lock to add
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RC.attributes.RemoteHost=10.21.209.150
jcs.auxiliary.RC.attributes.RemotePort=1102
# jcs.auxiliary.RC.attributes.LocalPort=1103
@@ -71,45 +71,45 @@
# unreliable
-jcs.auxiliary.LUDP=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LUDP.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LUDP=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LUDP.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LUDP.attributes.TransmissionTypeName=UDP
jcs.auxiliary.LUDP.attributes.UdpMulticastAddr=228.5.6.7
jcs.auxiliary.LUDP.attributes.UdpMulticastPort=6789
-jcs.auxiliary.LJG=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LJG.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LJG=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LJG.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LJG.attributes.TransmissionTypeName=JAVAGROUPS
jcs.auxiliary.LJG.attributes.UdpMulticastAddr=228.5.6.7
jcs.auxiliary.LJG.attributes.UdpMulticastPort=6789
jcs.auxiliary.LJG.attributes.PutOnlyMode=true
# almost complete
-jcs.auxiliary.LTCP=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LTCP=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LTCP.attributes.TransmissionTypeName=TCP
jcs.auxiliary.LTCP.attributes.TcpServers=localhost:1111
jcs.auxiliary.LTCP.attributes.TcpListenerPort=1112
jcs.auxiliary.LTCP.attributes.PutOnlyMode=false
-jcs.auxiliary.XMLRPC=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.XMLRPC.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.XMLRPC=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.XMLRPC.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.XMLRPC.attributes.TransmissionTypeName=XMLRPC
jcs.auxiliary.XMLRPC.attributes.HttpServers=localhost:8181
jcs.auxiliary.XMLRPC.attributes.HttpListenerPort=8182
jcs.auxiliary.XMLRPC.attributes.PutOnlyMode=false
-jcs.auxiliary.LTCP2=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LTCP2.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LTCP2=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LTCP2.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LTCP2.attributes.TransmissionTypeName=TCP
jcs.auxiliary.LTCP2.attributes.TcpServers=localhost:1111,localhost2:1112
jcs.auxiliary.LTCP2.attributes.TcpListenerPort=1111
# example of how to configure the http version of the lateral cache
# not converteed to new cache
-jcs.auxiliary.LCHTTP=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LCHTTP.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LCHTTP=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LCHTTP.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LCHTTP.attributes.TransmissionType=HTTP
jcs.auxiliary.LCHTTP.attributes.httpServers=localhost:8080,localhost:7001,localhost:80
jcs.auxiliary.LCHTTP.attributes.httpReceiveServlet=/cache/LateralCacheReceiverServlet
diff --git a/commons-jcs-core/src/test/conf/cacheB.ccf b/commons-jcs-core/src/test/conf/cacheB.ccf
index 4127e9b..835f439 100644
--- a/commons-jcs-core/src/test/conf/cacheB.ccf
+++ b/commons-jcs-core/src/test/conf/cacheB.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=1000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,27 +37,27 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=RC
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=1000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
jcs.region.testCache1.elementattributes.IsRemote=true
jcs.region.testCache2=DC
-jcs.region.testCache2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache2.cacheattributes.MaxObjects=100
-jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache2.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache2.cacheattributes.MaxMemoryIdleTimeSeconds=1000
jcs.region.testCache2.cacheattributes.ShrinkerIntervalSeconds=40
-jcs.region.testCache2.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache2.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache2.elementattributes.IsEternal=false
jcs.region.testCache2.elementattributes.MaxLifeSeconds=600
jcs.region.testCache2.elementattributes.IsSpool=true
@@ -65,13 +65,13 @@
jcs.region.testCache2.elementattributes.IsLateral=true
jcs.region.testCache3=
-jcs.region.testCache3.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache3.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache3.cacheattributes.MaxObjects=100000
-jcs.region.testCache3.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache3.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache3.cacheattributes.UseMemoryShrinker=false
jcs.region.testCache3.cacheattributes.MaxMemoryIdleTimeSeconds=10
jcs.region.testCache3.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.region.testCache3.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache3.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache3.elementattributes.IsEternal=false
jcs.region.testCache3.elementattributes.MaxLifeSeconds=3600
jcs.region.testCache3.elementattributes.IsSpool=true
@@ -83,23 +83,23 @@
# ################# AUXILIARY CACHES AVAILABLE ################
# Remote RMI cache without failover
-jcs.auxiliary.RGroup=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RGroup.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RGroup=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RGroup.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RGroup.attributes.RemoteTypeName=LOCAL
jcs.auxiliary.RGroup.attributes.RemoteHost=localhost
jcs.auxiliary.RGroup.attributes.RemotePort=1102
jcs.auxiliary.RGroup.attributes.GetOnly=true
# Remote RMI Cache set up to failover
-jcs.auxiliary.RFailover=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RFailover.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RFailover=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RFailover.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RFailover.attributes.RemoteTypeName=LOCAL
jcs.auxiliary.RFailover.attributes.FailoverServers=localhost:1102
jcs.auxiliary.RFailover.attributes.GetOnly=false
# Primary Disk Cache-- faster than the rest because of memory key storage
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=target/test-sandbox/raf
jcs.auxiliary.DC.attributes.MaxPurgatorySize=10000
jcs.auxiliary.DC.attributes.MaxKeySize=10000
@@ -112,8 +112,8 @@
# If you want to use a separate pool for each disk cache, either use
# the single model or define a different auxiliary for each region and use the Pooled.
# SINGLE is best unless you have a huge # of regions.
-jcs.auxiliary.DC2=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC2.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC2=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC2.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC2.attributes.DiskPath=target/test-sandbox/raf
jcs.auxiliary.DC2.attributes.MaxPurgatorySize=10000
jcs.auxiliary.DC2.attributes.MaxKeySize=10000
@@ -122,28 +122,28 @@
jcs.auxiliary.DC2.attributes.EventQueuePoolName=disk_cache_event_queue
# Berkeley DB JE
-jcs.auxiliary.JE=org.apache.commons.jcs.auxiliary.disk.bdbje.BDBJECacheFactory
-jcs.auxiliary.JE.attributes=org.apache.commons.jcs.auxiliary.disk.bdbje.BDBJECacheAttributes
+jcs.auxiliary.JE=org.apache.commons.jcs3.auxiliary.disk.bdbje.BDBJECacheFactory
+jcs.auxiliary.JE.attributes=org.apache.commons.jcs3.auxiliary.disk.bdbje.BDBJECacheAttributes
jcs.auxiliary.JE.attributes.DiskPath=target/test-sandbox/bdbje-disk-cache-conc
# the minimum cache size is 1024
jcs.auxiliary.indexedDiskCache.attributes.CacheSize=1024
# jcs.auxiliary.indexedDiskCache.attributes.CachePercent=0
# HSQL Disk Cache -- too slow as is
-jcs.auxiliary.HDC=org.apache.commons.jcs.auxiliary.disk.hsql.HSQLCacheFactory
-jcs.auxiliary.HDC.attributes=org.apache.commons.jcs.auxiliary.disk.hsql.HSQLCacheAttributes
+jcs.auxiliary.HDC=org.apache.commons.jcs3.auxiliary.disk.hsql.HSQLCacheFactory
+jcs.auxiliary.HDC.attributes=org.apache.commons.jcs3.auxiliary.disk.hsql.HSQLCacheAttributes
jcs.auxiliary.HDC.attributes.DiskPath=@project_home_f@hsql
# JISP Disk Cache -- save memory with disk key storage
-jcs.auxiliary.JDC=org.apache.commons.jcs.auxiliary.disk.jisp.JISPCacheFactory
-jcs.auxiliary.JDC.attributes=org.apache.commons.jcs.auxiliary.disk.jisp.JISPCacheAttributes
+jcs.auxiliary.JDC=org.apache.commons.jcs3.auxiliary.disk.jisp.JISPCacheFactory
+jcs.auxiliary.JDC.attributes=org.apache.commons.jcs3.auxiliary.disk.jisp.JISPCacheAttributes
jcs.auxiliary.JDC.attributes.DiskPath=@project_home_f@raf
jcs.auxiliary.JDC.attributes.ClearOnStart=false
# need to make put or invalidate an option
# just a remove lock to add
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RC.attributes.FailoverServers=localhost:1101,localhost:1102,localhost:1103
jcs.auxiliary.RC.attributes.LocalPort=1204
jcs.auxiliary.RC.attributes.RemoveUponRemotePut=false
@@ -152,42 +152,42 @@
jcs.auxiliary.RC.attributes.GetOnly=false
# unreliable
-jcs.auxiliary.LUDP=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LUDP.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LUDP=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LUDP.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LUDP.attributes.TransmissionTypeName=UDP
jcs.auxiliary.LUDP.attributes.UdpMulticastAddr=228.5.6.7
jcs.auxiliary.LUDP.attributes.UdpMulticastPort=6789
-jcs.auxiliary.LJG=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LJG.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LJG=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LJG.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LJG.attributes.TransmissionTypeName=JAVAGROUPS
jcs.auxiliary.LJG.attributes.PutOnlyMode=true
jcs.auxiliary.LJG.attributes.JGChannelProperties = UDP(mcast_addr=224.0.0.100;mcast_port=751):PING(timeout=3000):FD:STABLE:NAKACK:UNICAST:FRAG:FLUSH:GMS:VIEW_ENFORCER:QUEUE
-jcs.auxiliary.JG = org.apache.commons.jcs.auxiliary.javagroups.JavaGroupsCacheFactory
-jcs.auxiliary.JG.attributes = org.apache.commons.jcs.auxiliary.javagroups.JavaGroupsCacheAttributes
+jcs.auxiliary.JG = org.apache.commons.jcs3.auxiliary.javagroups.JavaGroupsCacheFactory
+jcs.auxiliary.JG.attributes = org.apache.commons.jcs3.auxiliary.javagroups.JavaGroupsCacheAttributes
jcs.auxiliary.JG.attributes.ChannelFactoryClassName = org.javagroups.JChannelFactory
jcs.auxiliary.JG.attributes.ChannelProperties = UDP(mcast_addr=224.0.0.100;mcast_port=7501):PING:FD:STABLE:NAKACK:UNICAST:FRAG:FLUSH:GMS:VIEW_ENFORCER:QUEUE
# almost complete
-jcs.auxiliary.LTCP=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LTCP=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LTCP.attributes.TransmissionTypeName=TCP
jcs.auxiliary.LTCP.attributes.TcpServers=localhost:1112
jcs.auxiliary.LTCP.attributes.TcpListenerPort=1111
jcs.auxiliary.LTCP.attributes.PutOnlyMode=false
-jcs.auxiliary.LTCP2=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LTCP2.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LTCP2=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LTCP2.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LTCP2.attributes.TransmissionTypeName=TCP
jcs.auxiliary.LTCP2.attributes.TcpServers=localhost:1112
jcs.auxiliary.LTCP2.attributes.TcpListenerPort=1111
jcs.auxiliary.LTCP2.attributes.PutOnlyMode=true
-jcs.auxiliary.XMLRPC=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.XMLRPC.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.XMLRPC=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.XMLRPC.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.XMLRPC.attributes.TransmissionTypeName=XMLRPC
jcs.auxiliary.XMLRPC.attributes.HttpServers=localhost:8182
jcs.auxiliary.XMLRPC.attributes.HttpListenerPort=8181
@@ -196,8 +196,8 @@
# example of how to configure the http version of the lateral cache
# not converteed to new cache
-jcs.auxiliary.LCHTTP=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LCHTTP.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LCHTTP=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LCHTTP.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LCHTTP.attributes.TransmissionType=HTTP
jcs.auxiliary.LCHTTP.attributes.httpServers=localhost:8080,localhost:7001,localhost:80
jcs.auxiliary.LCHTTP.attributes.httpReceiveServlet=/cache/LateralCacheReceiverServlet
diff --git a/commons-jcs-core/src/test/conf/cacheBDB.ccf b/commons-jcs-core/src/test/conf/cacheBDB.ccf
index 90178aa..b05eb5b 100644
--- a/commons-jcs-core/src/test/conf/cacheBDB.ccf
+++ b/commons-jcs-core/src/test/conf/cacheBDB.ccf
@@ -18,38 +18,38 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=bdbje
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### CACHE REGIONS FOR TEST
jcs.region.indexedRegion1=bdbje
-jcs.region.indexedRegion1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion1.cacheattributes.MaxObjects=100
-jcs.region.indexedRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.indexedRegion2=bdbje
-jcs.region.indexedRegion2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion2.cacheattributes.MaxObjects=100
-jcs.region.indexedRegion2.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion2.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.indexedRegion3=bdbje
-jcs.region.indexedRegion3.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion3.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion3.cacheattributes.MaxObjects=100
-jcs.region.indexedRegion3.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion3.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.indexedRegion4=bdbje
-jcs.region.indexedRegion4.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion4.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion4.cacheattributes.MaxObjects=100
-jcs.region.indexedRegion4.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion4.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.indexedRegion4.cacheattributes.UseMemoryShrinker=false
# #### AUXILIARY CACHES
# Berkeley DB JE
-jcs.auxiliary.bdbje=org.apache.commons.jcs.auxiliary.disk.bdbje.BDBJECacheFactory
-jcs.auxiliary.bdbje.attributes=org.apache.commons.jcs.auxiliary.disk.bdbje.BDBJECacheAttributes
+jcs.auxiliary.bdbje=org.apache.commons.jcs3.auxiliary.disk.bdbje.BDBJECacheFactory
+jcs.auxiliary.bdbje.attributes=org.apache.commons.jcs3.auxiliary.disk.bdbje.BDBJECacheAttributes
jcs.auxiliary.bdbje.attributes.DiskPath=target/
jcs.auxiliary.bdbje.attributes.MaxPurgatorySize=100000
diff --git a/commons-jcs-core/src/test/conf/cacheD10A.ccf b/commons-jcs-core/src/test/conf/cacheD10A.ccf
index 8e1969f..a797c80 100644
--- a/commons-jcs-core/src/test/conf/cacheD10A.ccf
+++ b/commons-jcs-core/src/test/conf/cacheD10A.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC,RC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200001
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,27 +37,27 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=DC,RC
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=1000000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
jcs.region.testCache1.elementattributes.IsRemote=true
jcs.region.testCache2=DC,RC
-jcs.region.testCache2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache2.cacheattributes.MaxObjects=100
-jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache2.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache2.cacheattributes.MaxMemoryIdleTimeSeconds=1000
jcs.region.testCache2.cacheattributes.ShrinkerIntervalSeconds=40
-jcs.region.testCache2.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache2.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache2.elementattributes.IsEternal=false
jcs.region.testCache2.elementattributes.MaxLifeSeconds=600
jcs.region.testCache2.elementattributes.IsSpool=true
@@ -65,13 +65,13 @@
jcs.region.testCache2.elementattributes.IsLateral=true
jcs.region.testCache3=
-jcs.region.testCache3.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache3.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache3.cacheattributes.MaxObjects=100000
-jcs.region.testCache3.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache3.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache3.cacheattributes.UseMemoryShrinker=false
jcs.region.testCache3.cacheattributes.MaxMemoryIdleTimeSeconds=10
jcs.region.testCache3.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.region.testCache3.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache3.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache3.elementattributes.IsEternal=false
jcs.region.testCache3.elementattributes.MaxLifeSeconds=3600
jcs.region.testCache3.elementattributes.IsSpool=true
@@ -83,8 +83,8 @@
# ################# AUXILIARY CACHES AVAILABLE ################
# Primary Disk Cache-- faster than the rest because of memory key storage
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=target/test-sandbox/raf
jcs.auxiliary.DC.attributes.MaxPurgatorySize=10000000
jcs.auxiliary.DC.attributes.MaxKeySize=1000000
@@ -98,8 +98,8 @@
# If you want to use a separate pool for each disk cache, either use
# the single model or define a different auxiliary for each region and use the Pooled.
# SINGLE is best unless you have a huge # of regions.
-jcs.auxiliary.DC2=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC2.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC2=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC2.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC2.attributes.DiskPath=target/test-sandbox/raf
jcs.auxiliary.DC2.attributes.MaxPurgatorySize=10000
jcs.auxiliary.DC2.attributes.MaxKeySize=10000
@@ -110,8 +110,8 @@
# need to make put or invalidate an option
# just a remove lock to add
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RC.attributes.FailoverServers=dev10.hq.site59.com:1101
jcs.auxiliary.RC.attributes.LocalPort=1200
jcs.auxiliary.RC.attributes.RemoveUponRemotePut=false
@@ -122,8 +122,8 @@
# jcs.auxiliary.RC.attributes.GetOnly=false
# Remote RMI Cache set up to failover
-jcs.auxiliary.RFailover=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RFailover.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RFailover=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RFailover.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RFailover.attributes.FailoverServers=dev10.hq.site59.com:1101
jcs.auxiliary.RC.attributes.RemoveUponRemotePut=true
jcs.auxiliary.RFailover.attributes.GetOnly=false
diff --git a/commons-jcs-core/src/test/conf/cacheD10B.ccf b/commons-jcs-core/src/test/conf/cacheD10B.ccf
index 020ebce..f5103f3 100644
--- a/commons-jcs-core/src/test/conf/cacheD10B.ccf
+++ b/commons-jcs-core/src/test/conf/cacheD10B.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC,RC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200001
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,27 +37,27 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=DC,RC
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=1000000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
jcs.region.testCache1.elementattributes.IsRemote=true
jcs.region.testCache2=DC,RC
-jcs.region.testCache2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache2.cacheattributes.MaxObjects=100
-jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache2.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache2.cacheattributes.MaxMemoryIdleTimeSeconds=1000
jcs.region.testCache2.cacheattributes.ShrinkerIntervalSeconds=40
-jcs.region.testCache2.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache2.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache2.elementattributes.IsEternal=false
jcs.region.testCache2.elementattributes.MaxLifeSeconds=600
jcs.region.testCache2.elementattributes.IsSpool=true
@@ -65,13 +65,13 @@
jcs.region.testCache2.elementattributes.IsLateral=true
jcs.region.testCache3=
-jcs.region.testCache3.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache3.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache3.cacheattributes.MaxObjects=100000
-jcs.region.testCache3.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache3.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache3.cacheattributes.UseMemoryShrinker=false
jcs.region.testCache3.cacheattributes.MaxMemoryIdleTimeSeconds=10
jcs.region.testCache3.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.region.testCache3.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache3.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache3.elementattributes.IsEternal=false
jcs.region.testCache3.elementattributes.MaxLifeSeconds=3600
jcs.region.testCache3.elementattributes.IsSpool=true
@@ -83,8 +83,8 @@
# ################# AUXILIARY CACHES AVAILABLE ################
# Primary Disk Cache-- faster than the rest because of memory key storage
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=target/test-sandbox/raf
jcs.auxiliary.DC.attributes.MaxPurgatorySize=10000000
jcs.auxiliary.DC.attributes.MaxKeySize=1000000
@@ -98,8 +98,8 @@
# If you want to use a separate pool for each disk cache, either use
# the single model or define a different auxiliary for each region and use the Pooled.
# SINGLE is best unless you have a huge # of regions.
-jcs.auxiliary.DC2=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC2.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC2=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC2.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC2.attributes.DiskPath=target/test-sandbox/raf
jcs.auxiliary.DC2.attributes.MaxPurgatorySize=10000
jcs.auxiliary.DC2.attributes.MaxKeySize=10000
@@ -110,8 +110,8 @@
# need to make put or invalidate an option
# just a remove lock to add
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RC.attributes.FailoverServers=dev10.hq.site59.com:1101
jcs.auxiliary.RC.attributes.LocalPort=1201
jcs.auxiliary.RC.attributes.RemoveUponRemotePut=false
@@ -122,8 +122,8 @@
# jcs.auxiliary.RC.attributes.GetOnly=false
# Remote RMI Cache set up to failover
-jcs.auxiliary.RFailover=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RFailover.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RFailover=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RFailover.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RFailover.attributes.FailoverServers=dev10.hq.site59.com:1101
jcs.auxiliary.RC.attributes.RemoveUponRemotePut=true
jcs.auxiliary.RFailover.attributes.GetOnly=false
diff --git a/commons-jcs-core/src/test/conf/cacheID.ccf b/commons-jcs-core/src/test/conf/cacheID.ccf
index 5cd50e1..755daa0 100644
--- a/commons-jcs-core/src/test/conf/cacheID.ccf
+++ b/commons-jcs-core/src/test/conf/cacheID.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=0
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,14 +37,14 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=DC
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=0
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
@@ -55,8 +55,8 @@
# ################# AUXILIARY CACHES AVAILABLE ################
# Primary Disk Cache-- faster than the rest because of memory key storage
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=target/test-sandbox/raf
jcs.auxiliary.DC.attributes.MaxPurgatorySize=10000000
jcs.auxiliary.DC.attributes.MaxKeySize=1000000
diff --git a/commons-jcs-core/src/test/conf/cacheJG1.ccf b/commons-jcs-core/src/test/conf/cacheJG1.ccf
index d6f7baf..1d9681c 100644
--- a/commons-jcs-core/src/test/conf/cacheJG1.ccf
+++ b/commons-jcs-core/src/test/conf/cacheJG1.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=LJG
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=250000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLifeSeconds=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,14 +37,14 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=LJG
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=250000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=false
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
@@ -55,16 +55,16 @@
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# Primary Disk Cache-- faster than the rest because of memory key storage
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=logs/rafJG1
jcs.auxiliary.DC.attributes.MaxPurgatorySize=100000
jcs.auxiliary.DC.attributes.MaxKeySize=500000
jcs.auxiliary.DC.attributes.OptimizeAtRemoveCount=-1
# Lateral JavaGroups Distribution
-jcs.auxiliary.LJG=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LJG.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LJG=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LJG.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LJG.attributes.TransmissionTypeName=JAVAGROUPS
jcs.auxiliary.LJG.attributes.PutOnlyMode=true
jcs.auxiliary.LJG.attributes.JGChannelProperties=UDP(mcast_addr=224.0.0.100;mcast_port=7501):PING:FD:STABLE:NAKACK:UNICAST:FRAG:FLUSH:GMS:QUEUE
@@ -74,8 +74,8 @@
jcs.auxiliary.LJG.attributes.EventQueueType=POOLED
jcs.auxiliary.LJG.attributes.EventQueuePolName=lg_event_queue
-jcs.auxiliary.JG = org.apache.commons.jcs.auxiliary.javagroups.JavaGroupsCacheFactory
-jcs.auxiliary.JG.attributes = org.apache.commons.jcs.auxiliary.javagroups.JavaGroupsCacheAttributes
+jcs.auxiliary.JG = org.apache.commons.jcs3.auxiliary.javagroups.JavaGroupsCacheFactory
+jcs.auxiliary.JG.attributes = org.apache.commons.jcs3.auxiliary.javagroups.JavaGroupsCacheAttributes
jcs.auxiliary.JG.attributes.ChannelFactoryClassName = org.jgroups.JChannelFactory
jcs.auxiliary.JG.attributes.ChannelProperties = UDP(mcast_addr=224.0.0.100;mcast_port=7501):PING:FD:STABLE:NAKACK:UNICAST:FRAG:FLUSH:GMS:VIEW_ENFORCER:QUEUE
diff --git a/commons-jcs-core/src/test/conf/cacheJG2.ccf b/commons-jcs-core/src/test/conf/cacheJG2.ccf
index 8409ac5..ef2838f 100644
--- a/commons-jcs-core/src/test/conf/cacheJG2.ccf
+++ b/commons-jcs-core/src/test/conf/cacheJG2.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=LJG
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=250000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLifeSeconds=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,14 +37,14 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=LJG
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=250000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=false
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
@@ -55,16 +55,16 @@
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# Primary Disk Cache-- faster than the rest because of memory key storage
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=logs/rafJG2
jcs.auxiliary.DC.attributes.MaxPurgatorySize=100000
jcs.auxiliary.DC.attributes.MaxKeySize=500000
jcs.auxiliary.DC.attributes.OptimizeAtRemoveCount=-1
# Lateral JavaGroups Distribution
-jcs.auxiliary.LJG=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LJG.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LJG=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LJG.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LJG.attributes.TransmissionTypeName=JAVAGROUPS
jcs.auxiliary.LJG.attributes.PutOnlyMode=true
jcs.auxiliary.LJG.attributes.JGChannelProperties=UDP(mcast_addr=224.0.0.100;mcast_port=7501):PING:FD:STABLE:NAKACK:UNICAST:FRAG:FLUSH:GMS:QUEUE
@@ -74,7 +74,7 @@
# UDP(mcast_addr=225.0.0.100;mcast_port=7777):PING(timeout=3000):AUTOCONF:FD:STABLE:NAKACK:UNICAST:FRAG:FLUSH:GMS:STATE_TRANSFER:QUEUE
# UDP(mcast_addr=225.0.0.100;mcast_port=7777):PING(timeout=3000):pbcast.FD:pbcast.NAKACK:pbcast.STABLE:UNICAST:pbcast.GMS:FRAG
-jcs.auxiliary.JG = org.apache.commons.jcs.auxiliary.javagroups.JavaGroupsCacheFactory
-jcs.auxiliary.JG.attributes = org.apache.commons.jcs.auxiliary.javagroups.JavaGroupsCacheAttributes
+jcs.auxiliary.JG = org.apache.commons.jcs3.auxiliary.javagroups.JavaGroupsCacheFactory
+jcs.auxiliary.JG.attributes = org.apache.commons.jcs3.auxiliary.javagroups.JavaGroupsCacheAttributes
jcs.auxiliary.JG.attributes.ChannelFactoryClassName = org.jgroups.JChannelFactory
jcs.auxiliary.JG.attributes.ChannelProperties = UDP(mcast_addr=224.0.0.100;mcast_port=7501):PING:FD:STABLE:NAKACK:UNICAST:FRAG:FLUSH:GMS:VIEW_ENFORCER:QUEUE
diff --git a/commons-jcs-core/src/test/conf/cacheJG3.ccf b/commons-jcs-core/src/test/conf/cacheJG3.ccf
index 806ae26..c304617 100644
--- a/commons-jcs-core/src/test/conf/cacheJG3.ccf
+++ b/commons-jcs-core/src/test/conf/cacheJG3.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC,LJG
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=250000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLifeSeconds=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,14 +37,14 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=DC,LJG
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=250000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=false
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
@@ -55,16 +55,16 @@
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# Primary Disk Cache-- faster than the rest because of memory key storage
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=logs/rafJG1
jcs.auxiliary.DC.attributes.MaxPurgatorySize=100000
jcs.auxiliary.DC.attributes.MaxKeySize=500000
jcs.auxiliary.DC.attributes.OptimizeAtRemoveCount=-1
# Lateral JavaGroups Distribution
-jcs.auxiliary.LJG=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LJG.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LJG=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LJG.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LJG.attributes.TransmissionTypeName=JAVAGROUPS
jcs.auxiliary.LJG.attributes.PutOnlyMode=true
jcs.auxiliary.LJG.attributes.JGChannelProperties=UDP(mcast_addr=224.10.10.10;mcast_port=5555;ip_ttl=32):PING(timeout=3000;num_initial_members=6):FD(timeout=3000):VERIFY_SUSPECT(timeout=1500):pbcast.NAKACK(gc_lag=10;retransmit_timeout=600,1200,2400,4800):UNICAST(timeout=600,1200,2400,4800):pbcast.STABLE(desired_avg_gossip=10000):FRAG:pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;print_local_addr=true)
diff --git a/commons-jcs-core/src/test/conf/cacheLMD1.ccf b/commons-jcs-core/src/test/conf/cacheLMD1.ccf
index 14d3128..3df79a6 100644
--- a/commons-jcs-core/src/test/conf/cacheLMD1.ccf
+++ b/commons-jcs-core/src/test/conf/cacheLMD1.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC,LJG
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=1000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLifeSeconds=600
jcs.default.elementattributes.IdleTime=1800
@@ -38,15 +38,15 @@
# Regions preconfigured for caching
# LEAD_PRICE_CACHE_NAME
jcs.region.LeadPrice=DC,LJG
-jcs.region.LeadPrice.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.LeadPrice.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.LeadPrice.cacheattributes.MaxObjects=1000
# set it to zero, was 1000
-jcs.region.LeadPrice.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.LeadPrice.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.LeadPrice.cacheattributes.UseMemoryShrinker=true
jcs.region.LeadPrice.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.LeadPrice.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.LeadPrice.cacheattributes.MaxSpoolPerRun=100
-jcs.region.LeadPrice.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.LeadPrice.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.LeadPrice.elementattributes.IsEternal=false
jcs.region.LeadPrice.elementattributes.MaxLifeSeconds=600
jcs.region.LeadPrice.elementattributes.IsSpool=true
@@ -55,15 +55,15 @@
# HOTEL_OPTION_CACHE_NAME
jcs.region.HotelOption=DC,LJG
-jcs.region.HotelOption.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.HotelOption.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.HotelOption.cacheattributes.MaxObjects=1000
# set it to zero, was 1000
-jcs.region.HotelOption.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.HotelOption.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.HotelOption.cacheattributes.UseMemoryShrinker=true
jcs.region.HotelOption.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.HotelOption.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.HotelOption.cacheattributes.MaxSpoolPerRun=100
-jcs.region.HotelOption.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.HotelOption.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.HotelOption.elementattributes.IsEternal=false
jcs.region.HotelOption.elementattributes.MaxLifeSeconds=600
jcs.region.HotelOption.elementattributes.IsSpool=true
@@ -75,16 +75,16 @@
# ################# AUXILIARY CACHES AVAILABLE ################
# Primary Disk Cache-- faster than the rest because of memory key storage
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=log/raf
jcs.auxiliary.DC.attributes.MaxPurgatorySize=10000
jcs.auxiliary.DC.attributes.MaxKeySize=10000
jcs.auxiliary.DC.attributes.OptimizeAtRemoveCount=300000
# Lateral JavaGroups Distribution
-jcs.auxiliary.LJG=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LJG.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LJG=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LJG.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LJG.attributes.TransmissionTypeName=JAVAGROUPS
jcs.auxiliary.LJG.attributes.PutOnlyMode=true
jcs.auxiliary.LJG.attributes.JGChannelProperties=UDP(mcast_addr=224.0.0.100;mcast_port=751):PING(timeout=3000):FD:STABLE:NAKACK:UNICAST:FRAG:FLUSH:GMS:VIEW_ENFORCER:QUEUE
diff --git a/commons-jcs-core/src/test/conf/cacheNA.ccf b/commons-jcs-core/src/test/conf/cacheNA.ccf
index 8993040..26e69af 100644
--- a/commons-jcs-core/src/test/conf/cacheNA.ccf
+++ b/commons-jcs-core/src/test/conf/cacheNA.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC,RC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=250000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLifeSeconds=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,14 +37,14 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=DC,RC
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=250000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=false
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
@@ -55,16 +55,16 @@
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# Primary Disk Cache-- faster than the rest because of memory key storage
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=logs/rafNA
jcs.auxiliary.DC.attributes.MaxPurgatorySize=100000
jcs.auxiliary.DC.attributes.MaxKeySize=500000
jcs.auxiliary.DC.attributes.OptimizeAtRemoveCount=-1
# REMOTE SERVER RS1
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
# First server is primary, the rest will be tried in order if the primary fails
jcs.auxiliary.RC.attributes.FailoverServers=localhost:1101,localhost:1102
jcs.auxiliary.RC.attributes.LocalPort=1201
diff --git a/commons-jcs-core/src/test/conf/cacheNA2.ccf b/commons-jcs-core/src/test/conf/cacheNA2.ccf
index 505ba1b..003d356 100644
--- a/commons-jcs-core/src/test/conf/cacheNA2.ccf
+++ b/commons-jcs-core/src/test/conf/cacheNA2.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC,RC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=250000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLifeSeconds=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,14 +37,14 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=DC,RC
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=250000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=false
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
@@ -55,16 +55,16 @@
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# Primary Disk Cache-- faster than the rest because of memory key storage
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=logs/rafNA
jcs.auxiliary.DC.attributes.MaxPurgatorySize=100000
jcs.auxiliary.DC.attributes.MaxKeySize=500000
jcs.auxiliary.DC.attributes.OptimizeAtRemoveCount=-1
# REMOTE SERVER RS1
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
# First server is primary, the rest will be tried in order if the primary fails
jcs.auxiliary.RC.attributes.FailoverServers=server:1101
jcs.auxiliary.RC.attributes.LocalPort=1201
diff --git a/commons-jcs-core/src/test/conf/cacheNA3.ccf b/commons-jcs-core/src/test/conf/cacheNA3.ccf
index e4ed2ec..bace6b7 100644
--- a/commons-jcs-core/src/test/conf/cacheNA3.ccf
+++ b/commons-jcs-core/src/test/conf/cacheNA3.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC,RC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=250000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLifeSeconds=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,14 +37,14 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=DC,RC
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=250000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=false
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
@@ -55,16 +55,16 @@
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# Primary Disk Cache-- faster than the rest because of memory key storage
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=logs/rafNA
jcs.auxiliary.DC.attributes.MaxPurgatorySize=100000
jcs.auxiliary.DC.attributes.MaxKeySize=500000
jcs.auxiliary.DC.attributes.OptimizeAtRemoveCount=-1
# REMOTE SERVER RS1
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
# First server is primary, the rest will be tried in order if the primary fails
jcs.auxiliary.RC.attributes.FailoverServers=server:1101
jcs.auxiliary.RC.attributes.LocalPort=1200
diff --git a/commons-jcs-core/src/test/conf/cacheNB.ccf b/commons-jcs-core/src/test/conf/cacheNB.ccf
index f428a2e..cb9016c 100644
--- a/commons-jcs-core/src/test/conf/cacheNB.ccf
+++ b/commons-jcs-core/src/test/conf/cacheNB.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC,RC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=250000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLifeSeconds=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,14 +37,14 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=DC,RC
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=250000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=false
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
@@ -55,16 +55,16 @@
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# Primary Disk Cache-- faster than the rest because of memory key storage
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=logs/rafNB
jcs.auxiliary.DC.attributes.MaxPurgatorySize=100000
jcs.auxiliary.DC.attributes.MaxKeySize=500000
jcs.auxiliary.DC.attributes.OptimizeAtRemoveCount=-1
# REMOTE SERVER -- RS2
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
# First server is primary, the rest will be tried in order if the primary fails
jcs.auxiliary.RC.attributes.FailoverServers=localhost:1102,localhost:1101
jcs.auxiliary.RC.attributes.LocalPort=1202
diff --git a/commons-jcs-core/src/test/conf/cacheRC.ccf b/commons-jcs-core/src/test/conf/cacheRC.ccf
index a59c887..5b273f8 100644
--- a/commons-jcs-core/src/test/conf/cacheRC.ccf
+++ b/commons-jcs-core/src/test/conf/cacheRC.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC,RC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200001
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,27 +37,27 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=DC,RC
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=1000000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
jcs.region.testCache1.elementattributes.IsRemote=true
jcs.region.testCache2=DC,RC
-jcs.region.testCache2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache2.cacheattributes.MaxObjects=100
-jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache2.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache2.cacheattributes.MaxMemoryIdleTimeSeconds=1000
jcs.region.testCache2.cacheattributes.ShrinkerIntervalSeconds=40
-jcs.region.testCache2.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache2.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache2.elementattributes.IsEternal=false
jcs.region.testCache2.elementattributes.MaxLifeSeconds=600
jcs.region.testCache2.elementattributes.IsSpool=true
@@ -65,13 +65,13 @@
jcs.region.testCache2.elementattributes.IsLateral=true
jcs.region.testCache3=
-jcs.region.testCache3.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache3.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache3.cacheattributes.MaxObjects=100000
-jcs.region.testCache3.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache3.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache3.cacheattributes.UseMemoryShrinker=false
jcs.region.testCache3.cacheattributes.MaxMemoryIdleTimeSeconds=10
jcs.region.testCache3.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.region.testCache3.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache3.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache3.elementattributes.IsEternal=false
jcs.region.testCache3.elementattributes.MaxLifeSeconds=3600
jcs.region.testCache3.elementattributes.IsSpool=true
@@ -83,23 +83,23 @@
# ################# AUXILIARY CACHES AVAILABLE ################
# Remote RMI cache without failover
-jcs.auxiliary.RGroup=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RGroup.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RGroup=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RGroup.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RGroup.attributes.RemoteTypeName=LOCAL
jcs.auxiliary.RGroup.attributes.RemoteHost=localhost
jcs.auxiliary.RGroup.attributes.RemotePort=1102
jcs.auxiliary.RGroup.attributes.GetOnly=true
# Remote RMI Cache set up to failover
-jcs.auxiliary.RFailover=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RFailover.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RFailover=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RFailover.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RFailover.attributes.RemoteTypeName=LOCAL
jcs.auxiliary.RFailover.attributes.FailoverServers=localhost:1102
jcs.auxiliary.RFailover.attributes.GetOnly=false
# Primary Disk Cache-- faster than the rest because of memory key storage
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=target/test-sandbox/raf
jcs.auxiliary.DC.attributes.MaxPurgatorySize=10000000
jcs.auxiliary.DC.attributes.MaxKeySize=1000000
@@ -113,8 +113,8 @@
# If you want to use a separate pool for each disk cache, either use
# the single model or define a different auxiliary for each region and use the Pooled.
# SINGLE is best unless you have a huge # of regions.
-jcs.auxiliary.DC2=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC2.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC2=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC2.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC2.attributes.DiskPath=target/test-sandbox/raf
jcs.auxiliary.DC2.attributes.MaxPurgatorySize=10000
jcs.auxiliary.DC2.attributes.MaxKeySize=10000
@@ -123,28 +123,28 @@
jcs.auxiliary.DC2.attributes.EventQueuePoolName=disk_cache_event_queue
# Berkeley DB JE
-jcs.auxiliary.JE=org.apache.commons.jcs.auxiliary.disk.bdbje.BDBJECacheFactory
-jcs.auxiliary.JE.attributes=org.apache.commons.jcs.auxiliary.disk.bdbje.BDBJECacheAttributes
+jcs.auxiliary.JE=org.apache.commons.jcs3.auxiliary.disk.bdbje.BDBJECacheFactory
+jcs.auxiliary.JE.attributes=org.apache.commons.jcs3.auxiliary.disk.bdbje.BDBJECacheAttributes
jcs.auxiliary.JE.attributes.DiskPath=target/test-sandbox/bdbje-disk-cache-conc
# the minimum cache size is 1024
jcs.auxiliary.indexedDiskCache.attributes.CacheSize=1024
# jcs.auxiliary.indexedDiskCache.attributes.CachePercent=0
# HSQL Disk Cache -- too slow as is
-jcs.auxiliary.HDC=org.apache.commons.jcs.auxiliary.disk.hsql.HSQLCacheFactory
-jcs.auxiliary.HDC.attributes=org.apache.commons.jcs.auxiliary.disk.hsql.HSQLCacheAttributes
+jcs.auxiliary.HDC=org.apache.commons.jcs3.auxiliary.disk.hsql.HSQLCacheFactory
+jcs.auxiliary.HDC.attributes=org.apache.commons.jcs3.auxiliary.disk.hsql.HSQLCacheAttributes
jcs.auxiliary.HDC.attributes.DiskPath=@project_home_f@hsql
# JISP Disk Cache -- save memory with disk key storage
-jcs.auxiliary.JDC=org.apache.commons.jcs.auxiliary.disk.jisp.JISPCacheFactory
-jcs.auxiliary.JDC.attributes=org.apache.commons.jcs.auxiliary.disk.jisp.JISPCacheAttributes
+jcs.auxiliary.JDC=org.apache.commons.jcs3.auxiliary.disk.jisp.JISPCacheFactory
+jcs.auxiliary.JDC.attributes=org.apache.commons.jcs3.auxiliary.disk.jisp.JISPCacheAttributes
jcs.auxiliary.JDC.attributes.DiskPath=@project_home_f@raf
jcs.auxiliary.JDC.attributes.ClearOnStart=false
# need to make put or invalidate an option
# just a remove lock to add
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RC.attributes.FailoverServers=localhost:1101,localhost:1102
jcs.auxiliary.RC.attributes.LocalPort=1201
jcs.auxiliary.RC.attributes.RemoveUponRemotePut=false
@@ -156,42 +156,42 @@
jcs.auxiliary.RC.attributes.GetOnly=false
# unreliable
-jcs.auxiliary.LUDP=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LUDP.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LUDP=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LUDP.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LUDP.attributes.TransmissionTypeName=UDP
jcs.auxiliary.LUDP.attributes.UdpMulticastAddr=228.5.6.7
jcs.auxiliary.LUDP.attributes.UdpMulticastPort=6789
-jcs.auxiliary.LJG=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LJG.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LJG=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LJG.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LJG.attributes.TransmissionTypeName=JAVAGROUPS
jcs.auxiliary.LJG.attributes.PutOnlyMode=true
jcs.auxiliary.LJG.attributes.JGChannelProperties = UDP(mcast_addr=224.0.0.100;mcast_port=751):PING(timeout=3000):FD:STABLE:NAKACK:UNICAST:FRAG:FLUSH:GMS:VIEW_ENFORCER:QUEUE
-jcs.auxiliary.JG = org.apache.commons.jcs.auxiliary.javagroups.JavaGroupsCacheFactory
-jcs.auxiliary.JG.attributes = org.apache.commons.jcs.auxiliary.javagroups.JavaGroupsCacheAttributes
+jcs.auxiliary.JG = org.apache.commons.jcs3.auxiliary.javagroups.JavaGroupsCacheFactory
+jcs.auxiliary.JG.attributes = org.apache.commons.jcs3.auxiliary.javagroups.JavaGroupsCacheAttributes
jcs.auxiliary.JG.attributes.ChannelFactoryClassName = org.javagroups.JChannelFactory
jcs.auxiliary.JG.attributes.ChannelProperties = UDP(mcast_addr=224.0.0.100;mcast_port=7501):PING:FD:STABLE:NAKACK:UNICAST:FRAG:FLUSH:GMS:VIEW_ENFORCER:QUEUE
# almost complete
-jcs.auxiliary.LTCP=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LTCP=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LTCP.attributes.TransmissionTypeName=TCP
jcs.auxiliary.LTCP.attributes.TcpServers=localhost:1112
jcs.auxiliary.LTCP.attributes.TcpListenerPort=1111
jcs.auxiliary.LTCP.attributes.PutOnlyMode=true
-jcs.auxiliary.LTCP2=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LTCP2.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LTCP2=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LTCP2.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LTCP2.attributes.TransmissionTypeName=TCP
jcs.auxiliary.LTCP2.attributes.TcpServers=localhost:1112
jcs.auxiliary.LTCP2.attributes.TcpListenerPort=1111
jcs.auxiliary.LTCP2.attributes.PutOnlyMode=true
-jcs.auxiliary.XMLRPC=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.XMLRPC.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.XMLRPC=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.XMLRPC.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.XMLRPC.attributes.TransmissionTypeName=XMLRPC
jcs.auxiliary.XMLRPC.attributes.HttpServers=localhost:8182
jcs.auxiliary.XMLRPC.attributes.HttpListenerPort=8181
@@ -200,8 +200,8 @@
# example of how to configure the http version of the lateral cache
# not converteed to new cache
-jcs.auxiliary.LCHTTP=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LCHTTP.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LCHTTP=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LCHTTP.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LCHTTP.attributes.TransmissionType=HTTP
jcs.auxiliary.LCHTTP.attributes.httpServers=localhost:8080,localhost:7001,localhost:80
jcs.auxiliary.LCHTTP.attributes.httpReceiveServlet=/cache/LateralCacheReceiverServlet
diff --git a/commons-jcs-core/src/test/conf/cacheRC1.ccf b/commons-jcs-core/src/test/conf/cacheRC1.ccf
index 09890e3..71a2a4c 100644
--- a/commons-jcs-core/src/test/conf/cacheRC1.ccf
+++ b/commons-jcs-core/src/test/conf/cacheRC1.ccf
@@ -18,30 +18,30 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #############################################################
# ################# CACHE REGIONS AVAILABLE ###################
jcs.region.testCache1=RC
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=200000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.elementattributes.IsLateral=true
jcs.region.testCache1.elementattributes.IsRemote=true
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# standard disk cache
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=${user.dir}/raf1
# need to make put or invalidate an option
# just a remove lock to add
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RC.attributes.FailoverServers=localhost:1101,localhost:1102
jcs.auxiliary.RC.attributes.LocalPort=1201
jcs.auxiliary.RC.attributes.RemoveUponRemotePut=false
diff --git a/commons-jcs-core/src/test/conf/cacheRC2.ccf b/commons-jcs-core/src/test/conf/cacheRC2.ccf
index 935236c..58e9750 100644
--- a/commons-jcs-core/src/test/conf/cacheRC2.ccf
+++ b/commons-jcs-core/src/test/conf/cacheRC2.ccf
@@ -18,30 +18,30 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #############################################################
# ################# CACHE REGIONS AVAILABLE ###################
jcs.region.testCache1=RC
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=200000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.elementattributes.IsLateral=true
jcs.region.testCache1.elementattributes.IsRemote=true
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# standard disk cache
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=${user.dir}/raf2
# need to make put or invalidate an option
# just a remove lock to add
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RC.attributes.FailoverServers=localhost:1102,localhost:1101
jcs.auxiliary.RC.attributes.LocalPort=1202
jcs.auxiliary.RC.attributes.RemoveUponRemotePut=false
diff --git a/commons-jcs-core/src/test/conf/cacheRCN1.ccf b/commons-jcs-core/src/test/conf/cacheRCN1.ccf
index 7406467..e5cd48a 100644
--- a/commons-jcs-core/src/test/conf/cacheRCN1.ccf
+++ b/commons-jcs-core/src/test/conf/cacheRCN1.ccf
@@ -18,29 +18,29 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #############################################################
# ################# CACHE REGIONS AVAILABLE ###################
jcs.region.testCache1=RC
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=200000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.elementattributes.IsLateral=true
jcs.region.testCache1.elementattributes.IsRemote=true
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# standard disk cache
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=${user.dir}/raf1
# This remote client does not receive
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RC.attributes.FailoverServers=localhost:1101,localhost:1102
jcs.auxiliary.RC.attributes.LocalPort=1201
jcs.auxiliary.RC.attributes.RemoveUponRemotePut=false
diff --git a/commons-jcs-core/src/test/conf/cacheRCN2.ccf b/commons-jcs-core/src/test/conf/cacheRCN2.ccf
index 9ff900c..b52f532 100644
--- a/commons-jcs-core/src/test/conf/cacheRCN2.ccf
+++ b/commons-jcs-core/src/test/conf/cacheRCN2.ccf
@@ -18,29 +18,29 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #############################################################
# ################# CACHE REGIONS AVAILABLE ###################
jcs.region.testCache1=RC
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=200000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.elementattributes.IsLateral=true
jcs.region.testCache1.elementattributes.IsRemote=true
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# standard disk cache
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=${user.dir}/raf2
# This remote client does not receive
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RC.attributes.FailoverServers=localhost:1102,localhost:1101
jcs.auxiliary.RC.attributes.LocalPort=1202
jcs.auxiliary.RC.attributes.RemoveUponRemotePut=false
diff --git a/commons-jcs-core/src/test/conf/cacheRCSimple.ccf b/commons-jcs-core/src/test/conf/cacheRCSimple.ccf
index 14366f9..f3ac654 100644
--- a/commons-jcs-core/src/test/conf/cacheRCSimple.ccf
+++ b/commons-jcs-core/src/test/conf/cacheRCSimple.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=RC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200001
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,14 +37,14 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=RC
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=1000000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
@@ -54,23 +54,23 @@
# ################# AUXILIARY CACHES AVAILABLE ################
# Remote RMI cache without failover
-jcs.auxiliary.RGroup=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RGroup.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RGroup=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RGroup.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RGroup.attributes.RemoteTypeName=LOCAL
jcs.auxiliary.RGroup.attributes.RemoteHost=localhost
jcs.auxiliary.RGroup.attributes.RemotePort=1102
jcs.auxiliary.RGroup.attributes.GetOnly=true
# Remote RMI Cache set up to failover
-jcs.auxiliary.RFailover=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RFailover.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RFailover=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RFailover.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RFailover.attributes.RemoteTypeName=LOCAL
jcs.auxiliary.RFailover.attributes.FailoverServers=localhost:1102
jcs.auxiliary.RFailover.attributes.GetOnly=false
# Primary Disk Cache-- faster than the rest because of memory key storage
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=target/test-sandbox/raf
jcs.auxiliary.DC.attributes.MaxPurgatorySize=10000000
jcs.auxiliary.DC.attributes.MaxKeySize=1000000
@@ -84,8 +84,8 @@
# If you want to use a separate pool for each disk cache, either use
# the single model or define a different auxiliary for each region and use the Pooled.
# SINGLE is best unless you have a huge # of regions.
-jcs.auxiliary.DC2=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC2.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC2=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC2.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC2.attributes.DiskPath=target/test-sandbox/raf
jcs.auxiliary.DC2.attributes.MaxPurgatorySize=10000
jcs.auxiliary.DC2.attributes.MaxKeySize=10000
@@ -94,28 +94,28 @@
jcs.auxiliary.DC2.attributes.EventQueuePoolName=disk_cache_event_queue
# Berkeley DB JE
-jcs.auxiliary.JE=org.apache.commons.jcs.auxiliary.disk.bdbje.BDBJECacheFactory
-jcs.auxiliary.JE.attributes=org.apache.commons.jcs.auxiliary.disk.bdbje.BDBJECacheAttributes
+jcs.auxiliary.JE=org.apache.commons.jcs3.auxiliary.disk.bdbje.BDBJECacheFactory
+jcs.auxiliary.JE.attributes=org.apache.commons.jcs3.auxiliary.disk.bdbje.BDBJECacheAttributes
jcs.auxiliary.JE.attributes.DiskPath=target/test-sandbox/bdbje-disk-cache-conc
# the minimum cache size is 1024
jcs.auxiliary.indexedDiskCache.attributes.CacheSize=1024
# jcs.auxiliary.indexedDiskCache.attributes.CachePercent=0
# HSQL Disk Cache -- too slow as is
-jcs.auxiliary.HDC=org.apache.commons.jcs.auxiliary.disk.hsql.HSQLCacheFactory
-jcs.auxiliary.HDC.attributes=org.apache.commons.jcs.auxiliary.disk.hsql.HSQLCacheAttributes
+jcs.auxiliary.HDC=org.apache.commons.jcs3.auxiliary.disk.hsql.HSQLCacheFactory
+jcs.auxiliary.HDC.attributes=org.apache.commons.jcs3.auxiliary.disk.hsql.HSQLCacheAttributes
jcs.auxiliary.HDC.attributes.DiskPath=@project_home_f@hsql
# JISP Disk Cache -- save memory with disk key storage
-jcs.auxiliary.JDC=org.apache.commons.jcs.auxiliary.disk.jisp.JISPCacheFactory
-jcs.auxiliary.JDC.attributes=org.apache.commons.jcs.auxiliary.disk.jisp.JISPCacheAttributes
+jcs.auxiliary.JDC=org.apache.commons.jcs3.auxiliary.disk.jisp.JISPCacheFactory
+jcs.auxiliary.JDC.attributes=org.apache.commons.jcs3.auxiliary.disk.jisp.JISPCacheAttributes
jcs.auxiliary.JDC.attributes.DiskPath=@project_home_f@raf
jcs.auxiliary.JDC.attributes.ClearOnStart=false
# need to make put or invalidate an option
# just a remove lock to add
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RC.attributes.FailoverServers=localhost:1101
# ,localhost:1102
jcs.auxiliary.RC.attributes.LocalPort=1201
@@ -128,42 +128,42 @@
jcs.auxiliary.RC.attributes.GetOnly=false
# unreliable
-jcs.auxiliary.LUDP=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LUDP.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LUDP=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LUDP.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LUDP.attributes.TransmissionTypeName=UDP
jcs.auxiliary.LUDP.attributes.UdpMulticastAddr=228.5.6.7
jcs.auxiliary.LUDP.attributes.UdpMulticastPort=6789
-jcs.auxiliary.LJG=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LJG.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LJG=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LJG.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LJG.attributes.TransmissionTypeName=JAVAGROUPS
jcs.auxiliary.LJG.attributes.PutOnlyMode=true
jcs.auxiliary.LJG.attributes.JGChannelProperties = UDP(mcast_addr=224.0.0.100;mcast_port=751):PING(timeout=3000):FD:STABLE:NAKACK:UNICAST:FRAG:FLUSH:GMS:VIEW_ENFORCER:QUEUE
-jcs.auxiliary.JG = org.apache.commons.jcs.auxiliary.javagroups.JavaGroupsCacheFactory
-jcs.auxiliary.JG.attributes = org.apache.commons.jcs.auxiliary.javagroups.JavaGroupsCacheAttributes
+jcs.auxiliary.JG = org.apache.commons.jcs3.auxiliary.javagroups.JavaGroupsCacheFactory
+jcs.auxiliary.JG.attributes = org.apache.commons.jcs3.auxiliary.javagroups.JavaGroupsCacheAttributes
jcs.auxiliary.JG.attributes.ChannelFactoryClassName = org.javagroups.JChannelFactory
jcs.auxiliary.JG.attributes.ChannelProperties = UDP(mcast_addr=224.0.0.100;mcast_port=7501):PING:FD:STABLE:NAKACK:UNICAST:FRAG:FLUSH:GMS:VIEW_ENFORCER:QUEUE
# almost complete
-jcs.auxiliary.LTCP=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LTCP=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LTCP.attributes.TransmissionTypeName=TCP
jcs.auxiliary.LTCP.attributes.TcpServers=localhost:1112
jcs.auxiliary.LTCP.attributes.TcpListenerPort=1111
jcs.auxiliary.LTCP.attributes.PutOnlyMode=true
-jcs.auxiliary.LTCP2=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LTCP2.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LTCP2=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LTCP2.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LTCP2.attributes.TransmissionTypeName=TCP
jcs.auxiliary.LTCP2.attributes.TcpServers=localhost:1112
jcs.auxiliary.LTCP2.attributes.TcpListenerPort=1111
jcs.auxiliary.LTCP2.attributes.PutOnlyMode=true
-jcs.auxiliary.XMLRPC=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.XMLRPC.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.XMLRPC=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.XMLRPC.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.XMLRPC.attributes.TransmissionTypeName=XMLRPC
jcs.auxiliary.XMLRPC.attributes.HttpServers=localhost:8182
jcs.auxiliary.XMLRPC.attributes.HttpListenerPort=8181
@@ -172,8 +172,8 @@
# example of how to configure the http version of the lateral cache
# not converteed to new cache
-jcs.auxiliary.LCHTTP=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LCHTTP.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LCHTTP=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LCHTTP.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LCHTTP.attributes.TransmissionType=HTTP
jcs.auxiliary.LCHTTP.attributes.httpServers=localhost:8080,localhost:7001,localhost:80
jcs.auxiliary.LCHTTP.attributes.httpReceiveServlet=/cache/LateralCacheReceiverServlet
diff --git a/commons-jcs-core/src/test/conf/cacheRC_CEL.ccf b/commons-jcs-core/src/test/conf/cacheRC_CEL.ccf
index 59b7913..6e76421 100644
--- a/commons-jcs-core/src/test/conf/cacheRC_CEL.ccf
+++ b/commons-jcs-core/src/test/conf/cacheRC_CEL.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC,RC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200001
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,27 +37,27 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=DC,RC
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=1000000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
jcs.region.testCache1.elementattributes.IsRemote=true
jcs.region.testCache2=DC,RC
-jcs.region.testCache2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache2.cacheattributes.MaxObjects=100
-jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache2.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache2.cacheattributes.MaxMemoryIdleTimeSeconds=1000
jcs.region.testCache2.cacheattributes.ShrinkerIntervalSeconds=40
-jcs.region.testCache2.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache2.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache2.elementattributes.IsEternal=false
jcs.region.testCache2.elementattributes.MaxLifeSeconds=600
jcs.region.testCache2.elementattributes.IsSpool=true
@@ -65,13 +65,13 @@
jcs.region.testCache2.elementattributes.IsLateral=true
jcs.region.testCache3=
-jcs.region.testCache3.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache3.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache3.cacheattributes.MaxObjects=100000
-jcs.region.testCache3.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache3.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache3.cacheattributes.UseMemoryShrinker=false
jcs.region.testCache3.cacheattributes.MaxMemoryIdleTimeSeconds=10
jcs.region.testCache3.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.region.testCache3.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache3.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache3.elementattributes.IsEternal=false
jcs.region.testCache3.elementattributes.MaxLifeSeconds=3600
jcs.region.testCache3.elementattributes.IsSpool=true
@@ -83,8 +83,8 @@
# ################# AUXILIARY CACHES AVAILABLE ################
# Primary Disk Cache-- faster than the rest because of memory key storage
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=target/test-sandbox/raf
jcs.auxiliary.DC.attributes.MaxPurgatorySize=10000000
jcs.auxiliary.DC.attributes.MaxKeySize=1000000
@@ -93,8 +93,8 @@
# need to make put or invalidate an option
# just a remove lock to add
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RC.attributes.FailoverServers=localhost:1101,localhost:1102
jcs.auxiliary.RC.attributes.LocalPort=1201
jcs.auxiliary.RC.attributes.RemoveUponRemotePut=false
@@ -104,7 +104,7 @@
jcs.auxiliary.RC.attributes.GetTimeoutMillis=500
jcs.auxiliary.RC.attributes.ThreadPoolName=remote_cache_client
jcs.auxiliary.RC.attributes.GetOnly=false
-jcs.auxiliary.RC.cacheeventlogger=org.apache.commons.jcs.engine.logging.CacheEventLoggerDebugLogger
+jcs.auxiliary.RC.cacheeventlogger=org.apache.commons.jcs3.engine.logging.CacheEventLoggerDebugLogger
jcs.auxiliary.RC.cacheeventlogger.attributes.logCategoryName=test.RCCEventLogCategory
diff --git a/commons-jcs-core/src/test/conf/cacheRHTTP.ccf b/commons-jcs-core/src/test/conf/cacheRHTTP.ccf
index 9c2cff4..88bdd8a 100644
--- a/commons-jcs-core/src/test/conf/cacheRHTTP.ccf
+++ b/commons-jcs-core/src/test/conf/cacheRHTTP.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=RC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=0
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -34,7 +34,7 @@
## The Http Remote Cache Client
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.http.client.RemoteHttpCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.http.client.RemoteHttpCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.http.client.RemoteHttpCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.http.client.RemoteHttpCacheAttributes
jcs.auxiliary.RC.attributes.url=http://localhost:8000/jcs-app/RemoteCache
jcs.auxiliary.RC.attributes.maxConnectionsPerHost=500
diff --git a/commons-jcs-core/src/test/conf/cacheTCP1.ccf b/commons-jcs-core/src/test/conf/cacheTCP1.ccf
index 5fbfc03..11760d3 100644
--- a/commons-jcs-core/src/test/conf/cacheTCP1.ccf
+++ b/commons-jcs-core/src/test/conf/cacheTCP1.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=LTCP
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200001
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLifeSeconds=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,14 +37,14 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=LTCP
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=1000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
@@ -55,8 +55,8 @@
# ################# AUXILIARY CACHES AVAILABLE ################
# TCP
-jcs.auxiliary.LTCP=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
-jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
+jcs.auxiliary.LTCP=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
+jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
jcs.auxiliary.LTCP.attributes.TcpListenerPort=1118
jcs.auxiliary.LTCP.attributes.UdpDiscoveryAddr=228.5.6.8
jcs.auxiliary.LTCP.attributes.UdpDiscoveryPort=9780
diff --git a/commons-jcs-core/src/test/conf/cacheTCP2.ccf b/commons-jcs-core/src/test/conf/cacheTCP2.ccf
index 4f03854..c281feb 100644
--- a/commons-jcs-core/src/test/conf/cacheTCP2.ccf
+++ b/commons-jcs-core/src/test/conf/cacheTCP2.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200001
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLifeSeconds=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,28 +37,28 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=LTCP
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=1000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
jcs.region.testCache1.elementattributes.IsRemote=true
jcs.region.testCache2=LTCP
-jcs.region.testCache2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache2.cacheattributes.MaxObjects=1000
-jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache2.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache2.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache2.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache2.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache2.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache2.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache2.elementattributes.IsEternal=false
jcs.region.testCache2.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache2.elementattributes.IsLateral=true
@@ -68,8 +68,8 @@
# ################# AUXILIARY CACHES AVAILABLE ################
# TCP
-jcs.auxiliary.LTCP=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
-jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
+jcs.auxiliary.LTCP=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
+jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
jcs.auxiliary.LTCP.attributes.TcpListenerPort=1119
jcs.auxiliary.LTCP.attributes.UdpDiscoveryAddr=228.5.6.8
jcs.auxiliary.LTCP.attributes.UdpDiscoveryPort=9780
diff --git a/commons-jcs-core/src/test/conf/cacheTCP3.ccf b/commons-jcs-core/src/test/conf/cacheTCP3.ccf
index 15a119d..f9c67b3 100644
--- a/commons-jcs-core/src/test/conf/cacheTCP3.ccf
+++ b/commons-jcs-core/src/test/conf/cacheTCP3.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200001
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLifeSeconds=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,28 +37,28 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=LTCP
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=1000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
jcs.region.testCache1.elementattributes.IsRemote=true
jcs.region.testCache2=LTCP
-jcs.region.testCache2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache2.cacheattributes.MaxObjects=1000
-jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache2.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache2.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache2.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache2.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache2.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache2.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache2.elementattributes.IsEternal=false
jcs.region.testCache2.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache2.elementattributes.IsLateral=true
@@ -68,8 +68,8 @@
# ################# AUXILIARY CACHES AVAILABLE ################
# almost complete
-jcs.auxiliary.LTCP=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
-jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
+jcs.auxiliary.LTCP=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
+jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
jcs.auxiliary.LTCP.attributes.TransmissionTypeName=TCP
# jcs.auxiliary.LTCP.attributes.TcpServers=
jcs.auxiliary.LTCP.attributes.TcpListenerPort=1120
diff --git a/commons-jcs-core/src/test/conf/cacheTCP4.ccf b/commons-jcs-core/src/test/conf/cacheTCP4.ccf
index 69c6c1c..de3210c 100644
--- a/commons-jcs-core/src/test/conf/cacheTCP4.ccf
+++ b/commons-jcs-core/src/test/conf/cacheTCP4.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200001
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLifeSeconds=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,14 +37,14 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=LTCP
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=1000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
@@ -55,8 +55,8 @@
# ################# AUXILIARY CACHES AVAILABLE ################
# almost complete
-jcs.auxiliary.LTCP=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
-jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
+jcs.auxiliary.LTCP=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
+jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
jcs.auxiliary.LTCP.attributes.TransmissionTypeName=TCP
# jcs.auxiliary.LTCP.attributes.TcpServers=
jcs.auxiliary.LTCP.attributes.TcpListenerPort=1121
diff --git a/commons-jcs-core/src/test/conf/log4j.properties b/commons-jcs-core/src/test/conf/log4j.properties
index 90ea9c8..87047c6 100644
--- a/commons-jcs-core/src/test/conf/log4j.properties
+++ b/commons-jcs-core/src/test/conf/log4j.properties
@@ -42,28 +42,28 @@
log4j.category.org.jgroups=WARN
log4j.category.org.apache.commons.jcs=INFO
-log4j.category.org.apache.commons.jcs.engine=INFO
-# log4j.category.org.apache.commons.jcs.acess=WARN,WF
-# log4j.category.org.apache.commons.jcs.engine.control=WARN,WF
+log4j.category.org.apache.commons.jcs3.engine=INFO
+# log4j.category.org.apache.commons.jcs3.acess=WARN,WF
+# log4j.category.org.apache.commons.jcs3.engine.control=WARN,WF
-# log4j.logger.org.apache.commons.jcs.engine.memory.shrinking=INFO
-# log4j.logger.org.apache.commons.jcs.auxiliary.disk=INFO
-log4j.logger.org.apache.commons.jcs.auxiliary.disk.indexed=INFO
+# log4j.logger.org.apache.commons.jcs3.engine.memory.shrinking=INFO
+# log4j.logger.org.apache.commons.jcs3.auxiliary.disk=INFO
+log4j.logger.org.apache.commons.jcs3.auxiliary.disk.indexed=INFO
-# log4j.category.org.apache.commons.jcs.config=WARN,A1
+# log4j.category.org.apache.commons.jcs3.config=WARN,A1
-# log4j.category.org.apache.commons.jcs.auxiliary=INFO
-# log4j.category.org.apache.commons.jcs.auxiliary.disk=WARN,WF
-# log4j.category.org.apache.commons.jcs.auxiliary.lateral=INFO
-# log4j.category.org.apache.commons.jcs.auxiliary.lateral.javagroups=INFO
-# log4j.category.org.apache.commons.jcs.auxiliary.lateral.xmlrpc=INFO
-# log4j.category.org.apache.commons.jcs.auxiliary.remote=INFO
-# log4j.category.org.apache.commons.jcs.auxiliary.remote.RemoteCacheFailoverRunner=INFO
-# log4j.category.org.apache.commons.jcs.auxiliary.remote.RemoteCacheListener=DEBUG
-# log4j.category.org.apache.commons.jcs.auxiliary.remote.RemoteCacheManager=INFO
-# log4j.category.org.apache.commons.jcs.auxiliary.remote.server.RemoteCacheServer=DEBUG
-# log4j.category.org.apache.commons.jcs.auxiliary.remote.server=INFO
-# log4j.category.org.apache.commons.jcs.utils=WARN,WF
-# log4j.category.org.apache.commons.jcs.utils.discovery=DEBUG
+# log4j.category.org.apache.commons.jcs3.auxiliary=INFO
+# log4j.category.org.apache.commons.jcs3.auxiliary.disk=WARN,WF
+# log4j.category.org.apache.commons.jcs3.auxiliary.lateral=INFO
+# log4j.category.org.apache.commons.jcs3.auxiliary.lateral.javagroups=INFO
+# log4j.category.org.apache.commons.jcs3.auxiliary.lateral.xmlrpc=INFO
+# log4j.category.org.apache.commons.jcs3.auxiliary.remote=INFO
+# log4j.category.org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFailoverRunner=INFO
+# log4j.category.org.apache.commons.jcs3.auxiliary.remote.RemoteCacheListener=DEBUG
+# log4j.category.org.apache.commons.jcs3.auxiliary.remote.RemoteCacheManager=INFO
+# log4j.category.org.apache.commons.jcs3.auxiliary.remote.server.RemoteCacheServer=DEBUG
+# log4j.category.org.apache.commons.jcs3.auxiliary.remote.server=INFO
+# log4j.category.org.apache.commons.jcs3.utils=WARN,WF
+# log4j.category.org.apache.commons.jcs3.utils.discovery=DEBUG
-log4j.category.org.apache.commons.jcs.utils=INFO
+log4j.category.org.apache.commons.jcs3.utils=INFO
diff --git a/commons-jcs-core/src/test/conf/remote.cache.ccf b/commons-jcs-core/src/test/conf/remote.cache.ccf
index 40e6261..c069d15 100644
--- a/commons-jcs-core/src/test/conf/remote.cache.ccf
+++ b/commons-jcs-core/src/test/conf/remote.cache.ccf
@@ -21,20 +21,20 @@
registry.port=1101
remote.cache.service.port=1101
remote.cluster.LocalClusterConsistency=true
-#remote.cacheeventlogger=org.apache.commons.jcs.engine.logging.CacheEventLoggerDebugLogger
+#remote.cacheeventlogger=org.apache.commons.jcs3.engine.logging.CacheEventLoggerDebugLogger
#remote.cacheeventlogger.attributes.logCategoryName=TestEventLogCategory
# #############################################################
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC,RCluster
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=7000
jcs.default.elementattributes.IdleTime=1800
@@ -46,15 +46,15 @@
# #############################################################
# ################# CACHE REGIONS AVAILABLE ###################
jcs.region.testCache1=DC,RCluster
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=200002
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# server to update for clustering -- remote.cache2.ccf(1102) and remote.cache3.ccf(1103)
-jcs.auxiliary.RCluster=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RCluster.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RCluster=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RCluster.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RCluster.attributes.RemoteTypeName=CLUSTER
jcs.auxiliary.RCluster.attributes.RemoveUponRemotePut=false
jcs.auxiliary.RCluster.attributes.ClusterServers=localhost:1102
@@ -62,7 +62,7 @@
jcs.auxiliary.RCluster.attributes.LocalClusterConsistency=true
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=@project_home@/raf/remote
diff --git a/commons-jcs-core/src/test/conf/remote.cache2.ccf b/commons-jcs-core/src/test/conf/remote.cache2.ccf
index 803cdd6..352347c 100644
--- a/commons-jcs-core/src/test/conf/remote.cache2.ccf
+++ b/commons-jcs-core/src/test/conf/remote.cache2.ccf
@@ -29,13 +29,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC,RCluster
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=7000
jcs.default.elementattributes.IdleTime=1800
@@ -47,15 +47,15 @@
# #############################################################
# ################# CACHE REGIONS AVAILABLE ###################
jcs.region.testCache1=DC,RCluster
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=200000
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# server to update for clustering -- remote.cache1.ccf(1101) and remote.cache3.ccf(1103)
-jcs.auxiliary.RCluster=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RCluster.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RCluster=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RCluster.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RCluster.attributes.RemoteTypeName=CLUSTER
jcs.auxiliary.RCluster.attributes.RemoveUponRemotePut=false
jcs.auxiliary.RCluster.attributes.ClusterServers=localhost:1101
@@ -63,8 +63,8 @@
jcs.auxiliary.RCluster.attributes.LocalClusterConsistency=true
# disk cache
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=@project_home@/raf/remote-rc2
diff --git a/commons-jcs-core/src/test/conf/remote.cache3.ccf b/commons-jcs-core/src/test/conf/remote.cache3.ccf
index 116a208..13108b8 100644
--- a/commons-jcs-core/src/test/conf/remote.cache3.ccf
+++ b/commons-jcs-core/src/test/conf/remote.cache3.ccf
@@ -29,14 +29,14 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC,RCluster
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=1000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=7000
jcs.default.elementattributes.IdleTime=1800
@@ -48,15 +48,15 @@
# #############################################################
# ################# CACHE REGIONS AVAILABLE ###################
jcs.region.testCache1=DC,RCluster
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=1000
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# server to update for clustering -- remote.cache1.ccf(1101) and remote.cache2.ccf(1102)
-jcs.auxiliary.RCluster=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RCluster.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RCluster=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RCluster.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RCluster.attributes.RemoteTypeName=CLUSTER
jcs.auxiliary.RCluster.attributes.RemoveUponRemotePut=false
jcs.auxiliary.RCluster.attributes.ClusterServers=localhost:1101,localhost:1102
@@ -65,7 +65,7 @@
# disk cache
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=@project_home@/raf/remote
diff --git a/commons-jcs-core/src/test/conf/remote.cacheCEL.ccf b/commons-jcs-core/src/test/conf/remote.cacheCEL.ccf
index a2bf52a..3b24f0f 100644
--- a/commons-jcs-core/src/test/conf/remote.cacheCEL.ccf
+++ b/commons-jcs-core/src/test/conf/remote.cacheCEL.ccf
@@ -21,20 +21,20 @@
registry.port=1101
remote.cache.service.port=1101
remote.cluster.LocalClusterConsistency=true
-remote.cacheeventlogger=org.apache.commons.jcs.engine.logging.CacheEventLoggerDebugLogger
+remote.cacheeventlogger=org.apache.commons.jcs3.engine.logging.CacheEventLoggerDebugLogger
remote.cacheeventlogger.attributes.logCategoryName=test.RCSEventLogCategory
# #############################################################
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC,RCluster
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=7000
jcs.default.elementattributes.IdleTime=1800
@@ -46,15 +46,15 @@
# #############################################################
# ################# CACHE REGIONS AVAILABLE ###################
jcs.region.testCache1=DC,RCluster
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=200002
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# server to update for clustering -- remote.cache2.ccf(1102) and remote.cache3.ccf(1103)
-jcs.auxiliary.RCluster=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RCluster.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RCluster=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RCluster.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RCluster.attributes.RemoteTypeName=CLUSTER
jcs.auxiliary.RCluster.attributes.RemoveUponRemotePut=false
jcs.auxiliary.RCluster.attributes.ClusterServers=localhost:1102
@@ -62,7 +62,7 @@
jcs.auxiliary.RCluster.attributes.LocalClusterConsistency=true
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=@project_home@/raf/remote
diff --git a/commons-jcs-core/src/test/conf/remote.cacheCEL_CSF.ccf b/commons-jcs-core/src/test/conf/remote.cacheCEL_CSF.ccf
index 892a435..3876eb1 100644
--- a/commons-jcs-core/src/test/conf/remote.cacheCEL_CSF.ccf
+++ b/commons-jcs-core/src/test/conf/remote.cacheCEL_CSF.ccf
@@ -21,21 +21,21 @@
registry.port=1101
jcs.remotecache.serverattributes.servicePort=1301
jcs.remotecache.serverattributes.localClusterConsistency=true
-jcs.remotecache.customrmisocketfactory=org.apache.commons.jcs.auxiliary.remote.server.MockRMISocketFactory
-jcs.remotecache.cacheeventlogger=org.apache.commons.jcs.engine.logging.CacheEventLoggerDebugLogger
+jcs.remotecache.customrmisocketfactory=org.apache.commons.jcs3.auxiliary.remote.server.MockRMISocketFactory
+jcs.remotecache.cacheeventlogger=org.apache.commons.jcs3.engine.logging.CacheEventLoggerDebugLogger
jcs.remotecache.cacheeventlogger.attributes.logCategoryName=test.RCSEventLogCategory
# #############################################################
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC,RCluster
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=7000
jcs.default.elementattributes.IdleTime=1800
@@ -47,15 +47,15 @@
# #############################################################
# ################# CACHE REGIONS AVAILABLE ###################
jcs.region.testCache1=DC,RCluster
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=200002
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# server to update for clustering -- remote.cache2.ccf(1102) and remote.cache3.ccf(1103)
-jcs.auxiliary.RCluster=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RCluster.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RCluster=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RCluster.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RCluster.attributes.RemoteTypeName=CLUSTER
jcs.auxiliary.RCluster.attributes.RemoveUponRemotePut=false
jcs.auxiliary.RCluster.attributes.ClusterServers=localhost:1102
@@ -63,7 +63,7 @@
jcs.auxiliary.RCluster.attributes.LocalClusterConsistency=true
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=@project_home@/raf/remote
diff --git a/commons-jcs-core/src/test/conf/remote.cacheRS1.ccf b/commons-jcs-core/src/test/conf/remote.cacheRS1.ccf
index 6c525d6..5e9c2e1 100644
--- a/commons-jcs-core/src/test/conf/remote.cacheRS1.ccf
+++ b/commons-jcs-core/src/test/conf/remote.cacheRS1.ccf
@@ -29,13 +29,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC,RCluster
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=250000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLifeSeconds=700
jcs.default.elementattributes.IdleTime=1800
@@ -48,14 +48,14 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=DC,RCluster
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=250000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=false
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
@@ -66,16 +66,16 @@
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# Primary Disk Cache-- faster than the rest because of memory key storage
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=logs/rafRS1
jcs.auxiliary.DC.attributes.MaxPurgatorySize=100000
jcs.auxiliary.DC.attributes.MaxKeySize=500000
jcs.auxiliary.DC.attributes.OptimizeAtRemoveCount=-1
# RS2 SERVER to update for clustering
-jcs.auxiliary.RCluster=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RCluster.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RCluster=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RCluster.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RCluster.attributes.RemoteTypeName=CLUSTER
jcs.auxiliary.RCluster.attributes.RemoveUponRemotePut=false
jcs.auxiliary.RCluster.attributes.ClusterServers=localhost:1102
diff --git a/commons-jcs-core/src/test/conf/remote.cacheRS2.ccf b/commons-jcs-core/src/test/conf/remote.cacheRS2.ccf
index dd561c9..ac10baf 100644
--- a/commons-jcs-core/src/test/conf/remote.cacheRS2.ccf
+++ b/commons-jcs-core/src/test/conf/remote.cacheRS2.ccf
@@ -29,13 +29,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC,RCluster
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=250000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLifeSeconds=700
jcs.default.elementattributes.IdleTime=1800
@@ -48,14 +48,14 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=DC,RCluster
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=250000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=false
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLifeSeconds=60000
jcs.region.testCache1.elementattributes.IsLateral=true
@@ -66,16 +66,16 @@
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# Primary Disk Cache-- faster than the rest because of memory key storage
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=logs/rafRS2
jcs.auxiliary.DC.attributes.MaxPurgatorySize=100000
jcs.auxiliary.DC.attributes.MaxKeySize=500000
jcs.auxiliary.DC.attributes.OptimizeAtRemoveCount=-1
# RS1 SERVER to update for clustering
-jcs.auxiliary.RCluster=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RCluster.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RCluster=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RCluster.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RCluster.attributes.RemoteTypeName=CLUSTER
jcs.auxiliary.RCluster.attributes.RemoveUponRemotePut=false
jcs.auxiliary.RCluster.attributes.ClusterServers=localhost:1101
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/ConcurrentRemovalLoadTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/ConcurrentRemovalLoadTest.java
deleted file mode 100644
index 7cfcc44..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/ConcurrentRemovalLoadTest.java
+++ /dev/null
@@ -1,137 +0,0 @@
-package org.apache.commons.jcs;
-
-/*
- * 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.
- */
-
-import junit.extensions.ActiveTestSuite;
-import junit.framework.Test;
-import junit.framework.TestCase;
-
-/**
- * Test which exercises the hierarchical removal when the cache is active.
- */
-public class ConcurrentRemovalLoadTest
- extends TestCase
-{
- /**
- * A unit test suite for JUnit. This verifies that we can remove hierarchically while the region
- * is active.
- * @return The test suite
- */
- public static Test suite()
- {
- ActiveTestSuite suite = new ActiveTestSuite();
-
- suite.addTest( new RemovalTestUtil( "testRemoveCache1" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- runTestPutThenRemoveCategorical( 0, 200 );
- }
- } );
-
- suite.addTest( new RemovalTestUtil( "testPutCache1" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- runPutInRange( 300, 400 );
- }
- } );
-
- suite.addTest( new RemovalTestUtil( "testPutCache2" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- runPutInRange( 401, 600 );
- }
- } );
-
- // stomp on previous put
- suite.addTest( new RemovalTestUtil( "testPutCache3" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- runPutInRange( 401, 600 );
- }
- } );
-
- suite.addTest( new RemovalTestUtil( "testRemoveCache1" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- runTestPutThenRemoveCategorical( 601, 700 );
- }
- } );
-
- suite.addTest( new RemovalTestUtil( "testRemoveCache1" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- runTestPutThenRemoveCategorical( 701, 800 );
- }
- } );
-
- suite.addTest( new RemovalTestUtil( "testRemoveCache1" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- runTestPutThenRemoveCategorical( 901, 1000 );
- }
- } );
-
- suite.addTest( new RemovalTestUtil( "testPutCache2" )
- {
- // verify that there are no errors with concurrent gets.
- @Override
- public void runTest()
- throws Exception
- {
- runGetInRange( 0, 1000, false );
- }
- } );
- return suite;
- }
-
- /**
- * Test setup
- * <p>
- * @throws Exception
- */
- @Override
- public void setUp()
- throws Exception
- {
- JCS.setConfigFilename( "/TestRemoval.ccf" );
- JCS.getInstance( "testCache1" );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSCacheElementRetrievalUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSCacheElementRetrievalUnitTest.java
deleted file mode 100644
index 8b90b3d..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSCacheElementRetrievalUnitTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.apache.commons.jcs;
-
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/**
- * @author Aaron Smuts
- *
- */
-public class JCSCacheElementRetrievalUnitTest
- extends TestCase
-{
- /**
- *
- * @throws Exception
- */
- public void testSimpleElementRetrieval()
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
-
- jcs.put( "test_key", "test_data" );
-
- long now = System.currentTimeMillis();
- ICacheElement<String, String> elem = jcs.getCacheElement( "test_key" );
- assertEquals( "Name wasn't right", "testCache1", elem.getCacheName() );
-
- long diff = now - elem.getElementAttributes().getCreateTime();
- assertTrue( "Create time should have been at or after the call", diff >= 0 );
-
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSConcurrentCacheAccessUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSConcurrentCacheAccessUnitTest.java
deleted file mode 100644
index 48932cb..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSConcurrentCacheAccessUnitTest.java
+++ /dev/null
@@ -1,182 +0,0 @@
-package org.apache.commons.jcs;
-
-/*
- * 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.
- */
-
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.commons.jcs.access.GroupCacheAccess;
-import org.apache.commons.jcs.access.exception.CacheException;
-
-import junit.framework.TestCase;
-
-/**
- * Test Case for JCS-73, modeled after the Groovy code by Alexander Kleymenov
- *
- * @author Thomas Vandahl
- *
- */
-public class JCSConcurrentCacheAccessUnitTest extends TestCase
-{
- private final static int THREADS = 20;
- private final static int LOOPS = 10000;
-
- /**
- * the cache instance
- */
- protected GroupCacheAccess<Integer, String> cache;
-
- /**
- * the group name
- */
- protected String group = "group";
-
- /**
- * the error count
- */
- protected AtomicInteger errcount;
-
- /**
- * Collect all value mismatches
- */
- protected List<String> valueMismatchList;
-
- @Override
- protected void setUp() throws Exception
- {
- super.setUp();
- JCS.setConfigFilename( "/TestJCS-73.ccf" );
- cache = JCS.getGroupCacheInstance( "cache" );
- errcount = new AtomicInteger(0);
- valueMismatchList = new CopyOnWriteArrayList<>();
- }
-
- @Override
- protected void tearDown()
- throws Exception
- {
- super.tearDown();
- cache.clear();
- cache.dispose();
- }
-
- /**
- * Worker thread
- */
- protected class Worker extends Thread
- {
- @Override
- public void run()
- {
- String name = getName();
-
- for (int idx = 0; idx < LOOPS; idx++)
- {
- if (idx > 0)
- {
- // get previously stored value
- String res = cache.getFromGroup(Integer.valueOf(idx-1), group);
-
- if (res == null)
- {
- // null value got inspite of the fact it was placed in cache!
- System.out.println("ERROR: for " + idx + " in " + name);
- errcount.incrementAndGet();
-
- // try to get the value again:
- int n = 5;
- while (n-- > 0)
- {
- res = cache.getFromGroup(Integer.valueOf(idx-1), group);
- if (res != null)
- {
- // the value finally appeared in cache
- System.out.println("ERROR FIXED for " + idx + ": " + res + " " + name);
- errcount.decrementAndGet();
- break;
- }
-
- System.out.println("ERROR STILL PERSISTS for " + idx + " in " + name);
- try
- {
- Thread.sleep(1000);
- }
- catch (InterruptedException e)
- {
- // continue
- }
- }
- }
-
- if (!String.valueOf(idx-1).equals(res))
- {
- valueMismatchList.add(String.format("Values do not match: %s - %s", String.valueOf(idx-1), res));
- }
- }
-
- // put value in the cache
- try
- {
- cache.putInGroup(Integer.valueOf(idx), group, String.valueOf(idx));
- }
- catch (CacheException e)
- {
- // continue
- }
-
-// if ((idx % 1000) == 0)
-// {
-// System.out.println(name + " " + idx);
-// }
- }
-
- }
- }
-
- /**
- *
- * @throws Exception
- */
- public void testConcurrentAccess()
- throws Exception
- {
- Worker[] worker = new Worker[THREADS];
-
- for (int i = 0; i < THREADS; i++)
- {
- worker[i] = new Worker();
- worker[i].start();
- }
-
- for (int i = 0; i < THREADS; i++)
- {
- worker[i].join();
- }
-
- assertEquals("Error count should be 0", 0, errcount.intValue());
- for (String msg : valueMismatchList)
- {
- System.out.println(msg);
- }
- assertEquals("Value mismatch count should be 0", 0, valueMismatchList.size());
- }
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSLightLoadUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSLightLoadUnitTest.java
deleted file mode 100644
index 92e1011..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSLightLoadUnitTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package org.apache.commons.jcs;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.access.CacheAccess;
-
-import junit.framework.TestCase;
-
-/**
- * Runs a few thousand queries.
- */
-public class JCSLightLoadUnitTest
- extends TestCase
-{
- /** number to use for the test */
- private static int items = 20000;
-
- /**
- * Test setup
- * @throws Exception
- */
- @Override
- public void setUp()
- throws Exception
- {
- JCS.setConfigFilename( "/TestSimpleLoad.ccf" );
- JCS.getInstance( "testCache1" );
- }
-
- /**
- * A unit test for JUnit
- * @throws Exception Description of the Exception
- */
- public void testSimpleLoad()
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
- // ICompositeCacheAttributes cattr = jcs.getCacheAttributes();
- // cattr.setMaxObjects( 20002 );
- // jcs.setCacheAttributes( cattr );
-
- for ( int i = 1; i <= items; i++ )
- {
- jcs.put( i + ":key", "data" + i );
- }
-
- for ( int i = items; i > 0; i-- )
- {
- String res = jcs.get( i + ":key" );
- assertNotNull( "[" + i + ":key] should not be null", res );
- }
-
- // test removal
- jcs.remove( "300:key" );
- assertNull( jcs.get( "300:key" ) );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSRemovalSimpleConcurrentTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSRemovalSimpleConcurrentTest.java
deleted file mode 100644
index 92a3a56..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSRemovalSimpleConcurrentTest.java
+++ /dev/null
@@ -1,192 +0,0 @@
-package org.apache.commons.jcs;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.access.CacheAccess;
-
-/**
- * Verify that basic removal functionality works.
- */
-public class JCSRemovalSimpleConcurrentTest
- extends TestCase
-{
- /**
- * @param testName
- */
- public JCSRemovalSimpleConcurrentTest( String testName )
- {
- super( testName );
- }
-
- /**
- * Test setup
- * <p>
- * @throws Exception
- */
- @Override
- public void setUp()
- throws Exception
- {
- JCS.setConfigFilename( "/TestRemoval.ccf" );
- JCS.getInstance( "testCache1" );
- }
-
- /**
- * Main method passes this test to the text test runner.
- * <p>
- * @param args
- */
- public static void main( String args[] )
- {
- String[] testCaseName = { JCSRemovalSimpleConcurrentTest.class.getName() };
- junit.textui.TestRunner.main( testCaseName );
- }
-
- /**
- * Verify that 2 level deep hierchical removal works.
- * <p>
- * @throws Exception
- */
- public void testTwoDeepRemoval()
- throws Exception
- {
- int count = 500;
- CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
-
- for ( int i = 0; i <= count; i++ )
- {
- jcs.put( "key:" + i + ":anotherpart", "data" + i );
- }
-
- for ( int i = count; i >= 0; i-- )
- {
- String res = jcs.get( "key:" + i + ":anotherpart" );
- assertNotNull( "[key:" + i + ":anotherpart] should not be null, " + jcs.getStats(), res );
- }
-
- for ( int i = 0; i <= count; i++ )
- {
- jcs.remove( "key:" + i + ":" );
- assertNull( jcs.getStats(), jcs.get( "key:" + i + ":anotherpart" ) );
- }
-
- }
-
- /**
- * Verify that 1 level deep hierchical removal works.
- *
- * @throws Exception
- */
- public void testSingleDepthRemoval()
- throws Exception
- {
-
- int count = 500;
- CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
-
- for ( int i = 0; i <= count; i++ )
- {
- jcs.put( i + ":key", "data" + i );
- }
-
- for ( int i = count; i >= 0; i-- )
- {
- String res = jcs.get( i + ":key" );
- assertNotNull( "[" + i + ":key] should not be null", res );
- }
-
- for ( int i = 0; i <= count; i++ )
- {
- jcs.remove( i + ":" );
- assertNull( jcs.get( i + ":key" ) );
- }
- }
-
- /**
- * Verify that clear removes everyting as it should.
- * <p>
- * @throws Exception
- */
- public void testClear()
- throws Exception
- {
-
- int count = 500;
- CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
-
- for ( int i = 0; i <= count; i++ )
- {
- jcs.put( i + ":key", "data" + i );
- }
-
- for ( int i = count; i >= 0; i-- )
- {
- String res = jcs.get( i + ":key" );
- assertNotNull( "[" + i + ":key] should not be null", res );
- }
- jcs.clear();
-
- for ( int i = count; i >= 0; i-- )
- {
- String res = jcs.get( i + ":key" );
- if ( res != null )
- {
- assertNull( "[" + i + ":key] should be null after remvoeall" + jcs.getStats(), res );
- }
- }
- }
-
- /**
- * Verify that we can clear repeatedly without error.
- *
- * @throws Exception
- */
- public void testClearRepeatedlyWithoutError()
- throws Exception
- {
- int count = 500;
- CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
-
- jcs.clear();
-
- for ( int i = 0; i <= count; i++ )
- {
- jcs.put( i + ":key", "data" + i );
- }
-
- for ( int i = count; i >= 0; i-- )
- {
- String res = jcs.get( i + ":key" );
- assertNotNull( "[" + i + ":key] should not be null", res );
- }
-
- for ( int i = count; i >= 0; i-- )
- {
- jcs.put( i + ":key", "data" + i );
- jcs.clear();
- String res = jcs.get( i + ":key" );
- if ( res != null )
- {
- assertNull( "[" + i + ":key] should be null after remvoeall" + jcs.getStats(), res );
- }
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSThrashTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSThrashTest.java
deleted file mode 100644
index 42869ae..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSThrashTest.java
+++ /dev/null
@@ -1,316 +0,0 @@
-package org.apache.commons.jcs;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-import junit.framework.TestCase;
-
-/**
- * This is based on a test that was posted to the user's list:
- * <p>
- * http://www.opensubscriber.com/message/jcs-users@jakarta.apache.org/2435965.html
- */
-public class JCSThrashTest
- extends TestCase
-{
- /** The logger. */
- private static final Log LOG = LogManager.getLog( JCSThrashTest.class.getName() );
-
- /**
- * the cache instance
- */
- protected CacheAccess<String, Serializable> jcs;
-
- /**
- * Sets up the test
- * @throws Exception
- */
- @Override
- protected void setUp()
- throws Exception
- {
- super.setUp();
- JCS.setConfigFilename( "/TestThrash.ccf" );
- jcs = JCS.getInstance( "testcache" );
- }
-
- /**
- * @throws Exception
- */
- @Override
- protected void tearDown()
- throws Exception
- {
- super.tearDown();
- jcs.clear();
- jcs.dispose();
- }
-
- /**
- * Tests adding an entry.
- * @throws Exception
- */
- public void testPut()
- throws Exception
- {
- final String value = "value";
- final String key = "key";
-
- // Make sure the element is not found
- assertEquals( 0, getListSize() );
-
- assertNull( jcs.get( key ) );
-
- jcs.put( key, value );
-
- // Get the element
- LOG.info( "jcs.getStats(): " + jcs.getStatistics() );
- assertEquals( 1, getListSize() );
- assertNotNull( jcs.get( key ) );
- assertEquals( value, jcs.get( key ) );
- }
-
- /**
- * Test elements can be removed from the store
- * @throws Exception
- */
- public void testRemove()
- throws Exception
- {
- jcs.put( "key1", "value1" );
- assertEquals( 1, getListSize() );
-
- jcs.remove( "key1" );
- assertEquals( 0, getListSize() );
-
- jcs.put( "key2", "value2" );
- jcs.put( "key3", "value3" );
- assertEquals( 2, getListSize() );
-
- jcs.remove( "key2" );
- assertEquals( 1, getListSize() );
-
- // Try to remove an object that is not there in the store
- jcs.remove( "key4" );
- assertEquals( 1, getListSize() );
- }
-
- /**
- * This does a bunch of work and then verifies that the memory has not grown by much. Most of
- * the time the amount of memory used after the test is less.
- * @throws Exception
- */
- public void testForMemoryLeaks()
- throws Exception
- {
- long differenceMemoryCache = thrashCache();
- LOG.info( "Memory Difference is: " + differenceMemoryCache );
- assertTrue( differenceMemoryCache < 500000 );
-
- //LOG.info( "Memory Used is: " + measureMemoryUse() );
- }
-
- /**
- * @return time
- * @throws Exception
- */
- protected long thrashCache()
- throws Exception
- {
- long startingSize = measureMemoryUse();
- LOG.info( "Memory Used is: " + startingSize );
-
- final String value = "value";
- final String key = "key";
-
- // Add the entry
- jcs.put( key, value );
-
- // Create 15 threads that read the keys;
- final List<Executable> executables = new ArrayList<>();
- for ( int i = 0; i < 15; i++ )
- {
- final JCSThrashTest.Executable executable = new JCSThrashTest.Executable()
- {
- @Override
- public void execute()
- throws Exception
- {
- for ( int j = 0; j < 500; j++ )
- {
- final String keyj = "key" + j;
- jcs.get( keyj );
- }
- jcs.get( "key" );
- }
- };
- executables.add( executable );
- }
-
- // Create 15 threads that are insert 500 keys with large byte[] as
- // values
- for ( int i = 0; i < 15; i++ )
- {
- final JCSThrashTest.Executable executable = new JCSThrashTest.Executable()
- {
- @Override
- public void execute()
- throws Exception
- {
-
- // Add a bunch of entries
- for ( int j = 0; j < 500; j++ )
- {
- // Use a random length value
- final String keyj = "key" + j;
- byte[] valuej = new byte[10000];
- jcs.put( keyj, valuej );
- }
- }
- };
- executables.add( executable );
- }
-
- runThreads( executables );
- jcs.clear();
-
- long finishingSize = measureMemoryUse();
- LOG.info( "Memory Used is: " + finishingSize );
- return finishingSize - startingSize;
- }
-
- /**
- * Runs a set of threads, for a fixed amount of time.
- * <p>
- * @param executables
- * @throws Exception
- */
- protected void runThreads( final List<Executable> executables )
- throws Exception
- {
-
- final long endTime = System.currentTimeMillis() + 10000;
- final Throwable[] errors = new Throwable[1];
-
- // Spin up the threads
- final Thread[] threads = new Thread[executables.size()];
- for ( int i = 0; i < threads.length; i++ )
- {
- final JCSThrashTest.Executable executable = executables.get( i );
- threads[i] = new Thread()
- {
- @Override
- public void run()
- {
- try
- {
- // Run the thread until the given end time
- while ( System.currentTimeMillis() < endTime )
- {
- executable.execute();
- }
- }
- catch ( Throwable t )
- {
- // Hang on to any errors
- errors[0] = t;
- }
- }
- };
- threads[i].start();
- }
-
- // Wait for the threads to finish
- for ( int i = 0; i < threads.length; i++ )
- {
- threads[i].join();
- }
-
- // Throw any error that happened
- if ( errors[0] != null )
- {
- throw new Exception( "Test thread failed.", errors[0] );
- }
- }
-
- /**
- * Measure memory used by the VM.
- * <p>
- * @return bytes
- * @throws InterruptedException
- */
- protected long measureMemoryUse()
- throws InterruptedException
- {
- System.gc();
- Thread.sleep( 3000 );
- System.gc();
- return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
- }
-
- /**
- * A runnable, that can throw an exception.
- */
- protected interface Executable
- {
- /**
- * Executes this object.
- * @throws Exception
- */
- void execute()
- throws Exception;
- }
-
- /**
- * @return size
- */
- private int getListSize()
- {
- final String listSize = "List Size";
- final String lruMemoryCache = "LRU Memory Cache";
- String result = "0";
- List<IStats> istats = jcs.getStatistics().getAuxiliaryCacheStats();
- for ( IStats istat : istats )
- {
- List<IStatElement<?>> statElements = istat.getStatElements();
- if ( lruMemoryCache.equals( istat.getTypeName() ) )
- {
- for ( IStatElement<?> statElement : statElements )
- {
- if ( listSize.equals( statElement.getName() ) )
- {
- result = statElement.getData().toString();
- break;
- }
- }
- }
- }
- return Integer.parseInt( result );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSUnitTest.java
deleted file mode 100644
index 4d09330..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSUnitTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package org.apache.commons.jcs;
-
-/*
- * 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.
- */
-
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Random;
-
-import org.apache.commons.jcs.access.CacheAccess;
-
-import junit.framework.TestCase;
-
-/**
- * Simple test for the JCS class.
- */
-public class JCSUnitTest
- extends TestCase
-{
- /** A random for key generation. */
- Random random = new Random();
-
- /**
- * @throws Exception
- */
- public void testJCS()
- throws Exception
- {
- CacheAccess<String, LinkedList<HashMap<String, String>>> jcs = JCS.getInstance( "testCache1" );
-
- LinkedList<HashMap<String, String>> list = buildList();
-
- jcs.put( "some:key", list );
-
- assertEquals( list, jcs.get( "some:key" ) );
- }
-
- /**
- * @return builds a list
- */
- private LinkedList<HashMap<String, String>> buildList()
- {
- LinkedList<HashMap<String, String>> list = new LinkedList<>();
-
- for ( int i = 0; i < 100; i++ )
- {
- list.add( buildMap() );
- }
-
- return list;
- }
-
- /**
- * @return a map
- */
- private HashMap<String, String> buildMap()
- {
- HashMap<String, String> map = new HashMap<>();
-
- byte[] keyBytes = new byte[32];
- byte[] valBytes = new byte[128];
-
- for ( int i = 0; i < 10; i++ )
- {
- random.nextBytes( keyBytes );
- random.nextBytes( valBytes );
-
- map.put( new String( keyBytes ), new String( valBytes ) );
- }
-
- return map;
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSvsHashtablePerformanceTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSvsHashtablePerformanceTest.java
deleted file mode 100644
index cb0d4e4..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/JCSvsHashtablePerformanceTest.java
+++ /dev/null
@@ -1,180 +0,0 @@
-package org.apache.commons.jcs;
-
-/*
- * 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.
- */
-
-import java.util.Hashtable;
-
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-import junit.framework.TestCase;
-
-/**
- * This test ensures that basic memory operations are with a specified order of magnitude of the
- * java.util.Hashtable.
- * <p>
- * Currently JCS is under 2x a hashtable for gets, and under 1.2x for puts.
- */
-public class JCSvsHashtablePerformanceTest
- extends TestCase
-{
- /** jcs / hashtable */
- float ratioPut = 0;
-
- /** jcs / hashtable */
- float ratioGet = 0;
-
- /** ration goal */
- float target = 3.50f;
-
- /** Times to run the test */
- int loops = 20;
-
- /** how many puts and gets to run */
- int tries = 50000;
-
- /**
- * A unit test for JUnit
- * @throws Exception Description of the Exception
- */
- public void testSimpleLoad()
- throws Exception
- {
- Log log1 = LogManager.getLog( LRUMemoryCache.class );
- if ( log1.isDebugEnabled() )
- {
- System.out.println( "The log level must be at info or above for the a performance test." );
- return;
- }
- Log log2 = LogManager.getLog( JCS.class );
- if ( log2.isDebugEnabled() )
- {
- System.out.println( "The log level must be at info or above for the a performance test." );
- return;
- }
- doWork();
- assertTrue( this.ratioPut < target );
- assertTrue( this.ratioGet < target );
- }
-
- /**
- *
- */
- public void doWork()
- {
- long start = 0;
- long end = 0;
- long time = 0;
- float tPer = 0;
-
- long putTotalJCS = 0;
- long getTotalJCS = 0;
- long putTotalHashtable = 0;
- long getTotalHashtable = 0;
-
- try
- {
-
- JCS.setConfigFilename( "/TestJCSvHashtablePerf.ccf" );
- CacheAccess<String, String> cache = JCS.getInstance( "testCache1" );
-
- for ( int j = 0; j < loops; j++ )
- {
-
- String name = "JCS ";
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- cache.put( "key:" + i, "data" + i );
- }
- end = System.currentTimeMillis();
- time = end - start;
- putTotalJCS += time;
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( name + " put time for " + tries + " = " + time + "; millis per = " + tPer );
-
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- cache.get( "key:" + i );
- }
- end = System.currentTimeMillis();
- time = end - start;
- getTotalJCS += time;
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
-
- // /////////////////////////////////////////////////////////////
- name = "Hashtable";
- Hashtable<String, String> cache2 = new Hashtable<>();
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- cache2.put( "key:" + i, "data" + i );
- }
- end = System.currentTimeMillis();
- time = end - start;
- putTotalHashtable += time;
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( name + " put time for " + tries + " = " + time + "; millis per = " + tPer );
-
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- cache2.get( "key:" + i );
- }
- end = System.currentTimeMillis();
- time = end - start;
- getTotalHashtable += time;
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
-
- System.out.println( "\n" );
- }
-
- }
- catch ( Exception e )
- {
- e.printStackTrace( System.out );
- System.out.println( e );
- }
-
- long putAvJCS = putTotalJCS / loops;
- long getAvJCS = getTotalJCS / loops;
- long putAvHashtable = putTotalHashtable / loops;
- long getAvHashtable = getTotalHashtable / loops;
-
- System.out.println( "Finished " + loops + " loops of " + tries + " gets and puts" );
-
- System.out.println( "\n" );
- System.out.println( "Put average for JCS = " + putAvJCS );
- System.out.println( "Put average for Hashtable = " + putAvHashtable );
- ratioPut = Float.intBitsToFloat( (int) putAvJCS ) / Float.intBitsToFloat( (int) putAvHashtable );
- System.out.println( "JCS puts took " + ratioPut + " times the Hashtable, the goal is <" + target + "x" );
-
- System.out.println( "\n" );
- System.out.println( "Get average for JCS = " + getAvJCS );
- System.out.println( "Get average for Hashtable = " + getAvHashtable );
- ratioGet = Float.intBitsToFloat( (int) getAvJCS ) / Float.intBitsToFloat( (int) getAvHashtable );
- System.out.println( "JCS gets took " + ratioGet + " times the Hashtable, the goal is <" + target + "x" );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/RemovalTestUtil.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/RemovalTestUtil.java
deleted file mode 100644
index 793b884..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/RemovalTestUtil.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package org.apache.commons.jcs;
-
-import org.apache.commons.jcs.access.CacheAccess;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/**
- * Simple methods to be run by active test suites that test removal.
- *
- */
-public class RemovalTestUtil
- extends TestCase
-{
- /**
- * Constructor for the TestSimpleLoad object
- *
- * @param testName
- * Description of the Parameter
- */
- public RemovalTestUtil( String testName )
- {
- super( testName );
- }
-
- /**
- * Adds elements in the range specified and then removes them using the
- * categorical or substring removal method.
- *
- * @param start
- * @param end
- *
- * @throws Exception
- * Description of the Exception
- */
- public void runTestPutThenRemoveCategorical( int start, int end )
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
-
- for ( int i = start; i <= end; i++ )
- {
- jcs.put( i + ":key", "data" + i );
- }
-
- for ( int i = end; i >= start; i-- )
- {
- String res = jcs.get( i + ":key" );
- assertNotNull( "[" + i + ":key] should not be null", res );
- }
-
- for ( int i = start; i <= end; i++ )
- {
- jcs.remove( i + ":" );
- assertNull( jcs.get( i + ":key" ) );
- }
- }
-
- /**
- * Put items in the cache in this key range. Can be used to verify that
- * concurrent operations are not effected by things like hierchical removal.
- *
- * @param start
- * int
- * @param end
- * int
- * @throws Exception
- */
- public void runPutInRange( int start, int end )
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
-
- for ( int i = start; i <= end; i++ )
- {
- jcs.put( i + ":key", "data" + i );
- }
-
- for ( int i = end; i >= start; i-- )
- {
- String res = jcs.get( i + ":key" );
- assertNotNull( "[" + i + ":key] should not be null", res );
- }
- }
-
- /**
- * Just get from start to end.
- *
- * @param start
- * int
- * @param end
- * int
- * @param check
- * boolean -- check to see if the items are in the cache.
- * @throws Exception
- */
- public void runGetInRange( int start, int end, boolean check )
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
-
- // don't care if they are found
- for ( int i = end; i >= start; i-- )
- {
- String res = jcs.get( i + ":key" );
- if ( check )
- {
- assertNotNull( "[" + i + ":key] should not be null", res );
- }
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/TestLogConfigurationUtil.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/TestLogConfigurationUtil.java
deleted file mode 100644
index 9609718..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/TestLogConfigurationUtil.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package org.apache.commons.jcs;
-
-import java.io.StringWriter;
-import java.util.logging.Handler;
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
-import java.util.logging.Logger;
-
-import org.apache.commons.jcs.log.LogManager;
-
-/*
- * 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.
- */
-
-/** Utility for testing log messages. */
-public class TestLogConfigurationUtil
-{
- /**
- * Configures a logger for the given name. This allows us to check the log output.
- * <p>
- * @param stringWriter string writer
- * @param loggerName logger name
- */
- public static void configureLogger( StringWriter stringWriter, String loggerName )
- {
- LogManager.setLogSystem("jul");
- java.util.logging.LogManager.getLogManager().reset();
- Logger rootLogger = java.util.logging.LogManager.getLogManager().getLogger("");
-
- rootLogger.addHandler(new MockLogHandler(stringWriter));
- rootLogger.setLevel(Level.FINE);
- }
-
- private static class MockLogHandler extends Handler
- {
- private StringWriter writer;
-
- public MockLogHandler(StringWriter writer)
- {
- super();
- this.writer = writer;
- }
-
- @Override
- public void publish(LogRecord record)
- {
- StringBuilder sb = new StringBuilder();
- sb.append(record.getMillis())
- .append(" - ")
- .append(record.getSourceClassName())
- .append("#")
- .append(record.getSourceMethodName())
- .append(" - ")
- .append(record.getMessage())
- .append('\n');
- writer.append(sb.toString());
- }
-
- @Override
- public void flush()
- {
- writer.flush();
- }
-
- @Override
- public void close() throws SecurityException
- {
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/TestTCPLateralCache.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/TestTCPLateralCache.java
deleted file mode 100644
index c229df5..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/TestTCPLateralCache.java
+++ /dev/null
@@ -1,145 +0,0 @@
-package org.apache.commons.jcs;
-
-import org.apache.commons.jcs.access.CacheAccess;
-
-/*
- * 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.
- */
-
-import junit.extensions.ActiveTestSuite;
-import junit.framework.Test;
-import junit.framework.TestCase;
-
-/**
- * Test which exercises the indexed disk cache. This one uses three different
- * regions for thre threads.
- *
- * @version $Id$
- */
-public class TestTCPLateralCache
- extends TestCase
-{
- /**
- * Number of items to cache, twice the configured maxObjects for the memory
- * cache regions.
- */
- private static int items = 200;
-
- /**
- * Constructor for the TestTCPLateralCache object.
- *
- * @param testName
- */
- public TestTCPLateralCache( String testName )
- {
- super( testName );
- }
-
- /**
- * A unit test suite for JUnit
- *
- * @return The test suite
- */
- public static Test suite()
- {
- ActiveTestSuite suite = new ActiveTestSuite();
-
- suite.addTest( new TestTCPLateralCache( "testTcpRegion1_no_receiver" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "testTcpRegion1" );
- }
- } );
-
- // suite.addTest( new TestTCPLateralCache( "testIndexedDiskCache2" )
- // {
- // public void runTest() throws Exception
- // {
- // this.runTestForRegion( "indexedRegion2" );
- // }
- // } );
- //
- // suite.addTest( new TestTCPLateralCache( "testIndexedDiskCache3" )
- // {
- // public void runTest() throws Exception
- // {
- // this.runTestForRegion( "indexedRegion3" );
- // }
- // } );
-
- return suite;
- }
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestTCPLateralCache.ccf" );
- }
-
- /**
- * Adds items to cache, gets them, and removes them. The item count is more
- * than the size of the memory cache, so items should spool to disk.
- *
- * @param region
- * Name of the region to access
- *
- * @throws Exception
- * If an error occurs
- */
- public void runTestForRegion( String region )
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-
- // Add items to cache
-
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
-
- // Test that all items are in cache
-
- for ( int i = 0; i <= items; i++ )
- {
- String value = jcs.get( i + ":key" );
-
- assertEquals( region + " data " + i, value );
- }
-
- // Remove all the items
-
- for ( int i = 0; i <= items; i++ )
- {
- jcs.remove( i + ":key" );
- }
-
- // Verify removal
-
- for ( int i = 0; i <= items; i++ )
- {
- assertNull( "Removed key should be null: " + i + ":key", jcs.get( i + ":key" ) );
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/ZeroSizeCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/ZeroSizeCacheUnitTest.java
deleted file mode 100644
index fc6d6be..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/ZeroSizeCacheUnitTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package org.apache.commons.jcs;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.access.CacheAccess;
-
-/**
- *
- * @author Aaron Smuts
- *
- */
-public class ZeroSizeCacheUnitTest
- extends TestCase
-{
- /** number to get each loop */
- private static int items = 20000;
-
- /**
- * Test setup
- * <p>
- * @throws Exception
- */
- @Override
- public void setUp()
- throws Exception
- {
- JCS.setConfigFilename( "/TestZeroSizeCache.ccf" );
- JCS.getInstance( "testCache1" );
- }
-
- /**
- * Verify that a 0 size cache does not result in errors. You should be able
- * to disable a region this way.
- * @throws Exception
- *
- */
- public void testPutGetRemove()
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
-
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", "data" + i );
- }
-
- // all the gets should be null
- for ( int i = items; i >= 0; i-- )
- {
- String res = jcs.get( i + ":key" );
- assertNull( "[" + i + ":key] should be null", res );
- }
-
- // test removal, should be no exceptions
- jcs.remove( "300:key" );
-
- // allow the shrinker to run
- Thread.sleep( 500 );
-
- // do it again.
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", "data" + i );
- }
-
- for ( int i = items; i >= 0; i-- )
- {
- String res = jcs.get( i + ":key" );
- assertNull( "[" + i + ":key] should be null", res );
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/access/CacheAccessUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/access/CacheAccessUnitTest.java
deleted file mode 100644
index 2a508c1..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/access/CacheAccessUnitTest.java
+++ /dev/null
@@ -1,366 +0,0 @@
-package org.apache.commons.jcs.access;
-
-/*
- * 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.
- */
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.access.exception.ObjectExistsException;
-import org.apache.commons.jcs.engine.CompositeCacheAttributes;
-import org.apache.commons.jcs.engine.ElementAttributes;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-
-import junit.framework.TestCase;
-
-/**
- * Tests the methods of the cache access class.
- * <p>
- * @author Aaron Smuts
- */
-public class CacheAccessUnitTest
- extends TestCase
-{
- /**
- * Verify that we get an object exists exception if the item is in the cache.
- * @throws Exception
- */
- public void testPutSafe()
- throws Exception
- {
- CacheAccess<String, String> access = JCS.getInstance( "test" );
- assertNotNull( "We should have an access class", access );
-
- String key = "mykey";
- String value = "myvalue";
-
- access.put( key, value );
-
- String returnedValue1 = access.get( key );
- assertEquals( "Wrong value returned.", value, returnedValue1 );
-
- try
- {
- access.putSafe( key, "someothervalue" );
- fail( "We should have received an exception since this key is already in the cache." );
- }
- catch ( CacheException e )
- {
- assertTrue( "Wrong type of exception.", e instanceof ObjectExistsException );
- assertTrue( "Should have the key in the error message.", e.getMessage().indexOf( "[" + key + "]" ) != -1 );
- }
-
- String returnedValue2 = access.get( key );
- assertEquals( "Wrong value returned. Should still be the original.", value, returnedValue2 );
- }
-
- /**
- * Try to put a null key and verify that we get an exception.
- * @throws Exception
- */
- public void testPutNullKey()
- throws Exception
- {
- CacheAccess<String, String> access = JCS.getInstance( "test" );
- assertNotNull( "We should have an access class", access );
-
- String key = null;
- String value = "myvalue";
-
- try
- {
- access.put( key, value );
- fail( "Should not have been able to put a null key." );
- }
- catch ( CacheException e )
- {
- assertTrue( "Should have the word null in the error message.", e.getMessage().indexOf( "null" ) != -1 );
- }
- }
-
- /**
- * Try to put a null value and verify that we get an exception.
- * @throws Exception
- */
- public void testPutNullValue()
- throws Exception
- {
- CacheAccess<String, String> access = JCS.getInstance( "test" );
- assertNotNull( "We should have an access class", access );
-
- String key = "myKey";
- String value = null;
-
- try
- {
- access.put( key, value );
- fail( "Should not have been able to put a null object." );
- }
- catch ( CacheException e )
- {
- assertTrue( "Should have the word null in the error message.", e.getMessage().indexOf( "null" ) != -1 );
- }
- }
-
- /**
- * Verify that elements that go in the region after this call take the new attributes.
- * @throws Exception
- */
- public void testSetDefaultElementAttributes()
- throws Exception
- {
- CacheAccess<String, String> access = JCS.getInstance( "test" );
- assertNotNull( "We should have an access class", access );
-
- long maxLife = 9876;
- IElementAttributes attr = new ElementAttributes();
- attr.setMaxLife(maxLife);
-
- access.setDefaultElementAttributes( attr );
-
- assertEquals( "Wrong element attributes.", attr.getMaxLife(), access.getDefaultElementAttributes()
- .getMaxLife() );
-
- String key = "mykey";
- String value = "myvalue";
-
- access.put( key, value );
-
- ICacheElement<String, String> element = access.getCacheElement( key );
-
- assertEquals( "Wrong max life. Should have the new value.", maxLife, element.getElementAttributes()
- .getMaxLife() );
- }
-
- /**
- * Verify that getCacheElements returns the elements requested based on the key.
- * @throws Exception
- */
- public void testGetCacheElements()
- throws Exception
- {
- //SETUP
- CacheAccess<String, String> access = JCS.getInstance( "test" );
- assertNotNull( "We should have an access class", access );
-
- String keyOne = "mykeyone";
- String keyTwo = "mykeytwo";
- String keyThree = "mykeythree";
- String keyFour = "mykeyfour";
- String valueOne = "myvalueone";
- String valueTwo = "myvaluetwo";
- String valueThree = "myvaluethree";
- String valueFour = "myvaluefour";
-
- access.put( keyOne, valueOne );
- access.put( keyTwo, valueTwo );
- access.put( keyThree, valueThree );
-
- Set<String> input = new HashSet<>();
- input.add( keyOne );
- input.add( keyTwo );
-
- //DO WORK
- Map<String, ICacheElement<String, String>> result = access.getCacheElements( input );
-
- //VERIFY
- assertEquals( "map size", 2, result.size() );
- ICacheElement<String, String> elementOne = result.get( keyOne );
- assertEquals( "value one", keyOne, elementOne.getKey() );
- assertEquals( "value one", valueOne, elementOne.getVal() );
- ICacheElement<String, String> elementTwo = result.get( keyTwo );
- assertEquals( "value two", keyTwo, elementTwo.getKey() );
- assertEquals( "value two", valueTwo, elementTwo.getVal() );
-
- assertNull(access.get(keyFour));
- String suppliedValue1 = access.get(keyFour, () -> valueFour);
- assertNotNull( "value four", suppliedValue1);
- assertEquals( "value four", valueFour, suppliedValue1);
- String suppliedValue2 = access.get(keyFour);
- assertNotNull( "value four", suppliedValue2);
- assertEquals( "value four", suppliedValue1, suppliedValue2);
- }
-
- /**
- * Verify that we can get a region using the define region method.
- * @throws Exception
- */
- public void testRegionDefiniton()
- throws Exception
- {
- CacheAccess<String, String> access = JCS.getInstance( "test" );
- assertNotNull( "We should have an access class", access );
- }
-
- /**
- * Verify that we can get a region using the define region method with cache attributes.
- * @throws Exception
- */
- public void testRegionDefinitonWithAttributes()
- throws Exception
- {
- ICompositeCacheAttributes ca = new CompositeCacheAttributes();
-
- long maxIdleTime = 8765;
- ca.setMaxMemoryIdleTimeSeconds( maxIdleTime );
-
- CacheAccess<String, String> access = JCS.getInstance( "testRegionDefinitonWithAttributes", ca );
- assertNotNull( "We should have an access class", access );
-
- ICompositeCacheAttributes ca2 = access.getCacheAttributes();
- assertEquals( "Wrong idle time setting.", ca.getMaxMemoryIdleTimeSeconds(), ca2.getMaxMemoryIdleTimeSeconds() );
- }
-
- /**
- * Verify that we can get a region using the define region method with cache attributes and
- * element attributes.
- * @throws Exception
- */
- public void testRegionDefinitonWithBothAttributes()
- throws Exception
- {
- ICompositeCacheAttributes ca = new CompositeCacheAttributes();
-
- long maxIdleTime = 8765;
- ca.setMaxMemoryIdleTimeSeconds( maxIdleTime );
-
- long maxLife = 9876;
- IElementAttributes attr = new ElementAttributes();
- attr.setMaxLife(maxLife);
-
- CacheAccess<String, String> access = JCS.getInstance( "testRegionDefinitonWithAttributes", ca, attr );
- assertNotNull( "We should have an access class", access );
-
- ICompositeCacheAttributes ca2 = access.getCacheAttributes();
- assertEquals( "Wrong idle time setting.", ca.getMaxMemoryIdleTimeSeconds(), ca2.getMaxMemoryIdleTimeSeconds() );
- }
-
- /**
- * Verify we can get some matching elements..
- * <p>
- * @throws Exception
- */
- public void testGetMatching_Normal()
- throws Exception
- {
- // SETUP
- int maxMemorySize = 1000;
- String keyprefix1 = "MyPrefix1";
- String keyprefix2 = "MyPrefix2";
- String memoryCacheClassName = "org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache";
- ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
- cattr.setMemoryCacheName( memoryCacheClassName );
- cattr.setMaxObjects( maxMemorySize );
-
- long maxLife = 9876;
- IElementAttributes attr = new ElementAttributes();
- attr.setMaxLife(maxLife);
-
- CacheAccess<String, Integer> access = JCS.getInstance( "testGetMatching_Normal", cattr, attr );
-
- // DO WORK
- int numToInsertPrefix1 = 10;
- // insert with prefix1
- for ( int i = 0; i < numToInsertPrefix1; i++ )
- {
- access.put( keyprefix1 + String.valueOf( i ), Integer.valueOf( i ) );
- }
-
- int numToInsertPrefix2 = 50;
- // insert with prefix1
- for ( int i = 0; i < numToInsertPrefix2; i++ )
- {
- access.put( keyprefix2 + String.valueOf( i ), Integer.valueOf( i ) );
- }
-
- Map<String, Integer> result1 = access.getMatching( keyprefix1 + ".+" );
- Map<String, Integer> result2 = access.getMatching( keyprefix2 + "\\S+" );
-
- // VERIFY
- assertEquals( "Wrong number returned 1:", numToInsertPrefix1, result1.size() );
- assertEquals( "Wrong number returned 2:", numToInsertPrefix2, result2.size() );
- //System.out.println( result1 );
-
- // verify that the elements are unwrapped
- for (Map.Entry<String, Integer> entry : result1.entrySet())
- {
- Object value = entry.getValue();
- assertFalse( "Should not be a cache element.", value instanceof ICacheElement );
- }
- }
-
- /**
- * Verify we can get some matching elements..
- * <p>
- * @throws Exception
- */
- public void testGetMatchingElements_Normal()
- throws Exception
- {
- // SETUP
- int maxMemorySize = 1000;
- String keyprefix1 = "MyPrefix1";
- String keyprefix2 = "MyPrefix2";
- String memoryCacheClassName = "org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache";
- ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
- cattr.setMemoryCacheName( memoryCacheClassName );
- cattr.setMaxObjects( maxMemorySize );
-
- long maxLife = 9876;
- IElementAttributes attr = new ElementAttributes();
- attr.setMaxLife(maxLife);
-
- CacheAccess<String, Integer> access = JCS.getInstance( "testGetMatching_Normal", cattr, attr );
-
- // DO WORK
- int numToInsertPrefix1 = 10;
- // insert with prefix1
- for ( int i = 0; i < numToInsertPrefix1; i++ )
- {
- access.put( keyprefix1 + String.valueOf( i ), Integer.valueOf( i ) );
- }
-
- int numToInsertPrefix2 = 50;
- // insert with prefix1
- for ( int i = 0; i < numToInsertPrefix2; i++ )
- {
- access.put( keyprefix2 + String.valueOf( i ), Integer.valueOf( i ) );
- }
-
- Map<String, ICacheElement<String, Integer>> result1 = access.getMatchingCacheElements( keyprefix1 + "\\S+" );
- Map<String, ICacheElement<String, Integer>> result2 = access.getMatchingCacheElements( keyprefix2 + ".+" );
-
- // VERIFY
- assertEquals( "Wrong number returned 1:", numToInsertPrefix1, result1.size() );
- assertEquals( "Wrong number returned 2:", numToInsertPrefix2, result2.size() );
- //System.out.println( result1 );
-
- // verify that the elements are wrapped
- for (Map.Entry<String, ICacheElement<String, Integer>> entry : result1.entrySet())
- {
- Object value = entry.getValue();
- assertTrue( "Should be a cache element.", value instanceof ICacheElement );
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/access/GroupCacheAccessUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/access/GroupCacheAccessUnitTest.java
deleted file mode 100644
index 414b314..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/access/GroupCacheAccessUnitTest.java
+++ /dev/null
@@ -1,240 +0,0 @@
-package org.apache.commons.jcs.access;
-
-/*
- * 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.
- */
-
-import java.util.Set;
-
-import junit.framework.TestCase;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.exception.CacheException;
-
-/**
- * Tests the methods of the group cache access class.
- * <p>
- * @author Aaron Smuts
- */
-public class GroupCacheAccessUnitTest
- extends TestCase
-{
- /**
- * Verify that we can put and get an object
- * @throws Exception
- */
- public void testPutAndGet()
- throws Exception
- {
- GroupCacheAccess<String, String> access = JCS.getGroupCacheInstance( "test" );
- assertNotNull( "We should have an access class", access );
-
- String key = "mykey";
- String group = "mygroup";
- String value = "myvalue";
-
- access.putInGroup(key, group, value);
-
- String returnedValue1 = access.getFromGroup(key, group);
- assertEquals( "Wrong value returned.", value, returnedValue1 );
- }
-
- /**
- * Try to put a null key and verify that we get an exception.
- * @throws Exception
- */
- public void testPutNullKey()
- throws Exception
- {
- GroupCacheAccess<String, String> access = JCS.getGroupCacheInstance( "test" );
- assertNotNull( "We should have an access class", access );
-
- String key = null;
- String group = "mygroup";
- String value = "myvalue";
-
- try
- {
- access.putInGroup(key, group, value);
- fail( "Should not have been able to put a null key." );
- }
- catch ( CacheException e )
- {
- assertTrue( "Should have the word null in the error message.", e.getMessage().indexOf( "null" ) != -1 );
- }
- }
-
- /**
- * Try to put a null value and verify that we get an exception.
- * @throws Exception
- */
- public void testPutNullValue()
- throws Exception
- {
- GroupCacheAccess<String, String> access = JCS.getGroupCacheInstance( "test" );
- assertNotNull( "We should have an access class", access );
-
- String key = "myKey";
- String group = "mygroup";
- String value = null;
-
- try
- {
- access.putInGroup(key, group, value);
- fail( "Should not have been able to put a null object." );
- }
- catch ( CacheException e )
- {
- assertTrue( "Should have the word null in the error message.", e.getMessage().indexOf( "null" ) != -1 );
- }
- }
-
- /**
- * Verify that we can remove items from the cache
- * @throws Exception
- */
- public void testRemove()
- throws Exception
- {
- GroupCacheAccess<String, String> access = JCS.getGroupCacheInstance( "test" );
- assertNotNull( "We should have an access class", access );
-
- String key = "mykey";
- String group = "mygroup";
- String value = "myvalue";
-
- for (int i = 0; i < 10; i++)
- {
- access.putInGroup(key + i, group, value + i);
- }
-
- // Make sure cache contains some data
- for (int i = 0; i < 10; i++)
- {
- String returnedValue1 = access.getFromGroup(key + i, group);
- assertEquals( "Wrong value returned.", value + i, returnedValue1 );
- }
-
- access.removeFromGroup(key + 0, group);
-
- assertNull("Should not be in cache", access.getFromGroup(key + 0, group));
-
- for (int i = 1; i < 10; i++)
- {
- String returnedValue1 = access.getFromGroup(key + i, group);
- assertEquals( "Wrong value returned.", value + i, returnedValue1 );
- }
- }
-
- /**
- * Verify that we can invalidate the group
- * @throws Exception
- */
- public void testInvalidate()
- throws Exception
- {
- GroupCacheAccess<String, String> access = JCS.getGroupCacheInstance( "test" );
- assertNotNull( "We should have an access class", access );
-
- String key = "mykey";
- String group = "mygroup";
- String value = "myvalue";
-
- for (int i = 0; i < 10; i++)
- {
- access.putInGroup(key + i, group + 0, value + i);
- }
-
- for (int i = 0; i < 10; i++)
- {
- access.putInGroup(key + i, group + 1, value + i);
- }
-
- // Make sure cache contains some data
- for (int i = 0; i < 10; i++)
- {
- String returnedValue1 = access.getFromGroup(key + i, group + 0);
- assertEquals( "Wrong value returned.", value + i, returnedValue1 );
- String returnedValue2 = access.getFromGroup(key + i, group + 1);
- assertEquals( "Wrong value returned.", value + i, returnedValue2 );
- }
-
- access.invalidateGroup(group + 0);
-
- for (int i = 0; i < 10; i++)
- {
- assertNull("Should not be in cache", access.getFromGroup(key + i, group + 0));
- }
-
- for (int i = 0; i < 10; i++)
- {
- String returnedValue1 = access.getFromGroup(key + i, group + 1);
- assertEquals( "Wrong value returned.", value + i, returnedValue1 );
- }
- }
-
- /**
- * Verify we can use the group cache.
- * <p>
- * @throws Exception
- */
- public void testGroupCache()
- throws Exception
- {
- GroupCacheAccess<String, Integer> access = JCS.getGroupCacheInstance( "testGroup" );
- String groupName1 = "testgroup1";
- String groupName2 = "testgroup2";
-
- Set<String> keys1 = access.getGroupKeys( groupName1 );
- assertNotNull(keys1);
- assertEquals(0, keys1.size());
-
- Set<String> keys2 = access.getGroupKeys( groupName2 );
- assertNotNull(keys2);
- assertEquals(0, keys2.size());
-
- // DO WORK
- int numToInsertGroup1 = 10;
- // insert with prefix1
- for ( int i = 0; i < numToInsertGroup1; i++ )
- {
- access.putInGroup(String.valueOf( i ), groupName1, Integer.valueOf( i ) );
- }
-
- int numToInsertGroup2 = 50;
- // insert with prefix1
- for ( int i = 0; i < numToInsertGroup2; i++ )
- {
- access.putInGroup(String.valueOf( i ), groupName2, Integer.valueOf( i + 1 ) );
- }
-
- keys1 = access.getGroupKeys( groupName1 ); // Test for JCS-102
- assertNotNull(keys1);
- assertEquals("Wrong number returned 1:", 10, keys1.size());
-
- keys2 = access.getGroupKeys( groupName2 );
- assertNotNull(keys2);
- assertEquals("Wrong number returned 2:", 50, keys2.size());
-
- assertEquals(Integer.valueOf(5), access.getFromGroup("5", groupName1));
- assertEquals(Integer.valueOf(6), access.getFromGroup("5", groupName2));
-
- assertTrue(access.getGroupNames().contains(groupName1));
- assertTrue(access.getGroupNames().contains(groupName2));
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/access/SystemPropertyUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/access/SystemPropertyUnitTest.java
deleted file mode 100644
index a301efd..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/access/SystemPropertyUnitTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package org.apache.commons.jcs.access;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-import org.junit.FixMethodOrder;
-import org.junit.runners.MethodSorters;
-
-/**
- * This test is for the system property usage in configuration values.
- *
- * @author Aaron Smuts
- *
- */
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class SystemPropertyUnitTest
- extends TestCase
-{
-
- /**
- * Verify that we use a system property for a ${FOO} string in a value.
- *
- * @throws Exception
- *
- */
- public void test1SystemPropertyInValueDelimiter()
- throws Exception
- {
-
- int maxMemory = 1234;
- System.getProperties().setProperty( "MY_SYSTEM_PROPERTY_DISK_DIR", "system_set" );
- System.getProperties().setProperty( "MY_SYSTEM_PROPERTY_MAX_SIZE", String.valueOf( maxMemory ) );
-
- JCS.setConfigFilename( "/TestSystemProperties.ccf" );
-
- CacheAccess<String, String> cache = JCS.getInstance( "test1" );
- assertEquals( "We should have used the system property for the memory size", maxMemory, cache
- .getCacheAttributes().getMaxObjects() );
-
- System.clearProperty("MY_SYSTEM_PROPERTY_DISK_DIR");
- System.clearProperty("MY_SYSTEM_PROPERTY_MAX_SIZE");
- }
-
- /**
- * Verify that we use a system property for a ${FOO} string in a value. We
- * define a propety in the cache.ccf file, but we do not have it as a system
- * property. The default value should be used, if one exists.
- *
- * @throws Exception
- *
- */
- public void test2SystemPropertyMissingInValueDelimeter()
- throws Exception
- {
- System.getProperties().setProperty( "MY_SYSTEM_PROPERTY_DISK_DIR", "system_set" );
-
- CompositeCacheManager mgr = CompositeCacheManager.getUnconfiguredInstance();
- mgr.configure( "/TestSystemProperties.ccf" );
-
- CacheAccess<String, String> cache = JCS.getInstance( "missing" );
- // TODO check against the actual default def
- assertEquals( "We should have used the default property for the memory size", 100, cache.getCacheAttributes()
- .getMaxObjects() );
-
- System.clearProperty("MY_SYSTEM_PROPERTY_DISK_DIR");
-
- }
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/access/TestCacheAccess.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/access/TestCacheAccess.java
deleted file mode 100644
index 7cd9bf7..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/access/TestCacheAccess.java
+++ /dev/null
@@ -1,957 +0,0 @@
-package org.apache.commons.jcs.access;
-
-/*
- * 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.
- */
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Random;
-import java.util.StringTokenizer;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.engine.ElementAttributes;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-import org.apache.commons.jcs.engine.control.event.ElementEventHandlerMockImpl;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * Allows the user to run common cache commands from the command line for a test cache. This also
- * provide basic methods for use in unit tests.
- */
-public class TestCacheAccess
-{
- /** log instance */
- private static final Log log = LogManager.getLog( TestCacheAccess.class );
-
- /** cache instance to use in testing */
- private CacheAccess<String, String> cache_control = null;
-
- /** cache instance to use in testing */
- private GroupCacheAccess<String, String> group_cache_control = null;
-
- /** do we use system.out.println to print out debug data? */
- private static boolean isSysOut = false;
-
- /** Construct and initialize the cachecontrol based on the config file. */
- public TestCacheAccess()
- {
- this( "testCache1" );
- }
-
- /**
- * @param regionName the name of the region.
- */
- public TestCacheAccess( String regionName )
- {
- try
- {
- cache_control = JCS.getInstance( regionName );
- group_cache_control = JCS.getGroupCacheInstance( regionName );
- }
- catch ( Exception e )
- {
- log.error( "Problem getting cache instance", e );
- p( e.toString() );
- }
- }
-
- /**
- * This is the main loop called by the main method.
- */
- public void runLoop()
- {
- try
- {
- // process user input till done
- boolean notDone = true;
- String message = null;
- // wait to dispose
- BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) );
-
- help();
-
- while ( notDone )
- {
- p( "enter command:" );
-
- message = br.readLine();
-
- if ( message == null || message.startsWith( "help" ) )
- {
- help();
- }
- else if ( message.startsWith( "gc" ) )
- {
- System.gc();
- }
- else if ( message.startsWith( "getAttributeNames" ) )
- {
- long n_start = System.currentTimeMillis();
- String groupName = null;
- StringTokenizer toke = new StringTokenizer( message );
- int tcnt = 0;
- while ( toke.hasMoreElements() )
- {
- tcnt++;
- String t = (String) toke.nextElement();
- if ( tcnt == 2 )
- {
- groupName = t.trim();
- }
- }
- getAttributeNames( groupName );
- long n_end = System.currentTimeMillis();
- p( "---got attrNames for " + groupName + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
- }
- else if ( message.startsWith( "shutDown" ) )
- {
- CompositeCacheManager.getInstance().shutDown();
- //cache_control.dispose();
- notDone = false;
- //System.exit( -1 );
- return;
- }
- /////////////////////////////////////////////////////////////////////
- // get multiple from a region
- else if ( message.startsWith( "getm" ) )
- {
- processGetMultiple( message );
- }
- else if ( message.startsWith( "getg" ) )
- {
- processGetGroup( message );
- }
- else if ( message.startsWith( "getag" ) )
- {
- processGetAutoGroup( message );
- }
- else if ( message.startsWith( "getMatching" ) )
- {
- processGetMatching( message );
- }
- else if ( message.startsWith( "get" ) )
- {
- processGet( message );
- }
- else if ( message.startsWith( "putg" ) )
- {
- processPutGroup( message );
- }
- // put automatically
- else if ( message.startsWith( "putag" ) )
- {
- processPutAutoGroup( message );
- }
- else if ( message.startsWith( "putm" ) )
- {
- String numS = message.substring( message.indexOf( " " ) + 1, message.length() );
- if ( numS == null )
- {
- p( "usage: putm numbertoput" );
- }
- else
- {
- int num = Integer.parseInt( numS.trim() );
- putMultiple( num );
- }
- }
- else if ( message.startsWith( "pute" ) )
- {
- String numS = message.substring( message.indexOf( " " ) + 1, message.length() );
- if ( numS == null )
- {
- p( "usage: putme numbertoput" );
- }
- else
- {
- int num = Integer.parseInt( numS.trim() );
- long n_start = System.currentTimeMillis();
- for ( int n = 0; n < num; n++ )
- {
- IElementAttributes attrp = cache_control.getDefaultElementAttributes();
- ElementEventHandlerMockImpl hand = new ElementEventHandlerMockImpl();
- attrp.addElementEventHandler( hand );
- cache_control.put( "key" + n, "data" + n + " put from ta = junk", attrp );
- }
- long n_end = System.currentTimeMillis();
- p( "---put " + num + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
- }
- }
- else if ( message.startsWith( "put" ) )
- {
- processPut( message );
- }
- else if ( message.startsWith( "removem" ) )
- {
- String numS = message.substring( message.indexOf( " " ) + 1, message.length() );
- if ( numS == null )
- {
- p( "usage: removem numbertoremove" );
- }
- else
- {
- int num = Integer.parseInt( numS.trim() );
- removeMultiple( num );
- }
- }
- else if ( message.startsWith( "removeall" ) )
- {
- cache_control.clear();
- p( "removed all" );
- }
- else if ( message.startsWith( "remove" ) )
- {
- String key = message.substring( message.indexOf( " " ) + 1, message.length() );
- cache_control.remove( key );
- p( "removed " + key );
- }
- else if ( message.startsWith( "deattr" ) )
- {
- IElementAttributes ae = cache_control.getDefaultElementAttributes();
- p( "Default IElementAttributes " + ae );
- }
- else if ( message.startsWith( "cloneattr" ) )
- {
- String numS = message.substring( message.indexOf( " " ) + 1, message.length() );
- if ( numS == null )
- {
- p( "usage: put numbertoput" );
- }
- else
- {
- int num = Integer.parseInt( numS.trim() );
- IElementAttributes attrp = new ElementAttributes();
- long n_start = System.currentTimeMillis();
- for ( int n = 0; n < num; n++ )
- {
- attrp.clone();
- }
- long n_end = System.currentTimeMillis();
- p( "---cloned attr " + num + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
- }
- }
- else if ( message.startsWith( "switch" ) )
- {
- String name = message.substring( message.indexOf( " " ) + 1, message.length() );
-
- setRegion( name );
- p( "switched to cache = " + name );
- p( cache_control.toString() );
- }
- else if ( message.startsWith( "stats" ) )
- {
- p( cache_control.getStats() );
- }
- else if ( message.startsWith( "gc" ) )
- {
- System.gc();
- p( "Called system.gc()" );
- }
- else if ( message.startsWith( "random" ) )
- {
- processRandom( message );
- }
- }
- }
- catch ( CacheException | IOException e )
- {
- p( e.toString() );
- e.printStackTrace( System.out );
- }
- }
-
- /**
- * @param message
- */
- private void processGetMultiple( String message )
- {
- int num = 0;
- boolean show = true;
-
- StringTokenizer toke = new StringTokenizer( message );
- int tcnt = 0;
- while ( toke.hasMoreElements() )
- {
- tcnt++;
- String t = (String) toke.nextElement();
- if ( tcnt == 2 )
- {
- try
- {
- num = Integer.parseInt( t.trim() );
- }
- catch ( NumberFormatException nfe )
- {
- p( t + "not a number" );
- }
- }
- else if ( tcnt == 3 )
- {
- show = Boolean.valueOf( t ).booleanValue();
- }
- }
-
- if ( tcnt < 2 )
- {
- p( "usage: get numbertoget show values[true|false]" );
- }
- else
- {
- getMultiple( num, show );
- }
- }
-
- /**
- * @param message
- */
- private void processGetGroup( String message )
- {
- String key = null;
- String group = null;
- boolean show = true;
-
- StringTokenizer toke = new StringTokenizer( message );
- int tcnt = 0;
- while ( toke.hasMoreElements() )
- {
- tcnt++;
- String t = (String) toke.nextElement();
- if ( tcnt == 2 )
- {
- key = t.trim();
- }
- else if ( tcnt == 3 )
- {
- group = t.trim();
- }
- else if ( tcnt == 4 )
- {
- show = Boolean.valueOf( t ).booleanValue();
- }
- }
-
- if ( tcnt < 2 )
- {
- p( "usage: get key show values[true|false]" );
- }
- else
- {
- long n_start = System.currentTimeMillis();
- try
- {
- Object obj = group_cache_control.getFromGroup( key, group );
- if ( show && obj != null )
- {
- p( obj.toString() );
- }
- }
- catch ( Exception e )
- {
- log.error( e );
- }
- long n_end = System.currentTimeMillis();
- p( "---got " + key + " from group " + group + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
- }
- }
-
- /**
- * @param message
- */
- private void processGetAutoGroup( String message )
- {
- // get auto from group
-
- int num = 0;
- String group = null;
- boolean show = true;
-
- StringTokenizer toke = new StringTokenizer( message );
- int tcnt = 0;
- while ( toke.hasMoreElements() )
- {
- tcnt++;
- String t = (String) toke.nextElement();
- if ( tcnt == 2 )
- {
- num = Integer.parseInt( t.trim() );
- }
- else if ( tcnt == 3 )
- {
- group = t.trim();
- }
- else if ( tcnt == 4 )
- {
- show = Boolean.valueOf( t ).booleanValue();
- }
- }
-
- if ( tcnt < 2 )
- {
- p( "usage: get key show values[true|false]" );
- }
- else
- {
- long n_start = System.currentTimeMillis();
- try
- {
- for ( int a = 0; a < num; a++ )
- {
- Object obj = group_cache_control.getFromGroup( "keygr" + a, group );
- if ( show && obj != null )
- {
- p( obj.toString() );
- }
- }
- }
- catch ( Exception e )
- {
- log.error( e );
- }
- long n_end = System.currentTimeMillis();
- p( "---got " + num + " from group " + group + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
- }
- }
-
- /**
- * @param message
- * @throws CacheException
- */
- private void processPutGroup( String message )
- throws CacheException
- {
- String group = null;
- String key = null;
- StringTokenizer toke = new StringTokenizer( message );
- int tcnt = 0;
- while ( toke.hasMoreElements() )
- {
- tcnt++;
- String t = (String) toke.nextElement();
- if ( tcnt == 2 )
- {
- key = t.trim();
- }
- else if ( tcnt == 3 )
- {
- group = t.trim();
- }
- }
-
- if ( tcnt < 3 )
- {
- p( "usage: putg key group" );
- }
- else
- {
- long n_start = System.currentTimeMillis();
- group_cache_control.putInGroup( key, group, "data from putg ----asdfasfas-asfasfas-asfas in group " + group );
- long n_end = System.currentTimeMillis();
- p( "---put " + key + " in group " + group + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
- }
- }
-
- /**
- * @param message
- * @throws CacheException
- */
- private void processPutAutoGroup( String message )
- throws CacheException
- {
- String group = null;
- int num = 0;
- StringTokenizer toke = new StringTokenizer( message );
- int tcnt = 0;
- while ( toke.hasMoreElements() )
- {
- tcnt++;
- String t = (String) toke.nextElement();
- if ( tcnt == 2 )
- {
- num = Integer.parseInt( t.trim() );
- }
- else if ( tcnt == 3 )
- {
- group = t.trim();
- }
- }
-
- if ( tcnt < 3 )
- {
- p( "usage: putag num group" );
- }
- else
- {
- long n_start = System.currentTimeMillis();
- for ( int a = 0; a < num; a++ )
- {
- group_cache_control.putInGroup( "keygr" + a, group, "data " + a
- + " from putag ----asdfasfas-asfasfas-asfas in group " + group );
- }
- long n_end = System.currentTimeMillis();
- p( "---put " + num + " in group " + group + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
- }
- }
-
- /**
- * @param message
- * @throws CacheException
- */
- private void processPut( String message )
- throws CacheException
- {
- String key = null;
- String val = null;
- StringTokenizer toke = new StringTokenizer( message );
- int tcnt = 0;
- while ( toke.hasMoreElements() )
- {
- tcnt++;
- String t = (String) toke.nextElement();
- if ( tcnt == 2 )
- {
- key = t.trim();
- }
- else if ( tcnt == 3 )
- {
- val = t.trim();
- }
- }
-
- if ( tcnt < 3 )
- {
- p( "usage: put key val" );
- }
- else
- {
-
- long n_start = System.currentTimeMillis();
- cache_control.put( key, val );
- long n_end = System.currentTimeMillis();
- p( "---put " + key + " | " + val + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
- }
- }
-
- /**
- * @param message
- */
- private void processRandom( String message )
- {
- String rangeS = "";
- String numOpsS = "";
- boolean show = true;
-
- StringTokenizer toke = new StringTokenizer( message );
- int tcnt = 0;
- while ( toke.hasMoreElements() )
- {
- tcnt++;
- String t = (String) toke.nextElement();
- if ( tcnt == 2 )
- {
- rangeS = t.trim();
- }
- else if ( tcnt == 3 )
- {
- numOpsS = t.trim();
- }
- else if ( tcnt == 4 )
- {
- show = Boolean.valueOf( t ).booleanValue();
- }
- }
-
- String numS = message.substring( message.indexOf( " " ) + 1, message.length() );
-
- int range = 0;
- int numOps = 0;
- try
- {
- range = Integer.parseInt( rangeS.trim() );
- numOps = Integer.parseInt( numOpsS.trim() );
- }
- catch ( Exception e )
- {
- p( "usage: random range numOps show" );
- p( "ex. random 100 1000 false" );
- }
- if ( numS == null )
- {
- p( "usage: random range numOps show" );
- p( "ex. random 100 1000 false" );
- }
- else
- {
- random( range, numOps, show );
- }
- }
-
- /**
- * @param message
- */
- private void processGet( String message )
- {
- // plain old get
-
- String key = null;
- boolean show = true;
-
- StringTokenizer toke = new StringTokenizer( message );
- int tcnt = 0;
- while ( toke.hasMoreElements() )
- {
- tcnt++;
- String t = (String) toke.nextElement();
- if ( tcnt == 2 )
- {
- key = t.trim();
- }
- else if ( tcnt == 3 )
- {
- show = Boolean.valueOf( t ).booleanValue();
- }
- }
-
- if ( tcnt < 2 )
- {
- p( "usage: get key show values[true|false]" );
- }
- else
- {
- long n_start = System.currentTimeMillis();
- try
- {
- Object obj = cache_control.get( key );
- if ( show && obj != null )
- {
- p( obj.toString() );
- }
- }
- catch ( Exception e )
- {
- log.error( e );
- }
- long n_end = System.currentTimeMillis();
- p( "---got " + key + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
- }
- }
-
- /**
- * @param message
- */
- private void processGetMatching( String message )
- {
- // plain old get
-
- String pattern = null;
- boolean show = true;
-
- StringTokenizer toke = new StringTokenizer( message );
- int tcnt = 0;
- while ( toke.hasMoreElements() )
- {
- tcnt++;
- String t = (String) toke.nextElement();
- if ( tcnt == 2 )
- {
- pattern = t.trim();
- }
- else if ( tcnt == 3 )
- {
- show = Boolean.valueOf( t ).booleanValue();
- }
- }
-
- if ( tcnt < 2 )
- {
- p( "usage: getMatching key show values[true|false]" );
- }
- else
- {
- long n_start = System.currentTimeMillis();
- try
- {
- Map<String, String> results = cache_control.getMatching( pattern );
- if ( show && results != null )
- {
- p( results.toString() );
- }
- }
- catch ( Exception e )
- {
- log.error( e );
- }
- long n_end = System.currentTimeMillis();
- p( "---gotMatching [" + pattern + "] in " + String.valueOf( n_end - n_start ) + " millis ---" );
- }
- }
-
- /**
- * Test harness.
- * @param args The command line arguments
- */
- public static void main( String[] args )
- {
- isSysOut = true;
- String ccfFileName = args[0];
- if ( ccfFileName != null )
- {
- JCS.setConfigFilename( ccfFileName );
- }
- TestCacheAccess tca = new TestCacheAccess( "testCache1" );
- tca.runLoop();
- }
-
- // end main
- /////////////////////////////////////////////////////////////////////////////
-
- /**
- * Gets multiple items from the cache with keys of the form key1, key2, key3 up to key[num].
- * @param num int
- */
- public void getMultiple( int num )
- {
- getMultiple( num, false );
- }
-
- /**
- * @param num
- * @param show
- */
- public void getMultiple( int num, boolean show )
- {
- long n_start = System.currentTimeMillis();
- for ( int n = 0; n < num; n++ )
- {
- try
- {
- Object obj = cache_control.get( "key" + n );
- if ( show && obj != null )
- {
- p( obj.toString() );
- }
- }
- catch ( Exception e )
- {
- log.error( e );
- }
- }
- long n_end = System.currentTimeMillis();
- p( "---got " + num + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
- }
-
- /**
- * Puts multiple items into the cache.
- * @param num int
- */
- public void putMultiple( int num )
- {
- try
- {
- long n_start = System.currentTimeMillis();
- for ( int n = 0; n < num; n++ )
- {
- cache_control.put( "key" + n, "data" + n + " put from ta = junk" );
- }
- long n_end = System.currentTimeMillis();
- p( "---put " + num + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
- }
- catch ( Exception e )
- {
- log.error( e );
- }
- }
-
- /**
- * Removes multiple items from the cache.
- * @param num int
- */
- public void removeMultiple( int num )
- {
- try
- {
- long n_start = System.currentTimeMillis();
- for ( int n = 0; n < num; n++ )
- {
- cache_control.remove( "key" + n );
- }
- long n_end = System.currentTimeMillis();
- p( "---removed " + num + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
- }
- catch ( Exception e )
- {
- log.error( e );
- }
- }
-
- /**
- * The random method performs numOps number of operations. The operations will be a mix of puts,
- * gets, and removes. The key range will be from 0 to range.
- * @param range int The end of the key range.
- * @param numOps int The number of operations to perform
- */
- public void random( int range, int numOps )
- {
- random( range, numOps, false );
- }
-
- /**
- * @param range
- * @param numOps
- * @param show
- */
- public void random( int range, int numOps, boolean show )
- {
- try
- {
- for ( int i = 1; i < numOps; i++ )
- {
- Random ran = new Random( i );
- int n = ran.nextInt( 4 );
- int kn = ran.nextInt( range );
- String key = "key" + kn;
- if ( n == 1 )
- {
- cache_control.put( key, "data" + i + " junk asdfffffffadfasdfasf " + kn + ":" + n );
- if ( show )
- {
- p( "put " + key );
- }
- }
- else if ( n == 2 )
- {
- cache_control.remove( key );
- if ( show )
- {
- p( "removed " + key );
- }
- }
- else
- {
- // slightly greater chance of get
- Object obj = cache_control.get( key );
- if ( show && obj != null )
- {
- p( obj.toString() );
- }
- }
-
- if ( i % 10000 == 0 )
- {
- p( cache_control.getStats() );
- }
-
- }
- p( "Finished random cycle of " + numOps );
- }
- catch ( Exception e )
- {
- p( e.toString() );
- e.printStackTrace( System.out );
- }
- }
-
- /**
- * Sets the region to be used by test methods.
- * @param name String -- Name of region
- */
- public void setRegion( String name )
- {
- try
- {
- cache_control = JCS.getInstance( name );
- }
- catch ( Exception e )
- {
- p( e.toString() );
- e.printStackTrace( System.out );
- }
-
- }
-
- /////////////////////////////////////////////////////////////////////////////
- /**
- * The tester will print to the console if isSysOut is true, else it will log. It is false by
- * default. When run via the main method, isSysOut will be set to true
- * @param s String to print or log
- */
- public static void p( String s )
- {
- if ( isSysOut )
- {
- System.out.println( s );
- }
- else
- {
- if ( log.isDebugEnabled() )
- {
- log.debug( s );
- }
- }
- }
-
- /**
- * Displays usage information for command line testing.
- */
- public static void help()
- {
- p( "\n\n\n\n" );
- p( "type 'shutDown' to shutdown the cache" );
- p( "type 'getm num show[false|true]' to get num automatically from a region" );
- p( "type 'putm num' to put num automatically to a region" );
- p( "type 'removeall' to remove all items in a region" );
- p( "type 'remove key' to remove" );
- p( "type 'removem num' to remove a number automatically" );
- p( "type 'getMatching pattern show' to getMatching" );
- p( "type 'get key show' to get" );
- p( "type 'getg key group show' to get" );
- p( "type 'getag num group show' to get automatically from a group" );
- p( "type 'getAttributeNames group' to get a list og the group elements" );
- p( "type 'putg key group val' to put" );
- p( "type 'putag num group' to put automatically from a group" );
- p( "type 'put key val' to put" );
- p( "type 'stats' to get stats" );
- p( "type 'deattr' to get the default element attributes" );
- p( "type 'cloneattr num' to clone attr" );
- p( "type 'random range numOps' to put, get, and remove randomly" );
- p( "type 'switch name' to switch to this region name" );
- p( "type 'gc' to call System.gc()" );
- p( "type 'help' for commands" );
-
- }
-
- /**
- * Gets the attributeNames attribute of the TestCacheAccess class
- * @param groupName
- */
- public void getAttributeNames( String groupName )
- {
- Iterator<String> iter = group_cache_control.getGroupKeys( groupName ).iterator();
-
- while ( iter.hasNext() )
- {
- p( "=" + iter.next() );
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/admin/AdminBeanUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/admin/AdminBeanUnitTest.java
deleted file mode 100644
index 38a75ff..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/admin/AdminBeanUnitTest.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package org.apache.commons.jcs.admin;
-
-import java.util.List;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/**
- * Test the admin bean that is used by the JCSAdmin.jsp
- *
- * @author Aaron Smuts
- *
- */
-public class AdminBeanUnitTest
- extends TestCase
-{
-
- /**
- * Create a test region and then verify that we get it from the list.
- *
- * @throws Exception
- *
- */
- public void testGetRegionInfo()
- throws Exception
- {
- String regionName = "myRegion";
- CacheAccess<String, String> cache = JCS.getInstance( regionName );
-
- cache.put( "key", "value" );
-
- JCSAdminBean admin = new JCSAdminBean();
-
- List<CacheRegionInfo> regions = admin.buildCacheInfo();
-
- boolean foundRegion = false;
-
- for (CacheRegionInfo info : regions)
- {
-
- if ( info.getCacheName().equals( regionName ) )
- {
- foundRegion = true;
-
- assertTrue( "Byte count should be greater than 5.", info.getByteCount() > 5 );
-
- assertNotNull( "Should have stats.", info.getCacheStatistics() );
- }
- }
-
- assertTrue( "Should have found the region we just created.", foundRegion );
- }
-
- /**
- * Put a value in a region and verify that it shows up.
- *
- * @throws Exception
- */
- public void testGetElementForRegionInfo()
- throws Exception
- {
- String regionName = "myRegion";
- CacheAccess<String, String> cache = JCS.getInstance( regionName );
-
- // clear the region
- cache.clear();
-
- String key = "myKey";
- cache.put( key, "value" );
-
- JCSAdminBean admin = new JCSAdminBean();
-
- List<CacheElementInfo> elements = admin.buildElementInfo( regionName );
- assertEquals( "Wrong number of elements in the region.", 1, elements.size() );
-
- CacheElementInfo elementInfo = elements.get(0);
- assertEquals( "Wrong key." + elementInfo, key, elementInfo.getKey() );
- }
-
- /**
- * Remove an item via the remove method.
- *
- * @throws Exception
- */
- public void testRemove()
- throws Exception
- {
- JCSAdminBean admin = new JCSAdminBean();
-
- String regionName = "myRegion";
- CacheAccess<String, String> cache = JCS.getInstance( regionName );
-
- // clear the region
- cache.clear();
- admin.clearRegion( regionName );
-
- String key = "myKey";
- cache.put( key, "value" );
-
- List<CacheElementInfo> elements = admin.buildElementInfo( regionName );
- assertEquals( "Wrong number of elements in the region.", 1, elements.size() );
-
- CacheElementInfo elementInfo = elements.get(0);
- assertEquals( "Wrong key.", key, elementInfo.getKey() );
-
- admin.removeItem( regionName, key );
-
- List<CacheElementInfo> elements2 = admin.buildElementInfo( regionName );
- assertEquals( "Wrong number of elements in the region after remove.", 0, elements2.size() );
- }
-
- /**
- * Add an item to a region. Call clear all and verify that it doesn't exist.
- *
- * @throws Exception
- */
- public void testClearAll()
- throws Exception
- {
- JCSAdminBean admin = new JCSAdminBean();
-
- String regionName = "myRegion";
- CacheAccess<String, String> cache = JCS.getInstance( regionName );
-
- String key = "myKey";
- cache.put( key, "value" );
-
- admin.clearAllRegions();
-
- List<CacheElementInfo> elements2 = admin.buildElementInfo( regionName );
- assertEquals( "Wrong number of elements in the region after remove.", 0, elements2.size() );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/admin/CountingStreamUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/admin/CountingStreamUnitTest.java
deleted file mode 100644
index 129575b..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/admin/CountingStreamUnitTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package org.apache.commons.jcs.admin;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/**
- * Tests for the counting only output stream.
- *
- * @author Aaron Smuts
- *
- */
-public class CountingStreamUnitTest
- extends TestCase
-{
-
- /**
- * Write a single byte and verify the count.
- *
- * @throws Exception
- */
- public void testSingleByte() throws Exception
- {
- CountingOnlyOutputStream out = new CountingOnlyOutputStream();
- out.write( 1 );
- assertEquals( "Wrong number of bytes written.", 1, out.getCount() );
- out.write( 1 );
- assertEquals( "Wrong number of bytes written.", 2, out.getCount() );
- out.close();
- }
-
- /**
- * This should count the size of the array.
- *
- * @throws Exception
- */
- public void testByteArray() throws Exception
- {
- CountingOnlyOutputStream out = new CountingOnlyOutputStream();
- byte[] array = new byte[]{1,2,3,4,5};
- out.write( array );
- assertEquals( "Wrong number of bytes written.", array.length, out.getCount() );
- out.close();
- }
-
- /**
- * This should count the len -- the third arg
- *
- * @throws Exception
- */
- public void testByteArrayLenCount() throws Exception
- {
- CountingOnlyOutputStream out = new CountingOnlyOutputStream();
- byte[] array = new byte[]{1,2,3,4,5};
- int len = 3;
- out.write( array, 0, len );
- assertEquals( "Wrong number of bytes written.", len, out.getCount() );
- out.close();
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/admin/TestJMX.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/admin/TestJMX.java
deleted file mode 100644
index 5a7b3ba..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/admin/TestJMX.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.apache.commons.jcs.admin;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-
-/**
- * Helper class to test the JMX registration
- */
-public class TestJMX
-{
- public static void main(String[] args) throws Exception
- {
- CacheAccess<String, String> cache = JCS.getInstance("test");
-
- cache.put("key", "value");
- System.out.println("Waiting...");
- Thread.sleep(Long.MAX_VALUE);
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/AuxiliaryCacheConfiguratorUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/AuxiliaryCacheConfiguratorUnitTest.java
deleted file mode 100644
index 685e3e6..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/AuxiliaryCacheConfiguratorUnitTest.java
+++ /dev/null
@@ -1,129 +0,0 @@
-package org.apache.commons.jcs.auxiliary;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.control.MockElementSerializer;
-import org.apache.commons.jcs.engine.logging.MockCacheEventLogger;
-import org.apache.commons.jcs.utils.serialization.StandardSerializer;
-
-import java.util.Properties;
-
-/** Unit tests for the auxiliary cache configurator. */
-public class AuxiliaryCacheConfiguratorUnitTest
- extends TestCase
-{
- /**
- * Verify that we don't get an error.
- */
- public void testParseCacheEventLogger_Null()
- {
- // SETUP
- Properties props = new Properties();
-
- // DO WORK
- MockCacheEventLogger result = (MockCacheEventLogger) AuxiliaryCacheConfigurator.parseCacheEventLogger( props,
- "junk" );
-
- // VERIFY
- assertNull( "Should not have a logger.", result );
- }
-
- /**
- * Verify that we don't get an error.
- */
- public void testParseCacheEventLogger_NullName()
- {
- // SETUP
- Properties props = new Properties();
-
- // DO WORK
- MockCacheEventLogger result = (MockCacheEventLogger) AuxiliaryCacheConfigurator.parseCacheEventLogger( props,
- null );
-
- // VERIFY
- assertNull( "Should not have a logger.", result );
- }
-
- /**
- * Verify that we can parse the event logger.
- */
- public void testParseCacheEventLogger_Normal()
- {
- // SETUP
- String auxPrefix = "jcs.auxiliary." + "MYAux";
- String testPropertyValue = "This is the value";
- String className = MockCacheEventLogger.class.getName();
-
- Properties props = new Properties();
- props.put( auxPrefix + AuxiliaryCacheConfigurator.CACHE_EVENT_LOGGER_PREFIX, className );
- props.put( auxPrefix + AuxiliaryCacheConfigurator.CACHE_EVENT_LOGGER_PREFIX
- + AuxiliaryCacheConfigurator.ATTRIBUTE_PREFIX + ".testProperty", testPropertyValue );
-
- // DO WORK
- MockCacheEventLogger result = (MockCacheEventLogger) AuxiliaryCacheConfigurator
- .parseCacheEventLogger( props, auxPrefix );
-
- // VERIFY
- assertNotNull( "Should have a logger.", result );
- assertEquals( "Property should be set.", testPropertyValue, result.getTestProperty() );
- }
-
- /**
- * Verify that we can parse the ElementSerializer.
- */
- public void testParseElementSerializer_Normal()
- {
- // SETUP
- String auxPrefix = "jcs.auxiliary." + "MYAux";
- String testPropertyValue = "This is the value";
- String className = MockElementSerializer.class.getName();
-
- Properties props = new Properties();
- props.put( auxPrefix + AuxiliaryCacheConfigurator.SERIALIZER_PREFIX, className );
- props.put( auxPrefix + AuxiliaryCacheConfigurator.SERIALIZER_PREFIX
- + AuxiliaryCacheConfigurator.ATTRIBUTE_PREFIX + ".testProperty", testPropertyValue );
-
- // DO WORK
- MockElementSerializer result = (MockElementSerializer) AuxiliaryCacheConfigurator
- .parseElementSerializer( props, auxPrefix );
-
- // VERIFY
- assertNotNull( "Should have a Serializer.", result );
- assertEquals( "Property should be set.", testPropertyValue, result.getTestProperty() );
- }
-
- /**
- * Verify that we can parse the ElementSerializer.
- */
- public void testParseElementSerializer_Null()
- {
- // SETUP
- Properties props = new Properties();
-
- // DO WORK
- IElementSerializer result = AuxiliaryCacheConfigurator
- .parseElementSerializer( props, "junk" );
-
- // VERIFY
- assertTrue( "Should have the default Serializer.", result instanceof StandardSerializer );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/MockAuxiliaryCache.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/MockAuxiliaryCache.java
deleted file mode 100644
index f17d430..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/MockAuxiliaryCache.java
+++ /dev/null
@@ -1,215 +0,0 @@
-package org.apache.commons.jcs.auxiliary;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-
-/**
- * Mock auxiliary for unit tests.
- * <p>
- * @author Aaron Smuts
- */
-public class MockAuxiliaryCache<K, V>
- extends AbstractAuxiliaryCache<K, V>
-{
- /** Can setup the cache type */
- public CacheType cacheType = CacheType.DISK_CACHE;
-
- /** Can setup status */
- public CacheStatus status = CacheStatus.ALIVE;
-
- /** Times getMatching was Called */
- public int getMatchingCallCount = 0;
-
- /**
- * @param ce
- * @throws IOException
- */
- @Override
- public void update( ICacheElement<K, V> ce )
- throws IOException
- {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * @param key
- * @return ICacheElement
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> get( K key )
- throws IOException
- {
- // TODO Auto-generated method stub
- return null;
- }
-
- /**
- * @param pattern
- * @return Map
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching(String pattern)
- throws IOException
- {
- getMatchingCallCount++;
- return new HashMap<>();
- }
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * @param keys
- * @return a map of K key to ICacheElement<String, String> element, or an empty map if there is no
- * data in cache for any of these keys
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
- {
- return new HashMap<>();
- }
-
- /**
- * @param key
- * @return boolean
- * @throws IOException
- */
- @Override
- public boolean remove( K key )
- throws IOException
- {
- // TODO Auto-generated method stub
- return false;
- }
-
- /**
- * @throws IOException
- */
- @Override
- public void removeAll()
- throws IOException
- {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * @throws IOException
- */
- @Override
- public void dispose()
- throws IOException
- {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * @return int
- */
- @Override
- public int getSize()
- {
- // TODO Auto-generated method stub
- return 0;
- }
-
- /**
- * @return int
- */
- @Override
- public CacheStatus getStatus()
- {
- return status;
- }
-
- /**
- * @return null
- */
- @Override
- public String getCacheName()
- {
- return null;
- }
-
- /**
- * Return the keys in this cache.
- * <p>
- * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#getKeySet()
- */
- @Override
- public Set<K> getKeySet() throws IOException
- {
- return null;
- }
-
- /**
- * @return null
- */
- @Override
- public IStats getStatistics()
- {
- return null;
- }
-
- /**
- * @return null
- */
- @Override
- public String getStats()
- {
- return null;
- }
-
- /**
- * @return cacheType
- */
- @Override
- public CacheType getCacheType()
- {
- return cacheType;
- }
-
- /**
- * @return Returns the AuxiliaryCacheAttributes.
- */
- @Override
- public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
- {
- return null;
- }
-
- /** @return null */
- @Override
- public String getEventLoggingExtraInfo()
- {
- return null;
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/MockAuxiliaryCacheAttributes.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/MockAuxiliaryCacheAttributes.java
deleted file mode 100644
index 68deff8..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/MockAuxiliaryCacheAttributes.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.apache.commons.jcs.auxiliary;
-
-/*
- * 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.
- */
-
-/** For testing. */
-public class MockAuxiliaryCacheAttributes
- extends AbstractAuxiliaryCacheAttributes
-{
- /** Don't change. */
- private static final long serialVersionUID = 1091238902450504108L;
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/MockAuxiliaryCacheFactory.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/MockAuxiliaryCacheFactory.java
deleted file mode 100644
index 26677e4..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/MockAuxiliaryCacheFactory.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package org.apache.commons.jcs.auxiliary;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-
-/** For testing */
-public class MockAuxiliaryCacheFactory
- extends AbstractAuxiliaryCacheFactory
-{
- /** the name of the aux */
- public String name = "MockAuxiliaryCacheFactory";
-
- /**
- * Creates a mock aux.
- * <p>
- * @param attr
- * @param cacheMgr
- * @param cacheEventLogger
- * @param elementSerializer
- * @return AuxiliaryCache
- */
- @Override
- public <K, V> AuxiliaryCache<K, V>
- createCache( AuxiliaryCacheAttributes attr, ICompositeCacheManager cacheMgr,
- ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
- {
- MockAuxiliaryCache<K, V> auxCache = new MockAuxiliaryCache<>();
- auxCache.setCacheEventLogger( cacheEventLogger );
- auxCache.setElementSerializer( elementSerializer );
- return auxCache;
- }
-
- /**
- * @return String
- */
- @Override
- public String getName()
- {
- return name;
- }
-
- /**
- * @param s
- */
- @Override
- public void setName( String s )
- {
- this.name = s;
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/MockCacheEventLogger.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/MockCacheEventLogger.java
deleted file mode 100644
index e049ca0..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/MockCacheEventLogger.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package org.apache.commons.jcs.auxiliary;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.logging.CacheEvent;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * For testing auxiliary event logging. Improve later so we can test the details. This is very
- * crude.
- */
-public class MockCacheEventLogger
- implements ICacheEventLogger
-{
- /** times called */
- public int applicationEventCalls = 0;
-
- /** times called */
- public int startICacheEventCalls = 0;
-
- /** times called */
- public int endICacheEventCalls = 0;
-
- /** times called */
- public int errorEventCalls = 0;
-
- /** list of messages */
- public List<String> errorMessages = new ArrayList<>();
-
- /**
- * @param source
- * @param eventName
- * @param optionalDetails
- */
- @Override
- public void logApplicationEvent( String source, String eventName, String optionalDetails )
- {
- applicationEventCalls++;
- }
-
- /**
- * @param event
- */
- @Override
- public <T> void logICacheEvent( ICacheEvent<T> event )
- {
- endICacheEventCalls++;
- }
-
- /**
- * @param source
- * @param eventName
- * @param errorMessage
- */
- @Override
- public void logError( String source, String eventName, String errorMessage )
- {
- errorEventCalls++;
- errorMessages.add( errorMessage );
- }
-
- /**
- * @param source
- * @param region
- * @param eventName
- * @param optionalDetails
- * @param key
- * @return ICacheEvent
- */
- @Override
- public <T> ICacheEvent<T> createICacheEvent( String source, String region,
- String eventName, String optionalDetails, T key )
- {
- startICacheEventCalls++;
- return new CacheEvent<>();
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCacheUnitTest.java
deleted file mode 100644
index 14f6445..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/AbstractDiskCacheUnitTest.java
+++ /dev/null
@@ -1,301 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import junit.framework.TestCase;
-
-import org.apache.commons.jcs.TestLogConfigurationUtil;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes;
-import org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.ElementAttributes;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-
-/** Tests for the abstract disk cache. It's largely tested by actual instances. */
-public class AbstractDiskCacheUnitTest
- extends TestCase
-{
- /**
- * Verify that update and get work.
- * <p>
- * @throws IOException
- */
- public void testUpdateGet_allowed()
- throws IOException
- {
- // SETUP
- String cacheName = "testUpdateGet_allowed";
- IDiskCacheAttributes diskCacheAttributes = new IndexedDiskCacheAttributes();
- diskCacheAttributes.setCacheName( cacheName );
-
- AbstractDiskCacheTestInstance<String, String> diskCache = new AbstractDiskCacheTestInstance<>( diskCacheAttributes );
-
- String key = "myKey";
- String value = "myValue";
- IElementAttributes elementAttributes = new ElementAttributes();
- ICacheElement<String, String> cacheElement = new CacheElement<>( cacheName, key, value, elementAttributes );
-
- diskCache.update( cacheElement );
-
- // DO WORK
- ICacheElement<String, String> result = diskCache.get( key );
-
- // VERIFY
- //System.out.println( diskCache.getStats() );
- assertNotNull( "Item should be in the map.", result );
- }
-
- /**
- * Verify that alive is set to false..
- * <p>
- * @throws IOException
- */
- public void testDispose()
- throws IOException
- {
- // SETUP
- String cacheName = "testDispose";
- IDiskCacheAttributes diskCacheAttributes = new IndexedDiskCacheAttributes();
- diskCacheAttributes.setCacheName( cacheName );
-
- AbstractDiskCacheTestInstance<String, String> diskCache = new AbstractDiskCacheTestInstance<>( diskCacheAttributes );
-
- String key = "myKey";
- String value = "myValue";
- IElementAttributes elementAttributes = new ElementAttributes();
- ICacheElement<String, String> cacheElement = new CacheElement<>( cacheName, key, value, elementAttributes );
-
- diskCache.update( cacheElement );
-
- // DO WORK
- diskCache.dispose();
-
- // VERIFY
- assertFalse( "disk cache should not be alive.", diskCache.isAlive() );
- assertEquals( "Status should be disposed", CacheStatus.DISPOSED, diskCache.getStatus() );
- }
-
- /**
- * Verify that removeAll is prohibited.
- * <p>
- * @throws IOException
- */
- public void testRemoveAll_notAllowed()
- throws IOException
- {
- // SETUP
- StringWriter stringWriter = new StringWriter();
- TestLogConfigurationUtil.configureLogger( stringWriter, AbstractDiskCache.class.getName() );
-
- IDiskCacheAttributes diskCacheAttributes = new IndexedDiskCacheAttributes();
- diskCacheAttributes.setAllowRemoveAll( false );
-
- AbstractDiskCacheTestInstance<String, String> diskCache = new AbstractDiskCacheTestInstance<>( diskCacheAttributes );
-
- String cacheName = "testRemoveAll_notAllowed";
- String key = "myKey";
- String value = "myValue";
- IElementAttributes elementAttributes = new ElementAttributes();
- ICacheElement<String, String> cacheElement = new CacheElement<>( cacheName, key, value, elementAttributes );
-
- diskCache.update( cacheElement );
-
- // DO WORK
- diskCache.removeAll();
- String result = stringWriter.toString();
-
- // VERIFY
- assertTrue( "Should say not allowed.", result.indexOf( "set to false" ) != -1 );
- assertNotNull( "Item should be in the map.", diskCache.get( key ) );
- }
-
- /**
- * Verify that removeAll is allowed.
- * <p>
- * @throws IOException
- */
- public void testRemoveAll_allowed()
- throws IOException
- {
- // SETUP
- IDiskCacheAttributes diskCacheAttributes = new IndexedDiskCacheAttributes();
- diskCacheAttributes.setAllowRemoveAll( true );
-
- AbstractDiskCacheTestInstance<String, String> diskCache = new AbstractDiskCacheTestInstance<>( diskCacheAttributes );
-
- String cacheName = "testRemoveAll_allowed";
- String key = "myKey";
- String value = "myValue";
- IElementAttributes elementAttributes = new ElementAttributes();
- ICacheElement<String, String> cacheElement = new CacheElement<>( cacheName, key, value, elementAttributes );
-
- diskCache.update( cacheElement );
-
- // DO WORK
- diskCache.removeAll();
-
- // VERIFY
- assertNull( "Item should not be in the map.", diskCache.get( key ) );
- }
-
- /** Concrete, testable instance. */
- protected static class AbstractDiskCacheTestInstance<K, V>
- extends AbstractDiskCache<K, V>
- {
- /** Internal map */
- protected Map<K, ICacheElement<K, V>> map = new HashMap<>();
-
- /** used by the abstract aux class */
- protected IDiskCacheAttributes diskCacheAttributes;
-
- /**
- * Creates the disk cache.
- * <p>
- * @param attr
- */
- public AbstractDiskCacheTestInstance( IDiskCacheAttributes attr )
- {
- super( attr );
- diskCacheAttributes = attr;
- setAlive(true);
- }
-
- /**
- * The location on disk
- * <p>
- * @return "memory"
- */
- @Override
- protected String getDiskLocation()
- {
- return "memory";
- }
-
- /**
- * Return the keys in this cache.
- * <p>
- * @see org.apache.commons.jcs.auxiliary.disk.AbstractDiskCache#getKeySet()
- */
- @Override
- public Set<K> getKeySet() throws IOException
- {
- return new HashSet<>(map.keySet());
- }
-
- /**
- * @return map.size()
- */
- @Override
- public int getSize()
- {
- return map.size();
- }
-
- /**
- * @throws IOException
- */
- @Override
- protected void processDispose()
- throws IOException
- {
- //System.out.println( "processDispose" );
- }
-
- /**
- * @param key
- * @return ICacheElement
- * @throws IOException
- */
- @Override
- protected ICacheElement<K, V> processGet( K key )
- throws IOException
- {
- //System.out.println( "processGet: " + key );
- return map.get( key );
- }
-
- /**
- * @param pattern
- * @return Collections.EMPTY_MAP
- * @throws IOException
- */
- @Override
- protected Map<K, ICacheElement<K, V>> processGetMatching( String pattern )
- throws IOException
- {
- return Collections.emptyMap();
- }
-
- /**
- * @param key
- * @return false
- * @throws IOException
- */
- @Override
- protected boolean processRemove( K key )
- throws IOException
- {
- return map.remove( key ) != null;
- }
-
- /**
- * @throws IOException
- */
- @Override
- protected void processRemoveAll()
- throws IOException
- {
- //System.out.println( "processRemoveAll" );
- map.clear();
- }
-
- /**
- * @param cacheElement
- * @throws IOException
- */
- @Override
- protected void processUpdate( ICacheElement<K, V> cacheElement )
- throws IOException
- {
- //System.out.println( "processUpdate: " + cacheElement );
- map.put( cacheElement.getKey(), cacheElement );
- }
-
- /**
- * @return null
- */
- @Override
- public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
- {
- return diskCacheAttributes;
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/DiskTestObject.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/DiskTestObject.java
deleted file mode 100644
index b9927c1..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/DiskTestObject.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-import java.util.Arrays;
-
-/**
- * Resembles a cached image.
- */
-public class DiskTestObject implements Serializable
-{
- /** don't change */
- private static final long serialVersionUID = 1L;
-
- /**
- * Key
- */
- public Integer id;
-
- /**
- * Byte size
- */
- public byte[] imageBytes;
-
- /**
- * @param id
- * @param imageBytes
- */
- public DiskTestObject(Integer id, byte[] imageBytes)
- {
- this.id = id;
- this.imageBytes = imageBytes;
- }
-
- /**
- * @see java.lang.Object#equals(Object other)
- */
- @Override
- public boolean equals(Object other)
- {
- if (other instanceof DiskTestObject)
- {
- DiskTestObject o = (DiskTestObject) other;
- if (id != null)
- return id.equals(o.id) && Arrays.equals(imageBytes, o.imageBytes);
- else if (id == null && o.id == null) return Arrays.equals(imageBytes, o.imageBytes);
- }
- return false;
- }
-
- /**
- * @see java.lang.Object#hashCode()
- */
- @Override
- public int hashCode()
- {
- return id.hashCode();
- }
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/PurgatoryElementUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/PurgatoryElementUnitTest.java
deleted file mode 100644
index 5b937d2..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/PurgatoryElementUnitTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.ElementAttributes;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-
-/** Simple unit tests for the Purgatory Element. */
-public class PurgatoryElementUnitTest
- extends TestCase
-{
- /** Verify basic data */
- public void testSpoolable_normal()
- {
- // SETUP
- String cacheName = "myCacheName";
- String key = "myKey";
- String value = "myValue";
- IElementAttributes elementAttributes = new ElementAttributes();
- ICacheElement<String, String> cacheElement = new CacheElement<>( cacheName, key, value, elementAttributes );
- PurgatoryElement<String, String> purgatoryElement = new PurgatoryElement<>( cacheElement );
- purgatoryElement.setSpoolable( false );
-
- // DO WORK
- boolean result = purgatoryElement.isSpoolable();
-
- // VERIFY
- assertFalse( "Should not be spoolable.", result );
- }
-
- /** Verify basic data */
- public void testElementAttributes_normal()
- {
- // SETUP
- String cacheName = "myCacheName";
- String key = "myKey";
- String value = "myValue";
- IElementAttributes elementAttributes = new ElementAttributes();
-
- ICacheElement<String, String> cacheElement = new CacheElement<>( cacheName, key, value );
- PurgatoryElement<String, String> purgatoryElement = new PurgatoryElement<>( cacheElement );
- purgatoryElement.setElementAttributes( elementAttributes );
-
- // DO WORK
- IElementAttributes result = cacheElement.getElementAttributes();
-
- // VERIFY
- assertEquals( "Should have set the attributes on the element", elementAttributes, result );
- }
-
- /** Verify basic data */
- public void testToString_normal()
- {
- // SETUP
- String cacheName = "myCacheName";
- String key = "myKey";
- String value = "myValue";
- IElementAttributes elementAttributes = new ElementAttributes();
- ICacheElement<String, String> cacheElement = new CacheElement<>( cacheName, key, value, elementAttributes );
- PurgatoryElement<String, String> purgatoryElement = new PurgatoryElement<>( cacheElement );
-
- // DO WORK
- String result = purgatoryElement.toString();
-
- // VERIFY
- assertTrue( "Should have the cacheName.", result.indexOf( cacheName ) != -1 );
- assertTrue( "Should have the key.", result.indexOf( key ) != -1 );
- assertTrue( "Should have the value.", result.indexOf( value ) != -1 );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheConcurrentUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheConcurrentUnitTest.java
deleted file mode 100644
index 1a4f4dc..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheConcurrentUnitTest.java
+++ /dev/null
@@ -1,258 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.block;
-
-/*
- * 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.
- */
-
-import junit.extensions.ActiveTestSuite;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Test which exercises the block disk cache. This one uses three different
- * regions for three threads.
- */
-public class BlockDiskCacheConcurrentUnitTest
- extends TestCase
-{
- /**
- * Number of items to cache, twice the configured maxObjects for the memory
- * cache regions.
- */
- private static int items = 200;
-
- /**
- * Constructor for the TestDiskCache object.
- *
- * @param testName
- * @throws Exception
- */
- public BlockDiskCacheConcurrentUnitTest( String testName )
- throws Exception
- {
- super( testName );
- }
-
- /**
- * Main method passes this test to the text test runner.
- *
- * @param args
- */
- public static void main( String args[] )
- {
- String[] testCaseName = { BlockDiskCacheConcurrentUnitTest.class.getName() };
- junit.textui.TestRunner.main( testCaseName );
- }
-
- /**
- * A unit test suite for JUnit
- *
- * @return The test suite
- * @throws Exception
- */
- public static Test suite()
- throws Exception
- {
- ActiveTestSuite suite = new ActiveTestSuite();
-
- JCS.setConfigFilename( "/TestBlockDiskCache.ccf" );
- JCS.getInstance( "indexedRegion1" ).clear();
- JCS.getInstance( "indexedRegion2" ).clear();
- JCS.getInstance( "indexedRegion3" ).clear();
-
- suite.addTest( new BlockDiskCacheConcurrentUnitTest( "testBlockDiskCache1" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion1" );
- }
- } );
-
- suite.addTest( new BlockDiskCacheConcurrentUnitTest( "testBlockDiskCache2" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion2" );
- }
- } );
-
- suite.addTest( new BlockDiskCacheConcurrentUnitTest( "testBlockDiskCache3" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion3" );
- }
- } );
-
- suite.addTest( new BlockDiskCacheConcurrentUnitTest( "testBlockDiskCache4" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegionInRange( "indexedRegion3", 300, 600 );
- }
- } );
-
- return suite;
- }
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestBlockDiskCache.ccf" );
- }
-
- /**
- * Adds items to cache, gets them, and removes them. The item count is more
- * than the size of the memory cache, so items should spool to disk.
- *
- * @param region
- * Name of the region to access
- *
- * @throws Exception
- * If an error occurs
- */
- public void runTestForRegion( String region )
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-
- // Add items to cache
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
-
- // Test that all items are in cache
- for ( int i = 0; i <= items; i++ )
- {
- String value = jcs.get( i + ":key" );
-
- assertEquals( region + " data " + i, value );
- }
-
- // Test that getElements returns all the expected values
- Set<String> keys = new HashSet<>();
- for ( int i = 0; i <= items; i++ )
- {
- keys.add( i + ":key" );
- }
-
- Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
- for ( int i = 0; i <= items; i++ )
- {
- ICacheElement<String, String> element = elements.get( i + ":key" );
- assertNotNull( "element " + i + ":key is missing", element );
- assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
- }
-
- // Remove all the items
- for ( int i = 0; i <= items; i++ )
- {
- jcs.remove( i + ":key" );
- }
-
- // Verify removal
- // another thread may have inserted since
- for ( int i = 0; i <= items; i++ )
- {
- assertNull( "Removed key should be null: " + i + ":key" + "\n stats " + jcs.getStats(), jcs
- .get( i + ":key" ) );
- }
- }
-
- /**
- * Adds items to cache, gets them, and removes them. The item count is more
- * than the size of the memory cache, so items should spool to disk.
- *
- * @param region
- * Name of the region to access
- * @param start
- * @param end
- *
- * @throws Exception
- * If an error occurs
- */
- public void runTestForRegionInRange( String region, int start, int end )
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-
- // Add items to cache
- for ( int i = start; i <= end; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
-
- // Test that all items are in cache
- for ( int i = start; i <= end; i++ )
- {
- String value = jcs.get( i + ":key" );
-
- assertEquals( region + " data " + i, value );
- }
-
- // Test that getElements returns all the expected values
- Set<String> keys = new HashSet<>();
- for ( int i = start; i <= end; i++ )
- {
- keys.add( i + ":key" );
- }
-
- Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
- for ( int i = start; i <= end; i++ )
- {
- ICacheElement<String, String> element = elements.get( i + ":key" );
- assertNotNull( "element " + i + ":key is missing", element );
- assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
- }
-
- // Remove all the items
- for ( int i = start; i <= end; i++ )
- {
- jcs.remove( i + ":key" );
- }
-
-// System.out.println( jcs.getStats() );
-
- // Verify removal
- // another thread may have inserted since
- for ( int i = start; i <= end; i++ )
- {
- assertNull( "Removed key should be null: " + i + ":key " + "\n stats " + jcs.getStats(), jcs.get( i
- + ":key" ) );
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheCountUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheCountUnitTest.java
deleted file mode 100644
index 5f7d57e..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheCountUnitTest.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.block;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
-
-public class BlockDiskCacheCountUnitTest extends BlockDiskCacheUnitTestAbstract
-{
-
- @Override
- public BlockDiskCacheAttributes getCacheAttributes()
- {
- BlockDiskCacheAttributes ret = new BlockDiskCacheAttributes();
- ret.setDiskLimitType(DiskLimitType.COUNT);
- return ret;
- }
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheKeyStoreUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheKeyStoreUnitTest.java
deleted file mode 100644
index 8e3da94..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheKeyStoreUnitTest.java
+++ /dev/null
@@ -1,190 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.block;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
-
-/**
- * Tests for the keyStore.
- * <p>
- *
- * @author Aaron Smuts
- */
-public class BlockDiskCacheKeyStoreUnitTest
- extends TestCase
-{
- /** Directory name */
- private final String rootDirName = "target/test-sandbox/block";
-
- /**
- * Put a bunch of keys in the key store and verify that they are present.
- * <p>
- *
- * @throws Exception
- */
- public void testPutKeys()
- throws Exception
- {
- // SETUP
- BlockDiskCacheAttributes attributes = new BlockDiskCacheAttributes();
- attributes.setCacheName("testPutKeys");
- attributes.setDiskPath(rootDirName);
- attributes.setMaxKeySize(1000);
- attributes.setBlockSizeBytes(2000);
-
- innerTestPutKeys(attributes);
- }
-
- public void testPutKeysSize()
- throws Exception
- {
- // SETUP
- BlockDiskCacheAttributes attributes = new BlockDiskCacheAttributes();
- attributes.setCacheName("testPutKeys");
- attributes.setDiskPath(rootDirName);
- attributes.setMaxKeySize(100000);
- attributes.setBlockSizeBytes(1024);
- attributes.setDiskLimitType(DiskLimitType.SIZE);
-
- innerTestPutKeys(attributes);
- }
-
- private void innerTestPutKeys(BlockDiskCacheAttributes attributes)
- {
- BlockDiskCache<String, String> blockDiskCache = new BlockDiskCache<>(attributes);
- BlockDiskKeyStore<String> keyStore = new BlockDiskKeyStore<>(attributes, blockDiskCache);
-
- // DO WORK
- int numElements = 100;
- for (int i = 0; i < numElements; i++)
- {
- keyStore.put(String.valueOf(i), new int[i]);
- }
- // System.out.println( "testPutKeys " + keyStore );
-
- // VERIFY
- assertEquals("Wrong number of keys", numElements, keyStore.size());
- for (int i = 0; i < numElements; i++)
- {
- int[] result = keyStore.get(String.valueOf(i));
- assertEquals("Wrong array returned.", i, result.length);
- }
- }
-
- /**
- * Verify that we can load keys that we saved. Add a bunch. Save them. Clear
- * the memory key hash. Load the keys. Verify.
- * <p>
- *
- * @throws Exception
- */
- public void testSaveLoadKeys()
- throws Exception
- {
- // SETUP
- BlockDiskCacheAttributes attributes = new BlockDiskCacheAttributes();
- attributes.setCacheName("testSaveLoadKeys");
- attributes.setDiskPath(rootDirName);
- attributes.setMaxKeySize(10000);
- attributes.setBlockSizeBytes(2000);
-
- testSaveLoadKeysInner(attributes);
- }
-
- public void testSaveLoadKeysSize()
- throws Exception
- {
- // SETUP
- BlockDiskCacheAttributes attributes = new BlockDiskCacheAttributes();
- attributes.setCacheName("testSaveLoadKeys");
- attributes.setDiskPath(rootDirName);
- attributes.setMaxKeySize(10000);
- attributes.setBlockSizeBytes(2000);
-
- testSaveLoadKeysInner(attributes);
- }
-
- private void testSaveLoadKeysInner(BlockDiskCacheAttributes attributes)
- {
- BlockDiskKeyStore<String> keyStore = new BlockDiskKeyStore<>(attributes, null);
-
- // DO WORK
- int numElements = 1000;
- int blockIndex = 0;
- // Random random = new Random( 89 );
- for (int i = 0; i < numElements; i++)
- {
- int blocks = i;// random.nextInt( 10 );
-
- // fill with reasonable data to make verify() happy
- int[] block1 = new int[blocks];
- int[] block2 = new int[blocks];
- for (int j = 0; j < blocks; j++)
- {
- block1[j] = blockIndex++;
- block2[j] = blockIndex++;
- }
- keyStore.put(String.valueOf(i), block1);
- keyStore.put(String.valueOf(i), block2);
- }
- // System.out.println( "testSaveLoadKeys " + keyStore );
-
- // VERIFY
- assertEquals("Wrong number of keys", numElements, keyStore.size());
-
- // DO WORK
- keyStore.saveKeys();
- keyStore.clearMemoryMap();
-
- // VERIFY
- assertEquals("Wrong number of keys after clearing memory", 0, keyStore.size());
-
- // DO WORK
- keyStore.loadKeys();
-
- // VERIFY
- assertEquals("Wrong number of keys after loading", numElements, keyStore.size());
- for (int i = 0; i < numElements; i++)
- {
- int[] result = keyStore.get(String.valueOf(i));
- assertEquals("Wrong array returned.", i, result.length);
- }
- }
-
- public void testObjectLargerThanMaxSize()
- {
- BlockDiskCacheAttributes attributes = new BlockDiskCacheAttributes();
- attributes.setCacheName("testObjectLargerThanMaxSize");
- attributes.setDiskPath(rootDirName);
- attributes.setMaxKeySize(1000);
- attributes.setBlockSizeBytes(2000);
- attributes.setDiskLimitType(DiskLimitType.SIZE);
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- BlockDiskKeyStore<String> keyStore = new BlockDiskKeyStore<>(attributes, new BlockDiskCache(attributes));
-
- keyStore.put("1", new int[1000]);
- keyStore.put("2", new int[1000]);
- assertNull(keyStore.get("1"));
- assertNotNull(keyStore.get("2"));
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheRandomConcurrentTestUtil.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheRandomConcurrentTestUtil.java
deleted file mode 100644
index c76f582..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheRandomConcurrentTestUtil.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.block;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.access.TestCacheAccess;
-import org.junit.Test;
-
-/**
- * This is used by other tests to generate a random load on the disk cache.
- */
-public class BlockDiskCacheRandomConcurrentTestUtil
- extends TestCase
-{
- /**
- * Constructor for the TestDiskCache object.
- *
- * @param testName
- */
- public BlockDiskCacheRandomConcurrentTestUtil( String testName )
- {
- super( testName );
- }
-
- @Test
- public void test()
- {
-
- }
-
- /**
- * Randomly adds items to cache, gets them, and removes them. The range
- * count is more than the size of the memory cache, so items should spool to
- * disk.
- * <p>
- * @param region
- * Name of the region to access
- * @param range
- * @param numOps
- * @param testNum
- *
- * @throws Exception
- * If an error occurs
- */
- public void runTestForRegion( String region, int range, int numOps, int testNum )
- throws Exception
- {
- // run a rondom operation test to detect deadlocks
- TestCacheAccess tca = new TestCacheAccess( "/TestBlockDiskCacheCon.ccf" );
- tca.setRegion( region );
- tca.random( range, numOps );
-
- // make sure a simple put then get works
- // this may fail if the other tests are flooding the disk cache
- CacheAccess<String, String> jcs = JCS.getInstance( region );
- String key = "testKey" + testNum;
- String data = "testData" + testNum;
- jcs.put( key, data );
- String value = jcs.get( key );
- assertEquals( data, value );
- }
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestBlockDiskCacheCon.ccf" );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheSameRegionConcurrentUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheSameRegionConcurrentUnitTest.java
deleted file mode 100644
index 1cb9656..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheSameRegionConcurrentUnitTest.java
+++ /dev/null
@@ -1,172 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.block;
-
-/*
- * 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.
- */
-
-import junit.extensions.ActiveTestSuite;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Test which exercises the block disk cache. Runs three threads against the same region.
- */
-public class BlockDiskCacheSameRegionConcurrentUnitTest
- extends TestCase
-{
- /**
- * Constructor for the TestDiskCache object.
- * <p>
- * @param testName
- */
- public BlockDiskCacheSameRegionConcurrentUnitTest( String testName )
- {
- super( testName );
- }
-
- /**
- * Main method passes this test to the text test runner.
- * <p>
- * @param args
- * @throws InterruptedException
- */
- public static void main( String args[] ) throws InterruptedException
- {
- String[] testCaseName = { BlockDiskCacheSameRegionConcurrentUnitTest.class.getName() };
- junit.textui.TestRunner.main( testCaseName );
-
- // Give test threads some time to finish
- Thread.sleep(2000);
- }
-
- /**
- * A unit test suite for JUnit
- * @return The test suite
- */
- public static Test suite()
- {
- ActiveTestSuite suite = new ActiveTestSuite();
-
- suite.addTest( new BlockDiskCacheSameRegionConcurrentUnitTest( "testBlockDiskCache1" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "blockRegion4", 0, 200 );
- }
- } );
-
- suite.addTest( new BlockDiskCacheSameRegionConcurrentUnitTest( "testBlockDiskCache2" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "blockRegion4", 1000, 1200 );
- }
- } );
-
- suite.addTest( new BlockDiskCacheSameRegionConcurrentUnitTest( "testBlockDiskCache3" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "blockRegion4", 2000, 2200 );
- }
- } );
-
- suite.addTest( new BlockDiskCacheSameRegionConcurrentUnitTest( "testBlockDiskCache4" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "blockRegion4", 2200, 5200 );
- }
- } );
-
- return suite;
- }
-
- /**
- * Test setup. Sets the config name and clears the region.
- * <p>
- * @throws Exception
- */
- @Override
- public void setUp()
- throws Exception
- {
- JCS.setConfigFilename( "/TestBlockDiskCacheCon.ccf" );
- }
-
- /**
- * Adds items to cache, gets them, and removes them. The item count is more than the size of the
- * memory cache, so items should spool to disk.
- * @param region Name of the region to access
- * @param start
- * @param end
- * @throws Exception If an error occurs
- */
- public void runTestForRegion( String region, int start, int end )
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-
- // Add items to cache
-
- for ( int i = start; i <= end; i++ )
- {
- jcs.put( i + ":key", region + " data " + i + "-" + region );
- }
-
- // Test that all items are in cache
-
- for ( int i = start; i <= end; i++ )
- {
- String key = i + ":key";
- String value = jcs.get( key );
-
- assertEquals( "Wrong value for key [" + key + "]", region + " data " + i + "-" + region, value );
- }
-
- // Test that getElements returns all the expected values
- Set<String> keys = new HashSet<>();
- for ( int i = start; i <= end; i++ )
- {
- keys.add( i + ":key" );
- }
-
- Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
- for ( int i = start; i <= end; i++ )
- {
- ICacheElement<String, String> element = elements.get( i + ":key" );
- assertNotNull( "element " + i + ":key is missing", element );
- assertEquals( "value " + i + ":key", region + " data " + i + "-" + region, element.getVal() );
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheSizeUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheSizeUnitTest.java
deleted file mode 100644
index 4a093ff..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheSizeUnitTest.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.block;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
-
-public class BlockDiskCacheSizeUnitTest extends BlockDiskCacheUnitTestAbstract
-{
-
- @Override
- public BlockDiskCacheAttributes getCacheAttributes()
- {
- BlockDiskCacheAttributes ret = new BlockDiskCacheAttributes();
- ret.setDiskLimitType(DiskLimitType.SIZE);
- return ret;
- }
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheSteadyLoadTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheSteadyLoadTest.java
deleted file mode 100644
index 135131e..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheSteadyLoadTest.java
+++ /dev/null
@@ -1,161 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.block;
-
-/*
- * 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.
- */
-
-import java.text.DecimalFormat;
-import java.util.Random;
-
-import junit.framework.TestCase;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.auxiliary.disk.DiskTestObject;
-
-/**
- * This allows you to put thousands of large objects into the disk cache and to force removes to
- * trigger optimizations along the way.
- * <p>
- * @author Aaron Smuts
- */
-public class BlockDiskCacheSteadyLoadTest
- extends TestCase
-{
- /** String for separating log entries. */
- private static final String LOG_DIVIDER = "---------------------------";
-
- /** the runtime. */
- private static Runtime rt = Runtime.getRuntime();
-
- /** The decimal format to use int he logs. */
- private static DecimalFormat format = new DecimalFormat( "#,###" );
-
- /**
- * Insert 2000 wait 1 second, repeat. Average 1000 / sec.
- * <p>
- * @throws Exception
- */
- public void testRunSteadyLoadTest()
- throws Exception
- {
- JCS.setConfigFilename( "/TestBlockDiskCacheSteadyLoad.ccf" );
-
- logMemoryUsage();
-
- int numPerRun = 250;
- long pauseBetweenRuns = 1000;
- int runCount = 0;
- int runs = 1000;
- int upperKB = 50;
-
- CacheAccess<String, DiskTestObject> jcs = JCS.getInstance( ( numPerRun / 2 ) + "aSecond" );
-
-// ElapsedTimer timer = new ElapsedTimer();
- int numToGet = numPerRun * ( runs / 10 );
- for ( int i = 0; i < numToGet; i++ )
- {
- jcs.get( String.valueOf( i ) );
- }
-// System.out.println( LOG_DIVIDER );
-// System.out.println( "After getting " + numToGet );
-// System.out.println( "Elapsed " + timer.getElapsedTimeString() );
- logMemoryUsage();
-
- jcs.clear();
- Thread.sleep( 3000 );
-// System.out.println( LOG_DIVIDER );
-// System.out.println( "Start putting" );
-
-// long totalSize = 0;
- int totalPut = 0;
-
- Random random = new Random( 89 );
- while ( runCount < runs )
- {
- runCount++;
- for ( int i = 0; i < numPerRun; i++ )
- {
- // 1/2 upper to upperKB-4 KB
- int kiloBytes = Math.max( upperKB / 2, random.nextInt( upperKB ) );
- int bytes = ( kiloBytes ) * 1024;
-// totalSize += bytes;
- totalPut++;
- DiskTestObject object = new DiskTestObject( Integer.valueOf( i ), new byte[bytes] );
- jcs.put( String.valueOf( totalPut ), object );
- }
-
- // get half of those inserted the previous run
- if ( runCount > 1 )
- {
- for ( int j = ( ( totalPut - numPerRun ) - ( numPerRun / 2 ) ); j < ( totalPut - numPerRun ); j++ )
- {
- jcs.get( String.valueOf( j ) );
- }
- }
-
- // remove half of those inserted the previous run
- if ( runCount > 1 )
- {
- for ( int j = ( ( totalPut - numPerRun ) - ( numPerRun / 2 ) ); j < ( totalPut - numPerRun ); j++ )
- {
- jcs.remove( String.valueOf( j ) );
- }
- }
-
-
- Thread.sleep( pauseBetweenRuns );
- if ( runCount % 100 == 0 )
- {
-// System.out.println( LOG_DIVIDER );
-// System.out.println( "Elapsed " + timer.getElapsedTimeString() );
-// System.out.println( "Run count: " + runCount + " Average size: " + ( totalSize / totalPut ) + "\n"
-// + jcs.getStats() );
- logMemoryUsage();
- }
- }
-
- Thread.sleep( 3000 );
-// System.out.println( jcs.getStats() );
- logMemoryUsage();
-
- Thread.sleep( 10000 );
-// System.out.println( jcs.getStats() );
- logMemoryUsage();
-
- System.gc();
- Thread.sleep( 3000 );
- System.gc();
-// System.out.println( jcs.getStats() );
- logMemoryUsage();
- }
-
- /**
- * Logs the memory usage.
- */
- private static void logMemoryUsage()
- {
- long byte2MB = 1024 * 1024;
- long total = rt.totalMemory() / byte2MB;
- long free = rt.freeMemory() / byte2MB;
- long used = total - free;
- System.out.println( LOG_DIVIDER );
- System.out.println( "Memory:" + " Used:" + format.format( used ) + "MB" + " Free:" + format.format( free )
- + "MB" + " Total:" + format.format( total ) + "MB" );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTestAbstract.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTestAbstract.java
deleted file mode 100644
index fb6e7db..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskCacheUnitTestAbstract.java
+++ /dev/null
@@ -1,571 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.block;
-
-/*
- * 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.
- */
-
-import java.io.File;
-import java.io.IOException;
-import java.io.Serializable;
-import java.nio.charset.StandardCharsets;
-import java.util.Map;
-
-import junit.framework.TestCase;
-
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.ElementAttributes;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.control.group.GroupAttrName;
-import org.apache.commons.jcs.engine.control.group.GroupId;
-import org.apache.commons.jcs.utils.serialization.StandardSerializer;
-
-/** Unit tests for the Block Disk Cache */
-public abstract class BlockDiskCacheUnitTestAbstract extends TestCase
-{
- public abstract BlockDiskCacheAttributes getCacheAttributes();
-
- public void testPutGetMatching_SmallWait() throws Exception
- {
- // SETUP
- int items = 200;
-
- String cacheName = "testPutGetMatching_SmallWait";
- BlockDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
- BlockDiskCache<String, String> diskCache = new BlockDiskCache<>(cattr);
-
- // DO WORK
- for (int i = 0; i <= items; i++)
- {
- diskCache.update(new CacheElement<>(cacheName, i + ":key", cacheName + " data " + i));
- }
- Thread.sleep(500);
-
- Map<String, ICacheElement<String, String>> matchingResults = diskCache.getMatching("1.8.+");
-
- // VERIFY
- assertEquals("Wrong number returned", 10, matchingResults.size());
- // System.out.println( "matchingResults.keySet() " + matchingResults.keySet() );
- // System.out.println( "\nAFTER TEST \n" + diskCache.getStats() );
- }
-
- /**
- * Test the basic get matching. With no wait this will all come from purgatory.
- * <p>
- *
- * @throws Exception
- */
- public void testPutGetMatching_NoWait() throws Exception
- {
- // SETUP
- int items = 200;
-
- String cacheName = "testPutGetMatching_NoWait";
- BlockDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
- BlockDiskCache<String, String> diskCache = new BlockDiskCache<>(cattr);
-
- // DO WORK
- for (int i = 0; i <= items; i++)
- {
- diskCache.update(new CacheElement<>(cacheName, i + ":key", cacheName + " data " + i));
- }
-
- Map<String, ICacheElement<String, String>> matchingResults = diskCache.getMatching("1.8.+");
-
- // VERIFY
- assertEquals("Wrong number returned", 10, matchingResults.size());
- // System.out.println( "matchingResults.keySet() " + matchingResults.keySet() );
- // System.out.println( "\nAFTER TEST \n" + diskCache.getStats() );
- }
-
- /**
- * Verify that the block disk cache can handle a big string.
- * <p>
- *
- * @throws Exception
- */
- public void testChunk_BigString() throws Exception
- {
- String string = "This is my big string ABCDEFGH";
- StringBuilder sb = new StringBuilder();
- sb.append(string);
- for (int i = 0; i < 4; i++)
- {
- sb.append("|" + i + ":" + sb.toString()); // big string
- }
- string = sb.toString();
-
- StandardSerializer elementSerializer = new StandardSerializer();
- byte[] data = elementSerializer.serialize(string);
-
- File file = new File("target/test-sandbox/BlockDiskCacheUnitTest/testChunk_BigString.data");
-
- BlockDisk blockDisk = new BlockDisk(file, 200, elementSerializer);
-
- int numBlocksNeeded = blockDisk.calculateTheNumberOfBlocksNeeded(data);
- // System.out.println( numBlocksNeeded );
-
- // get the individual sub arrays.
- byte[][] chunks = blockDisk.getBlockChunks(data, numBlocksNeeded);
-
- byte[] resultData = new byte[0];
-
- for (short i = 0; i < chunks.length; i++)
- {
- byte[] chunk = chunks[i];
- byte[] newTotal = new byte[data.length + chunk.length];
- // copy data into the new array
- System.arraycopy(data, 0, newTotal, 0, data.length);
- // copy the chunk into the new array
- System.arraycopy(chunk, 0, newTotal, data.length, chunk.length);
- // swap the new and old.
- resultData = newTotal;
- }
-
- Serializable result = elementSerializer.deSerialize(resultData, null);
- // System.out.println( result );
- assertEquals("wrong string after retrieval", string, result);
- blockDisk.close();
- }
-
- /**
- * Verify that the block disk cache can handle a big string.
- * <p>
- *
- * @throws Exception
- */
- public void testPutGet_BigString() throws Exception
- {
- String string = "This is my big string ABCDEFGH";
- StringBuilder sb = new StringBuilder();
- sb.append(string);
- for (int i = 0; i < 4; i++)
- {
- sb.append(" " + i + sb.toString()); // big string
- }
- string = sb.toString();
-
- String cacheName = "testPutGet_BigString";
-
- BlockDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMaxKeySize(100);
- cattr.setBlockSizeBytes(200);
- cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
- BlockDiskCache<String, String> diskCache = new BlockDiskCache<>(cattr);
-
- // DO WORK
- diskCache.update(new CacheElement<>(cacheName, "x", string));
-
- // VERIFY
- assertNotNull(diskCache.get("x"));
- Thread.sleep(1000);
- ICacheElement<String, String> afterElement = diskCache.get("x");
- assertNotNull(afterElement);
- // System.out.println( "afterElement = " + afterElement );
- String after = afterElement.getVal();
-
- assertNotNull(after);
- assertEquals("wrong string after retrieval", string, after);
- }
-
- /**
- * Verify that the block disk cache can handle utf encoded strings.
- * <p>
- *
- * @throws Exception
- */
- public void testUTF8String() throws Exception
- {
- String string = "IÒtÎrn‚tiÙn‡lizÊti¯n";
- StringBuilder sb = new StringBuilder();
- sb.append(string);
- for (int i = 0; i < 4; i++)
- {
- sb.append(sb.toString()); // big string
- }
- string = sb.toString();
-
- // System.out.println( "The string contains " + string.length() + " characters" );
-
- String cacheName = "testUTF8String";
-
- BlockDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMaxKeySize(100);
- cattr.setBlockSizeBytes(200);
- cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
- BlockDiskCache<String, String> diskCache = new BlockDiskCache<>(cattr);
-
- // DO WORK
- diskCache.update(new CacheElement<>(cacheName, "x", string));
-
- // VERIFY
- assertNotNull(diskCache.get("x"));
- Thread.sleep(1000);
- ICacheElement<String, String> afterElement = diskCache.get("x");
- assertNotNull(afterElement);
- // System.out.println( "afterElement = " + afterElement );
- String after = afterElement.getVal();
-
- assertNotNull(after);
- assertEquals("wrong string after retrieval", string, after);
- }
-
- /**
- * Verify that the block disk cache can handle utf encoded strings.
- * <p>
- *
- * @throws Exception
- */
- public void testUTF8ByteArray() throws Exception
- {
- String string = "IÒtÎrn‚tiÙn‡lizÊti¯n";
- StringBuilder sb = new StringBuilder();
- sb.append(string);
- for (int i = 0; i < 4; i++)
- {
- sb.append(sb.toString()); // big string
- }
- string = sb.toString();
- // System.out.println( "The string contains " + string.length() + " characters" );
- byte[] bytes = string.getBytes(StandardCharsets.UTF_8);
-
- String cacheName = "testUTF8ByteArray";
-
- BlockDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMaxKeySize(100);
- cattr.setBlockSizeBytes(200);
- cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
- BlockDiskCache<String, byte[]> diskCache = new BlockDiskCache<>(cattr);
-
- // DO WORK
- diskCache.update(new CacheElement<>(cacheName, "x", bytes));
-
- // VERIFY
- assertNotNull(diskCache.get("x"));
- Thread.sleep(1000);
- ICacheElement<String, byte[]> afterElement = diskCache.get("x");
- assertNotNull(afterElement);
- // System.out.println( "afterElement = " + afterElement );
- byte[] after = afterElement.getVal();
-
- assertNotNull(after);
- assertEquals("wrong bytes after retrieval", bytes.length, after.length);
- // assertEquals( "wrong bytes after retrieval", bytes, after );
- // assertEquals( "wrong bytes after retrieval", string, new String( after, StandardCharsets.UTF_8 ) );
-
- }
-
- /**
- * Verify that the block disk cache can handle utf encoded strings.
- * <p>
- *
- * @throws Exception
- */
- public void testUTF8StringAndBytes() throws Exception
- {
- X before = new X();
- String string = "IÒtÎrn‚tiÙn‡lizÊti¯n";
- StringBuilder sb = new StringBuilder();
- sb.append(string);
- for (int i = 0; i < 4; i++)
- {
- sb.append(sb.toString()); // big string
- }
- string = sb.toString();
- // System.out.println( "The string contains " + string.length() + " characters" );
- before.string = string;
- before.bytes = string.getBytes(StandardCharsets.UTF_8);
-
- String cacheName = "testUTF8StringAndBytes";
-
- BlockDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMaxKeySize(100);
- cattr.setBlockSizeBytes(500);
- cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
- BlockDiskCache<String, X> diskCache = new BlockDiskCache<>(cattr);
-
- // DO WORK
- diskCache.update(new CacheElement<>(cacheName, "x", before));
-
- // VERIFY
- assertNotNull(diskCache.get("x"));
- Thread.sleep(1000);
- ICacheElement<String, X> afterElement = diskCache.get("x");
- // System.out.println( "afterElement = " + afterElement );
- X after = (afterElement.getVal());
-
- assertNotNull(after);
- assertEquals("wrong string after retrieval", string, after.string);
- assertEquals("wrong bytes after retrieval", string, new String(after.bytes, StandardCharsets.UTF_8));
-
- }
-
- public void testLoadFromDisk() throws Exception
- {
- for (int i = 0; i < 20; i++)
- { // usually after 2 time it fails
- oneLoadFromDisk();
- }
- }
-
- public void testAppendToDisk() throws Exception
- {
- String cacheName = "testAppendToDisk";
- BlockDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMaxKeySize(100);
- cattr.setBlockSizeBytes(500);
- cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
- BlockDiskCache<String, X> diskCache = new BlockDiskCache<>(cattr);
- diskCache.removeAll();
- X value1 = new X();
- value1.string = "1234567890";
- X value2 = new X();
- value2.string = "0987654321";
- diskCache.update(new CacheElement<>(cacheName, "1", value1));
- diskCache.dispose();
- diskCache = new BlockDiskCache<>(cattr);
- diskCache.update(new CacheElement<>(cacheName, "2", value2));
- diskCache.dispose();
- diskCache = new BlockDiskCache<>(cattr);
- assertTrue(diskCache.verifyDisk());
- assertEquals(2, diskCache.getKeySet().size());
- assertEquals(value1.string, diskCache.get("1").getVal().string);
- assertEquals(value2.string, diskCache.get("2").getVal().string);
- }
-
- public void oneLoadFromDisk() throws Exception
- {
- // initialize object to be stored
- X before = new X();
- String string = "IÒtÎrn‚tiÙn‡lizÊti¯n";
- StringBuilder sb = new StringBuilder();
- sb.append(string);
- for (int i = 0; i < 4; i++)
- {
- sb.append(sb.toString()); // big string
- }
- string = sb.toString();
- before.string = string;
- before.bytes = string.getBytes(StandardCharsets.UTF_8);
-
- // initialize cache
- String cacheName = "testLoadFromDisk";
- BlockDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMaxKeySize(100);
- cattr.setBlockSizeBytes(500);
- cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
- BlockDiskCache<String, X> diskCache = new BlockDiskCache<>(cattr);
-
- // DO WORK
- for (int i = 0; i < 50; i++)
- {
- diskCache.update(new CacheElement<>(cacheName, "x" + i, before));
- }
- diskCache.dispose();
-
- // VERIFY
- diskCache = new BlockDiskCache<>(cattr);
-
- for (int i = 0; i < 50; i++)
- {
- ICacheElement<String, X> afterElement = diskCache.get("x" + i);
- assertNotNull("Missing element from cache. Cache size: " + diskCache.getSize() + " element: x" + i, afterElement);
- X after = (afterElement.getVal());
-
- assertNotNull(after);
- assertEquals("wrong string after retrieval", string, after.string);
- assertEquals("wrong bytes after retrieval", string, new String(after.bytes, StandardCharsets.UTF_8));
- }
-
- diskCache.dispose();
- }
-
- /**
- * Add some items to the disk cache and then remove them one by one.
- *
- * @throws IOException
- */
- public void testRemoveItems() throws IOException
- {
- BlockDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName("testRemoveItems");
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
- BlockDiskCache<String, String> disk = new BlockDiskCache<>(cattr);
-
- disk.processRemoveAll();
-
- int cnt = 25;
- for (int i = 0; i < cnt; i++)
- {
- IElementAttributes eAttr = new ElementAttributes();
- eAttr.setIsSpool(true);
- ICacheElement<String, String> element = new CacheElement<>("testRemoveItems", "key:" + i, "data:" + i);
- element.setElementAttributes(eAttr);
- disk.processUpdate(element);
- }
-
- // remove each
- for (int i = 0; i < cnt; i++)
- {
- disk.remove("key:" + i);
- ICacheElement<String, String> element = disk.processGet("key:" + i);
- assertNull("Should not have received an element.", element);
- }
- }
-
- /**
- * Add some items to the disk cache and then remove them one by one.
- * <p>
- *
- * @throws IOException
- */
- public void testRemove_PartialKey() throws IOException
- {
- BlockDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName("testRemove_PartialKey");
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
- BlockDiskCache<String, String> disk = new BlockDiskCache<>(cattr);
-
- disk.processRemoveAll();
-
- int cnt = 25;
- for (int i = 0; i < cnt; i++)
- {
- IElementAttributes eAttr = new ElementAttributes();
- eAttr.setIsSpool(true);
- ICacheElement<String, String> element = new CacheElement<>("testRemove_PartialKey", i + ":key", "data:"
- + i);
- element.setElementAttributes(eAttr);
- disk.processUpdate(element);
- }
-
- // verify each
- for (int i = 0; i < cnt; i++)
- {
- ICacheElement<String, String> element = disk.processGet(i + ":key");
- assertNotNull("Shoulds have received an element.", element);
- }
-
- // remove each
- for (int i = 0; i < cnt; i++)
- {
- disk.remove(i + ":");
- ICacheElement<String, String> element = disk.processGet(i + ":key");
- assertNull("Should not have received an element.", element);
- }
- }
-
-
- /**
- * Verify that group members are removed if we call remove with a group.
- *
- * @throws IOException
- */
- public void testRemove_Group() throws IOException
- {
- // SETUP
- BlockDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName("testRemove_Group");
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
- BlockDiskCache<GroupAttrName<String>, String> disk = new BlockDiskCache<>(cattr);
-
- disk.processRemoveAll();
-
- String cacheName = "testRemove_Group_Region";
- String groupName = "testRemove_Group";
-
- int cnt = 25;
- for (int i = 0; i < cnt; i++)
- {
- GroupAttrName<String> groupAttrName = getGroupAttrName(cacheName, groupName, i + ":key");
- CacheElement<GroupAttrName<String>, String> element = new CacheElement<>(cacheName,
- groupAttrName, "data:" + i);
-
- IElementAttributes eAttr = new ElementAttributes();
- eAttr.setIsSpool(true);
- element.setElementAttributes(eAttr);
-
- disk.processUpdate(element);
- }
-
- // verify each
- for (int i = 0; i < cnt; i++)
- {
- GroupAttrName<String> groupAttrName = getGroupAttrName(cacheName, groupName, i + ":key");
- ICacheElement<GroupAttrName<String>, String> element = disk.processGet(groupAttrName);
- assertNotNull("Should have received an element.", element);
- }
-
- // DO WORK
- // remove the group
- disk.remove(getGroupAttrName(cacheName, groupName, null));
-
- for (int i = 0; i < cnt; i++)
- {
- GroupAttrName<String> groupAttrName = getGroupAttrName(cacheName, groupName, i + ":key");
- ICacheElement<GroupAttrName<String>, String> element = disk.processGet(groupAttrName);
-
- // VERIFY
- assertNull("Should not have received an element.", element);
- }
-
- }
-
- /**
- * Internal method used for group functionality.
- * <p>
- *
- * @param cacheName
- * @param group
- * @param name
- * @return GroupAttrName
- */
- private GroupAttrName<String> getGroupAttrName(String cacheName, String group, String name)
- {
- GroupId gid = new GroupId(cacheName, group);
- return new GroupAttrName<>(gid, name);
- }
-
- /** Holder for a string and byte array. */
- static class X implements Serializable
- {
- /** ignore */
- private static final long serialVersionUID = 1L;
-
- /** Test string */
- String string;
-
- /*** test byte array. */
- byte[] bytes;
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskUnitTest.java
deleted file mode 100644
index cf95502..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/BlockDiskUnitTest.java
+++ /dev/null
@@ -1,368 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.block;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Random;
-
-import org.apache.commons.jcs.utils.serialization.StandardSerializer;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/**
- * Test for the disk access layer of the Block Disk Cache.
- * <p>
- * @author Aaron Smuts
- */
-public class BlockDiskUnitTest
- extends TestCase
-{
- /** data file. */
- private File rafDir;
- private BlockDisk disk;
-
- /**
- * @see junit.framework.TestCase#setUp()
- * Creates the base directory
- */
- @Override
- protected void setUp() throws Exception
- {
- super.setUp();
- String rootDirName = "target/test-sandbox/block";
- this.rafDir = new File( rootDirName );
- this.rafDir.mkdirs();
- }
-
- private void setUpBlockDisk(String fileName) throws IOException
- {
- File file = new File(rafDir, fileName + ".data");
- file.delete();
- this.disk = new BlockDisk(file, new StandardSerializer());
- }
-
- private void setUpBlockDisk(String fileName, int blockSize) throws IOException
- {
- File file = new File(rafDir, fileName + ".data");
- file.delete();
- this.disk = new BlockDisk(file, blockSize, new StandardSerializer());
- }
-
- /**
- * @see junit.framework.TestCase#tearDown()
- */
- @Override
- protected void tearDown() throws Exception
- {
- disk.close();
- super.tearDown();
- }
-
- /**
- * Test writing a null object within a single block size.
- * <p>
- * @throws Exception
- */
- public void testWrite_NullBlockElement()
- throws Exception
- {
- // SETUP
- setUpBlockDisk("testWrite_NullBlockElement");
-
- // DO WORK
- int[] blocks = disk.write( null );
-
- // VERIFY
- assertEquals( "Wrong number of blocks recorded.", 1, disk.getNumberOfBlocks() );
- assertEquals( "Wrong number of blocks returned.", 1, blocks.length );
- assertEquals( "Wrong block returned.", 0, blocks[0] );
- }
-
- /**
- * Test writing an element within a single block size.
- * <p>
- * @throws Exception
- */
- public void testWrite_SingleBlockElement()
- throws Exception
- {
- // SETUP
- setUpBlockDisk("testWrite_SingleBlockElement");
-
- // DO WORK
- int bytes = 1 * 1024;
- int[] blocks = disk.write( new byte[bytes] );
-
- // VERIFY
- assertEquals( "Wrong number of blocks recorded.", 1, disk.getNumberOfBlocks() );
- assertEquals( "Wrong number of blocks returned.", 1, blocks.length );
- assertEquals( "Wrong block returned.", 0, blocks[0] );
- }
-
- /**
- * Test writing and reading an element within a single block size.
- * <p>
- * @throws Exception
- */
- public void testWriteAndRead_SingleBlockElement()
- throws Exception
- {
- // SETUP
- setUpBlockDisk("testWriteAndRead_SingleBlockElement");
-
- // DO WORK
- int bytes = 1 * 1024;
- int[] blocks = disk.write( new byte[bytes] );
-
- byte[] result = (byte[]) disk.read( blocks );
-
- // VERIFY
- assertEquals( "Wrong item retured.", new byte[bytes].length, result.length );
- }
-
- /**
- * Test writing two elements that each fit within a single block size.
- * <p>
- * @throws Exception
- */
- public void testWrite_TwoSingleBlockElements()
- throws Exception
- {
- // SETUP
- setUpBlockDisk("testWrite_TwoSingleBlockElements");
-
- // DO WORK
- int bytes = 1 * 1024;
- int[] blocks1 = disk.write( new byte[bytes] );
- int[] blocks2 = disk.write( new byte[bytes] );
-
- // VERIFY
- assertEquals( "Wrong number of blocks recorded.", 2, disk.getNumberOfBlocks() );
- assertEquals( "Wrong number of blocks returned.", 1, blocks1.length );
- assertEquals( "Wrong block returned.", 0, blocks1[0] );
- assertEquals( "Wrong number of blocks returned.", 1, blocks2.length );
- assertEquals( "Wrong block returned.", 1, blocks2[0] );
- }
-
- /**
- * Verify that it says we need two blocks if the total size will fit.
- * <p>
- * @throws Exception
- */
- public void testCalculateBlocksNeededDouble()
- throws Exception
- {
- // SETUP
- setUpBlockDisk("testCalculateBlocksNeededDouble");
-
- // DO WORK
- int result = disk.calculateTheNumberOfBlocksNeeded( new byte[disk.getBlockSizeBytes() * 2
- - ( 2 * BlockDisk.HEADER_SIZE_BYTES )] );
-
- // Verify
- assertEquals( "Wrong number of blocks", 2, result );
- }
-
- /**
- * Test writing an element that takes two blocks.
- * <p>
- * @throws Exception
- */
- public void testWrite_DoubleBlockElement()
- throws Exception
- {
- // SETUP
- setUpBlockDisk("testWriteDoubleBlockElement");
-
- // DO WORK
- // byte arrays encur 27 bytes of serialization overhead.
- int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), 2 );
- int[] blocks = disk.write( new byte[bytes] );
-
- // VERIFY
- assertEquals( "Wrong number of blocks recorded.", 2, disk.getNumberOfBlocks() );
- assertEquals( "Wrong number of blocks returned.", 2, blocks.length );
- assertEquals( "Wrong block returned.", 0, blocks[0] );
- }
-
- /**
- * Test writing an element that takes 128 blocks. There was a byte in a for loop that limited the number to 127. I fixed this.
- * <p>
- * @throws Exception
- */
- public void testWrite_128BlockElement()
- throws Exception
- {
- // SETUP
- int numBlocks = 128;
-
- setUpBlockDisk("testWrite_128BlockElement");
-
- // DO WORK
- // byte arrays encur 27 bytes of serialization overhead.
- int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), numBlocks );
- int[] blocks = disk.write( new byte[bytes] );
-
- // VERIFY
- assertEquals( "Wrong number of blocks recorded.", numBlocks, disk.getNumberOfBlocks() );
- assertEquals( "Wrong number of blocks returned.", numBlocks, blocks.length );
- assertEquals( "Wrong block returned.", 0, blocks[0] );
- }
-
- /**
- * Test writing and reading elements that do not fit within a single block.
- * <p>
- * @throws Exception
- */
- public void testWriteAndReadMultipleMultiBlockElement()
- throws Exception
- {
- // SETUP
- setUpBlockDisk("testWriteAndReadSingleBlockElement");
-
- // DO WORK
- int numBlocksPerElement = 4;
- int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), numBlocksPerElement );
-
- int numElements = 100;
- for ( int i = 0; i < numElements; i++ )
- {
- int[] blocks = disk.write( new byte[bytes] );
- byte[] result = (byte[]) disk.read( blocks );
-
- // VERIFY
- assertEquals( "Wrong item retured.", new byte[bytes].length, result.length );
- assertEquals( "Wrong number of blocks returned.", numBlocksPerElement, blocks.length );
- }
- }
-
- /**
- * Test writing and reading elements that do not fit within a single block.
- * <p>
- * @throws Exception
- */
- public void testWriteAndReadMultipleMultiBlockElement_setSize()
- throws Exception
- {
- // SETUP
- setUpBlockDisk("testWriteAndReadSingleBlockElement", 1024);
-
- // DO WORK
- int numBlocksPerElement = 4;
- int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), numBlocksPerElement );
-
- int numElements = 100;
- Random r = new Random(System.currentTimeMillis());
- final byte[] src = new byte[bytes];
- for ( int i = 0; i < numElements; i++ )
- {
- r.nextBytes(src); // Ensure we don't just write zeros out
- int[] blocks = disk.write( src );
- byte[] result = (byte[]) disk.read( blocks );
-
- // VERIFY
- assertEquals( "Wrong item length retured.", src.length, result.length );
- assertEquals( "Wrong number of blocks returned.", numBlocksPerElement, blocks.length );
-
- // We check the array contents, too, to ensure we read back what we wrote out
- for (int j = 0 ; j < src.length ; j++) {
- assertEquals( "Mismatch at offset " + j + " in attempt # " + (i + 1), src[j], result[j] );
- }
- }
- assertEquals( "Wrong number of elements. "+disk, numBlocksPerElement * numElements, disk.getNumberOfBlocks() );
- }
-
- /**
- * Used to get the size for byte arrays that will take up the number of blocks specified.
- * <p>
- * @param blockSize
- * @param numBlocks
- * @return num bytes.
- */
- private int getBytesForBlocksOfByteArrays( int blockSize, int numBlocks )
- {
- // byte arrays encur some bytes of serialization overhead.
- return blockSize * numBlocks - ( numBlocks * BlockDisk.HEADER_SIZE_BYTES ) - ( numBlocks * 14 );
- }
-
- /**
- * Verify that the block disk can handle a big string.
- * <p>
- * @throws Exception
- */
- public void testWriteAndRead_BigString()
- throws Exception
- {
- // SETUP
- setUpBlockDisk("testWriteAndRead_BigString", 4096); //1024
-
- String string = "This is my big string ABCDEFGH";
- StringBuilder sb = new StringBuilder();
- sb.append( string );
- for ( int i = 0; i < 8; i++ )
- {
- sb.append( " " + i + sb.toString() ); // big string
- }
- string = sb.toString();
-
- // DO WORK
- int[] blocks = disk.write( string );
- String result = (String) disk.read( blocks );
-
- // VERIFY
-// System.out.println( string );
-// System.out.println( result );
-// System.out.println( disk );
- assertEquals( "Wrong item retured.", string, result );
- }
-
- /**
- * Verify that the block disk can handle a big string.
- * <p>
- * @throws Exception
- */
- public void testWriteAndRead_BigString2()
- throws Exception
- {
- // SETUP
- setUpBlockDisk("testWriteAndRead_BigString", 47); //4096;//1024
-
- String string = "abcdefghijklmnopqrstuvwxyz1234567890";
- string += string;
- string += string;
-
- // DO WORK
- int[] blocks = disk.write( string );
- String result = (String) disk.read( blocks );
-
- // VERIFY
- assertEquals( "Wrong item retured.", string, result );
- }
-
- public void testJCS156() throws Exception
- {
- // SETUP
- setUpBlockDisk("testJCS156", 4096);
- long offset = disk.calculateByteOffsetForBlockAsLong(Integer.MAX_VALUE);
- assertTrue("Must not wrap round", offset > 0);
- assertEquals(Integer.MAX_VALUE*4096L,offset);
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/HugeQuantityBlockDiskCacheLoadTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/HugeQuantityBlockDiskCacheLoadTest.java
deleted file mode 100644
index a22a449..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/block/HugeQuantityBlockDiskCacheLoadTest.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.block;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.utils.timing.ElapsedTimer;
-import org.apache.commons.jcs.utils.timing.SleepUtil;
-
-/**
- * Put a few hundred thousand entries in the block disk cache.
- * @author Aaron Smuts
- */
-public class HugeQuantityBlockDiskCacheLoadTest
- extends TestCase
-{
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestBlockDiskCacheHuge.ccf" );
- }
-
- /**
- * Adds items to cache, gets them, and removes them. The item count is more than the size of the
- * memory cache, so items should spool to disk.
- * <p>
- * @throws Exception If an error occurs
- */
- public void testLargeNumberOfItems()
- throws Exception
- {
- int items = 300000;
- String region = "testCache1";
-
- System.out.println( "--------------------------" );
- long initialMemory = measureMemoryUse();
- System.out.println( "Before getting JCS: " + initialMemory );
-
- CacheAccess<String, String> jcs = JCS.getInstance( region );
- jcs.clear();
-
- try
- {
- ElapsedTimer timer = new ElapsedTimer();
- System.out.println( "Start: " + measureMemoryUse() );
-
- // Add items to cache
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
-
- System.out.println( jcs.getStats() );
- System.out.println( "--------------------------" );
- System.out.println( "After put: " + measureMemoryUse() );
-
- Thread.sleep( 5000 );
-
- System.out.println( jcs.getStats() );
- System.out.println( "--------------------------" );
- System.out.println( "After wait: " + measureMemoryUse() );
-
- for ( int i = 0; i < 10; i++ )
- {
- SleepUtil.sleepAtLeast( 3000 );
- System.out.println( "--------------------------" );
- System.out.println( "After sleep. " + timer.getElapsedTimeString() + " memory used = "
- + measureMemoryUse() );
- System.out.println( jcs.getStats() );
- }
-
- // Test that all items are in cache
- System.out.println( "--------------------------" );
- System.out.println( "Retrieving all." );
- for ( int i = 0; i <= items; i++ )
- {
- //System.out.print( "\033[s" );
- String value = jcs.get( i + ":key" );
- if ( i % 1000 == 0 )
- {
- //System.out.print( "\033[r" );
- System.out.println( i + " " );
- }
- assertEquals( "Wrong value returned.", region + " data " + i, value );
- }
- long aftetGet = measureMemoryUse();
- System.out.println( "After get: " + aftetGet + " diff = " + ( aftetGet - initialMemory ) );
-
- }
- finally
- {
- // dump the stats to the report
- System.out.println( jcs.getStats() );
- System.out.println( "--------------------------" );
- long endMemory = measureMemoryUse();
- System.out.println( "End: " + endMemory + " diff = " + ( endMemory - initialMemory ) );
- }
- }
-
- /**
- * Measure memory used by the VM.
- * @return long
- * @throws InterruptedException
- */
- protected long measureMemoryUse()
- throws InterruptedException
- {
- System.gc();
- Thread.sleep( 3000 );
- System.gc();
- return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/DiskTestObjectUtil.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/DiskTestObjectUtil.java
deleted file mode 100644
index eca8864..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/DiskTestObjectUtil.java
+++ /dev/null
@@ -1,143 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.Random;
-
-import org.apache.commons.jcs.auxiliary.disk.DiskTestObject;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.utils.serialization.StandardSerializer;
-
-/**
- * Utility for dealing with test objects.
- * <p>
- * @author Aaron Smuts
- */
-public class DiskTestObjectUtil
-{
- /**
- * Total from the start to the endPostion.
- * <p>
- * @param testObjects
- * @param endPosition
- * @return size
- * @throws IOException
- */
- public static long totalSize( DiskTestObject[] testObjects, int endPosition )
- throws IOException
- {
- StandardSerializer serializer = new StandardSerializer();
- long total = 0;
- for ( int i = 0; i < endPosition; i++ )
- {
- int tileSize = serializer.serialize( testObjects[i] ).length + IndexedDisk.HEADER_SIZE_BYTES;
- total += tileSize;
- }
- return total;
- }
-
- /**
- * Total from the start to the endPostion.
- * <p>
- * @param elements
- * @param endPosition
- * @return size
- * @throws IOException
- */
- public static <K, V> long totalSize( ICacheElement<K, V>[] elements, int endPosition )
- throws IOException
- {
- return totalSize( elements, 0, endPosition );
- }
-
- /**
- * Total from the start to the endPostion.
- * <p>
- * @param elements
- * @param startPosition
- * @param endPosition
- * @return size
- * @throws IOException
- */
- public static <K, V> long totalSize( ICacheElement<K, V>[] elements, int startPosition, int endPosition )
- throws IOException
- {
- StandardSerializer serializer = new StandardSerializer();
- long total = 0;
- for ( int i = startPosition; i < endPosition; i++ )
- {
- int tileSize = serializer.serialize( elements[i] ).length + IndexedDisk.HEADER_SIZE_BYTES;
- total += tileSize;
- }
- return total;
- }
-
- /**
- * Creates an array of ICacheElements with DiskTestObjects with payloads the byte size.
- * <p>
- * @param numToCreate
- * @param bytes
- * @param cacheName
- * @return ICacheElement[]
- */
- public static ICacheElement<Integer, DiskTestObject>[] createCacheElementsWithTestObjects( int numToCreate, int bytes, String cacheName )
- {
- @SuppressWarnings("unchecked")
- ICacheElement<Integer, DiskTestObject>[] elements = new ICacheElement[numToCreate];
- for ( int i = 0; i < numToCreate; i++ )
- {
- // 24 KB
- int size = bytes * 1024;
- DiskTestObject tile = new DiskTestObject( Integer.valueOf( i ), new byte[size] );
-
- ICacheElement<Integer, DiskTestObject> element = new CacheElement<>( cacheName, tile.id, tile );
- elements[i] = element;
- }
- return elements;
- }
-
- /**
- * Creates an array of ICacheElements with DiskTestObjects with payloads the byte size.
- * <p>
- * @param numToCreate
- * @param cacheName
- * @return ICacheElement[]
- */
- public static ICacheElement<Integer, DiskTestObject>[] createCacheElementsWithTestObjectsOfVariableSizes( int numToCreate, String cacheName )
- {
- @SuppressWarnings("unchecked")
- ICacheElement<Integer, DiskTestObject>[] elements = new ICacheElement[numToCreate];
- Random random = new Random( 89 );
- for ( int i = 0; i < numToCreate; i++ )
- {
- int bytes = random.nextInt( 20 );
- // 4-24 KB
- int size = ( bytes + 4 ) * 1024;
- DiskTestObject tile = new DiskTestObject( Integer.valueOf( i ), new byte[size] );
-
- ICacheElement<Integer, DiskTestObject> element = new CacheElement<>( cacheName, tile.id, tile );
- elements[i] = element;
- }
- return elements;
- }
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/HugeQuantityIndDiskCacheLoadTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/HugeQuantityIndDiskCacheLoadTest.java
deleted file mode 100644
index fc082cb..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/HugeQuantityIndDiskCacheLoadTest.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-
-/**
- * Put a few hundred thousand entries in the disk cache.
- * <p>
- * @author Aaron Smuts
- */
-public class HugeQuantityIndDiskCacheLoadTest
- extends TestCase
-{
- /** Test setup. */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestDiskCacheHuge.ccf" );
- }
-
- /**
- * Adds items to cache, gets them, and removes them. The item count is more than the size of the
- * memory cache, so items should spool to disk.
- * <p>
- * @throws Exception If an error occurs
- */
- public void testLargeNumberOfItems()
- throws Exception
- {
- int items = 300000;
- String region = "testCache1";
-
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-
- try
- {
- System.out.println( "Start: " + measureMemoryUse() );
-
- // Add items to cache
-
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
-
- System.out.println( jcs.getStats() );
- System.out.println( "--------------------------" );
- System.out.println( "After put: " + measureMemoryUse() );
-
- Thread.sleep( 5000 );
-
- System.out.println( jcs.getStats() );
- System.out.println( "--------------------------" );
- System.out.println( "After wait: " + measureMemoryUse() );
-
- // Test that all items are in cache
-
- for ( int i = 0; i <= items; i++ )
- {
- String value = jcs.get( i + ":key" );
-
- assertEquals( region + " data " + i, value );
- }
-
- System.out.println( "After get: " + measureMemoryUse() );
-
- // // Remove all the items
- // for ( int i = 0; i <= items; i++ )
- // {
- // jcs.remove( i + ":key" );
- // }
- //
- // // Verify removal
- // for ( int i = 0; i <= items; i++ )
- // {
- // assertNull( "Removed key should be null: " + i + ":key" + "\n
- // stats " + jcs.getStats(), jcs.get( i + ":key" ) );
- // }
-
- }
- finally
- {
- // dump the stats to the report
- System.out.println( jcs.getStats() );
- System.out.println( "--------------------------" );
- System.out.println( "End: " + measureMemoryUse() );
- }
- }
-
- /**
- * Measure memory used by the VM.
- * <p>
- * @return memory used
- * @throws InterruptedException
- */
- protected long measureMemoryUse()
- throws InterruptedException
- {
- System.gc();
- Thread.sleep( 3000 );
- System.gc();
- return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexDiskCacheCountUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexDiskCacheCountUnitTest.java
deleted file mode 100644
index ef8eea3..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexDiskCacheCountUnitTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-
-import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-public class IndexDiskCacheCountUnitTest extends IndexDiskCacheUnitTestAbstract {
-
- @Override
- public IndexedDiskCacheAttributes getCacheAttributes() {
- IndexedDiskCacheAttributes ret = new IndexedDiskCacheAttributes();
- ret.setDiskLimitType(DiskLimitType.COUNT);
- return ret;
- }
- public void testRecycleBin()
- throws IOException
- {
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName( "testRemoveItems" );
- cattr.setOptimizeAtRemoveCount( 7 );
- cattr.setMaxKeySize( 5 );
- cattr.setMaxPurgatorySize( 0 );
- cattr.setDiskPath( "target/test-sandbox/BreakIndexTest" );
- IndexedDiskCache<String, String> disk = new IndexedDiskCache<>( cattr );
-
- String[] test = { "a", "bb", "ccc", "dddd", "eeeee", "ffffff", "ggggggg", "hhhhhhhhh", "iiiiiiiiii" };
- String[] expect = { null, "bb", "ccc", null, null, "ffffff", null, "hhhhhhhhh", "iiiiiiiiii" };
-
- //System.out.println( "------------------------- testRecycleBin " );
-
- for ( int i = 0; i < 6; i++ )
- {
- ICacheElement<String, String> element = new CacheElement<>( "testRecycleBin", "key:" + test[i], test[i] );
- //System.out.println( "About to add " + "key:" + test[i] + " i = " + i );
- disk.processUpdate( element );
- }
-
- for ( int i = 3; i < 5; i++ )
- {
- //System.out.println( "About to remove " + "key:" + test[i] + " i = " + i );
- disk.remove( "key:" + test[i] );
- }
-
- // there was a bug where 7 would try to be put in the empty slot left by 4's removal, but it
- // will not fit.
- for ( int i = 7; i < 9; i++ )
- {
- ICacheElement<String, String> element = new CacheElement<>( "testRecycleBin", "key:" + test[i], test[i] );
- //System.out.println( "About to add " + "key:" + test[i] + " i = " + i );
- disk.processUpdate( element );
- }
-
- try
- {
- for ( int i = 0; i < 9; i++ )
- {
- ICacheElement<String, String> element = disk.get( "key:" + test[i] );
- if ( element != null )
- {
- //System.out.println( "element = " + element.getVal() );
- }
- else
- {
- //System.out.println( "null --" + "key:" + test[i] );
- }
-
- String expectedValue = expect[i];
- if ( expectedValue == null )
- {
- assertNull( "Expected a null element", element );
- }
- else
- {
- assertNotNull( "The element for key [" + "key:" + test[i] + "] should not be null. i = " + i,
- element );
- assertEquals( "Elements contents do not match expected", element.getVal(), expectedValue );
- }
- }
- }
- catch ( Exception e )
- {
- e.printStackTrace();
- fail( "Should not get an exception: " + e.toString() );
- }
-
- disk.removeAll();
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexDiskCacheSizeUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexDiskCacheSizeUnitTest.java
deleted file mode 100644
index 1a3456b..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexDiskCacheSizeUnitTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-
-import org.apache.commons.jcs.auxiliary.disk.DiskTestObject;
-import org.apache.commons.jcs.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-public class IndexDiskCacheSizeUnitTest extends IndexDiskCacheUnitTestAbstract {
-
- @Override
- public IndexedDiskCacheAttributes getCacheAttributes() {
- IndexedDiskCacheAttributes ret = new IndexedDiskCacheAttributes();
- ret.setDiskLimitType(DiskLimitType.SIZE);
- return ret;
- }
- public void testRecycleBin()
- throws IOException
- {
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName( "testRemoveItems" );
- cattr.setOptimizeAtRemoveCount( 7 );
- cattr.setMaxKeySize( 8); // 1kb DiskTestObject takes 1420 bytes, so 5*1420 = 7100, so to keep 5 ojbects, we need max key size of 8
- cattr.setMaxPurgatorySize( 0 );
- cattr.setDiskPath( "target/test-sandbox/BreakIndexTest" );
- IndexedDiskCache<String, DiskTestObject> disk = new IndexedDiskCache<>( cattr );
-
- String[] test = { "a", "bb", "ccc", "dddd", "eeeee", "ffffff", "ggggggg", "hhhhhhhhh", "iiiiiiiiii" };
- String[] expect = { null, "bb", "ccc", null, null, "ffffff", null, "hhhhhhhhh", "iiiiiiiiii" };
- DiskTestObject value = DiskTestObjectUtil.createCacheElementsWithTestObjects( 1, 1, cattr .getCacheName())[0].getVal();
- //System.out.println( "------------------------- testRecycleBin " );
-
- for ( int i = 0; i < 6; i++ )
- {
- ICacheElement<String, DiskTestObject> element = new CacheElement<>( "testRecycleBin", "key:" + test[i], value);
- //System.out.println( "About to add " + "key:" + test[i] + " i = " + i );
- disk.processUpdate( element );
- }
-
- for ( int i = 3; i < 5; i++ )
- {
- //System.out.println( "About to remove " + "key:" + test[i] + " i = " + i );
- disk.remove( "key:" + test[i] );
- }
-
- // there was a bug where 7 would try to be put in the empty slot left by 4's removal, but it
- // will not fit.
- for ( int i = 7; i < 9; i++ )
- {
- ICacheElement<String, DiskTestObject> element = new CacheElement<>( "testRecycleBin", "key:" + test[i], value);
- //System.out.println( "About to add " + "key:" + test[i] + " i = " + i );
- disk.processUpdate( element );
- }
-
- try
- {
- for ( int i = 0; i < 9; i++ )
- {
- ICacheElement<String, DiskTestObject> element = disk.get( "key:" + test[i] );
- if ( element != null )
- {
- //System.out.println( "element = " + element.getVal() );
- }
- else
- {
- //System.out.println( "null --" + "key:" + test[i] );
- }
-
- String expectedValue = expect[i];
- if ( expectedValue == null )
- {
- assertNull( "Expected a null element", element );
- }
- else
- {
- assertNotNull( "The element for key [" + "key:" + test[i] + "] should not be null. i = " + i,
- element );
- assertEquals( "Elements contents do not match expected", element.getVal(), value );
- }
- }
- }
- catch ( Exception e )
- {
- e.printStackTrace();
- fail( "Should not get an exception: " + e.toString() );
- }
-
- disk.removeAll();
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexDiskCacheUnitTestAbstract.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexDiskCacheUnitTestAbstract.java
deleted file mode 100644
index 3bc4eb8..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexDiskCacheUnitTestAbstract.java
+++ /dev/null
@@ -1,989 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.auxiliary.MockCacheEventLogger;
-import org.apache.commons.jcs.auxiliary.disk.DiskTestObject;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.ElementAttributes;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.control.group.GroupAttrName;
-import org.apache.commons.jcs.engine.control.group.GroupId;
-import org.apache.commons.jcs.utils.timing.SleepUtil;
-
-import junit.framework.TestCase;
-
-/**
- * Tests for common functionality.
- * <p>
- *
- * @author Aaron Smuts
- */
-public abstract class IndexDiskCacheUnitTestAbstract extends TestCase
-{
- public abstract IndexedDiskCacheAttributes getCacheAttributes();
-
- /**
- * Simply verify that we can put items in the disk cache and retrieve them.
- *
- * @throws IOException
- */
- public void testSimplePutAndGet() throws IOException
- {
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName("testSimplePutAndGet");
- cattr.setMaxKeySize(1000);
- cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
- IndexedDiskCache<String, String> disk = new IndexedDiskCache<>(cattr);
-
- disk.processRemoveAll();
-
- int cnt = 999;
- for (int i = 0; i < cnt; i++)
- {
- IElementAttributes eAttr = new ElementAttributes();
- eAttr.setIsSpool(true);
- ICacheElement<String, String> element = new CacheElement<>("testSimplePutAndGet", "key:" + i, "data:" + i);
- element.setElementAttributes(eAttr);
- disk.processUpdate(element);
- }
-
- for (int i = 0; i < cnt; i++)
- {
- ICacheElement<String, String> element = disk.processGet("key:" + i);
- assertNotNull("Should have received an element.", element);
- assertEquals("Element is wrong.", "data:" + i, element.getVal());
- }
-
- // Test that getMultiple returns all the expected values
- Set<String> keys = new HashSet<>();
- for (int i = 0; i < cnt; i++)
- {
- keys.add("key:" + i);
- }
-
- Map<String, ICacheElement<String, String>> elements = disk.getMultiple(keys);
- for (int i = 0; i < cnt; i++)
- {
- ICacheElement<String, String> element = elements.get("key:" + i);
- assertNotNull("element " + i + ":key is missing", element);
- assertEquals("value key:" + i, "data:" + i, element.getVal());
- }
- // System.out.println( disk.getStats() );
- }
-
- /**
- * Add some items to the disk cache and then remove them one by one.
- *
- * @throws IOException
- */
- public void testRemoveItems() throws IOException
- {
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName("testRemoveItems");
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
- IndexedDiskCache<String, String> disk = new IndexedDiskCache<>(cattr);
-
- disk.processRemoveAll();
-
- int cnt = 25;
- for (int i = 0; i < cnt; i++)
- {
- IElementAttributes eAttr = new ElementAttributes();
- eAttr.setIsSpool(true);
- ICacheElement<String, String> element = new CacheElement<>("testRemoveItems", "key:" + i, "data:" + i);
- element.setElementAttributes(eAttr);
- disk.processUpdate(element);
- }
-
- // remove each
- for (int i = 0; i < cnt; i++)
- {
- disk.remove("key:" + i);
- ICacheElement<String, String> element = disk.processGet("key:" + i);
- assertNull("Should not have received an element.", element);
- }
- }
-
- /**
- * Verify that we don't override the largest item.
- * <p>
- *
- * @throws IOException
- */
-
- /**
- * Verify that the overlap check returns true when there are no overlaps.
- */
- public void testCheckForDedOverlaps_noOverlap()
- {
- // SETUP
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName("testCheckForDedOverlaps_noOverlap");
- cattr.setDiskPath("target/test-sandbox/UnitTest");
- IndexedDiskCache<String, String> disk = new IndexedDiskCache<>(cattr);
-
- int numDescriptors = 5;
- int pos = 0;
- IndexedDiskElementDescriptor[] sortedDescriptors = new IndexedDiskElementDescriptor[numDescriptors];
- for (int i = 0; i < numDescriptors; i++)
- {
- IndexedDiskElementDescriptor descriptor = new IndexedDiskElementDescriptor(pos, i * 2);
- pos = pos + (i * 2) + IndexedDisk.HEADER_SIZE_BYTES;
- sortedDescriptors[i] = descriptor;
- }
-
- // DO WORK
- boolean result = disk.checkForDedOverlaps(sortedDescriptors);
-
- // VERIFY
- assertTrue("There should be no overlap. it should be ok", result);
- }
-
- /**
- * Verify that the overlap check returns false when there are overlaps.
- */
- public void testCheckForDedOverlaps_overlaps()
- {
- // SETUP
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName("testCheckForDedOverlaps_overlaps");
- cattr.setDiskPath("target/test-sandbox/UnitTest");
- IndexedDiskCache<String, String> disk = new IndexedDiskCache<>(cattr);
-
- int numDescriptors = 5;
- int pos = 0;
- IndexedDiskElementDescriptor[] sortedDescriptors = new IndexedDiskElementDescriptor[numDescriptors];
- for (int i = 0; i < numDescriptors; i++)
- {
- IndexedDiskElementDescriptor descriptor = new IndexedDiskElementDescriptor(pos, i * 2);
- // don't add the header + IndexedDisk.RECORD_HEADER;
- pos = pos + (i * 2);
- sortedDescriptors[i] = descriptor;
- }
-
- // DO WORK
- boolean result = disk.checkForDedOverlaps(sortedDescriptors);
-
- // VERIFY
- assertFalse("There should be overlaps. it should be not ok", result);
- }
-
- /**
- * Verify that the file size is as expected.
- * <p>
- *
- * @throws IOException
- * @throws InterruptedException
- */
- public void testFileSize() throws IOException, InterruptedException
- {
- // SETUP
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName("testFileSize");
- cattr.setDiskPath("target/test-sandbox/UnitTest");
- IndexedDiskCache<Integer, DiskTestObject> disk = new IndexedDiskCache<>(cattr);
-
- int numberToInsert = 20;
- int bytes = 24;
- ICacheElement<Integer, DiskTestObject>[] elements = DiskTestObjectUtil.createCacheElementsWithTestObjects(numberToInsert,
- bytes, cattr.getCacheName());
-
- for (int i = 0; i < elements.length; i++)
- {
- disk.processUpdate(elements[i]);
- }
-
- Thread.yield();
- Thread.sleep(100);
- Thread.yield();
-
- long expectedSize = DiskTestObjectUtil.totalSize(elements, numberToInsert);
- long resultSize = disk.getDataFileSize();
-
- // System.out.println( "testFileSize stats " + disk.getStats() );
-
- assertEquals("Wrong file size", expectedSize, resultSize);
- }
-
- /**
- * Verify that items are added to the recycle bin on removal.
- * <p>
- *
- * @throws IOException
- * @throws InterruptedException
- */
- public void testRecyleBinSize() throws IOException, InterruptedException
- {
- // SETUP
- int numberToInsert = 20;
-
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName("testRecyleBinSize");
- cattr.setDiskPath("target/test-sandbox/UnitTest");
- cattr.setOptimizeAtRemoveCount(numberToInsert);
- cattr.setMaxKeySize(numberToInsert * 2);
- cattr.setMaxPurgatorySize(numberToInsert);
- IndexedDiskCache<Integer, DiskTestObject> disk = new IndexedDiskCache<>(cattr);
-
- int bytes = 1;
- ICacheElement<Integer, DiskTestObject>[] elements = DiskTestObjectUtil.createCacheElementsWithTestObjects(numberToInsert,
- bytes, cattr.getCacheName());
-
- for (int i = 0; i < elements.length; i++)
- {
- disk.processUpdate(elements[i]);
- }
-
- Thread.yield();
- Thread.sleep(100);
- Thread.yield();
-
- // remove half
- int numberToRemove = elements.length / 2;
- for (int i = 0; i < numberToRemove; i++)
- {
- disk.processRemove(elements[i].getKey());
- }
-
- // verify that the recycle bin has the correct amount.
- assertEquals("The recycle bin should have the number removed.", numberToRemove, disk.getRecyleBinSize());
- }
-
- /**
- * Verify that items of the same size use recycle bin spots. Setup the recycle bin by removing
- * some items. Add some of the same size. Verify that the recycle count is the number added.
- * <p>
- *
- * @throws IOException
- * @throws InterruptedException
- */
- public void testRecyleBinUsage() throws IOException, InterruptedException
- {
- // SETUP
- int numberToInsert = 20;
-
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName("testRecyleBinUsage");
- cattr.setDiskPath("target/test-sandbox/UnitTest");
- cattr.setOptimizeAtRemoveCount(numberToInsert);
- cattr.setMaxKeySize(numberToInsert * 2);
- cattr.setMaxPurgatorySize(numberToInsert);
- IndexedDiskCache<Integer, DiskTestObject> disk = new IndexedDiskCache<>(cattr);
-
- // we will reuse these
- int bytes = 1;
- ICacheElement<Integer, DiskTestObject>[] elements = DiskTestObjectUtil.createCacheElementsWithTestObjects(numberToInsert,
- bytes, cattr.getCacheName());
-
- // Add some to the disk
- for (int i = 0; i < elements.length; i++)
- {
- disk.processUpdate(elements[i]);
- }
-
- Thread.yield();
- Thread.sleep(100);
- Thread.yield();
-
- // remove half of those added
- int numberToRemove = elements.length / 2;
- for (int i = 0; i < numberToRemove; i++)
- {
- disk.processRemove(elements[i].getKey());
- }
-
- // verify that the recycle bin has the correct amount.
- assertEquals("The recycle bin should have the number removed.", numberToRemove, disk.getRecyleBinSize());
-
- // add half as many as we removed. These should all use spots in the recycle bin.
- int numberToAdd = numberToRemove / 2;
- for (int i = 0; i < numberToAdd; i++)
- {
- disk.processUpdate(elements[i]);
- }
-
- // verify that we used the correct number of spots
- assertEquals("The recycle bin should have the number removed." + disk.getStats(), numberToAdd, disk.getRecyleCount());
- }
-
- /**
- * Verify that the data size is as expected after a remove and after a put that should use the
- * spots.
- * <p>
- *
- * @throws IOException
- * @throws InterruptedException
- */
- public void testBytesFreeSize() throws IOException, InterruptedException
- {
- // SETUP
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName("testBytesFreeSize");
- cattr.setDiskPath("target/test-sandbox/UnitTest");
- IndexedDiskCache<Integer, DiskTestObject> disk = new IndexedDiskCache<>(cattr);
-
- int numberToInsert = 20;
- int bytes = 24;
- ICacheElement<Integer, DiskTestObject>[] elements = DiskTestObjectUtil.createCacheElementsWithTestObjects(numberToInsert,
- bytes, cattr.getCacheName());
-
- for (int i = 0; i < elements.length; i++)
- {
- disk.processUpdate(elements[i]);
- }
-
- Thread.yield();
- Thread.sleep(100);
- Thread.yield();
-
- // remove half of those added
- int numberToRemove = elements.length / 2;
- for (int i = 0; i < numberToRemove; i++)
- {
- disk.processRemove(elements[i].getKey());
- }
-
- long expectedSize = DiskTestObjectUtil.totalSize(elements, numberToRemove);
- long resultSize = disk.getBytesFree();
-
- // System.out.println( "testBytesFreeSize stats " + disk.getStats() );
-
- assertEquals("Wrong bytes free size" + disk.getStats(), expectedSize, resultSize);
-
- // add half as many as we removed. These should all use spots in the recycle bin.
- int numberToAdd = numberToRemove / 2;
- for (int i = 0; i < numberToAdd; i++)
- {
- disk.processUpdate(elements[i]);
- }
-
- long expectedSize2 = DiskTestObjectUtil.totalSize(elements, numberToAdd);
- long resultSize2 = disk.getBytesFree();
- assertEquals("Wrong bytes free size" + disk.getStats(), expectedSize2, resultSize2);
- }
-
- /**
- * Add some items to the disk cache and then remove them one by one.
- * <p>
- *
- * @throws IOException
- */
- public void testRemove_PartialKey() throws IOException
- {
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName("testRemove_PartialKey");
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
- IndexedDiskCache<String, String> disk = new IndexedDiskCache<>(cattr);
-
- disk.processRemoveAll();
-
- int cnt = 25;
- for (int i = 0; i < cnt; i++)
- {
- IElementAttributes eAttr = new ElementAttributes();
- eAttr.setIsSpool(true);
- ICacheElement<String, String> element = new CacheElement<>("testRemove_PartialKey", i + ":key", "data:"
- + i);
- element.setElementAttributes(eAttr);
- disk.processUpdate(element);
- }
-
- // verif each
- for (int i = 0; i < cnt; i++)
- {
- ICacheElement<String, String> element = disk.processGet(i + ":key");
- assertNotNull("Shoulds have received an element.", element);
- }
-
- // remove each
- for (int i = 0; i < cnt; i++)
- {
- disk.remove(i + ":");
- ICacheElement<String, String> element = disk.processGet(i + ":key");
- assertNull("Should not have received an element.", element);
- }
- // https://issues.apache.org/jira/browse/JCS-67
- assertEquals("Recylenbin should not have more elements than we removed. Check for JCS-67", cnt, disk.getRecyleBinSize());
- }
-
- /**
- * Verify that group members are removed if we call remove with a group.
- *
- * @throws IOException
- */
- public void testRemove_Group() throws IOException
- {
- // SETUP
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName("testRemove_Group");
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
- IndexedDiskCache<GroupAttrName<String>, String> disk = new IndexedDiskCache<>(cattr);
-
- disk.processRemoveAll();
-
- String cacheName = "testRemove_Group_Region";
- String groupName = "testRemove_Group";
-
- int cnt = 25;
- for (int i = 0; i < cnt; i++)
- {
- GroupAttrName<String> groupAttrName = getGroupAttrName(cacheName, groupName, i + ":key");
- CacheElement<GroupAttrName<String>, String> element = new CacheElement<>(cacheName,
- groupAttrName, "data:" + i);
-
- IElementAttributes eAttr = new ElementAttributes();
- eAttr.setIsSpool(true);
- element.setElementAttributes(eAttr);
-
- disk.processUpdate(element);
- }
-
- // verify each
- for (int i = 0; i < cnt; i++)
- {
- GroupAttrName<String> groupAttrName = getGroupAttrName(cacheName, groupName, i + ":key");
- ICacheElement<GroupAttrName<String>, String> element = disk.processGet(groupAttrName);
- assertNotNull("Should have received an element.", element);
- }
-
- // DO WORK
- // remove the group
- disk.remove(getGroupAttrName(cacheName, groupName, null));
-
- for (int i = 0; i < cnt; i++)
- {
- GroupAttrName<String> groupAttrName = getGroupAttrName(cacheName, groupName, i + ":key");
- ICacheElement<GroupAttrName<String>, String> element = disk.processGet(groupAttrName);
-
- // VERIFY
- assertNull("Should not have received an element.", element);
- }
-
- }
-
- /**
- * Internal method used for group functionality.
- * <p>
- *
- * @param cacheName
- * @param group
- * @param name
- * @return GroupAttrName
- */
- private GroupAttrName<String> getGroupAttrName(String cacheName, String group, String name)
- {
- GroupId gid = new GroupId(cacheName, group);
- return new GroupAttrName<>(gid, name);
- }
-
- /**
- * Verify event log calls.
- * <p>
- *
- * @throws Exception
- */
- public void testUpdate_EventLogging_simple() throws Exception
- {
- // SETUP
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName("testUpdate_EventLogging_simple");
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTestCEL");
- IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
- diskCache.processRemoveAll();
-
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- diskCache.setCacheEventLogger(cacheEventLogger);
-
- ICacheElement<String, String> item = new CacheElement<>("region", "key", "value");
-
- // DO WORK
- diskCache.update(item);
-
- SleepUtil.sleepAtLeast(200);
-
- // VERIFY
- assertEquals("Start should have been called.", 1, cacheEventLogger.startICacheEventCalls);
- assertEquals("End should have been called.", 1, cacheEventLogger.endICacheEventCalls);
- }
-
- /**
- * Verify event log calls.
- * <p>
- *
- * @throws Exception
- */
- public void testGet_EventLogging_simple() throws Exception
- {
- // SETUP
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName("testGet_EventLogging_simple");
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTestCEL");
- IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
- diskCache.processRemoveAll();
-
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- diskCache.setCacheEventLogger(cacheEventLogger);
-
- // DO WORK
- diskCache.get("key");
-
- // VERIFY
- assertEquals("Start should have been called.", 1, cacheEventLogger.startICacheEventCalls);
- assertEquals("End should have been called.", 1, cacheEventLogger.endICacheEventCalls);
- }
-
- /**
- * Verify event log calls.
- * <p>
- *
- * @throws Exception
- */
- public void testGetMultiple_EventLogging_simple() throws Exception
- {
- // SETUP
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName("testGetMultiple_EventLogging_simple");
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTestCEL");
- IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
- diskCache.processRemoveAll();
-
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- diskCache.setCacheEventLogger(cacheEventLogger);
-
- Set<String> keys = new HashSet<>();
- keys.add("junk");
-
- // DO WORK
- diskCache.getMultiple(keys);
-
- // VERIFY
- // 1 for get multiple and 1 for get.
- assertEquals("Start should have been called.", 2, cacheEventLogger.startICacheEventCalls);
- assertEquals("End should have been called.", 2, cacheEventLogger.endICacheEventCalls);
- }
-
- /**
- * Verify event log calls.
- * <p>
- *
- * @throws Exception
- */
- public void testRemove_EventLogging_simple() throws Exception
- {
- // SETUP
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName("testRemoveAll_EventLogging_simple");
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTestCEL");
- IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
- diskCache.processRemoveAll();
-
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- diskCache.setCacheEventLogger(cacheEventLogger);
-
- // DO WORK
- diskCache.remove("key");
-
- // VERIFY
- assertEquals("Start should have been called.", 1, cacheEventLogger.startICacheEventCalls);
- assertEquals("End should have been called.", 1, cacheEventLogger.endICacheEventCalls);
- }
-
- /**
- * Verify event log calls.
- * <p>
- *
- * @throws Exception
- */
- public void testRemoveAll_EventLogging_simple() throws Exception
- {
- // SETUP
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName("testRemoveAll_EventLogging_simple");
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTestCEL");
- IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
- diskCache.processRemoveAll();
-
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- diskCache.setCacheEventLogger(cacheEventLogger);
-
- // DO WORK
- diskCache.remove("key");
-
- // VERIFY
- assertEquals("Start should have been called.", 1, cacheEventLogger.startICacheEventCalls);
- assertEquals("End should have been called.", 1, cacheEventLogger.endICacheEventCalls);
- }
-
- /**
- * Test the basic get matching.
- * <p>
- *
- * @throws Exception
- */
- public void testPutGetMatching_SmallWait() throws Exception
- {
- // SETUP
- int items = 200;
-
- String cacheName = "testPutGetMatching_SmallWait";
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
- IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
-
- // DO WORK
- for (int i = 0; i <= items; i++)
- {
- diskCache.update(new CacheElement<>(cacheName, i + ":key", cacheName + " data " + i));
- }
- Thread.sleep(500);
-
- Map<String, ICacheElement<String, String>> matchingResults = diskCache.getMatching("1.8.+");
-
- // VERIFY
- assertEquals("Wrong number returned", 10, matchingResults.size());
- // System.out.println( "matchingResults.keySet() " + matchingResults.keySet() );
- // System.out.println( "\nAFTER TEST \n" + diskCache.getStats() );
- }
-
- /**
- * Test the basic get matching. With no wait this will all come from purgatory.
- * <p>
- *
- * @throws Exception
- */
- public void testPutGetMatching_NoWait() throws Exception
- {
- // SETUP
- int items = 200;
-
- String cacheName = "testPutGetMatching_NoWait";
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
- IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
-
- // DO WORK
- for (int i = 0; i <= items; i++)
- {
- diskCache.update(new CacheElement<>(cacheName, i + ":key", cacheName + " data " + i));
- }
-
- Map<String, ICacheElement<String, String>> matchingResults = diskCache.getMatching("1.8.+");
-
- // VERIFY
- assertEquals("Wrong number returned", 10, matchingResults.size());
- // System.out.println( "matchingResults.keySet() " + matchingResults.keySet() );
- // System.out.println( "\nAFTER TEST \n" + diskCache.getStats() );
- }
-
- /**
- * Verify that the block disk cache can handle utf encoded strings.
- * <p>
- *
- * @throws Exception
- */
- public void testUTF8String() throws Exception
- {
- String string = "IÒtÎrn‚tiÙn‡lizÊti¯n";
- StringBuilder sb = new StringBuilder();
- sb.append(string);
- for (int i = 0; i < 4; i++)
- {
- sb.append(sb.toString()); // big string
- }
- string = sb.toString();
-
- // System.out.println( "The string contains " + string.length() + " characters" );
-
- String cacheName = "testUTF8String";
-
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
- IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
-
- // DO WORK
- diskCache.update(new CacheElement<>(cacheName, "x", string));
-
- // VERIFY
- assertNotNull(diskCache.get("x"));
- Thread.sleep(1000);
- ICacheElement<String, String> afterElement = diskCache.get("x");
- assertNotNull(afterElement);
- // System.out.println( "afterElement = " + afterElement );
- String after = afterElement.getVal();
-
- assertNotNull(after);
- assertEquals("wrong string after retrieval", string, after);
- }
-
- /**
- * Verify that the block disk cache can handle utf encoded strings.
- * <p>
- *
- * @throws Exception
- */
- public void testUTF8ByteArray() throws Exception
- {
- String string = "IÒtÎrn‚tiÙn‡lizÊti¯n";
- StringBuilder sb = new StringBuilder();
- sb.append(string);
- for (int i = 0; i < 4; i++)
- {
- sb.append(sb.toString()); // big string
- }
- string = sb.toString();
- // System.out.println( "The string contains " + string.length() + " characters" );
- byte[] bytes = string.getBytes(StandardCharsets.UTF_8);
-
- String cacheName = "testUTF8ByteArray";
-
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
- IndexedDiskCache<String, byte[]> diskCache = new IndexedDiskCache<>(cattr);
-
- // DO WORK
- diskCache.update(new CacheElement<>(cacheName, "x", bytes));
-
- // VERIFY
- assertNotNull(diskCache.get("x"));
- Thread.sleep(1000);
- ICacheElement<String, byte[]> afterElement = diskCache.get("x");
- assertNotNull(afterElement);
- // System.out.println( "afterElement = " + afterElement );
- byte[] after = afterElement.getVal();
-
- assertNotNull(after);
- assertEquals("wrong bytes after retrieval", string, new String(after, StandardCharsets.UTF_8));
- }
-
- /**
- * Verify the item makes it to disk.
- * <p>
- *
- * @throws IOException
- */
- public void testProcessUpdate_Simple() throws IOException
- {
- // SETUP
- String cacheName = "testProcessUpdate_Simple";
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
- IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
-
- String key = "myKey";
- String value = "myValue";
- ICacheElement<String, String> ce = new CacheElement<>(cacheName, key, value);
-
- // DO WORK
- diskCache.processUpdate(ce);
- ICacheElement<String, String> result = diskCache.processGet(key);
-
- // VERIFY
- assertNotNull("Should have a result", result);
- long fileSize = diskCache.getDataFileSize();
- assertTrue("File should be greater than 0", fileSize > 0);
- }
-
- /**
- * Verify the item makes it to disk.
- * <p>
- *
- * @throws IOException
- */
- public void testProcessUpdate_SameKeySameSize() throws IOException
- {
- // SETUP
- String cacheName = "testProcessUpdate_SameKeySameSize";
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
- IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
-
- String key = "myKey";
- String value = "myValue";
- ICacheElement<String, String> ce1 = new CacheElement<>(cacheName, key, value);
-
- // DO WORK
- diskCache.processUpdate(ce1);
- long fileSize1 = diskCache.getDataFileSize();
-
- // DO WORK
- ICacheElement<String, String> ce2 = new CacheElement<>(cacheName, key, value);
- diskCache.processUpdate(ce2);
- ICacheElement<String, String> result = diskCache.processGet(key);
-
- // VERIFY
- assertNotNull("Should have a result", result);
- long fileSize2 = diskCache.getDataFileSize();
- assertEquals("File should be the same", fileSize1, fileSize2);
- int binSize = diskCache.getRecyleBinSize();
- assertEquals("Should be nothing in the bin.", 0, binSize);
- }
-
- /**
- * Verify the item makes it to disk.
- * <p>
- *
- * @throws IOException
- */
- public void testProcessUpdate_SameKeySmallerSize() throws IOException
- {
- // SETUP
- String cacheName = "testProcessUpdate_SameKeySmallerSize";
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
- IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
-
- String key = "myKey";
- String value = "myValue";
- String value2 = "myValu";
- ICacheElement<String, String> ce1 = new CacheElement<>(cacheName, key, value);
-
- // DO WORK
- diskCache.processUpdate(ce1);
- long fileSize1 = diskCache.getDataFileSize();
-
- // DO WORK
- ICacheElement<String, String> ce2 = new CacheElement<>(cacheName, key, value2);
- diskCache.processUpdate(ce2);
- ICacheElement<String, String> result = diskCache.processGet(key);
-
- // VERIFY
- assertNotNull("Should have a result", result);
- long fileSize2 = diskCache.getDataFileSize();
- assertEquals("File should be the same", fileSize1, fileSize2);
- int binSize = diskCache.getRecyleBinSize();
- assertEquals("Should be nothing in the bin.", 0, binSize);
- }
-
- /**
- * Verify that the old slot gets in the recycle bin.
- * <p>
- *
- * @throws IOException
- */
- public void testProcessUpdate_SameKeyBiggerSize() throws IOException
- {
- // SETUP
- String cacheName = "testProcessUpdate_SameKeyBiggerSize";
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
- IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
-
- String key = "myKey";
- String value = "myValue";
- String value2 = "myValue2";
- ICacheElement<String, String> ce1 = new CacheElement<>(cacheName, key, value);
-
- // DO WORK
- diskCache.processUpdate(ce1);
- long fileSize1 = diskCache.getDataFileSize();
-
- // DO WORK
- ICacheElement<String, String> ce2 = new CacheElement<>(cacheName, key, value2);
- diskCache.processUpdate(ce2);
- ICacheElement<String, String> result = diskCache.processGet(key);
-
- // VERIFY
- assertNotNull("Should have a result", result);
- long fileSize2 = diskCache.getDataFileSize();
- assertTrue("File should be greater.", fileSize1 < fileSize2);
- int binSize = diskCache.getRecyleBinSize();
- assertEquals("Should be one in the bin.", 1, binSize);
- }
-
- public void testLoadFromDisk() throws Exception
- {
- for (int i = 0; i < 15; i++)
- { // usually after 2 time it fails
- oneLoadFromDisk();
- }
- }
-
- public void oneLoadFromDisk() throws Exception
- {
- // initialize object to be stored
- String string = "IÒtÎrn‚tiÙn‡lizÊti¯n";
- StringBuilder sb = new StringBuilder();
- sb.append(string);
- for (int i = 0; i < 4; i++)
- {
- sb.append(sb.toString()); // big string
- }
- string = sb.toString();
-
- // initialize cache
- String cacheName = "testLoadFromDisk";
- IndexedDiskCacheAttributes cattr = getCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMaxKeySize(100);
- cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
- IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
-
- // DO WORK
- for (int i = 0; i < 50; i++)
- {
- diskCache.update(new CacheElement<>(cacheName, "x" + i, string));
- }
- // Thread.sleep(1000);
- // VERIFY
- diskCache.dispose();
- // Thread.sleep(1000);
-
- diskCache = new IndexedDiskCache<>(cattr);
-
- for (int i = 0; i < 50; i++)
- {
- ICacheElement<String, String> afterElement = diskCache.get("x" + i);
- assertNotNull("Missing element from cache. Cache size: " + diskCache.getSize() + " element: x" + i, afterElement);
- assertEquals("wrong string after retrieval", string, afterElement.getVal());
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheConcurrentNoDeadLockUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheConcurrentNoDeadLockUnitTest.java
deleted file mode 100644
index eca55d6..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheConcurrentNoDeadLockUnitTest.java
+++ /dev/null
@@ -1,148 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import junit.extensions.ActiveTestSuite;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.textui.TestRunner;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-
-/**
- * Test which exercises the indexed disk cache. Runs three threads against the
- * same region.
- *
- * @version $Id: TestDiskCacheConcurrentForDeadLock.java,v 1.2 2005/02/01
- * 00:01:59 asmuts Exp $
- */
-public class IndexedDiskCacheConcurrentNoDeadLockUnitTest
- extends TestCase
-{
- /**
- * Constructor for the TestDiskCache object.
- *
- * @param testName
- */
- public IndexedDiskCacheConcurrentNoDeadLockUnitTest( String testName )
- {
- super( testName );
- }
-
- /**
- * Main method passes this test to the text test runner.
- *
- * @param args
- */
- public static void main( String args[] )
- {
- String[] testCaseName = { IndexedDiskCacheConcurrentNoDeadLockUnitTest.class.getName() };
- TestRunner.main( testCaseName );
- }
-
- /**
- * A unit test suite for JUnit
- *
- * @return The test suite
- */
- public static Test suite()
- {
- ActiveTestSuite suite = new ActiveTestSuite();
-
- suite.addTest( new IndexedDiskCacheRandomConcurrentTestUtil( "testIndexedDiskCache1" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion4", 1, 200, 1 );
- }
- } );
-
- suite.addTest( new IndexedDiskCacheRandomConcurrentTestUtil( "testIndexedDiskCache2" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion4", 10000, 50000, 2 );
- }
- } );
-
- suite.addTest( new IndexedDiskCacheRandomConcurrentTestUtil( "testIndexedDiskCache3" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion4", 10000, 50000, 3 );
- }
- } );
-
- suite.addTest( new IndexedDiskCacheRandomConcurrentTestUtil( "testIndexedDiskCache4" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion4", 10000, 50000, 4 );
- }
- } );
-
- suite.addTest( new IndexedDiskCacheRandomConcurrentTestUtil( "testIndexedDiskCache5" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion4", 10000, 50000, 5 );
- }
- } );
-
- return suite;
- }
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestDiskCacheCon.ccf" );
- }
-
- /**
- * Test tearDown. Dispose of the cache.
- */
- @Override
- public void tearDown()
- {
- try
- {
- CompositeCacheManager cacheMgr = CompositeCacheManager.getInstance();
- cacheMgr.shutDown();
- }
- catch ( Exception e )
- {
- // log.error(e);
- }
- }
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheConcurrentUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheConcurrentUnitTest.java
deleted file mode 100644
index 0661254..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheConcurrentUnitTest.java
+++ /dev/null
@@ -1,251 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import junit.extensions.ActiveTestSuite;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Test which exercises the indexed disk cache. This one uses three different
- * regions for thre threads.
- *
- * @version $Id$
- */
-public class IndexedDiskCacheConcurrentUnitTest
- extends TestCase
-{
- /**
- * Number of items to cache, twice the configured maxObjects for the memory
- * cache regions.
- */
- private static int items = 200;
-
- /**
- * Constructor for the TestDiskCache object.
- *
- * @param testName
- */
- public IndexedDiskCacheConcurrentUnitTest( String testName )
- {
- super( testName );
- }
-
- /**
- * Main method passes this test to the text test runner.
- *
- * @param args
- */
- public static void main( String args[] )
- {
- String[] testCaseName = { IndexedDiskCacheConcurrentUnitTest.class.getName() };
- junit.textui.TestRunner.main( testCaseName );
- }
-
- /**
- * A unit test suite for JUnit
- *
- * @return The test suite
- */
- public static Test suite()
- {
- ActiveTestSuite suite = new ActiveTestSuite();
-
- suite.addTest( new IndexedDiskCacheConcurrentUnitTest( "testIndexedDiskCache1" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion1" );
- }
- } );
-
- suite.addTest( new IndexedDiskCacheConcurrentUnitTest( "testIndexedDiskCache2" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion2" );
- }
- } );
-
- suite.addTest( new IndexedDiskCacheConcurrentUnitTest( "testIndexedDiskCache3" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion3" );
- }
- } );
-
- suite.addTest( new IndexedDiskCacheConcurrentUnitTest( "testIndexedDiskCache4" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegionInRange( "indexedRegion3", 300, 600 );
- }
- } );
-
- return suite;
- }
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestDiskCache.ccf" );
- }
-
- /**
- * Adds items to cache, gets them, and removes them. The item count is more
- * than the size of the memory cache, so items should spool to disk.
- *
- * @param region
- * Name of the region to access
- *
- * @throws Exception
- * If an error occurs
- */
- public void runTestForRegion( String region )
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-
- // Add items to cache
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
-
- // Test that all items are in cache
- for ( int i = 0; i <= items; i++ )
- {
- String value = jcs.get( i + ":key" );
-
- assertEquals( region + " data " + i, value );
- }
-
- // Test that getElements returns all the expected values
- Set<String> keys = new HashSet<>();
- for ( int i = 0; i <= items; i++ )
- {
- keys.add( i + ":key" );
- }
-
- Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
- for ( int i = 0; i <= items; i++ )
- {
- ICacheElement<String, String> element = elements.get( i + ":key" );
- assertNotNull( "element " + i + ":key is missing", element );
- assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
- }
-
- // Remove all the items
- for ( int i = 0; i <= items; i++ )
- {
- jcs.remove( i + ":key" );
- }
-
- // Verify removal
- // another thread may have inserted since
- for ( int i = 0; i <= items; i++ )
- {
- assertNull( "Removed key should be null: " + i + ":key" + "\n stats " + jcs.getStats(), jcs
- .get( i + ":key" ) );
- }
- }
-
- /**
- * Adds items to cache, gets them, and removes them. The item count is more
- * than the size of the memory cache, so items should spool to disk.
- *
- * @param region
- * Name of the region to access
- * @param start
- * @param end
- *
- * @throws Exception
- * If an error occurs
- */
- public void runTestForRegionInRange( String region, int start, int end )
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-
- // Add items to cache
- for ( int i = start; i <= end; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
-
- // Test that all items are in cache
- for ( int i = start; i <= end; i++ )
- {
- String value = jcs.get( i + ":key" );
-
- assertEquals( region + " data " + i, value );
- }
-
- // Test that getElements returns all the expected values
- Set<String> keys = new HashSet<>();
- for ( int i = start; i <= end; i++ )
- {
- keys.add( i + ":key" );
- }
-
- Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
- for ( int i = start; i <= end; i++ )
- {
- ICacheElement<String, String> element = elements.get( i + ":key" );
- assertNotNull( "element " + i + ":key is missing", element );
- assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
- }
-
- // Remove all the items
- for ( int i = start; i <= end; i++ )
- {
- jcs.remove( i + ":key" );
- }
-
-// System.out.println( jcs.getStats() );
-
- // Verify removal
- // another thread may have inserted since
- for ( int i = start; i <= end; i++ )
- {
- assertNull( "Removed key should be null: " + i + ":key " + "\n stats " + jcs.getStats(), jcs.get( i
- + ":key" ) );
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheDefragPerformanceTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheDefragPerformanceTest.java
deleted file mode 100644
index 7ce6788..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheDefragPerformanceTest.java
+++ /dev/null
@@ -1,180 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-
-import java.io.Serializable;
-import java.text.DecimalFormat;
-import java.util.Random;
-
-/**
- * This is for manually testing the defrag process.
- */
-public class IndexedDiskCacheDefragPerformanceTest
- extends TestCase
-{
- /** For readability */
- private static final String LOG_DIVIDER = "---------------------------";
-
- /** total to test with */
- private static final int TOTAL_ELEMENTS = 30000;
-
- /** time to wait */
- private static final long SLEEP_TIME_DISK = 8000;
-
- /** how often to log */
- private static final int LOG_INCREMENT = 5000;
-
- /** for getting memory usage */
- private static Runtime rt = Runtime.getRuntime();
-
- /** for displaying memory usage */
- private static DecimalFormat format = new DecimalFormat( "#,###" );
-
- /**
- * @throws Exception
- */
- public void testRealTimeOptimization()
- throws Exception
- {
- System.out.println( LOG_DIVIDER );
- System.out.println( "JCS DEFRAG PERFORMANCE TESTS" );
- System.out.println( LOG_DIVIDER );
- logMemoryUsage();
- IndexedDiskCacheDefragPerformanceTest.runRealTimeOptimizationTest();
- logMemoryUsage();
-
- System.out.println( LOG_DIVIDER );
- }
-
- /**
- * @throws Exception
- */
- private static void runRealTimeOptimizationTest()
- throws Exception
- {
- JCS.setConfigFilename( "/TestDiskCacheDefragPerformance.ccf" );
- CacheAccess<Integer, Tile> jcs = JCS.getInstance( "defrag" );
-
- Tile tile;
- System.out.println( "Cache Defrag Test" );
-
- Random random = new Random( 89 );
- for ( int i = 0; i < TOTAL_ELEMENTS; i++ )
- {
- int bytes = random.nextInt( 20 );
- // 4-24 KB
- tile = new Tile( Integer.valueOf( i ), new byte[( bytes + 4 ) * 1024] );
- // images
-
- jcs.put( tile.id, tile );
-
- if ( ( i != 0 ) && ( 0 == ( i % 100 ) ) )
- {
- jcs.get( Integer.valueOf( random.nextInt( i ) ) );
- }
-
- if ( 0 == ( i % LOG_INCREMENT ) )
- {
- System.out.print( i + ", " );
- Thread.sleep( SLEEP_TIME_DISK );
- }
- }
-
- System.out.println( LOG_DIVIDER );
- System.out.println( "Total elements = " + TOTAL_ELEMENTS );
- System.out.println( "Stats prior to sleeping " + jcs.getStats() );
-
- // Allow system to settle down
- System.out.println( "Sleeping for a a minute." );
- Thread.sleep( 60000 );
-
- System.out.println( LOG_DIVIDER );
- System.out.println( "Stats prior to dispose " + jcs.getStats() );
-
- jcs.dispose();
- System.out.println( LOG_DIVIDER );
- System.out.println( "Stats after dispose " + jcs.getStats() );
- System.out.println( "Done testing." );
- }
-
- /**
- * Logs the memory usage.
- */
- private static void logMemoryUsage()
- {
- long byte2MB = 1024 * 1024;
- long total = rt.totalMemory() / byte2MB;
- long free = rt.freeMemory() / byte2MB;
- long used = total - free;
- System.out.println( LOG_DIVIDER );
- System.out.println( "Memory:" + " Used:" + format.format( used ) + "MB" + " Free:" + format.format( free )
- + "MB" + " Total:" + format.format( total ) + "MB" );
- }
-
- /**
- * Resembles a cached image.
- */
- private static class Tile
- implements Serializable
- {
- /** Don't change */
- private static final long serialVersionUID = 1L;
-
- /**
- * Key
- */
- public Integer id;
-
- /**Byte size
- *
- */
- public byte[] imageBytes;
-
- /**
- * @param id
- * @param imageBytes
- */
- public Tile( Integer id, byte[] imageBytes )
- {
- this.id = id;
- this.imageBytes = imageBytes;
- }
- }
-
- /**
- * @param args
- */
- public static void main( String args[] )
- {
- try
- {
- IndexedDiskCacheDefragPerformanceTest tester = new IndexedDiskCacheDefragPerformanceTest();
- tester.testRealTimeOptimization();
- }
- catch ( Exception e )
- {
- e.printStackTrace();
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheKeyStoreUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheKeyStoreUnitTest.java
deleted file mode 100644
index 239b575..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheKeyStoreUnitTest.java
+++ /dev/null
@@ -1,149 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.ElementAttributes;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-
-/**
- * Test store and load keys.
- *
- * @author Aaron Smuts
- *
- */
-public class IndexedDiskCacheKeyStoreUnitTest
- extends TestCase
-{
-
- /**
- * Add some keys, store them, load them from disk, then check to see that we
- * can get the items.
- *
- * @throws Exception
- *
- */
- public void testStoreKeys()
- throws Exception
- {
- IndexedDiskCacheAttributes cattr = new IndexedDiskCacheAttributes();
- cattr.setCacheName( "testStoreKeys" );
- cattr.setMaxKeySize( 100 );
- cattr.setDiskPath( "target/test-sandbox/KeyStoreUnitTest" );
- IndexedDiskCache<String, String> disk = new IndexedDiskCache<>( cattr );
-
- disk.processRemoveAll();
-
- int cnt = 25;
- for ( int i = 0; i < cnt; i++ )
- {
- IElementAttributes eAttr = new ElementAttributes();
- eAttr.setIsSpool( true );
- ICacheElement<String, String> element = new CacheElement<>( cattr.getCacheName(), "key:" + i, "data:" + i );
- element.setElementAttributes( eAttr );
- disk.processUpdate( element );
- }
-
- for ( int i = 0; i < cnt; i++ )
- {
- ICacheElement<String, String> element = disk.processGet( "key:" + i );
- assertNotNull( "presave, Should have received an element.", element );
- assertEquals( "presave, element is wrong.", "data:" + i, element.getVal() );
- }
-
- disk.saveKeys();
-
- disk.loadKeys();
-
- assertEquals( "The disk is the wrong size.", cnt, disk.getSize() );
-
- for ( int i = 0; i < cnt; i++ )
- {
- ICacheElement<String, String> element = disk.processGet( "key:" + i );
- assertNotNull( "postsave, Should have received an element.", element );
- assertEquals( "postsave, element is wrong.", "data:" + i, element.getVal() );
- }
-
- disk.dump();
-
- }
-
-
- /**
- * Add some elements, remove 1, call optimize, verify that the removed isn't present.
- *
- * We should also compare the data file sizes. . . .
- *
- * @throws Exception
- *
- */
- public void testOptiimize()
- throws Exception
- {
- IndexedDiskCacheAttributes cattr = new IndexedDiskCacheAttributes();
- cattr.setCacheName( "testOptimize" );
- cattr.setMaxKeySize( 100 );
- cattr.setDiskPath( "target/test-sandbox/KeyStoreUnitTest" );
- IndexedDiskCache<String, String> disk = new IndexedDiskCache<>( cattr );
-
- disk.processRemoveAll();
-
- int cnt = 25;
- for ( int i = 0; i < cnt; i++ )
- {
- IElementAttributes eAttr = new ElementAttributes();
- eAttr.setIsSpool( true );
- ICacheElement<String, String> element = new CacheElement<>( cattr.getCacheName(), "key:" + i, "data:" + i );
- element.setElementAttributes( eAttr );
- disk.processUpdate( element );
- }
-
- long preAddRemoveSize = disk.getDataFileSize();
-
- IElementAttributes eAttr = new ElementAttributes();
- eAttr.setIsSpool( true );
- ICacheElement<String, String> elementSetup = new CacheElement<>( cattr.getCacheName(), "key:" + "A", "data:" + "A" );
- elementSetup.setElementAttributes( eAttr );
- disk.processUpdate( elementSetup );
-
- ICacheElement<String, String> elementRet = disk.processGet( "key:" + "A" );
- assertNotNull( "postsave, Should have received an element.", elementRet );
- assertEquals( "postsave, element is wrong.", "data:" + "A", elementRet.getVal() );
-
- disk.remove( "key:" + "A" );
-
- long preSize = disk.getDataFileSize();
- // synchronous versoin
- disk.optimizeFile(); //deoptimizeRealTime();
- long postSize = disk.getDataFileSize();
-
- assertTrue( "Should be smaller. postsize="+postSize+" preSize="+preSize, postSize < preSize );
- assertEquals( "Should be the same size after optimization as before add and remove.", preAddRemoveSize, postSize );
-
- for ( int i = 0; i < cnt; i++ )
- {
- ICacheElement<String, String> element = disk.processGet( "key:" + i );
- assertNotNull( "postsave, Should have received an element.", element );
- assertEquals( "postsave, element is wrong.", "data:" + i, element.getVal() );
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheNoMemoryUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheNoMemoryUnitTest.java
deleted file mode 100644
index bbce378..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheNoMemoryUnitTest.java
+++ /dev/null
@@ -1,178 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import junit.extensions.ActiveTestSuite;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Test which exercises the indexed disk cache. This one uses three different
- * regions for thre threads. It uses a config file that specifies 0 items in
- * memory.
- */
-public class IndexedDiskCacheNoMemoryUnitTest
- extends TestCase
-{
- /**
- * Number of items to cache; the configured maxObjects for the memory cache
- * regions is 0.
- */
- private static int items = 2000;
-
- /**
- * @param testName
- */
- public IndexedDiskCacheNoMemoryUnitTest( String testName )
- {
- super( testName );
- }
-
- /**
- * Main method passes this test to the text test runner.
- * <p>
- * @param args
- */
- public static void main( String args[] )
- {
- String[] testCaseName = { IndexedDiskCacheNoMemoryUnitTest.class.getName() };
- junit.textui.TestRunner.main( testCaseName );
- }
-
- /**
- * A unit test suite for JUnit
- * <p>
- * @return The test suite
- */
- public static Test suite()
- {
- ActiveTestSuite suite = new ActiveTestSuite();
-
- suite.addTest( new IndexedDiskCacheNoMemoryUnitTest( "testIndexedDiskCache1" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion1" );
- }
- } );
-
- suite.addTest( new IndexedDiskCacheNoMemoryUnitTest( "testIndexedDiskCache2" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion2" );
- }
- } );
-
- suite.addTest( new IndexedDiskCacheNoMemoryUnitTest( "testIndexedDiskCache3" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion3" );
- }
- } );
-
- return suite;
- }
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestDiskCacheNoMemory.ccf" );
- }
-
- /**
- * Adds items to cache, gets them, and removes them. The item count is more
- * than the size of the memory cache, so items should spool to disk.
- *
- * @param region
- * Name of the region to access
- *
- * @throws Exception
- * If an error occurs
- */
- public void runTestForRegion( String region )
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-
- // Add items to cache
-
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
-
- // Test that all items are in cache
-
- for ( int i = 0; i <= items; i++ )
- {
- String value = jcs.get( i + ":key" );
-
- assertEquals( region + " data " + i, value );
- }
-
- // Test that getElements returns all the expected values
- Set<String> keys = new HashSet<>();
- for ( int i = 0; i <= items; i++ )
- {
- keys.add( i + ":key" );
- }
-
- Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
- for ( int i = 0; i <= items; i++ )
- {
- ICacheElement<String, String> element = elements.get( i + ":key" );
- assertNotNull( "element " + i + ":key is missing", element );
- assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
- }
-
- // Remove all the items
- for ( int i = 0; i <= items; i++ )
- {
- jcs.remove( i + ":key" );
- }
-
- // Verify removal
- for ( int i = 0; i <= items; i++ )
- {
- assertNull( "Removed key should be null: " + i + ":key" + "\n stats " + jcs.getStats(), jcs.get( i + ":key" ) );
- }
-
- // dump the stats to the report
-// System.out.println( jcs.getStats() );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheOptimizationUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheOptimizationUnitTest.java
deleted file mode 100644
index a76740d..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheOptimizationUnitTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-import org.apache.commons.jcs.auxiliary.disk.DiskTestObject;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.utils.timing.SleepUtil;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/**
- * Tests for the optimization routine.
- * <p>
- * @author Aaron Smuts
- */
-public class IndexedDiskCacheOptimizationUnitTest
- extends TestCase
-{
- /**
- * Set the optimize at remove count to 10. Add 20. Check the file size. Remove 10. Check the
- * times optimized. Check the file size.
- * @throws Exception
- */
- public void testBasicOptimization()
- throws Exception
- {
- // SETUP
- int removeCount = 50;
-
- IndexedDiskCacheAttributes cattr = new IndexedDiskCacheAttributes();
- cattr.setCacheName( "testOptimization" );
- cattr.setMaxKeySize( removeCount * 2 );
- cattr.setOptimizeAtRemoveCount( removeCount );
- cattr.setDiskPath( "target/test-sandbox/testOptimization" );
- IndexedDiskCache<Integer, DiskTestObject> disk = new IndexedDiskCache<>( cattr );
-
- disk.removeAll();
-
- int numberToInsert = removeCount * 3;
- ICacheElement<Integer, DiskTestObject>[] elements = DiskTestObjectUtil
- .createCacheElementsWithTestObjectsOfVariableSizes( numberToInsert, cattr.getCacheName() );
-
- for ( int i = 0; i < elements.length; i++ )
- {
- disk.processUpdate( elements[i] );
- }
-
-
- Thread.sleep( 1000 );
- long sizeBeforeRemove = disk.getDataFileSize();
- // System.out.println( "file sizeBeforeRemove " + sizeBeforeRemove );
- // System.out.println( "totalSize inserted " + DiskTestObjectUtil.totalSize( elements, numberToInsert ) );
-
- // DO WORK
- for ( int i = 0; i < removeCount; i++ )
- {
- disk.processRemove( Integer.valueOf( i ) );
- }
-
- SleepUtil.sleepAtLeast( 1000 );
-
- disk.optimizeFile();
- // VERIFY
- long sizeAfterRemove = disk.getDataFileSize();
- long expectedSizeAfterRemove = DiskTestObjectUtil.totalSize( elements, removeCount, elements.length );
-
- // test is prone to failure for timing reasons.
- if ( expectedSizeAfterRemove != sizeAfterRemove )
- {
- SleepUtil.sleepAtLeast( 2000 );
- }
-
- assertTrue( "The post optimization size should be smaller."
- +"sizeAfterRemove=" + sizeAfterRemove + " sizeBeforeRemove= " +sizeBeforeRemove
- , sizeAfterRemove < sizeBeforeRemove );
- assertEquals( "The file size is not as expected size.", expectedSizeAfterRemove, sizeAfterRemove );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheRandomConcurrentTestUtil.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheRandomConcurrentTestUtil.java
deleted file mode 100644
index 5d7b8cb..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheRandomConcurrentTestUtil.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.access.TestCacheAccess;
-
-/**
- * This is used by other tests to generate a random load on the disk cache.
- */
-public class IndexedDiskCacheRandomConcurrentTestUtil
- extends TestCase
-{
-
- /**
- * Constructor for the TestDiskCache object.
- *
- * @param testName
- */
- public IndexedDiskCacheRandomConcurrentTestUtil( String testName )
- {
- super( testName );
- }
-
- /**
- * Randomly adds items to cache, gets them, and removes them. The range
- * count is more than the size of the memory cache, so items should spool to
- * disk.
- *
- * @param region
- * Name of the region to access
- * @param range
- * @param numOps
- * @param testNum
- *
- * @throws Exception
- * If an error occurs
- */
- public void runTestForRegion( String region, int range, int numOps, int testNum )
- throws Exception
- {
- // run a rondom operation test to detect deadlocks
- TestCacheAccess tca = new TestCacheAccess( "/TestDiskCacheCon.ccf" );
- tca.setRegion( region );
- tca.random( range, numOps );
-
- // make sure a simple put then get works
- // this may fail if the other tests are flooding the disk cache
- CacheAccess<String, String> jcs = JCS.getInstance( region );
- String key = "testKey" + testNum;
- String data = "testData" + testNum;
- jcs.put( key, data );
- String value = jcs.get( key );
- assertEquals( data, value );
-
- }
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestDiskCacheCon.ccf" );
- }
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheSameRegionConcurrentUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheSameRegionConcurrentUnitTest.java
deleted file mode 100644
index 244410c..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheSameRegionConcurrentUnitTest.java
+++ /dev/null
@@ -1,208 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import junit.extensions.ActiveTestSuite;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Test which exercises the indexed disk cache. Runs three threads against the
- * same region.
- */
-public class IndexedDiskCacheSameRegionConcurrentUnitTest
- extends TestCase
-{
- /**
- * Constructor for the TestDiskCache object.
- *
- * @param testName
- */
- public IndexedDiskCacheSameRegionConcurrentUnitTest( String testName )
- {
- super( testName );
- }
-
- /**
- * Main method passes this test to the text test runner.
- *
- * @param args
- */
- public static void main( String args[] )
- {
- String[] testCaseName = { IndexedDiskCacheSameRegionConcurrentUnitTest.class.getName() };
- junit.textui.TestRunner.main( testCaseName );
- }
-
- /**
- * A unit test suite for JUnit
- *
- * @return The test suite
- */
- public static Test suite()
- {
- ActiveTestSuite suite = new ActiveTestSuite();
-
- suite.addTest( new IndexedDiskCacheSameRegionConcurrentUnitTest( "testIndexedDiskCache1" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion4", 0, 200 );
- }
- } );
-
- suite.addTest( new IndexedDiskCacheSameRegionConcurrentUnitTest( "testIndexedDiskCache2" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion4", 1000, 1200 );
- }
- } );
-
- suite.addTest( new IndexedDiskCacheSameRegionConcurrentUnitTest( "testIndexedDiskCache3" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion4", 2000, 2200 );
- }
- } );
-
- suite.addTest( new IndexedDiskCacheSameRegionConcurrentUnitTest( "testIndexedDiskCache4" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion4", 2200, 5200 );
- }
- } );
-
- suite.addTest( new IndexedDiskCacheSameRegionConcurrentUnitTest( "testIndexedDiskCache5" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion4", 0, 5100 );
- }
- } );
-
- return suite;
- }
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestDiskCacheCon.ccf" );
- }
-
- // /**
- // * Tests the region which uses the indexed disk cache
- // */
- // public void testIndexedDiskCache()
- // throws Exception
- // {
- // runTestForRegion( "indexedRegion" );
- // }
- //
- // /**
- // * Tests the region which uses the indexed disk cache
- // */
- // public void testIndexedDiskCache2()
- // throws Exception
- // {
- // runTestForRegion( "indexedRegion2" );
- // }
-
- /**
- * Adds items to cache, gets them, and removes them. The item count is more
- * than the size of the memory cache, so items should spool to disk.
- *
- * @param region
- * Name of the region to access
- * @param start
- * @param end
- *
- * @throws Exception
- * If an error occurs
- */
- public void runTestForRegion( String region, int start, int end )
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-
- // Add items to cache
-
- for ( int i = start; i <= end; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
-
- // Test that all items are in cache
-
- for ( int i = start; i <= end; i++ )
- {
- String key = i + ":key";
- String value = jcs.get( key );
-
- assertEquals( "Wrong value for key [" + key + "]", region + " data " + i, value );
- }
-
- // Test that getElements returns all the expected values
- Set<String> keys = new HashSet<>();
- for ( int i = start; i <= end; i++ )
- {
- keys.add( i + ":key" );
- }
-
- Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
- for ( int i = start; i <= end; i++ )
- {
- ICacheElement<String, String> element = elements.get( i + ":key" );
- assertNotNull( "element " + i + ":key is missing", element );
- assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
- }
-
- // you can't remove in one thread and expect them to be in another //
- // Remove all the items
- //
- // for ( int i = start; i <= end; i++ ) { jcs.remove( i + ":key" ); } //
- // Verify removal
- //
- // for ( int i = start; i <= end; i++ ) { assertNull( "Removed key
- // should be null: " + i + ":key", jcs.get( i + ":key" ) ); }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheSteadyLoadTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheSteadyLoadTest.java
deleted file mode 100644
index ebb24d3..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/IndexedDiskCacheSteadyLoadTest.java
+++ /dev/null
@@ -1,153 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.auxiliary.disk.DiskTestObject;
-import org.apache.commons.jcs.utils.timing.ElapsedTimer;
-
-import java.text.DecimalFormat;
-import java.util.Random;
-
-/**
- * This allows you to put thousands of large objects into the disk cache and to force removes to
- * trigger optimizations along the way.
- * <p>
- * @author Aaron Smuts
- */
-public class IndexedDiskCacheSteadyLoadTest
- extends TestCase
-{
- /** For display */
- private static final String LOG_DIVIDER = "---------------------------";
-
- /** For getting memory info */
- private static Runtime rt = Runtime.getRuntime();
-
- /** For display */
- private static DecimalFormat format = new DecimalFormat( "#,###" );
-
- /**
- * Insert 2000 wait 1 second, repeat. Average 1000 / sec.
- * <p>
- * @throws Exception
- */
- public void testRunSteadyLoadTest()
- throws Exception
- {
- JCS.setConfigFilename( "/TestDiskCacheSteadyLoad.ccf" );
-
- System.out.println( "runSteadyLoadTest" );
-
- logMemoryUsage();
-
- int numPerRun = 200;
- long pauseBetweenRuns = 1000;
- int runCount = 0;
- int runs = 1000;
- int upperKB = 50;
-
- CacheAccess<String, DiskTestObject> jcs = JCS.getInstance( ( numPerRun / 2 ) + "aSecond" );
-
- ElapsedTimer timer = new ElapsedTimer();
- int numToGet = numPerRun * ( runs / 10 );
- for ( int i = 0; i < numToGet; i++ )
- {
- jcs.get( String.valueOf( i ) );
- }
- System.out.println( LOG_DIVIDER );
- System.out.println( "After getting " + numToGet );
- System.out.println( "Elapsed " + timer.getElapsedTimeString() );
- logMemoryUsage();
-
- jcs.clear();
- Thread.sleep( 3000 );
- System.out.println( LOG_DIVIDER );
- System.out.println( "Start putting" );
-
- long totalSize = 0;
- int totalPut = 0;
-
- Random random = new Random( 89 );
- while ( runCount < runs )
- {
- runCount++;
- for ( int i = 0; i < numPerRun; i++ )
- {
- // 1/2 upper to upperKB-4 KB
- int kiloBytes = Math.max( upperKB / 2, random.nextInt( upperKB ) );
- int bytes = ( kiloBytes ) * 1024;
- totalSize += bytes;
- totalPut++;
- DiskTestObject object = new DiskTestObject( Integer.valueOf( i ), new byte[bytes] );
- jcs.put( String.valueOf( totalPut ), object );
- }
-
- // remove half of those inserted the previous run
- if ( runCount > 1 )
- {
- for ( int j = ( ( totalPut - numPerRun ) - ( numPerRun / 2 ) ); j < ( totalPut - numPerRun ); j++ )
- {
- jcs.remove( String.valueOf( j ) );
- }
- }
-
- Thread.sleep( pauseBetweenRuns );
- if ( runCount % 100 == 0 )
- {
- System.out.println( LOG_DIVIDER );
- System.out.println( "Elapsed " + timer.getElapsedTimeString() );
- System.out.println( "Run count: " + runCount + " Average size: " + ( totalSize / totalPut ) + "\n"
- + jcs.getStats() );
- logMemoryUsage();
- }
- }
-
- Thread.sleep( 3000 );
- System.out.println( jcs.getStats() );
- logMemoryUsage();
-
- Thread.sleep( 10000 );
- System.out.println( jcs.getStats() );
- logMemoryUsage();
-
- System.gc();
- Thread.sleep( 3000 );
- System.gc();
- System.out.println( jcs.getStats() );
- logMemoryUsage();
- }
-
- /**
- * Logs the memory usage.
- */
- private static void logMemoryUsage()
- {
- long byte2MB = 1024 * 1024;
- long total = rt.totalMemory() / byte2MB;
- long free = rt.freeMemory() / byte2MB;
- long used = total - free;
- System.out.println( LOG_DIVIDER );
- System.out.println( "Memory:" + " Used:" + format.format( used ) + "MB" + " Free:" + format.format( free )
- + "MB" + " Total:" + format.format( total ) + "MB" );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/LRUMapSizeVsCount.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/LRUMapSizeVsCount.java
deleted file mode 100644
index 587e462..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/indexed/LRUMapSizeVsCount.java
+++ /dev/null
@@ -1,236 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.indexed;
-
-/*
- * 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.
- */
-
-import java.util.Map;
-
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
-
-/**
- * This ensures that the jcs version of the LRU map is as fast as the commons
- * version. It has been testing at .6 to .7 times the commons LRU.
- * <p>
- * @author aaronsm
- *
- */
-public class LRUMapSizeVsCount
- extends TestCase
-{
- /** The put put ration after the test */
- double ratioPut = 0;
-
- /** The ratio after the test */
- double ratioGet = 0;
-
- /** put size / count ratio */
- float targetPut = 1.2f;
-
- /** get size / count ratio */
- float targetGet = 1.2f;
-
- /** Time to loop */
- int loops = 20;
-
- /** items to put and get per loop */
- int tries = 100000;
-
- /**
- * @param testName
- */
- public LRUMapSizeVsCount( String testName )
- {
- super( testName );
- }
-
- /**
- * A unit test suite for JUnit
- * <p>
- * @return The test suite
- */
- public static Test suite()
- {
- return new TestSuite( LRUMapSizeVsCount.class );
- }
-
- /**
- * A unit test for JUnit
- *
- * @throws Exception
- * Description of the Exception
- */
- public void testSimpleLoad()
- throws Exception
- {
- doWork();
- assertTrue( this.ratioPut < targetPut );
- assertTrue( this.ratioGet < targetGet );
- }
-
- /**
- *
- */
- public void doWork()
- {
- long start = 0;
- long end = 0;
- long time = 0;
- float tPer = 0;
-
- long putTotalCount = 0;
- long getTotalCount = 0;
- long putTotalSize = 0;
- long getTotalSize = 0;
-
- long minTimeSizePut = Long.MAX_VALUE;
- long minTimeSizeGet = Long.MAX_VALUE;
- long minTimeCountPut = Long.MAX_VALUE;
- long minTimeCountGet = Long.MAX_VALUE;
-
- String cacheName = "LRUMap";
- String cache2Name = "";
-
- try
- {
- IndexedDiskCacheAttributes cattr = new IndexedDiskCacheAttributes();
- cattr.setName("junit");
- cattr.setCacheName("junit");
- cattr.setDiskPath(".");
- IndexedDiskCache<String, String> idc = new IndexedDiskCache<>(cattr);
-
- Map<String, IndexedDiskElementDescriptor> cacheCount = idc.new LRUMapCountLimited( tries );
- Map<String, IndexedDiskElementDescriptor> cacheSize = idc.new LRUMapSizeLimited( tries/1024/2 );
-
- for ( int j = 0; j < loops; j++ )
- {
- cacheName = "LRU Count ";
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- cacheCount.put( "key:" + i, new IndexedDiskElementDescriptor(i, i) );
- }
- end = System.currentTimeMillis();
- time = end - start;
- putTotalCount += time;
- minTimeCountPut = Math.min(time, minTimeCountPut);
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( cacheName + " put time for " + tries + " = " + time + "; millis per = " + tPer );
-
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- cacheCount.get( "key:" + i );
- }
- end = System.currentTimeMillis();
- time = end - start;
- getTotalCount += time;
- minTimeCountGet = Math.min(minTimeCountGet, time);
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( cacheName + " get time for " + tries + " = " + time + "; millis per = " + tPer );
-
- ///////////////////////////////////////////////////////////////
- cache2Name = "LRU Size ";
- //or LRUMapJCS
- //cache2Name = "Hashtable";
- //Hashtable cache2 = new Hashtable();
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- cacheSize.put( "key:" + i, new IndexedDiskElementDescriptor(i, i) );
- }
- end = System.currentTimeMillis();
- time = end - start;
- putTotalSize += time;
- minTimeSizePut = Math.min(minTimeSizePut, time);
-
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( cache2Name + " put time for " + tries + " = " + time + "; millis per = " + tPer );
-
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- cacheSize.get( "key:" + i );
- }
- end = System.currentTimeMillis();
- time = end - start;
- getTotalSize += time;
- minTimeSizeGet = Math.min(minTimeSizeGet, time);
-
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( cache2Name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
-
- System.out.println( "\n" );
- }
- }
- catch ( Exception e )
- {
- e.printStackTrace( System.out );
- System.out.println( e );
- }
-
- long putAvCount = putTotalCount / loops;
- long getAvCount = getTotalCount / loops;
- long putAvSize = putTotalSize / loops;
- long getAvSize = getTotalSize / loops;
-
- System.out.println( "Finished " + loops + " loops of " + tries + " gets and puts" );
-
- System.out.println( "\n" );
- System.out.println( "Put average for " + cacheName + " = " + putAvCount );
- System.out.println( "Put average for " + cache2Name + " = " + putAvSize );
- ratioPut = (putAvSize *1.0) / putAvCount;
- System.out.println( cache2Name.trim() + " puts took " + ratioPut + " times the " + cacheName.trim() + ", the goal is <" + targetPut
- + "x" );
-
- System.out.println( "\n" );
- System.out.println( "Put minimum for " + cacheName + " = " + minTimeCountPut );
- System.out.println( "Put minimum for " + cache2Name + " = " + minTimeSizePut );
- ratioPut = (minTimeSizePut * 1.0) / minTimeCountPut;
- System.out.println( cache2Name.trim() + " puts took " + ratioPut + " times the " + cacheName.trim() + ", the goal is <" + targetPut
- + "x" );
-
- System.out.println( "\n" );
- System.out.println( "Get average for " + cacheName + " = " + getAvCount );
- System.out.println( "Get average for " + cache2Name + " = " + getAvSize );
- ratioGet = Float.intBitsToFloat( (int) getAvCount ) / Float.intBitsToFloat( (int) getAvSize );
- ratioGet = (getAvSize * 1.0) / getAvCount;
- System.out.println( cache2Name.trim() + " gets took " + ratioGet + " times the " + cacheName.trim() + ", the goal is <" + targetGet
- + "x" );
-
- System.out.println( "\n" );
- System.out.println( "Get minimum for " + cacheName + " = " + minTimeCountGet );
- System.out.println( "Get minimum for " + cache2Name + " = " + minTimeSizeGet );
- ratioPut = (minTimeSizeGet * 1.0) / minTimeCountGet;
- System.out.println( cache2Name.trim() + " puts took " + ratioPut + " times the " + cacheName.trim() + ", the goal is <" + targetGet
- + "x" );
-
- }
-
- /**
- * @param args
- */
- public static void main( String args[] )
- {
- LRUMapSizeVsCount test = new LRUMapSizeVsCount( "command" );
- test.doWork();
- }
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/HsqlSetupTableUtil.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/HsqlSetupTableUtil.java
deleted file mode 100644
index 0929c7b..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/HsqlSetupTableUtil.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc;
-
-/*
- * 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.
- */
-
-import java.sql.Connection;
-import java.sql.SQLException;
-
-import org.apache.commons.jcs.auxiliary.disk.jdbc.hsql.HSQLDiskCacheFactory;
-
-/** Can use this to setup a table. */
-public class HsqlSetupTableUtil extends HSQLDiskCacheFactory
-{
- /**
- * SETUP a TABLE FOR CACHE testing
- * <p>
- * @param cConn
- * @param tableName
- *
- * @throws SQLException if database problems occur
- */
- public static void setupTABLE( Connection cConn, String tableName ) throws SQLException
- {
- HsqlSetupTableUtil util = new HsqlSetupTableUtil();
- util.setupTable(cConn, tableName);
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDataSourceFactoryUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDataSourceFactoryUnitTest.java
deleted file mode 100644
index 2068bdf..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDataSourceFactoryUnitTest.java
+++ /dev/null
@@ -1,205 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc;
-
-/*
- * 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.
- */
-
-import java.sql.SQLException;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Map;
-import java.util.Properties;
-
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-import javax.naming.spi.InitialContextFactory;
-
-import org.apache.commons.dbcp2.BasicDataSource;
-import org.apache.commons.dbcp2.datasources.SharedPoolDataSource;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.JndiDataSourceFactory;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.SharedPoolDataSourceFactory;
-
-import junit.framework.TestCase;
-
-/** Unit tests for the data source factories */
-public class JDBCDataSourceFactoryUnitTest
- extends TestCase
-{
- /** Verify that we can configure the object based on the props.
- * @throws SQLException
- */
- public void testConfigureDataSourceFactory_Simple() throws SQLException
- {
- // SETUP
- String poolName = "testConfigurePoolAccessAttributes_Simple";
-
- String url = "adfads";
- String userName = "zvzvz";
- String password = "qewrrewq";
- int maxActive = 10;
- String driverClassName = "org.hsqldb.jdbcDriver";
-
- Properties props = new Properties();
- String prefix = JDBCDiskCacheFactory.POOL_CONFIGURATION_PREFIX
- + poolName
- + JDBCDiskCacheFactory.ATTRIBUTE_PREFIX;
- props.put( prefix + ".url", url );
- props.put( prefix + ".userName", userName );
- props.put( prefix + ".password", password );
- props.put( prefix + ".maxActive", String.valueOf( maxActive ) );
- props.put( prefix + ".driverClassName", driverClassName );
-
- JDBCDiskCacheFactory factory = new JDBCDiskCacheFactory();
- factory.initialize();
-
- JDBCDiskCacheAttributes cattr = new JDBCDiskCacheAttributes();
- cattr.setConnectionPoolName( poolName );
-
- // DO WORK
- DataSourceFactory result = factory.getDataSourceFactory( cattr, props );
- assertTrue("Should be a shared pool data source factory", result instanceof SharedPoolDataSourceFactory);
-
- SharedPoolDataSource spds = (SharedPoolDataSource) result.getDataSource();
- assertNotNull( "Should have a data source class", spds );
-
- // VERIFY
- assertEquals( "Wrong pool name", poolName, spds.getDescription() );
- assertEquals( "Wrong maxActive value", maxActive, spds.getMaxTotal() );
- }
-
- /** Verify that we can configure the object based on the attributes.
- * @throws SQLException
- */
- public void testConfigureDataSourceFactory_Attributes() throws SQLException
- {
- // SETUP
- String url = "adfads";
- String userName = "zvzvz";
- String password = "qewrrewq";
- int maxActive = 10;
- String driverClassName = "org.hsqldb.jdbcDriver";
-
- JDBCDiskCacheFactory factory = new JDBCDiskCacheFactory();
- factory.initialize();
-
- JDBCDiskCacheAttributes cattr = new JDBCDiskCacheAttributes();
- cattr.setUrl(url);
- cattr.setUserName(userName);
- cattr.setPassword(password);
- cattr.setMaxTotal(maxActive);
- cattr.setDriverClassName(driverClassName);
-
- // DO WORK
- DataSourceFactory result = factory.getDataSourceFactory( cattr, null );
- assertTrue("Should be a shared pool data source factory", result instanceof SharedPoolDataSourceFactory);
-
- SharedPoolDataSource spds = (SharedPoolDataSource) result.getDataSource();
- assertNotNull( "Should have a data source class", spds );
-
- // VERIFY
- assertEquals( "Wrong maxActive value", maxActive, spds.getMaxTotal() );
- }
-
- /** Verify that we can configure the object based on JNDI.
- * @throws SQLException
- */
- public void testConfigureDataSourceFactory_JNDI() throws SQLException
- {
- // SETUP
- String jndiPath = "java:comp/env/jdbc/MyDB";
- long ttl = 300000L;
-
- System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
- MockInitialContextFactory.class.getName());
-
- MockInitialContextFactory.bind(jndiPath, new BasicDataSource());
-
- JDBCDiskCacheFactory factory = new JDBCDiskCacheFactory();
- factory.initialize();
-
- JDBCDiskCacheAttributes cattr = new JDBCDiskCacheAttributes();
- cattr.setJndiPath(jndiPath);
- cattr.setJndiTTL(ttl);
-
- // DO WORK
- DataSourceFactory result = factory.getDataSourceFactory( cattr, null );
- assertTrue("Should be a JNDI data source factory", result instanceof JndiDataSourceFactory);
- }
-
- /* For JNDI mocking */
- public static class MockInitialContextFactory implements InitialContextFactory
- {
- private static Context context;
-
- static
- {
- try
- {
- context = new InitialContext(true)
- {
- Map<String, Object> bindings = new HashMap<>();
-
- @Override
- public void bind(String name, Object obj) throws NamingException
- {
- bindings.put(name, obj);
- }
-
- @Override
- public Object lookup(String name) throws NamingException
- {
- return bindings.get(name);
- }
-
- @Override
- public Hashtable<?, ?> getEnvironment() throws NamingException
- {
- return new Hashtable<>();
- }
- };
- }
- catch (NamingException e)
- {
- // can't happen.
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException
- {
- return context;
- }
-
- public static void bind(String name, Object obj)
- {
- try
- {
- context.bind(name, obj);
- }
- catch (NamingException e)
- {
- // can't happen.
- throw new RuntimeException(e);
- }
- }
- }
-}
-
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheRemovalUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheRemovalUnitTest.java
deleted file mode 100644
index a526d06..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheRemovalUnitTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc;
-
-/*
- * 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.
- */
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.util.Properties;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-
-import junit.framework.TestCase;
-
-/** Tests for the removal functionality. */
-public class JDBCDiskCacheRemovalUnitTest
- extends TestCase
-{
- /** db name -- set in system props */
- private final String databaseName = "JCS_STORE_REMOVAL";
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- System.setProperty( "DATABASE_NAME", databaseName );
- JCS.setConfigFilename( "/TestJDBCDiskCacheRemoval.ccf" );
- }
-
- /**
- * Verify the fix for BUG JCS-20
- * <p>
- * Setup an hsql db. Add an item. Remove using partial key.
- * @throws Exception
- */
- public void testPartialKeyRemoval_Good()
- throws Exception
- {
- // SETUP
- setupDatabase();
-
- String keyPart1 = "part1";
- String keyPart2 = "part2";
- String region = "testCache1";
- String data = "adfadsfasfddsafasasd";
-
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-
- // DO WORK
- jcs.put( keyPart1 + ":" + keyPart2, data );
- Thread.sleep( 1000 );
-
- // VERIFY
- String resultBeforeRemove = jcs.get( keyPart1 + ":" + keyPart2 );
- assertEquals( "Wrong result", data, resultBeforeRemove );
-
- jcs.remove( keyPart1 + ":" );
- String resultAfterRemove = jcs.get( keyPart1 + ":" + keyPart2 );
- assertNull( "Should not have a result after removal.", resultAfterRemove );
-
-// System.out.println( jcs.getStats() );
- }
-
- /**
- * Create the database.
- * @throws InstantiationException
- * @throws IllegalAccessException
- * @throws ClassNotFoundException
- * @throws SQLException
- */
- private void setupDatabase()
- throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException
- {
- System.setProperty( "hsqldb.cache_scale", "8" );
-
- String rafroot = "target";
- Properties p = new Properties();
- String driver = p.getProperty( "driver", "org.hsqldb.jdbcDriver" );
- String url = p.getProperty( "url", "jdbc:hsqldb:" );
- String database = p.getProperty( "database", rafroot + "/JDBCDiskCacheRemovalUnitTest" );
- String user = p.getProperty( "user", "sa" );
- String password = p.getProperty( "password", "" );
-
- new org.hsqldb.jdbcDriver();
- Class.forName( driver ).newInstance();
- Connection cConn = DriverManager.getConnection( url + database, user, password );
-
- HsqlSetupTableUtil.setupTABLE( cConn, databaseName );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheSharedPoolUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheSharedPoolUnitTest.java
deleted file mode 100644
index b33ae4d..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheSharedPoolUnitTest.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-
-/**
- * Runs basic tests for the JDBC disk cache using a shared connection pool.
- *<p>
- * @author Aaron Smuts
- */
-public class JDBCDiskCacheSharedPoolUnitTest
- extends TestCase
-{
- /** Test setup */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestJDBCDiskCacheSharedPool.ccf" );
- }
-
- /**
- * Test the basic JDBC disk cache functionality with a hsql backing.
- * @throws Exception
- */
- public void testSimpleJDBCPutGetWithHSQL()
- throws Exception
- {
- System.setProperty( "hsqldb.cache_scale", "8" );
-
- String rafroot = "target";
- Properties p = new Properties();
- String driver = p.getProperty( "driver", "org.hsqldb.jdbcDriver" );
- String url = p.getProperty( "url", "jdbc:hsqldb:" );
- String database = p.getProperty( "database", rafroot + "/cache_hsql_db_sharedpool" );
- String user = p.getProperty( "user", "sa" );
- String password = p.getProperty( "password", "" );
-
- new org.hsqldb.jdbcDriver();
- Class.forName( driver ).newInstance();
- Connection cConn = DriverManager.getConnection( url + database, user, password );
-
- HsqlSetupTableUtil.setupTABLE( cConn, "JCS_STORE_0" );
-
- HsqlSetupTableUtil.setupTABLE( cConn, "JCS_STORE_1" );
-
- runTestForRegion( "testCache1", 200 );
- }
-
- /**
- * Adds items to cache, gets them, and removes them. The item count is more than the size of the
- * memory cache, so items should spool to disk.
- * <p>
- * @param region Name of the region to access
- * @param items
- * @throws Exception If an error occurs
- */
- public void runTestForRegion( String region, int items )
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-
-// System.out.println( "BEFORE PUT \n" + jcs.getStats() );
-
- // Add items to cache
-
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
-
-// System.out.println( jcs.getStats() );
-
- Thread.sleep( 1000 );
-
-// System.out.println( jcs.getStats() );
-
- // Test that all items are in cache
-
- for ( int i = 0; i <= items; i++ )
- {
- String value = jcs.get( i + ":key" );
-
- assertEquals( "key = [" + i + ":key] value = [" + value + "]", region + " data " + i, value );
- }
-
- // Test that getElements returns all the expected values
- Set<String> keys = new HashSet<>();
- for ( int i = 0; i <= items; i++ )
- {
- keys.add( i + ":key" );
- }
-
- Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
- for ( int i = 0; i <= items; i++ )
- {
- ICacheElement<String, String> element = elements.get( i + ":key" );
- assertNotNull( "element " + i + ":key is missing", element );
- assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
- }
-
- // Remove all the items
- for ( int i = 0; i <= items; i++ )
- {
- jcs.remove( i + ":key" );
- }
-
- // Verify removal
- for ( int i = 0; i <= items; i++ )
- {
- assertNull( "Removed key should be null: " + i + ":key", jcs.get( i + ":key" ) );
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheShrinkUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheShrinkUnitTest.java
deleted file mode 100644
index 702a37b..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheShrinkUnitTest.java
+++ /dev/null
@@ -1,222 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc;
-
-/*
- * 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.
- */
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.util.Properties;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.utils.timing.SleepUtil;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-/**
- * Runs basic tests for the JDBC disk cache.
- * <p>
- * @author Aaron Smuts
- */
-public class JDBCDiskCacheShrinkUnitTest
-{
- /**
- * Creates the DB
- * <p>
- * @throws Exception
- */
- @BeforeClass
- public static void setupDatabase() throws Exception
- {
- System.setProperty( "hsqldb.cache_scale", "8" );
-
- String rafroot = "target";
- Properties p = new Properties();
- String driver = p.getProperty( "driver", "org.hsqldb.jdbcDriver" );
- String url = p.getProperty( "url", "jdbc:hsqldb:" );
- String database = p.getProperty( "database", rafroot + "/JDBCDiskCacheShrinkUnitTest" );
- String user = p.getProperty( "user", "sa" );
- String password = p.getProperty( "password", "" );
-
- new org.hsqldb.jdbcDriver();
- Class.forName( driver ).newInstance();
- Connection cConn = DriverManager.getConnection( url + database, user, password );
-
- HsqlSetupTableUtil.setupTABLE( cConn, "JCS_STORE_SHRINK" );
- }
-
- /**
- * Test setup
- */
- @Before
- public void setUp()
- {
- JCS.setConfigFilename( "/TestJDBCDiskCacheShrink.ccf" );
- }
-
- /**
- * Test the basic JDBC disk cache functionality with a hsql backing. Verify that items
- * configured to expire after 1 second actually expire.
- * <p>
- * @throws Exception
- */
- @Test
- public void testExpireInBackground()
- throws Exception
- {
- String regionExpire = "expire1Second";
- int items = 200;
-
- CacheAccess<String, String> jcsExpire = JCS.getInstance( regionExpire );
-
-// System.out.println( "BEFORE PUT \n" + jcsExpire.getStats() );
-
- // Add items to cache
-
- for ( int i = 0; i <= items; i++ )
- {
- jcsExpire.put( i + ":key", regionExpire + " data " + i );
- }
-
-// System.out.println( jcsExpire.getStats() );
-
- // the shrinker is supposed to run every second
- SleepUtil.sleepAtLeast( 3000 );
-
-// System.out.println( jcsExpire.getStats() );
-
- // Test that all items have been removed from the cache
- for ( int i = 0; i <= items; i++ )
- {
- assertNull( "Removed key should be null: " + i + ":key", jcsExpire.get( i + ":key" ) );
- }
- }
-
- /**
- * Verify that those not scheduled to expire do not expire.
- * <p>
- * @throws CacheException
- * @throws InterruptedException
- */
- @Test
- public void testDidNotExpire()
- throws CacheException, InterruptedException
- {
- String region = "expire100Second";
- int items = 200;
-
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-
-// System.out.println( "BEFORE PUT \n" + jcs.getStats() );
-
- // Add items to cache
-
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
-
-// System.out.println( jcs.getStats() );
-
- SleepUtil.sleepAtLeast( 1000 );
-
-// System.out.println( jcs.getStats() );
-
- // Test that all items are in cache
-
- for ( int i = 0; i <= items; i++ )
- {
- String value = jcs.get( i + ":key" );
-
- assertEquals( "key = [" + i + ":key] value = [" + value + "]", region + " data " + i, value );
- }
-
- // Remove all the items
-
- for ( int i = 0; i <= items; i++ )
- {
- jcs.remove( i + ":key" );
- }
-
- // Verify removal
-
- for ( int i = 0; i <= items; i++ )
- {
- assertNull( "Removed key should be null: " + i + ":key", jcs.get( i + ":key" ) );
- }
- }
-
- /**
- * Verify that eternal trumps max life.
- * @throws CacheException
- * @throws InterruptedException
- */
- @Test
- public void testDidNotExpireEternal()
- throws CacheException, InterruptedException
- {
- String region = "eternal";
- int items = 200;
-
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-
-// System.out.println( "BEFORE PUT \n" + jcs.getStats() );
-
- // Add items to cache
-
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
-
-// System.out.println( jcs.getStats() );
-
- SleepUtil.sleepAtLeast( 1000 );
-
-// System.out.println( jcs.getStats() );
-
- // Test that all items are in cache
-
- for ( int i = 0; i <= items; i++ )
- {
- String value = jcs.get( i + ":key" );
-
- assertEquals( "key = [" + i + ":key] value = [" + value + "]", region + " data " + i, value );
- }
-
- // Remove all the items
-
- for ( int i = 0; i <= items; i++ )
- {
- jcs.remove( i + ":key" );
- }
-
- // Verify removal
-
- for ( int i = 0; i <= items; i++ )
- {
- assertNull( "Removed key should be null: " + i + ":key", jcs.get( i + ":key" ) );
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheUnitTest.java
deleted file mode 100644
index bd79ab9..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/JDBCDiskCacheUnitTest.java
+++ /dev/null
@@ -1,206 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc;
-
-/*
- * 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.
- */
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.Executors;
-
-import junit.framework.TestCase;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.control.MockCompositeCacheManager;
-import org.apache.commons.jcs.utils.serialization.StandardSerializer;
-import org.apache.commons.jcs.utils.threadpool.DaemonThreadFactory;
-
-/**
- * Runs basic tests for the JDBC disk cache.
- *<p>
- * @author Aaron Smuts
- */
-public class JDBCDiskCacheUnitTest
- extends TestCase
-{
- /** Test setup */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestJDBCDiskCache.ccf" );
- }
-
- /**
- * Test the basic JDBC disk cache functionality with a hsql backing.
- * @throws Exception
- */
- public void testSimpleJDBCPutGetWithHSQL()
- throws Exception
- {
- System.setProperty( "hsqldb.cache_scale", "8" );
-
- String rafroot = "target";
- Properties p = new Properties();
- String driver = p.getProperty( "driver", "org.hsqldb.jdbcDriver" );
- String url = p.getProperty( "url", "jdbc:hsqldb:" );
- String database = p.getProperty( "database", rafroot + "/cache_hsql_db" );
- String user = p.getProperty( "user", "sa" );
- String password = p.getProperty( "password", "" );
-
- new org.hsqldb.jdbcDriver();
- Class.forName( driver ).newInstance();
- Connection cConn = DriverManager.getConnection( url + database, user, password );
-
- HsqlSetupTableUtil.setupTABLE( cConn, "JCS_STORE2" );
-
- runTestForRegion( "testCache1", 200 );
- }
-
- /**
- * Adds items to cache, gets them, and removes them. The item count is more than the size of the
- * memory cache, so items should spool to disk.
- * <p>
- * @param region Name of the region to access
- * @param items
- * @throws Exception If an error occurs
- */
- public void runTestForRegion( String region, int items )
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-
-// System.out.println( "BEFORE PUT \n" + jcs.getStats() );
-
- // Add items to cache
-
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
-
-// System.out.println( jcs.getStats() );
-
- Thread.sleep( 1000 );
-
-// System.out.println( jcs.getStats() );
-
- // Test that all items are in cache
-
- for ( int i = 0; i <= items; i++ )
- {
- String value = jcs.get( i + ":key" );
-
- assertEquals( "key = [" + i + ":key] value = [" + value + "]", region + " data " + i, value );
- }
-
- // Test that getElements returns all the expected values
- Set<String> keys = new HashSet<>();
- for ( int i = 0; i <= items; i++ )
- {
- keys.add( i + ":key" );
- }
-
- Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
- for ( int i = 0; i <= items; i++ )
- {
- ICacheElement<String, String> element = elements.get( i + ":key" );
- assertNotNull( "element " + i + ":key is missing", element );
- assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
- }
-
- // Remove all the items
- for ( int i = 0; i <= items; i++ )
- {
- jcs.remove( i + ":key" );
- }
-
- // Verify removal
- for ( int i = 0; i <= items; i++ )
- {
- assertNull( "Removed key should be null: " + i + ":key", jcs.get( i + ":key" ) );
- }
- }
-
- /**
- * Verfiy that it uses the pool access manager config.
- * <p>
- * @throws Exception
- */
- public void testInitializePoolAccess_withPoolName()
- throws Exception
- {
- // SETUP
- String poolName = "testInitializePoolAccess_withPoolName";
-
- String url = "jdbc:hsqldb:";
- String userName = "sa";
- String password = "";
- int maxActive = 10;
- String driverClassName = "org.hsqldb.jdbcDriver";
-
- Properties props = new Properties();
- String prefix = JDBCDiskCacheFactory.POOL_CONFIGURATION_PREFIX
- + poolName
- + JDBCDiskCacheFactory.ATTRIBUTE_PREFIX;
- props.put( prefix + ".url", url );
- props.put( prefix + ".userName", userName );
- props.put( prefix + ".password", password );
- props.put( prefix + ".maxActive", String.valueOf( maxActive ) );
- props.put( prefix + ".driverClassName", driverClassName );
-
- JDBCDiskCacheAttributes cattr = new JDBCDiskCacheAttributes();
- cattr.setConnectionPoolName( poolName );
- cattr.setTableName("JCSTESTTABLE_InitializePoolAccess");
-
- MockCompositeCacheManager compositeCacheManager = new MockCompositeCacheManager();
- compositeCacheManager.setConfigurationProperties( props );
- JDBCDiskCacheFactory dcFactory = new JDBCDiskCacheFactory();
- dcFactory.initialize();
- dcFactory.setScheduledExecutorService(Executors.newScheduledThreadPool(2,
- new DaemonThreadFactory("JCS-JDBCDiskCacheManager-", Thread.MIN_PRIORITY)));
-
- JDBCDiskCache<String, String> diskCache = dcFactory.createCache( cattr, compositeCacheManager, null, new StandardSerializer() );
- assertNotNull( "Should have a cache instance", diskCache );
-
- // DO WORK
- DataSourceFactory result = dcFactory.getDataSourceFactory(cattr, props);
-
- // VERIFY
- assertNotNull( "Should have a data source factory class", result );
- assertEquals( "wrong name", poolName, result.getName() );
-
- System.setProperty( "hsqldb.cache_scale", "8" );
-
- String rafroot = "target";
- String database = rafroot + "/cache_hsql_db";
-
- new org.hsqldb.jdbcDriver();
- Class.forName( driverClassName ).newInstance();
- Connection cConn = DriverManager.getConnection( url + database, userName, password );
-
- HsqlSetupTableUtil.setupTABLE( cConn, "JCSTESTTABLE_InitializePoolAccess" );
-
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/hsql/HSQLDiskCacheConcurrentUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/hsql/HSQLDiskCacheConcurrentUnitTest.java
deleted file mode 100644
index 4a666b8..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/hsql/HSQLDiskCacheConcurrentUnitTest.java
+++ /dev/null
@@ -1,161 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc.hsql;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-/*
- * 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.
- */
-
-import junit.extensions.ActiveTestSuite;
-import junit.framework.Test;
-import junit.framework.TestCase;
-
-/**
- * Test which exercises the indexed disk cache. This one uses three different regions for thre
- * threads.
- */
-public class HSQLDiskCacheConcurrentUnitTest
- extends TestCase
-{
- /**
- * Number of items to cache, twice the configured maxObjects for the memory cache regions.
- */
- private static int items = 100;
-
- /**
- * Constructor for the TestDiskCache object.
- * @param testName
- */
- public HSQLDiskCacheConcurrentUnitTest( String testName )
- {
- super( testName );
- }
-
- /**
- * A unit test suite for JUnit. Uses ActiveTestSuite to run multiple tests concurrently.
- * <p>
- * @return The test suite
- */
- public static Test suite()
- {
- ActiveTestSuite suite = new ActiveTestSuite();
-
- suite.addTest( new HSQLDiskCacheConcurrentUnitTest( "testHSQLDiskCache1" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion1" );
- }
- } );
-
- suite.addTest( new HSQLDiskCacheConcurrentUnitTest( "testHSQLDiskCache2" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion2" );
- }
- } );
-
- suite.addTest( new HSQLDiskCacheConcurrentUnitTest( "testHSQLDiskCache3" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion3" );
- }
- } );
-
- return suite;
- }
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestHSQLDiskCacheConcurrent.ccf" );
- }
-
- /**
- * Adds items to cache, gets them, and removes them. The item count is more than the size of the
- * memory cache, so items should spool to disk.
- * <p>
- * @param region Name of the region to access
- * @throws Exception If an error occurs
- */
- public void runTestForRegion( String region )
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-
- // Add items to cache
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
-
-// System.out.println( jcs.getStats() );
-
- // Test that all items are in cache
- for ( int i = 0; i <= items; i++ )
- {
- String value = jcs.get( i + ":key" );
-
- assertEquals( "key = [" + i + ":key] value = [" + value + "]", region + " data " + i, value );
- }
-
- // Test that getElements returns all the expected values
- Set<String> keys = new HashSet<>();
- for ( int i = 0; i <= items; i++ )
- {
- keys.add( i + ":key" );
- }
-
- Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
- for ( int i = 0; i <= items; i++ )
- {
- ICacheElement<String, String> element = elements.get( i + ":key" );
- assertNotNull( "element " + i + ":key is missing", element );
- assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
- }
-
- // Remove all the items
- for ( int i = 0; i <= items; i++ )
- {
- jcs.remove( i + ":key" );
- }
-
- // Verify removal
- for ( int i = 0; i <= items; i++ )
- {
- assertNull( "Removed key should be null: " + i + ":key", jcs.get( i + ":key" ) );
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/hsql/HSQLDiskCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/hsql/HSQLDiskCacheUnitTest.java
deleted file mode 100644
index 58d7e77..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/hsql/HSQLDiskCacheUnitTest.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc.hsql;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/**
- * Test which exercises the HSQL cache.
- */
-public class HSQLDiskCacheUnitTest
- extends TestCase
-{
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestHSQLDiskCache.ccf" );
- }
-
- /**
- * Adds items to cache, gets them, and removes them. The item count is more than the size of the
- * memory cache, so items should spool to disk.
- * <p>
- * @throws Exception If an error occurs
- */
- public void testBasicPutRemove()
- throws Exception
- {
- int items = 20;
-
- String region = "testBasicPutRemove";
-
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-
- // Add items to cache
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
-
- // Test that all items are in cache
- for ( int i = 0; i <= items; i++ )
- {
- String value = jcs.get( i + ":key" );
- assertEquals( "key = [" + i + ":key] value = [" + value + "]", region + " data " + i, value );
- }
-
- // Test that getElements returns all the expected values
- Set<String> keys = new HashSet<>();
- for ( int i = 0; i <= items; i++ )
- {
- keys.add( i + ":key" );
- }
-
- Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
- for ( int i = 0; i <= items; i++ )
- {
- ICacheElement<String, String> element = elements.get( i + ":key" );
- assertNotNull( "element " + i + ":key is missing", element );
- assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
- }
-
- // Remove all the items
- for ( int i = 0; i <= items; i++ )
- {
- jcs.remove( i + ":key" );
- }
-
- // Verify removal
- for ( int i = 0; i <= items; i++ )
- {
- assertNull( "Removed key should be null: " + i + ":key", jcs.get( i + ":key" ) );
- }
- }
-
- /**
- * Verify that remove all work son a region where it is not prohibited.
- * <p>
- * @throws CacheException
- * @throws InterruptedException
- */
- public void testRemoveAll()
- throws CacheException, InterruptedException
- {
- String region = "removeAllAllowed";
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-
- int items = 20;
-
- // Add items to cache
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
-
- // a db thread could be updating when we call remove all?
- // there was a race on remove all, an element may be put to disk after it is called even
- // though the put
- // was called before clear.
- // I discovered it and removed it.
- // Thread.sleep( 500 );
-
-// System.out.println( jcs.getStats() );
-
- jcs.clear();
-
- for ( int i = 0; i <= items; i++ )
- {
- String value = jcs.get( i + ":key" );
- assertNull( "value should be null key = [" + i + ":key] value = [" + value + "]", value );
- }
- }
-
- /**
- * Verify that remove all does not work on a region where it is prohibited.
- * <p>
- * @throws CacheException
- * @throws InterruptedException
- */
- public void testRemoveAllProhibition()
- throws CacheException, InterruptedException
- {
- String region = "noRemoveAll";
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-
- int items = 20;
-
- // Add items to cache
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
-
- // a db thread could be updating the disk when
- // Thread.sleep( 500 );
-
- jcs.clear();
-
- for ( int i = 0; i <= items; i++ )
- {
- String value = jcs.get( i + ":key" );
- assertEquals( "key = [" + i + ":key] value = [" + value + "]", region + " data " + i, value );
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCacheHsqlBackedUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCacheHsqlBackedUnitTest.java
deleted file mode 100644
index 7030397..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCacheHsqlBackedUnitTest.java
+++ /dev/null
@@ -1,178 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc.mysql;
-
-/*
- * 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.
- */
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.HsqlSetupTableUtil;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-/**
- * Runs basic tests for the JDBC disk cache.
- * @author Aaron Smuts
- */
-public class MySQLDiskCacheHsqlBackedUnitTest
-{
- /**
- * Creates the DB
- * <p>
- * @throws Exception
- */
- @BeforeClass
- public static void setupDatabase() throws Exception
- {
- System.setProperty( "hsqldb.cache_scale", "8" );
-
- String rafroot = "target";
- String url = "jdbc:hsqldb:";
- String database = rafroot + "/MySQLDiskCacheHsqlBackedUnitTest";
- String user = "sa";
- String password = "";
-
- new org.hsqldb.jdbcDriver();
- Connection cConn = DriverManager.getConnection( url + database, user, password );
-
- HsqlSetupTableUtil.setupTABLE( cConn, "JCS_STORE_MYSQL" );
- }
-
- /**
- * Test setup
- */
- @Before
- public void setUp()
- {
- JCS.setConfigFilename( "/TestMySQLDiskCache.ccf" );
- }
-
- /**
- * Test the basic JDBC disk cache functionality with a hsql backing.
- * @throws Exception
- */
- @Test
- public void testSimpleJDBCPutGetWithHSQL()
- throws Exception
- {
- runTestForRegion( "testCache1", 200 );
- }
-
- /**
- * Adds items to cache, gets them, and removes them. The item count is more than the size of the
- * memory cache, so items should spool to disk.
- * <p>
- * @param region Name of the region to access
- * @param items
- * @throws Exception If an error occurs
- */
- public void runTestForRegion( String region, int items )
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( region );
- //System.out.println( "BEFORE PUT \n" + jcs.getStats() );
-
- // Add items to cache
- for ( int i = 0; i < items; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
-
- //System.out.println( jcs.getStats() );
- Thread.sleep( 1000 );
- //System.out.println( jcs.getStats() );
-
- // Test that all items are in cache
- for ( int i = 0; i < items; i++ )
- {
- String value = jcs.get( i + ":key" );
-
- assertEquals( "key = [" + i + ":key] value = [" + value + "]", region + " data " + i, value );
- }
-
- // Test that getElements returns all the expected values
- Set<String> keys = new HashSet<>();
- for ( int i = 0; i < items; i++ )
- {
- keys.add( i + ":key" );
- }
-
- Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
- for ( int i = 0; i < items; i++ )
- {
- ICacheElement<String, String> element = elements.get( i + ":key" );
- assertNotNull( "element " + i + ":key is missing", element );
- assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
- }
-
- // Remove all the items
- for ( int i = 0; i < items; i++ )
- {
- jcs.remove( i + ":key" );
- }
-
- // Verify removal
-
- for ( int i = 0; i < items; i++ )
- {
- assertNull( "Removed key should be null: " + i + ":key", jcs.get( i + ":key" ) );
- }
- }
-
- /**
- * Test the basic JDBC disk cache functionality with a hsql backing.
- * <p>
- * @throws Exception
- */
- @Test
- public void testPutGetMatchingWithHSQL()
- throws Exception
- {
- // SETUP
- int items = 200;
- String region = "testCache2";
- CacheAccess<String, String> jcs = JCS.getInstance( region );
-// System.out.println( "BEFORE PUT \n" + jcs.getStats() );
-
- // DO WORK
- for ( int i = 0; i < items; i++ )
- {
- jcs.put( i + ":key", region + " data " + i );
- }
- Thread.sleep( 1000 );
-
- Map<String, ICacheElement<String, String>> matchingResults = jcs.getMatchingCacheElements( "1.8.+" );
-
- // VERIFY
- assertEquals( "Wrong number returned", 10, matchingResults.size() );
-// System.out.println( "matchingResults.keySet() " + matchingResults.keySet() );
-// System.out.println( "\nAFTER TEST \n" + jcs.getStats() );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCacheUnitTest.java
deleted file mode 100644
index 596252c..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/MySQLDiskCacheUnitTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc.mysql;
-
-/*
- * 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.
- */
-
-import java.sql.SQLException;
-
-import junit.framework.TestCase;
-
-import org.apache.commons.jcs.auxiliary.disk.jdbc.TableState;
-import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.SharedPoolDataSourceFactory;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-
-/**
- * Simple tests for the MySQLDisk Cache.
- * <p>
- * We will probably need to setup an hsql behind this, to test some of the pass through methods.
- * <p>
- * @author Aaron Smuts
- */
-public class MySQLDiskCacheUnitTest
- extends TestCase
-{
- /**
- * Verify that we simply return null on get if an optimization is in
- * progress and the cache is configured to balk on optimization.
- * <p>
- * This is a bit tricky since we don't want to have to have a mysql instance
- * running. Right now this doesn't really test much
- * @throws SQLException
- */
- public void testBalkOnGet() throws SQLException
- {
- // SETUP
- MySQLDiskCacheAttributes attributes = new MySQLDiskCacheAttributes();
- String tableName = "JCS_TEST";
- // Just use something that exists
- attributes.setDriverClassName( "org.hsqldb.jdbcDriver" );
- attributes.setTableName( tableName );
- attributes.setBalkDuringOptimization( true );
- SharedPoolDataSourceFactory dsFactory = new SharedPoolDataSourceFactory();
- dsFactory.initialize(attributes);
-
- TableState tableState = new TableState( tableName );
- tableState.setState( TableState.OPTIMIZATION_RUNNING );
-
- MySQLDiskCache<String, String> cache = new MySQLDiskCache<>( attributes, dsFactory, tableState,
- CompositeCacheManager.getUnconfiguredInstance() );
-
- // DO WORK
- Object result = cache.processGet( "myKey" );
-
- // VERIFY
- assertNull( "The result should be null", result );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/util/ScheduleParserUtilUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/util/ScheduleParserUtilUnitTest.java
deleted file mode 100644
index 14511d5..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/disk/jdbc/mysql/util/ScheduleParserUtilUnitTest.java
+++ /dev/null
@@ -1,129 +0,0 @@
-package org.apache.commons.jcs.auxiliary.disk.jdbc.mysql.util;
-
-/*
- * 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.
- */
-
-import java.text.ParseException;
-import java.util.Date;
-
-import junit.framework.TestCase;
-
-/**
- * Unit tests for the schedule parser.
- * <p>
- * @author Aaron Smuts
- */
-public class ScheduleParserUtilUnitTest
- extends TestCase
-{
-
- /**
- * Verify that we get an exception and not a null pointer for null input.
- */
- public void testGetDatesWithNullInput()
- {
- try
- {
- ScheduleParser.createDatesForSchedule( null );
-
- fail( "Should have thrown an exception" );
- }
- catch ( ParseException e )
- {
- // expected
- }
- }
-
- /**
- * Verify that we get an exception and not a null pointer for null input.
- */
- public void testGetDateWithNullInput()
- {
- try
- {
- ScheduleParser.getDateForSchedule( null );
-
- fail( "Should have thrown an exception" );
- }
- catch ( ParseException e )
- {
- // expected
- }
- }
-
- /**
- * Verify that we get one date for one date.
- * @throws ParseException
- */
- public void testGetsDatesSingle()
- throws ParseException
- {
- String schedule = "12:34:56";
- Date[] dates = ScheduleParser.createDatesForSchedule( schedule );
-
- assertEquals( "Wrong number of dates returned.", 1, dates.length );
- }
- /**
- * Verify that we get one date for one date.
- * @throws ParseException
- */
- public void testGetsDatesMultiple()
- throws ParseException
- {
- String schedule = "12:34:56,03:51:00,12:34:12";
- Date[] dates = ScheduleParser.createDatesForSchedule( schedule );
- //System.out.println( dates );
- assertEquals( "Wrong number of dates returned.", 3, dates.length );
- }
-
- /**
- * Verify that we get an exception for a single bad date in a list.
- */
- public void testGetDatesMalformedNoColon()
- {
- try
- {
- String schedule = "12:34:56,03:51:00,123234";
- ScheduleParser.createDatesForSchedule( schedule );
-
- fail( "Should have thrown an exception for a malformed date" );
- }
- catch ( ParseException e )
- {
- // expected
- }
- }
- /**
- * Verify that we get an exception for a schedule that has a non numeric item.
- */
- public void testGetDatesMalformedNan()
- {
- try
- {
- String schedule = "12:34:56,03:51:00,aa:12:12";
- ScheduleParser.createDatesForSchedule( schedule );
-
- fail( "Should have thrown an exception for a malformed date" );
- }
- catch ( ParseException e )
- {
- // expected
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheNoWaitFacadeUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheNoWaitFacadeUnitTest.java
deleted file mode 100644
index c36bd4f..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/LateralCacheNoWaitFacadeUnitTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheAttributes;
-
-/**
- * Tests for LateralCacheNoWaitFacade.
- */
-public class LateralCacheNoWaitFacadeUnitTest
- extends TestCase
-{
- /**
- * Verify that we can remove an item.
- */
- public void testAddThenRemoveNoWait_InList()
- {
- // SETUP
- @SuppressWarnings("unchecked")
- LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
- ILateralCacheAttributes cattr = new LateralCacheAttributes();
- cattr.setCacheName( "testCache1" );
-
- LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
-
- LateralCache<String, String> cache = new LateralCache<>( cattr );
- LateralCacheNoWait<String, String> noWait = new LateralCacheNoWait<>( cache );
-
- // DO WORK
- facade.addNoWait( noWait );
-
- // VERIFY
- assertTrue( "Should be in the list.", facade.containsNoWait( noWait ) );
-
- // DO WORK
- facade.removeNoWait( noWait );
-
- // VERIFY
- assertEquals( "Should have 0", 0, facade.noWaits.length );
- assertFalse( "Should not be in the list. ", facade.containsNoWait( noWait ) );
- }
-
- /**
- * Verify that we can remove an item.
- */
- public void testAddThenRemoveNoWait_InListSize2()
- {
- // SETUP
- @SuppressWarnings("unchecked")
- LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
- ILateralCacheAttributes cattr = new LateralCacheAttributes();
- cattr.setCacheName( "testCache1" );
-
- LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
-
- LateralCache<String, String> cache = new LateralCache<>( cattr );
- LateralCacheNoWait<String, String> noWait = new LateralCacheNoWait<>( cache );
- LateralCacheNoWait<String, String> noWait2 = new LateralCacheNoWait<>( cache );
-
- // DO WORK
- facade.addNoWait( noWait );
- facade.addNoWait( noWait2 );
-
- // VERIFY
- assertEquals( "Should have 2", 2, facade.noWaits.length );
- assertTrue( "Should be in the list.", facade.containsNoWait( noWait ) );
- assertTrue( "Should be in the list.", facade.containsNoWait( noWait2 ) );
-
- // DO WORK
- facade.removeNoWait( noWait );
-
- // VERIFY
- assertEquals( "Should only have 1", 1, facade.noWaits.length );
- assertFalse( "Should not be in the list. ", facade.containsNoWait( noWait ) );
- assertTrue( "Should be in the list.", facade.containsNoWait( noWait2 ) );
- }
-
- /**
- * Verify that we can remove an item.
- */
- public void testAdd_InList()
- {
- // SETUP
- @SuppressWarnings("unchecked")
- LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
- ILateralCacheAttributes cattr = new LateralCacheAttributes();
- cattr.setCacheName( "testCache1" );
-
- LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
-
- LateralCache<String, String> cache = new LateralCache<>( cattr );
- LateralCacheNoWait<String, String> noWait = new LateralCacheNoWait<>( cache );
-
- // DO WORK
- facade.addNoWait( noWait );
- facade.addNoWait( noWait );
-
- // VERIFY
- assertTrue( "Should be in the list.", facade.containsNoWait( noWait ) );
- assertEquals( "Should only have 1", 1, facade.noWaits.length );
- }
-
- /**
- * Verify that we can remove an item.
- */
- public void testAddThenRemoveNoWait_NotInList()
- {
- // SETUP
- @SuppressWarnings("unchecked")
- LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
- ILateralCacheAttributes cattr = new LateralCacheAttributes();
- cattr.setCacheName( "testCache1" );
-
- LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
-
- LateralCache<String, String> cache = new LateralCache<>( cattr );
- LateralCacheNoWait<String, String> noWait = new LateralCacheNoWait<>( cache );
-
- // DO WORK
- facade.removeNoWait( noWait );
-
- // VERIFY
- assertFalse( "Should not be in the list.", facade.containsNoWait( noWait ) );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/http/broadcast/LateralCacheTester.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/http/broadcast/LateralCacheTester.java
deleted file mode 100644
index 2326dff..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/http/broadcast/LateralCacheTester.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral.http.broadcast;
-
-/*
- * 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.
- */
-
-/**
- * @author Aaron Smuts
- * @version 1.0
- */
-public class LateralCacheTester
-{
-
- // /** Description of the Method */
- // public static void main( String args[] )
- // {
- //
- // String[] servers = {"10.1.17.109", "10.1.17.108"};
- //
- // try
- // {
- //
- // //for ( int i=0; i <100; i++ ) {
- // String val = "test object value";
- // LateralCacheThread dct = new LateralCacheThread( "testTable", "testkey",
- // val, servers );
- // dct.setPriority( Thread.NORM_PRIORITY - 1 );
- // dct.start();
- //
- // String val2 = "test object value2";
- // LateralCacheThread dct2 = new LateralCacheThread( "testTable", "testkey",
- // val, servers );
- // dct2.setPriority( Thread.NORM_PRIORITY - 1 );
- // dct2.start();
- // //}
- //
- // }
- // catch ( Exception e )
- // {
- // System.out.println( e.toString() );
- // }
- //
- // }
-
-}
-// end class
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPConcurrentRandomTestUtil.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPConcurrentRandomTestUtil.java
deleted file mode 100644
index ac2b159..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPConcurrentRandomTestUtil.java
+++ /dev/null
@@ -1,195 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral.socket.tcp;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-import java.util.Random;
-
-/**
- * @author Aaron Smuts
- */
-public class LateralTCPConcurrentRandomTestUtil
- extends TestCase
-{
- /** Should we write out. */
- private static boolean isSysOut = false;
- //private static boolean isSysOut = true;
-
- /**
- * Constructor for the TestDiskCache object.
- *
- * @param testName
- */
- public LateralTCPConcurrentRandomTestUtil( String testName )
- {
- super( testName );
- }
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestTCPLateralCacheConcurrent.ccf" );
- }
-
- /**
- * Randomly adds items to cache, gets them, and removes them. The range
- * count is more than the size of the memory cache, so items should spool to
- * disk.
- * <p>
- * @param region
- * Name of the region to access
- * @param range
- * @param numOps
- * @param testNum
- *
- * @throws Exception
- * If an error occurs
- */
- public void runTestForRegion( String region, int range, int numOps, int testNum )
- throws Exception
- {
- boolean show = true;//false;
-
- CacheAccess<String, String> cache = JCS.getInstance( region );
-
- TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
- lattr2.setTcpListenerPort( 1103 );
- lattr2.setTransmissionTypeName( "TCP" );
- lattr2.setTcpServer( "localhost:1102" );
-
- // this service will put and remove using the lateral to
- // the cache instance above
- // the cache thinks it is different since the listenerid is different
- LateralTCPService<String, String> service = new LateralTCPService<>( lattr2 );
- service.setListenerId( 123456 );
-
- try
- {
- for ( int i = 1; i < numOps; i++ )
- {
- Random ran = new Random( i );
- int n = ran.nextInt( 4 );
- int kn = ran.nextInt( range );
- String key = "key" + kn;
- if ( n == 1 )
- {
- ICacheElement<String, String> element = new CacheElement<>( region, key, region + ":data" + i
- + " junk asdfffffffadfasdfasf " + kn + ":" + n );
- service.update( element );
- if ( show )
- {
- p( "put " + key );
- }
- }
- /**/
- else if ( n == 2 )
- {
- service.remove( region, key );
- if ( show )
- {
- p( "removed " + key );
- }
- }
- /**/
- else
- {
- // slightly greater chance of get
- try
- {
- Object obj = service.get( region, key );
- if ( show && obj != null )
- {
- p( obj.toString() );
- }
- }
- catch ( Exception e )
- {
- // consider failing, some timeouts are expected
- e.printStackTrace();
- }
- }
-
- if ( i % 100 == 0 )
- {
- p( cache.getStats() );
- }
-
- }
- p( "Finished random cycle of " + numOps );
- }
- catch ( Exception e )
- {
- p( e.toString() );
- e.printStackTrace( System.out );
- throw e;
- }
-
- CacheAccess<String, String> jcs = JCS.getInstance( region );
- String key = "testKey" + testNum;
- String data = "testData" + testNum;
- jcs.put( key, data );
- String value = jcs.get( key );
- assertEquals( "Couldn't put normally.", data, value );
-
- // make sure the items we can find are in the correct region.
- for ( int i = 1; i < numOps; i++ )
- {
- String keyL = "key" + i;
- String dataL = jcs.get( keyL );
- if ( dataL != null )
- {
- assertTrue( "Incorrect region detected.", dataL.startsWith( region ) );
- }
-
- }
-
- //Thread.sleep( 1000 );
-
- //ICacheElement<String, String> element = new CacheElement( region, "abc", "testdata");
- //service.update( element );
-
- //Thread.sleep( 2500 );
- // could be too mcuh going on right now to get ti through, sot he test
- // might fail.
- //String value2 = (String) jcs.get( "abc" );
- //assertEquals( "Couldn't put laterally, could be too much traffic in
- // queue.", "testdata", value2 );
-
- }
-
- /**
- * @param s string to print
- */
- public static void p( String s )
- {
- if ( isSysOut )
- {
- System.out.println( s );
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPDiscoveryListenerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPDiscoveryListenerUnitTest.java
deleted file mode 100644
index 63b74a9..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPDiscoveryListenerUnitTest.java
+++ /dev/null
@@ -1,291 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral.socket.tcp;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.auxiliary.lateral.LateralCache;
-import org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes;
-import org.apache.commons.jcs.auxiliary.lateral.LateralCacheNoWait;
-import org.apache.commons.jcs.auxiliary.lateral.LateralCacheNoWaitFacade;
-import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheAttributes;
-import org.apache.commons.jcs.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-import org.apache.commons.jcs.engine.logging.MockCacheEventLogger;
-import org.apache.commons.jcs.utils.discovery.DiscoveredService;
-import org.apache.commons.jcs.utils.serialization.StandardSerializer;
-
-import java.util.ArrayList;
-
-/** Test for the listener that observers UDP discovery events. */
-public class LateralTCPDiscoveryListenerUnitTest
- extends TestCase
-{
- /** the listener */
- private LateralTCPDiscoveryListener listener;
-
- /** the cache factory */
- private LateralTCPCacheFactory factory;
-
- /** The cache manager. */
- private CompositeCacheManager cacheMgr;
-
- /** The event logger. */
- protected MockCacheEventLogger cacheEventLogger;
-
- /** The serializer. */
- protected IElementSerializer elementSerializer;
-
- /** Create the listener for testing */
- @Override
- protected void setUp() throws Exception
- {
- factory = new LateralTCPCacheFactory();
- factory.initialize();
-
- cacheMgr = CompositeCacheManager.getInstance();
- cacheEventLogger = new MockCacheEventLogger();
- elementSerializer = new StandardSerializer();
-
- listener = new LateralTCPDiscoveryListener( factory.getName(), cacheMgr );
- }
-
- /**
- * Add a no wait facade.
- */
- public void testAddNoWaitFacade_NotInList()
- {
- // SETUP
- String cacheName = "testAddNoWaitFacade_NotInList";
-
- @SuppressWarnings("unchecked")
- LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
- ILateralCacheAttributes cattr = new LateralCacheAttributes();
- cattr.setCacheName( cacheName );
-
- LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
-
- // DO WORK
- listener.addNoWaitFacade( cacheName, facade );
-
- // VERIFY
- assertTrue( "Should have the facade.", listener.containsNoWaitFacade( cacheName ) );
- }
-
- /**
- * Add a no wait to a known facade.
- */
- public void testAddNoWait_FacadeInList()
- {
- // SETUP
- String cacheName = "testAddNoWaitFacade_FacadeInList";
-
- @SuppressWarnings("unchecked")
- LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
- ILateralCacheAttributes cattr = new LateralCacheAttributes();
- cattr.setCacheName( cacheName );
-
- LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
- listener.addNoWaitFacade( cacheName, facade );
-
- LateralCache<String, String> cache = new LateralCache<>( cattr );
- LateralCacheNoWait<String, String> noWait = new LateralCacheNoWait<>( cache );
-
- // DO WORK
- boolean result = listener.addNoWait( noWait );
-
- // VERIFY
- assertTrue( "Should have added the no wait.", result );
- }
-
- /**
- * Add a no wait from an unknown facade.
- */
- public void testAddNoWait_FacadeNotInList()
- {
- // SETUP
- String cacheName = "testAddNoWaitFacade_FacadeInList";
- ILateralCacheAttributes cattr = new LateralCacheAttributes();
- cattr.setCacheName( cacheName );
-
- LateralCache<String, String> cache = new LateralCache<>( cattr );
- LateralCacheNoWait<String, String> noWait = new LateralCacheNoWait<>( cache );
-
- // DO WORK
- boolean result = listener.addNoWait( noWait );
-
- // VERIFY
- assertFalse( "Should not have added the no wait.", result );
- }
-
- /**
- * Remove a no wait from an unknown facade.
- */
- public void testRemoveNoWait_FacadeNotInList()
- {
- // SETUP
- String cacheName = "testRemoveNoWaitFacade_FacadeNotInList";
- ILateralCacheAttributes cattr = new LateralCacheAttributes();
- cattr.setCacheName( cacheName );
-
- LateralCache<String, String> cache = new LateralCache<>( cattr );
- LateralCacheNoWait<String, String> noWait = new LateralCacheNoWait<>( cache );
-
- // DO WORK
- boolean result = listener.removeNoWait( noWait );
-
- // VERIFY
- assertFalse( "Should not have removed the no wait.", result );
- }
-
- /**
- * Remove a no wait from a known facade.
- */
- public void testRemoveNoWait_FacadeInList_NoWaitNot()
- {
- // SETUP
- String cacheName = "testAddNoWaitFacade_FacadeInList";
-
- @SuppressWarnings("unchecked")
- LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
- ILateralCacheAttributes cattr = new LateralCacheAttributes();
- cattr.setCacheName( cacheName );
-
- LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
- listener.addNoWaitFacade( cacheName, facade );
-
- LateralCache<String, String> cache = new LateralCache<>( cattr );
- LateralCacheNoWait<String, String> noWait = new LateralCacheNoWait<>( cache );
-
- // DO WORK
- boolean result = listener.removeNoWait( noWait );
-
- // VERIFY
- assertFalse( "Should not have removed the no wait.", result );
- }
-
- /**
- * Remove a no wait from a known facade.
- */
- public void testRemoveNoWait_FacadeInList_NoWaitIs()
- {
- // SETUP
- String cacheName = "testRemoveNoWaitFacade_FacadeInListNoWaitIs";
-
- @SuppressWarnings("unchecked")
- LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
- ILateralCacheAttributes cattr = new LateralCacheAttributes();
- cattr.setCacheName( cacheName );
-
- LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
- listener.addNoWaitFacade( cacheName, facade );
-
- LateralCache<String, String> cache = new LateralCache<>( cattr );
- LateralCacheNoWait<String, String> noWait = new LateralCacheNoWait<>( cache );
- listener.addNoWait( noWait );
-
- // DO WORK
- boolean result = listener.removeNoWait( noWait );
-
- // VERIFY
- assertTrue( "Should have removed the no wait.", result );
- }
-
- /**
- * Add a no wait to a known facade.
- */
- public void testAddDiscoveredService_FacadeInList_NoWaitNot()
- {
- // SETUP
- String cacheName = "testAddDiscoveredService_FacadeInList_NoWaitNot";
-
- ArrayList<String> cacheNames = new ArrayList<>();
- cacheNames.add( cacheName );
-
- DiscoveredService service = new DiscoveredService();
- service.setCacheNames( cacheNames );
- service.setServiceAddress( "localhost" );
- service.setServicePort( 9999 );
-
- // since the no waits are compared by object equality, I have to do this
- // TODO add an equals method to the noWait. the problem if is figuring out what to compare.
- ITCPLateralCacheAttributes lca = new TCPLateralCacheAttributes();
- lca.setTransmissionType( LateralCacheAttributes.Type.TCP );
- lca.setTcpServer( service.getServiceAddress() + ":" + service.getServicePort() );
- lca.setCacheName(cacheName);
- LateralCacheNoWait<String, String> noWait = factory.createCacheNoWait(lca, cacheEventLogger, elementSerializer);
- // this is the normal process, the discovery service expects it there
- cacheMgr.addAuxiliaryCache(factory.getName(), cacheName, noWait);
-
- @SuppressWarnings("unchecked")
- LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
- ILateralCacheAttributes cattr = new LateralCacheAttributes();
- cattr.setCacheName( cacheName );
- LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
- listener.addNoWaitFacade( cacheName, facade );
-
- // DO WORK
- listener.addDiscoveredService( service );
-
- // VERIFY
- assertTrue( "Should have no wait.", listener.containsNoWait( cacheName, noWait ) );
- }
-
- /**
- * Remove a no wait from a known facade.
- */
- public void testRemoveDiscoveredService_FacadeInList_NoWaitIs()
- {
- // SETUP
- String cacheName = "testRemoveDiscoveredService_FacadeInList_NoWaitIs";
-
- ArrayList<String> cacheNames = new ArrayList<>();
- cacheNames.add( cacheName );
-
- DiscoveredService service = new DiscoveredService();
- service.setCacheNames( cacheNames );
- service.setServiceAddress( "localhost" );
- service.setServicePort( 9999 );
-
- // since the no waits are compared by object equality, I have to do this
- // TODO add an equals method to the noWait. the problem if is figuring out what to compare.
- ITCPLateralCacheAttributes lca = new TCPLateralCacheAttributes();
- lca.setTransmissionType( LateralCacheAttributes.Type.TCP );
- lca.setTcpServer( service.getServiceAddress() + ":" + service.getServicePort() );
- lca.setCacheName(cacheName);
- LateralCacheNoWait<String, String> noWait = factory.createCacheNoWait(lca, cacheEventLogger, elementSerializer);
- // this is the normal process, the discovery service expects it there
- cacheMgr.addAuxiliaryCache(factory.getName(), cacheName, noWait);
-
- @SuppressWarnings("unchecked")
- LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
- ILateralCacheAttributes cattr = new LateralCacheAttributes();
- cattr.setCacheName( cacheName );
- LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
- listener.addNoWaitFacade( cacheName, facade );
- listener.addDiscoveredService( service );
-
- // DO WORK
- listener.removeDiscoveredService( service );
-
- // VERIFY
- assertFalse( "Should not have no wait.", listener.containsNoWait( cacheName, noWait ) );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPFilterRemoveHashCodeUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPFilterRemoveHashCodeUnitTest.java
deleted file mode 100644
index 2084161..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPFilterRemoveHashCodeUnitTest.java
+++ /dev/null
@@ -1,192 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral.socket.tcp;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-import java.io.Serializable;
-
-/**
- * @author Aaron Smuts
- */
-public class LateralTCPFilterRemoveHashCodeUnitTest
- extends TestCase
-{
- /** Does the test print to system out. */
- private static boolean isSysOut = false;
-
- /** The port the server will listen to. */
- private final int serverPort = 2001;
-
- /**
- * Constructor for the TestDiskCache object.
- *
- * @param testName
- */
- public LateralTCPFilterRemoveHashCodeUnitTest( String testName )
- {
- super( testName );
- }
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- System.setProperty( "jcs.auxiliary.LTCP.attributes.TcpServers", "localhost:" + serverPort );
- JCS.setConfigFilename( "/TestTCPLateralRemoveFilter.ccf" );
- }
-
- /**
- *
- * @throws Exception
- */
- public void test()
- throws Exception
- {
- this.runTestForRegion( "region1", 200, 1 );
- }
-
- /**
- * This tests issues tons of puts. It also check to see that a key that was
- * put in was removed by the clients remove command.
- *
- * @param region
- * Name of the region to access
- * @param numOps
- * @param testNum
- *
- * @throws Exception
- * If an error occurs
- */
- public void runTestForRegion( String region, int numOps, int testNum )
- throws Exception
- {
- CacheAccess<String, Serializable> cache = JCS.getInstance( region );
-
- Thread.sleep( 100 );
-
- TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
- lattr2.setTcpListenerPort( 1102 );
- lattr2.setTransmissionTypeName( "TCP" );
- lattr2.setTcpServer( "localhost:" + serverPort );
- lattr2.setIssueRemoveOnPut( true );
- // should still try to remove
- lattr2.setAllowPut( false );
-
- // this service will put and remove using the lateral to
- // the cache instance above
- // the cache thinks it is different since the listenerid is different
- LateralTCPService<String, Serializable> service = new LateralTCPService<>( lattr2 );
- service.setListenerId( 123456 );
-
- String keyToBeRemovedOnPut = "test1";
-
- String keyToNotBeRemovedOnPut = "test2";
-
- Serializable dataToPassHashCodeCompare = new Serializable()
- {
- private static final long serialVersionUID = 1L;
-
- @Override
- public int hashCode()
- {
- return 1;
- }
- };
- //String dataToPassHashCodeCompare = "this should be the same and not
- // get removed.";
- //p( "dataToPassHashCodeCompare hashcode = " + +
- // dataToPassHashCodeCompare.hashCode() );
-
- cache.put( keyToBeRemovedOnPut, "this should get removed." );
- ICacheElement<String, Serializable> element1 = new CacheElement<>( region, keyToBeRemovedOnPut, region
- + ":data-this shouldn't get there" );
- service.update( element1 );
-
- cache.put( keyToNotBeRemovedOnPut, dataToPassHashCodeCompare );
- ICacheElement<String, Serializable> element2 = new CacheElement<>( region, keyToNotBeRemovedOnPut, dataToPassHashCodeCompare );
- service.update( element2 );
-
- /*
- * try { for ( int i = 1; i < numOps; i++ ) { Random ran = new Random( i );
- * int n = ran.nextInt( 4 ); int kn = ran.nextInt( range ); String key =
- * "key" + kn;
- *
- * ICacheElement<String, String> element = new CacheElement( region, key, region +
- * ":data" + i + " junk asdfffffffadfasdfasf " + kn + ":" + n );
- * service.update( element ); if ( show ) { p( "put " + key ); }
- *
- * if ( i % 100 == 0 ) { System.out.println( cache.getStats() ); }
- * } p( "Finished cycle of " + numOps ); } catch ( Exception e ) { p(
- * e.toString() ); e.printStackTrace( System.out ); throw e; }
- */
-
- CacheAccess<String, String> jcs = JCS.getInstance( region );
- String key = "testKey" + testNum;
- String data = "testData" + testNum;
- jcs.put( key, data );
- String value = jcs.get( key );
- assertEquals( "Couldn't put normally.", data, value );
-
- // make sure the items we can find are in the correct region.
- for ( int i = 1; i < numOps; i++ )
- {
- String keyL = "key" + i;
- String dataL = jcs.get( keyL );
- if ( dataL != null )
- {
- assertTrue( "Incorrect region detected.", dataL.startsWith( region ) );
- }
-
- }
-
- Thread.sleep( 200 );
-
- Object testObj1 = cache.get( keyToBeRemovedOnPut );
- p( "test object1 = " + testObj1 );
- assertNull( "The test object should have been remvoed by a put.", testObj1 );
-
- Object testObj2 = cache.get( keyToNotBeRemovedOnPut );
- p( "test object2 = " + testObj2 + " hashCode = " );
- if ( testObj2 != null )
- {
- p( "test2 hashcode = " + +testObj2.hashCode() );
- }
- assertNotNull( "This should not have been removed, since the hascode were the same.", testObj2 );
-
- }
-
- /**
- * @param s String to print
- */
- public static void p( String s )
- {
- if ( isSysOut )
- {
- System.out.println( s );
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPIssueRemoveOnPutUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPIssueRemoveOnPutUnitTest.java
deleted file mode 100644
index d2cd13e..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPIssueRemoveOnPutUnitTest.java
+++ /dev/null
@@ -1,225 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral.socket.tcp;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-import java.util.Random;
-
-/**
- * Tests the issue remove on put fuctionality.
- * @author asmuts
- */
-public class LateralTCPIssueRemoveOnPutUnitTest
- extends TestCase
-{
- /** Should log data go to system out. */
- private static boolean isSysOut = false;
-
- /** The port the server will listen to. */
- private final int serverPort = 1118;
-
- /**
- * Constructor for the TestDiskCache object.
- * <p>
- * @param testName
- */
- public LateralTCPIssueRemoveOnPutUnitTest( String testName )
- {
- super( testName );
- }
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- System.setProperty( "jcs.auxiliary.LTCP.attributes.TcpServers", "localhost:" + serverPort );
-
- JCS.setConfigFilename( "/TestTCPLateralIssueRemoveCache.ccf" );
- }
-
- /**
- * @throws Exception
- */
- public void testPutLocalPutRemoteGetBusyVerifyRemoved()
- throws Exception
- {
- this.runTestForRegion( "region1", 1, 200, 1 );
- }
-
- /**
- * Verify that a standard put works. Get the cache configured from a file. Create a tcp service
- * to talk to that cache. Put via the service. Verify that the cache got the data.
- * <p>
- * @throws Exception
- */
- public void testStandardPut()
- throws Exception
- {
- String region = "region1";
-
- CacheAccess<String, String> cache = JCS.getInstance( region );
-
- Thread.sleep( 100 );
-
- TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
- lattr2.setTcpListenerPort( 1102 );
- lattr2.setTransmissionTypeName( "TCP" );
- lattr2.setTcpServer( "localhost:" + serverPort );
- lattr2.setIssueRemoveOnPut( false );
- // should still try to remove
- // lattr2.setAllowPut( false );
-
- // Using the lateral, this service will put to and remove from
- // the cache instance above.
- // The cache thinks it is different since the listenerid is different
- LateralTCPService<String, String> service = new LateralTCPService<>( lattr2 );
- service.setListenerId( 123456 );
-
- String keyToBeRemovedOnPut = "test1_notremoved";
-
- ICacheElement<String, String> element1 = new CacheElement<>( region, keyToBeRemovedOnPut, region
- + ":data-this shouldn't get removed, it should get to the cache." );
- service.update( element1 );
-
- Thread.sleep( 1000 );
-
- Object testObj = cache.get( keyToBeRemovedOnPut );
- p( "testStandardPut, test object = " + testObj );
- assertNotNull( "The test object should not have been removed by a put.", testObj );
- }
-
- /**
- * This tests issues tons of puts. It also check to see that a key that was put in was removed
- * by the clients remove command.
- * <p>
- * @param region Name of the region to access
- * @param range
- * @param numOps
- * @param testNum
- * @throws Exception If an error occurs
- */
- public void runTestForRegion( String region, int range, int numOps, int testNum )
- throws Exception
- {
-
- boolean show = false;
-
- CacheAccess<String, String> cache = JCS.getInstance( region );
-
- Thread.sleep( 100 );
-
- TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
- lattr2.setTcpListenerPort( 1102 );
- lattr2.setTransmissionTypeName( "TCP" );
- lattr2.setTcpServer( "localhost:" + serverPort );
- lattr2.setIssueRemoveOnPut( true );
- // should still try to remove
- lattr2.setAllowPut( false );
-
- // Using the lateral, this service will put to and remove from
- // the cache instance above.
- // The cache thinks it is different since the listenerid is different
- LateralTCPService<String, String> service = new LateralTCPService<>( lattr2 );
- service.setListenerId( 123456 );
-
- String keyToBeRemovedOnPut = "test1";
- cache.put( keyToBeRemovedOnPut, "this should get removed." );
-
- ICacheElement<String, String> element1 = new CacheElement<>( region, keyToBeRemovedOnPut, region
- + ":data-this shouldn't get there" );
- service.update( element1 );
-
- try
- {
- for ( int i = 1; i < numOps; i++ )
- {
- Random ran = new Random( i );
- int n = ran.nextInt( 4 );
- int kn = ran.nextInt( range );
- String key = "key" + kn;
-
- ICacheElement<String, String> element = new CacheElement<>( region, key, region + ":data" + i
- + " junk asdfffffffadfasdfasf " + kn + ":" + n );
- service.update( element );
- if ( show )
- {
- p( "put " + key );
- }
-
- if (show && i % 100 == 0 )
- {
- System.out.println( cache.getStats() );
- }
-
- }
- p( "Finished cycle of " + numOps );
- }
- catch ( Exception e )
- {
- p( e.toString() );
- e.printStackTrace( System.out );
- throw e;
- }
-
- CacheAccess<String, String> jcs = JCS.getInstance( region );
- String key = "testKey" + testNum;
- String data = "testData" + testNum;
- jcs.put( key, data );
- String value = jcs.get( key );
- assertEquals( "Couldn't put normally.", data, value );
-
- // make sure the items we can find are in the correct region.
- for ( int i = 1; i < numOps; i++ )
- {
- String keyL = "key" + i;
- String dataL = jcs.get( keyL );
- if ( dataL != null )
- {
- assertTrue( "Incorrect region detected.", dataL.startsWith( region ) );
- }
-
- }
-
- Thread.sleep( 200 );
-
- Object testObj = cache.get( keyToBeRemovedOnPut );
- p( "runTestForRegion, test object = " + testObj );
- assertNull( "The test object should have been removed by a put.", testObj );
-
- }
-
- /**
- * @param s String to be printed
- */
- public static void p( String s )
- {
- if ( isSysOut )
- {
- System.out.println( s );
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPNoDeadLockConcurrentTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPNoDeadLockConcurrentTest.java
deleted file mode 100644
index 8019f85..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/LateralTCPNoDeadLockConcurrentTest.java
+++ /dev/null
@@ -1,146 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral.socket.tcp;
-
-/*
- * 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.
- */
-
-import junit.extensions.ActiveTestSuite;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-
-/**
- * Test which exercises the tcp lateral cache. Runs two threads against the
- * same region and two against other regions.
- */
-public class LateralTCPNoDeadLockConcurrentTest
- extends TestCase
-{
- /**
- * Constructor for the TestDiskCache object.
- *
- * @param testName
- */
- public LateralTCPNoDeadLockConcurrentTest( String testName )
- {
- super( testName );
- }
-
- /**
- * Main method passes this test to the text test runner.
- *
- * @param args
- */
- public static void main( String args[] )
- {
- String[] testCaseName = { LateralTCPNoDeadLockConcurrentTest.class.getName() };
- junit.textui.TestRunner.main( testCaseName );
- }
-
- /**
- * A unit test suite for JUnit
- *
- * @return The test suite
- */
- public static Test suite()
- {
-
- System.setProperty( "jcs.auxiliary.LTCP.attributes.PutOnlyMode", "false" );
-
- ActiveTestSuite suite = new ActiveTestSuite();
-
- suite.addTest( new LateralTCPConcurrentRandomTestUtil( "testLateralTCPCache1" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "region1", 1, 200, 1 );
- }
- } );
-
- suite.addTest( new LateralTCPConcurrentRandomTestUtil( "testLateralTCPCache2" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "region2", 10000, 12000, 2 );
- }
- } );
-
- suite.addTest( new LateralTCPConcurrentRandomTestUtil( "testLateralTCPCache3" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "region3", 10000, 12000, 3 );
- }
- } );
-
- suite.addTest( new LateralTCPConcurrentRandomTestUtil( "testLateralTCPCache4" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "region3", 10000, 13000, 4 );
- }
- } );
-
- suite.addTest( new LateralTCPConcurrentRandomTestUtil( "testLateralTCPCache5" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "region4", 10000, 11000, 5 );
- }
- } );
-
- return suite;
- }
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestTCPLateralCacheConcurrent.ccf" );
- }
-
- /**
- * Test tearDown. Dispose of the cache.
- */
- @Override
- public void tearDown()
- {
- try
- {
- CompositeCacheManager cacheMgr = CompositeCacheManager.getInstance();
- cacheMgr.shutDown();
- }
- catch ( Exception e )
- {
- e.printStackTrace();
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/TestTCPLateralUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/TestTCPLateralUnitTest.java
deleted file mode 100644
index 631ff0a..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/lateral/socket/tcp/TestTCPLateralUnitTest.java
+++ /dev/null
@@ -1,368 +0,0 @@
-package org.apache.commons.jcs.auxiliary.lateral.socket.tcp;
-
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes;
-import org.apache.commons.jcs.auxiliary.lateral.LateralCommand;
-import org.apache.commons.jcs.auxiliary.lateral.LateralElementDescriptor;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-import org.apache.commons.jcs.engine.control.MockCompositeCacheManager;
-import org.apache.commons.jcs.engine.control.group.GroupAttrName;
-import org.apache.commons.jcs.engine.control.group.GroupId;
-import org.apache.commons.jcs.utils.timing.SleepUtil;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/**
- * Basic unit tests for the sending and receiving portions of the lateral cache.
- * <p>
- * @author Aaron Smuts
- */
-public class TestTCPLateralUnitTest
- extends TestCase
-{
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestTCPLateralCache.ccf" );
- }
-
- /**
- * Make sure we can send a bunch to the listener. This would be better if we could plugin a Mock
- * CacheManger. The listener will instantiate it on its own. We have to configure one before
- * that.
- * <p>
- * @throws Exception
- */
- public void testSimpleSend()
- throws Exception
- {
- // SETUP
- // force initialization
- JCS.getInstance( "test" );
-
- TCPLateralCacheAttributes lac = new TCPLateralCacheAttributes();
- lac.setTransmissionType( LateralCacheAttributes.Type.TCP );
- lac.setTcpServer( "localhost" + ":" + 8111 );
- lac.setTcpListenerPort( 8111 );
-
- ICompositeCacheManager cacheMgr = CompositeCacheManager.getInstance();
-
- // start the listener
- LateralTCPListener<String, String> listener = LateralTCPListener.getInstance( lac, cacheMgr );
-
- // send to the listener
- LateralTCPSender lur = new LateralTCPSender( lac );
-
- // DO WORK
- int numMes = 10;
- for ( int i = 0; i < numMes; i++ )
- {
- String message = "adsfasasfasfasdasf";
- CacheElement<String, String> ce = new CacheElement<>( "test", "test", message );
- LateralElementDescriptor<String, String> led = new LateralElementDescriptor<>( ce );
- led.command = LateralCommand.UPDATE;
- led.requesterId = 1;
- lur.send( led );
- }
-
- SleepUtil.sleepAtLeast( numMes * 3 );
-
- // VERIFY
- assertEquals( "Should have received " + numMes + " by now.", numMes, listener.getPutCnt() );
- }
-
- /**
- * @throws Exception
- */
- public void testReceive()
- throws Exception
- {
- // VERIFY
- TCPLateralCacheAttributes lattr = new TCPLateralCacheAttributes();
- lattr.setTcpListenerPort( 1101 );
- lattr.setTransmissionTypeName( "TCP" );
- MockCompositeCacheManager cacheMgr = new MockCompositeCacheManager();
-// System.out.println( "mock cache = " + cacheMgr.getCache( "test" ) );
-
- LateralTCPListener.getInstance( lattr, cacheMgr );
-
- TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
- lattr2.setTcpListenerPort( 1102 );
- lattr2.setTransmissionTypeName( "TCP" );
- lattr2.setTcpServer( "localhost:1101" );
-
- LateralTCPService<String, String> service = new LateralTCPService<>( lattr2 );
- service.setListenerId( 123456 );
-
- // DO WORK
- int cnt = 100;
- for ( int i = 0; i < cnt; i++ )
- {
- ICacheElement<String, String> element = new CacheElement<>( "test", "key" + i, "value1" );
- service.update( element );
- }
-
- SleepUtil.sleepAtLeast( 1000 );
-
- // VERIFY
- assertEquals( "Didn't get the correct number", cnt, cacheMgr.getCache().getUpdateCount() );
- }
-
- /**
- * Send objects with the same key but different values.
- * <p>
- * @throws Exception
- */
- public void testSameKeyDifferentObject()
- throws Exception
- {
- // SETUP
- // setup a listener
- TCPLateralCacheAttributes lattr = new TCPLateralCacheAttributes();
- lattr.setTcpListenerPort( 1103 );
- MockCompositeCacheManager cacheMgr = new MockCompositeCacheManager();
- CompositeCache<String, String> cache = cacheMgr.getCache( "test" );
-// System.out.println( "mock cache = " + cache );
-
- // get the listener started
- // give it our mock cache manager
- //LateralTCPListener listener = (LateralTCPListener)
- LateralTCPListener.getInstance( lattr, cacheMgr );
-
- // setup a service to talk to the listener started above.
- TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
- lattr2.setTcpListenerPort( 1104 );
- lattr2.setTcpServer( "localhost:1103" );
-
- LateralTCPService<String, String> service = new LateralTCPService<>( lattr2 );
- service.setListenerId( 123456 );
-
- // DO WORK
- ICacheElement<String, String> element = new CacheElement<>( "test", "key", "value1" );
- service.update( element );
-
- SleepUtil.sleepAtLeast( 300 );
-
- ICacheElement<String, String> element2 = new CacheElement<>( "test", "key", "value2" );
- service.update( element2 );
-
- SleepUtil.sleepAtLeast( 1000 );
-
- // VERIFY
- ICacheElement<String, String> cacheElement = cache.get( "key" );
- assertEquals( "Didn't get the correct object "+ cacheElement, element2.getVal(), cacheElement.getVal() );
- }
-
- /**
- * Send objects with the same key but different values.
- * <p>
- * @throws Exception
- */
- public void testSameKeyObjectDifferentValueObject()
- throws Exception
- {
- TCPLateralCacheAttributes lattr = new TCPLateralCacheAttributes();
- lattr.setTcpListenerPort( 1105 );
- lattr.setTransmissionTypeName( "TCP" );
- MockCompositeCacheManager cacheMgr = new MockCompositeCacheManager();
- CompositeCache<String, String> cache = cacheMgr.getCache( "test" );
-// System.out.println( "mock cache = " + cache );
-
- // get the listener started
- // give it our mock cache manager
- //LateralTCPListener listener = (LateralTCPListener)
- LateralTCPListener.getInstance( lattr, cacheMgr );
-
- TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
- lattr2.setTcpListenerPort( 1106 );
- lattr2.setTransmissionTypeName( "TCP" );
- lattr2.setTcpServer( "localhost:1105" );
-
- LateralTCPService<String, String> service = new LateralTCPService<>( lattr2 );
- service.setListenerId( 123456 );
-
- // DO WORK
- String key = "key";
- ICacheElement<String, String> element = new CacheElement<>( "test", key, "value1" );
- service.update( element );
-
- SleepUtil.sleepAtLeast( 300 );
-
- ICacheElement<String, String> element2 = new CacheElement<>( "test", key, "value2" );
- service.update( element2 );
-
- SleepUtil.sleepAtLeast( 1000 );
-
- // VERIFY
- ICacheElement<String, String> cacheElement = cache.get( "key" );
- assertEquals( "Didn't get the correct object: " + cacheElement , element2.getVal(), cacheElement.getVal() );
- }
-
- /**
- * Create a listener. Add an element to the listeners cache. Setup a service. Try to get from
- * the service.
- * <p>
- * @throws Exception
- */
- public void testGet_SendAndReceived()
- throws Exception
- {
- // SETUP
- // setup a listener
- TCPLateralCacheAttributes lattr = new TCPLateralCacheAttributes();
- lattr.setTcpListenerPort( 1107 );
- MockCompositeCacheManager cacheMgr = new MockCompositeCacheManager();
- CompositeCache<String, String> cache = cacheMgr.getCache( "test" );
-// System.out.println( "mock cache = " + cache );
-
- // get the listener started
- // give it our mock cache manager
- LateralTCPListener.getInstance( lattr, cacheMgr );
-
- // add the item to the listeners cache
- ICacheElement<String, String> element = new CacheElement<>( "test", "key", "value1" );
- cache.update( element );
-
- // setup a service to talk to the listener started above.
- TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
- lattr2.setTcpListenerPort( 1108 );
- lattr2.setTcpServer( "localhost:1107" );
-
- LateralTCPService<String, String> service = new LateralTCPService<>( lattr2 );
- service.setListenerId( 123456 );
-
- SleepUtil.sleepAtLeast( 300 );
-
- // DO WORK
- ICacheElement<String, String> result = service.get( "test", "key" );
-
- // VERIFY
- assertNotNull( "Result should not be null.", result );
- assertEquals( "Didn't get the correct object", element.getVal(), result.getVal() );
- }
-
- /**
- * Create a listener. Add an element to the listeners cache. Setup a service. Try to get keys from
- * the service.
- * <p>
- * @throws Exception
- */
- public void testGetGroupKeys_SendAndReceived() throws Exception
- {
- // SETUP
- // setup a listener
- TCPLateralCacheAttributes lattr = new TCPLateralCacheAttributes();
- lattr.setTcpListenerPort( 1150 );
- MockCompositeCacheManager cacheMgr = new MockCompositeCacheManager();
- CompositeCache<GroupAttrName<String>, String> cache = cacheMgr.getCache( "test" );
-// System.out.println( "mock cache = " + cache );
-
- // get the listener started
- // give it our mock cache manager
- LateralTCPListener.getInstance( lattr, cacheMgr );
-
- // add the item to the listeners cache
- GroupAttrName<String> groupKey = new GroupAttrName<>(new GroupId("test", "group"), "key");
- ICacheElement<GroupAttrName<String>, String> element =
- new CacheElement<>( "test", groupKey, "value1" );
- cache.update( element );
-
- // setup a service to talk to the listener started above.
- TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
- lattr2.setTcpListenerPort( 1151 );
- lattr2.setTcpServer( "localhost:1150" );
-
- LateralTCPService<GroupAttrName<String>, String> service =
- new LateralTCPService<>( lattr2 );
- service.setListenerId( 123459 );
-
- SleepUtil.sleepAtLeast( 500 );
-
- // DO WORK
- Set<GroupAttrName<String>> result = service.getKeySet("test");
-
- // SleepUtil.sleepAtLeast( 5000000 );
-
- // VERIFY
- assertNotNull( "Result should not be null.", result );
- assertEquals( "Didn't get the correct object", "key", result.iterator().next().attrName );
- }
-
- /**
- * Create a listener. Add an element to the listeners cache. Setup a service. Try to get from
- * the service.
- * <p>
- * @throws Exception
- */
- public void testGetMatching_WithData()
- throws Exception
- {
- // SETUP
- // setup a listener
- TCPLateralCacheAttributes lattr = new TCPLateralCacheAttributes();
- lattr.setTcpListenerPort( 1108 );
- MockCompositeCacheManager cacheMgr = new MockCompositeCacheManager();
- CompositeCache<String, Integer> cache = cacheMgr.getCache( "test" );
-// System.out.println( "mock cache = " + cache );
-
- // get the listener started
- // give it our mock cache manager
- LateralTCPListener.getInstance( lattr, cacheMgr );
-
- String keyprefix1 = "MyPrefix1";
- int numToInsertPrefix1 = 10;
- // insert with prefix1
- for ( int i = 0; i < numToInsertPrefix1; i++ )
- {
- // add the item to the listeners cache
- ICacheElement<String, Integer> element = new CacheElement<>( "test", keyprefix1 + String.valueOf( i ), Integer.valueOf( i ) );
- cache.update( element );
- }
-
- // setup a service to talk to the listener started above.
- TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
- lattr2.setTcpListenerPort( 1108 );
- lattr2.setTcpServer( "localhost:1108" );
-
- LateralTCPService<String, Integer> service = new LateralTCPService<>( lattr2 );
- service.setListenerId( 123456 );
-
- SleepUtil.sleepAtLeast( 300 );
-
- // DO WORK
- Map<String, ICacheElement<String, Integer>> result = service.getMatching( "test", keyprefix1 + ".+" );
-
- // VERIFY
- assertNotNull( "Result should not be null.", result );
- assertEquals( "Wrong number returned 1:", numToInsertPrefix1, result.size() );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/MockRemoteCacheClient.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/MockRemoteCacheClient.java
deleted file mode 100644
index 9d78664..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/MockRemoteCacheClient.java
+++ /dev/null
@@ -1,261 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheClient;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheListener;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * Used for testing the no wait.
- * <p>
- * @author Aaron Smuts
- */
-public class MockRemoteCacheClient<K, V>
- extends AbstractAuxiliaryCache<K, V>
- implements IRemoteCacheClient<K, V>
-{
- /** log instance */
- private static final Log log = LogManager.getLog( MockRemoteCacheClient.class );
-
- /** List of ICacheElement<K, V> objects passed into update. */
- public List<ICacheElement<K, V>> updateList = new LinkedList<>();
-
- /** List of key objects passed into remove. */
- public List<K> removeList = new LinkedList<>();
-
- /** status to return. */
- public CacheStatus status = CacheStatus.ALIVE;
-
- /** Can setup values to return from get. values must be ICacheElement<K, V> */
- public Map<K, ICacheElement<K, V>> getSetupMap = new HashMap<>();
-
- /** Can setup values to return from get. values must be Map<K, ICacheElement<K, V>> */
- public Map<Set<K>, Map<K, ICacheElement<K, V>>> getMultipleSetupMap =
- new HashMap<>();
-
- /** The last service passed to fixCache */
- public ICacheServiceNonLocal<K, V> fixed;
-
- /** Attributes. */
- public RemoteCacheAttributes attributes = new RemoteCacheAttributes();
-
- /**
- * Stores the last argument as fixed.
- */
- @Override
- @SuppressWarnings("unchecked") // Don't know how to do this properly
- public void fixCache( ICacheServiceNonLocal<?, ?> remote )
- {
- fixed = (ICacheServiceNonLocal<K, V>)remote;
- }
-
- /**
- * @return long
- */
- @Override
- public long getListenerId()
- {
- return 0;
- }
-
- /**
- * @return null
- */
- @Override
- public IRemoteCacheListener<K, V> getListener()
- {
- return null;
- }
-
- /**
- * Adds the argument to the updatedList.
- */
- @Override
- public void update( ICacheElement<K, V> ce )
- {
- updateList.add( ce );
- }
-
- /**
- * Looks in the getSetupMap for a value.
- */
- @Override
- public ICacheElement<K, V> get( K key )
- {
- log.info( "get [" + key + "]" );
- return getSetupMap.get( key );
- }
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
- * data in cache for any of these keys
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
- {
- log.info( "get [" + keys + "]" );
- return getMultipleSetupMap.get( keys );
- }
-
- /**
- * Adds the key to the remove list.
- */
- @Override
- public boolean remove( K key )
- {
- removeList.add( key );
- return false;
- }
-
- /**
- * Removes all cached items from the cache.
- */
- @Override
- public void removeAll()
- {
- // do nothing
- }
-
- /**
- * Prepares for shutdown.
- */
- @Override
- public void dispose()
- {
- // do nothing
- }
-
- /**
- * Returns the current cache size in number of elements.
- * <p>
- * @return number of elements
- */
- @Override
- public int getSize()
- {
- return 0;
- }
-
- /**
- * Returns the status setup variable.
- */
- @Override
- public CacheStatus getStatus()
- {
- return status;
- }
-
- /**
- * Returns the cache name.
- * <p>
- * @return usually the region name.
- */
- @Override
- public String getCacheName()
- {
- return null;
- }
-
- /**
- * @return null
- */
- @Override
- public Set<K> getKeySet( )
- {
- return null;
- }
-
- /**
- * @return null
- */
- @Override
- public IStats getStatistics()
- {
- return null;
- }
-
- /**
- * Returns the setup attributes. By default they are not null.
- */
- @Override
- public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
- {
- return attributes;
- }
-
- /**
- * Returns the cache stats.
- * <p>
- * @return String of important historical information.
- */
- @Override
- public String getStats()
- {
- return null;
- }
-
- /** @return 0 */
- @Override
- public CacheType getCacheType()
- {
- return CacheType.REMOTE_CACHE;
- }
-
- /**
- * @param pattern
- * @return Map
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching(String pattern)
- throws IOException
- {
- return new HashMap<>();
- }
-
- /**
- * Nothing important
- * <p>
- * @return null
- */
- @Override
- public String getEventLoggingExtraInfo()
- {
- return null;
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/MockRemoteCacheListener.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/MockRemoteCacheListener.java
deleted file mode 100644
index 4295ec6..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/MockRemoteCacheListener.java
+++ /dev/null
@@ -1,168 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.LinkedList;
-import java.util.List;
-
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheListener;
-import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-/**
- * For testing.
- * <p>
- * @author Aaron Smuts
- */
-public class MockRemoteCacheListener<K, V>
- implements IRemoteCacheListener<K, V>
-{
- /** Setup the listener id that this will return. */
- private long listenerId;
-
- /** Setup the listener ip that this will return. */
- public String localAddress;
-
- /** Number of times handlePut was called. */
- public int putCount;
-
- /** List of ICacheElements passed to handlePut. */
- public List<ICacheElement<K, V>> putItems = new LinkedList<>();
-
- /** List of Serializable objects passed to handleRemove. */
- public List<K> removedKeys = new LinkedList<>();
-
- /** Number of times handleRemote was called. */
- public int removeCount;
-
- /** The type of remote listener */
- public RemoteType remoteType = RemoteType.LOCAL;
-
- /**
- * @throws IOException
- */
- @Override
- public void dispose()
- throws IOException
- {
- // TODO Auto-generated method stub
- }
-
- /**
- * returns the listener id, which can be setup.
- * @return listenerId
- * @throws IOException
- */
- @Override
- public long getListenerId()
- throws IOException
- {
- return listenerId;
- }
-
- /**
- * @return localAddress
- * @throws IOException
- */
- @Override
- public String getLocalHostAddress()
- throws IOException
- {
- return localAddress;
- }
-
- /**
- * Return the setup remoteType.
- * @return remoteType
- * @throws IOException
- */
- @Override
- public RemoteType getRemoteType()
- throws IOException
- {
- return remoteType;
- }
-
- /**
- * Allows you to setup the listener id.
- * <p>
- * @param id
- * @throws IOException
- */
- @Override
- public void setListenerId( long id )
- throws IOException
- {
- listenerId = id;
- }
-
- /**
- * @param cacheName
- * @throws IOException
- */
- @Override
- public void handleDispose( String cacheName )
- throws IOException
- {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * This increments the put count and adds the item to the putItem list.
- * <p>
- * @param item
- * @throws IOException
- */
- @Override
- public void handlePut( ICacheElement<K, V> item )
- throws IOException
- {
- putCount++;
- this.putItems.add( item );
- }
-
- /**
- * Increments the remove count and adds the key to the removedKeys list.
- * <p>
- * @param cacheName
- * @param key
- * @throws IOException
- */
- @Override
- public void handleRemove( String cacheName, K key )
- throws IOException
- {
- removeCount++;
- removedKeys.add( key );
- }
-
- /**
- * @param cacheName
- * @throws IOException
- */
- @Override
- public void handleRemoveAll( String cacheName )
- throws IOException
- {
- // TODO Auto-generated method stub
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/MockRemoteCacheService.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/MockRemoteCacheService.java
deleted file mode 100644
index b004220..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/MockRemoteCacheService.java
+++ /dev/null
@@ -1,241 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-
-/**
- * This is a mock impl of the remote cache service.
- */
-public class MockRemoteCacheService<K, V>
- implements ICacheServiceNonLocal<K, V>
-{
- /** The key last passed to get */
- public K lastGetKey;
-
- /** The pattern last passed to get */
- public String lastGetMatchingPattern;
-
- /** The keya last passed to getMatching */
- public Set<K> lastGetMultipleKeys;
-
- /** The object that was last passed to update. */
- public ICacheElement<K, V> lastUpdate;
-
- /** List of updates. */
- public List<ICacheElement<K, V>> updateRequestList = new ArrayList<>();
-
- /** List of request ids. */
- public List<Long> updateRequestIdList = new ArrayList<>();
-
- /** The key that was last passed to remove. */
- public K lastRemoveKey;
-
- /** The cache name that was last passed to removeAll. */
- public String lastRemoveAllCacheName;
-
- /**
- * @param cacheName
- * @param key
- * @param requesterId
- * @return null
- */
- @Override
- public ICacheElement<K, V> get( String cacheName, K key, long requesterId )
- {
- lastGetKey = key;
- return null;
- }
-
- /**
- * @param cacheName
- * @return empty set
- */
- @Override
- public Set<K> getKeySet( String cacheName )
- {
- return new HashSet<>();
- }
-
- /**
- * Set the last remove key.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId
- */
- @Override
- public void remove( String cacheName, K key, long requesterId )
- {
- lastRemoveKey = key;
- }
-
- /**
- * Set the lastRemoveAllCacheName to the cacheName.
- */
- @Override
- public void removeAll( String cacheName, long requesterId )
- throws IOException
- {
- lastRemoveAllCacheName = cacheName;
- }
-
- /**
- * Set the last update item.
- * <p>
- * @param item
- * @param requesterId
- */
- @Override
- public void update( ICacheElement<K, V> item, long requesterId )
- {
- lastUpdate = item;
- updateRequestList.add( item );
- updateRequestIdList.add( Long.valueOf( requesterId ) );
- }
-
- /**
- * Do nothing.
- * <p>
- * @param cacheName
- */
- @Override
- public void dispose( String cacheName )
- {
- return;
- }
-
- /**
- * @param cacheName
- * @param key
- * @return null
- */
- @Override
- public ICacheElement<K, V> get( String cacheName, K key )
- {
- return get( cacheName, key, 0 );
- }
-
- /**
- * Do nothing.
- */
- @Override
- public void release()
- {
- return;
- }
-
- /**
- * Set the last remove key.
- * <p>
- * @param cacheName
- * @param key
- */
- @Override
- public void remove( String cacheName, K key )
- {
- lastRemoveKey = key;
- }
-
- /**
- * Set the last remove all cache name.
- * <p>
- * @param cacheName
- */
- @Override
- public void removeAll( String cacheName )
- {
- lastRemoveAllCacheName = cacheName;
- }
-
- /**
- * Set the last update item.
- * <p>
- * @param item
- */
- @Override
- public void update( ICacheElement<K, V> item )
- {
- lastUpdate = item;
- }
-
- /**
- * @param cacheName
- * @param keys
- * @param requesterId
- * @return empty map
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys, long requesterId )
- {
- lastGetMultipleKeys = keys;
- return new HashMap<>();
- }
-
- /**
- * @param cacheName
- * @param keys
- * @return empty map
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys )
- {
- return getMultiple( cacheName, keys, 0 );
- }
-
- /**
- * Returns an empty map. Zombies have no internal data.
- * <p>
- * @param cacheName
- * @param pattern
- * @return an empty map
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern )
- throws IOException
- {
- return getMatching( cacheName, pattern, 0 );
- }
-
- /**
- * @param cacheName
- * @param pattern
- * @param requesterId
- * @return Map
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern, long requesterId )
- throws IOException
- {
- lastGetMatchingPattern = pattern;
- return new HashMap<>();
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheClientTester.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheClientTester.java
deleted file mode 100644
index cc62371..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheClientTester.java
+++ /dev/null
@@ -1,342 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.access.exception.ObjectExistsException;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheConstants;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheListener;
-import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheObserver;
-import org.apache.commons.jcs.engine.behavior.ICacheService;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.rmi.Naming;
-import java.rmi.NotBoundException;
-import java.rmi.Remote;
-import java.rmi.registry.Registry;
-import java.rmi.server.ExportException;
-import java.rmi.server.UnicastRemoteObject;
-
-/**
- * Manual tester.
- */
-public class RemoteCacheClientTester
- implements IRemoteCacheListener<String, String>, IRemoteCacheConstants, Remote
-{
- /** the observer */
- protected ICacheObserver watch;
-
- /** the service */
- protected ICacheService<String, String> cache;
-
- /** The registry host name. */
- final String host;
-
- /** The registry port number. */
- final int port;
-
- /** call count */
- final int count;
-
- /** Description of the Field */
- protected static long listenerId = 0;
-
- /**
- * Gets the remoteType attribute of the RemoteCacheClientTest object
- * @return The remoteType value
- * @throws IOException
- */
- @Override
- public RemoteType getRemoteType()
- throws IOException
- {
- return RemoteType.LOCAL;
- }
-
- /**
- * Constructor for the RemoteCacheClientTest object
- * @param count
- * @throws MalformedURLException
- * @throws NotBoundException
- * @throws IOException
- */
- public RemoteCacheClientTester( int count )
- throws MalformedURLException, NotBoundException, IOException
- {
- this( count, true, true, false );
- }
-
- /**
- * Constructor for the RemoteCacheClientTest object
- * @param count
- * @param write
- * @param read
- * @param delete
- * @throws MalformedURLException
- * @throws NotBoundException
- * @throws IOException
- */
- public RemoteCacheClientTester( int count, boolean write, boolean read, boolean delete )
- throws MalformedURLException, NotBoundException, IOException
- {
- this( "", Registry.REGISTRY_PORT, count, write, read, delete );
- }
-
- /**
- * Constructor for the RemoteCacheClientTest object
- * @param host
- * @param port
- * @param count
- * @param write
- * @param read
- * @param delete
- * @throws MalformedURLException
- * @throws NotBoundException
- * @throws IOException
- */
- @SuppressWarnings("unchecked")
- public RemoteCacheClientTester( String host, int port, int count, boolean write, boolean read, boolean delete )
- throws MalformedURLException, NotBoundException, IOException
- {
- this.count = count;
- this.host = host;
- this.port = port;
- // record export exception
- Exception ee = null;
-
- try
- {
- // Export this remote object to make it available to receive
- // incoming calls,
- // using an anonymous port.
- UnicastRemoteObject.exportObject( this );
- }
- catch ( ExportException e )
- {
- // use already exported object; remember exception
- ee = e;
- ee.printStackTrace();
- }
- String service = System.getProperty( REMOTE_CACHE_SERVICE_NAME );
-
- if ( service == null )
- {
- service = REMOTE_CACHE_SERVICE_VAL;
- }
- String registry = RemoteUtils.getNamingURL(host, port, service);
-
- p( "looking up server " + registry );
-
- Object obj = Naming.lookup( registry );
-
- p( "server found" );
-
- cache = (ICacheService<String, String>) obj;
- watch = (ICacheObserver) obj;
-
- p( "subscribing to the server" );
-
- watch.addCacheListener( "testCache", this );
- ICacheElement<String, String> cb = new CacheElement<>( "testCache", "testKey", "testVal" );
-
- for ( int i = 0; i < count; i++ )
- {
- cb = new CacheElement<>( "testCache", "" + i, "" + i );
-
- if ( delete )
- {
- p( "deleting a cache item from the server " + i );
-
- cache.remove( cb.getCacheName(), cb.getKey() );
- }
- if ( write )
- {
- p( "putting a cache bean to the server " + i );
-
- try
- {
- cache.update( cb );
- }
- catch ( ObjectExistsException oee )
- {
- p( oee.toString() );
- }
- }
- if ( read )
- {
- try
- {
- Object val = cache.get( cb.getCacheName(), cb.getKey() );
- p( "get " + cb.getKey() + " returns " + val );
- }
- catch ( CacheException onfe )
- {
- // nothing
- }
- }
- }
- }
-
- /**
- * @param cb
- * @throws IOException
- */
- @Override
- public void handlePut( ICacheElement<String, String> cb )
- throws IOException
- {
- p( "handlePut> cb=" + cb );
- }
-
- /**
- * @param cacheName
- * @param key
- * @throws IOException
- */
- @Override
- public void handleRemove( String cacheName, String key )
- throws IOException
- {
- p( "handleRemove> cacheName=" + cacheName + ", key=" + key );
- }
-
- /**
- * @param cacheName
- * @throws IOException
- */
- @Override
- public void handleRemoveAll( String cacheName )
- throws IOException
- {
- p( "handleRemove> cacheName=" + cacheName );
- }
-
- /**
- * @param cacheName
- * @throws IOException
- */
- @Override
- public void handleDispose( String cacheName )
- throws IOException
- {
- p( "handleDispose> cacheName=" + cacheName );
- }
-
- /*
- * public void handleRelease() throws IOException { p("handleRelease>"); }
- */
- /**
- * The main program for the RemoteCacheClientTest class
- * @param args The command line arguments
- * @throws Exception
- */
- public static void main( String[] args )
- throws Exception
- {
- int count = 0;
- boolean read = false;
- boolean write = false;
- boolean delete = false;
-
- for ( int i = 0; i < args.length; i++ )
- {
- if ( args[i].startsWith( "-" ) )
- {
- if ( !read )
- {
- read = args[i].indexOf( "r" ) != -1;
- }
- if ( !write )
- {
- write = args[i].indexOf( "w" ) != -1;
- }
- if ( !delete )
- {
- delete = args[i].indexOf( "d" ) != -1;
- }
- }
- else
- {
- count = Integer.parseInt( args[i] );
- }
- }
- new RemoteCacheClientTester( count, write, read, delete );
- }
-
- /**
- * Sets the listenerId attribute of the RemoteCacheClientTest object
- * @param id The new listenerId value
- * @throws IOException
- */
- @Override
- public void setListenerId( long id )
- throws IOException
- {
- listenerId = id;
- p( "listenerId = " + id );
- }
-
- /**
- * Gets the listenerId attribute of the RemoteCacheClientTest object
- * @return The listenerId value
- * @throws IOException
- */
- @Override
- public long getListenerId()
- throws IOException
- {
- return listenerId;
- }
-
- /**
- * Helper for output, this is an user run test class
- * @param s
- */
- private static void p( String s )
- {
- System.out.println( s );
- }
-
- /**
- * @return null
- * @throws IOException
- */
- @Override
- public String getLocalHostAddress()
- throws IOException
- {
- // TODO Auto-generated method stub
- return null;
- }
-
- /**
- * @throws IOException
- */
- @Override
- public void dispose()
- throws IOException
- {
- // TODO Auto-generated method stub
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheListenerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheListenerUnitTest.java
deleted file mode 100644
index 7cc7e7c..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheListenerUnitTest.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
-import org.apache.commons.jcs.engine.CacheElementSerialized;
-import org.apache.commons.jcs.engine.ElementAttributes;
-import org.apache.commons.jcs.engine.behavior.ICache;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElementSerialized;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.control.MockCompositeCacheManager;
-import org.apache.commons.jcs.utils.serialization.StandardSerializer;
-
-/**
- * Tests for the remote cache listener.
- * <p>
- * @author Aaron Smuts
- */
-public class RemoteCacheListenerUnitTest
- extends TestCase
-{
- /**
- * Create a RemoteCacheListener with a mock cache manager. Set remove on put to false.
- * Create a serialized element. Call put on the listener.
- * Verify that the deserialized element is in the cache.
- * <p>
- * @throws Exception
- */
- public void testUpdate_PutOnPut()
- throws Exception
- {
- // SETUP
- IRemoteCacheAttributes irca = new RemoteCacheAttributes();
- irca.setRemoveUponRemotePut( false );
- ICompositeCacheManager cacheMgr = new MockCompositeCacheManager();
- RemoteCacheListener<String, String> listener = new RemoteCacheListener<>( irca, cacheMgr, new StandardSerializer() );
-
- String cacheName = "testName";
- String key = "key";
- String value = "value fdsadf dsafdsa fdsaf dsafdsaf dsafdsaf dsaf dsaf dsaf dsafa dsaf dsaf dsafdsaf";
- IElementAttributes attr = new ElementAttributes();
- attr.setMaxLife(34);
-
- IElementSerializer elementSerializer = new StandardSerializer();
-
- ICacheElementSerialized<String, String> element =
- new CacheElementSerialized<>( cacheName, key, elementSerializer
- .serialize( value ), attr );
-
- // DO WORK
- listener.handlePut( element );
-
- // VERIFY
- ICache<String, String> cache = cacheMgr.getCache( cacheName );
- ICacheElement<String, String> after = cache.get( key );
-
- assertNotNull( "Should have a deserialized object.", after );
- assertEquals( "Values should be the same.", value, after.getVal() );
- assertEquals( "Attributes should be the same.", attr.getMaxLife(), after
- .getElementAttributes().getMaxLife() );
- assertEquals( "Keys should be the same.", key, after.getKey() );
- assertEquals( "Cache name should be the same.", cacheName, after.getCacheName() );
- }
-
- /**
- * Create a RemoteCacheListener with a mock cache manager. Set remove on put to true.
- * Create a serialized element. Call put on the listener.
- * Verify that the deserialized element is not in the cache.
- * <p>
- * @throws Exception
- */
- public void testUpdate_RemoveOnPut()
- throws Exception
- {
- // SETUP
- IRemoteCacheAttributes irca = new RemoteCacheAttributes();
- irca.setRemoveUponRemotePut( true );
- ICompositeCacheManager cacheMgr = new MockCompositeCacheManager();
- RemoteCacheListener<String, String> listener = new RemoteCacheListener<>( irca, cacheMgr, new StandardSerializer() );
-
- String cacheName = "testName";
- String key = "key";
- String value = "value fdsadf dsafdsa fdsaf dsafdsaf dsafdsaf dsaf dsaf dsaf dsafa dsaf dsaf dsafdsaf";
- IElementAttributes attr = new ElementAttributes();
- attr.setMaxLife(34);
-
- IElementSerializer elementSerializer = new StandardSerializer();
-
- ICacheElementSerialized<String, String> element =
- new CacheElementSerialized<>( cacheName, key, elementSerializer
- .serialize( value ), attr );
-
- // DO WORK
- listener.handlePut( element );
-
- // VERIFY
- ICache<String, String> cache = cacheMgr.getCache( cacheName );
- ICacheElement<String, String> after = cache.get( key );
-
- assertNull( "Should not have a deserialized object since remove on put is true.", after );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitFacadeUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitFacadeUnitTest.java
deleted file mode 100644
index 8af3017..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitFacadeUnitTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/**
- * Tests for RemoteCacheNoWaitFacade.
- */
-public class RemoteCacheNoWaitFacadeUnitTest
- extends TestCase
-{
- /**
- * Verify that we can add an item.
- */
- public void testAddNoWait_InList()
- {
- // SETUP
- List<RemoteCacheNoWait<String, String>> noWaits = new ArrayList<>();
- IRemoteCacheAttributes cattr = new RemoteCacheAttributes();
- cattr.setCacheName( "testCache1" );
-
- RemoteCache<String, String> client = new RemoteCache<>(cattr, null, null, null);
- RemoteCacheNoWait<String, String> noWait = new RemoteCacheNoWait<>( client );
- noWaits.add( noWait );
-
- RemoteCacheNoWaitFacade<String, String> facade = new RemoteCacheNoWaitFacade<>(noWaits, cattr, null, null, null );
-
- // VERIFY
- assertEquals( "Should have one entry.", 1, facade.noWaits.size() );
- assertTrue( "Should be in the list.", facade.noWaits.contains( noWait ) );
- assertSame( "Should have same facade.", facade, ((RemoteCache<String, String>)facade.noWaits.get(0).getRemoteCache()).getFacade() );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitUnitTest.java
deleted file mode 100644
index 93a7236..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitUnitTest.java
+++ /dev/null
@@ -1,211 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.utils.timing.SleepUtil;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/**
- * Unit tests for the remote cache no wait. The no wait manages a queue on top of the client.
- * <p>
- * @author Aaron Smuts
- */
-public class RemoteCacheNoWaitUnitTest
- extends TestCase
-{
- /**
- * Simply verify that the client gets updated via the no wait.
- * <p>
- * @throws Exception
- */
- public void testUpdate()
- throws Exception
- {
- // SETUP
- MockRemoteCacheClient<String, String> client = new MockRemoteCacheClient<>();
- RemoteCacheNoWait<String, String> noWait = new RemoteCacheNoWait<>( client );
-
- ICacheElement<String, String> element = new CacheElement<>( "testUpdate", "key", "value" );
-
- // DO WORK
- noWait.update( element );
-
- // VERIFY
- SleepUtil.sleepAtLeast( 10 );
-
- assertEquals( "Wrong number updated.", 1, client.updateList.size() );
- assertEquals( "Wrong element", element, client.updateList.get( 0 ) );
- }
-
- /**
- * Simply verify that the client get is called from the no wait.
- * <p>
- * @throws Exception
- */
- public void testGet()
- throws Exception
- {
- // SETUP
- MockRemoteCacheClient<String, String> client = new MockRemoteCacheClient<>();
- RemoteCacheNoWait<String, String> noWait = new RemoteCacheNoWait<>( client );
-
- ICacheElement<String, String> input = new CacheElement<>( "testUpdate", "key", "value" );
- client.getSetupMap.put( "key", input );
-
- // DO WORK
- ICacheElement<String, String> result = noWait.get( "key" );
-
- // VERIFY
- assertEquals( "Wrong element", input, result );
- }
-
- /**
- * Simply verify that the client getMultiple is called from the no wait.
- * <p>
- * @throws Exception
- */
- public void testGetMultiple()
- throws Exception
- {
- // SETUP
- MockRemoteCacheClient<String, String> client = new MockRemoteCacheClient<>();
- RemoteCacheNoWait<String, String> noWait = new RemoteCacheNoWait<>( client );
-
- ICacheElement<String, String> inputElement = new CacheElement<>( "testUpdate", "key", "value" );
- Map<String, ICacheElement<String, String>> inputMap = new HashMap<>();
- inputMap.put( "key", inputElement );
-
- Set<String> keys = new HashSet<>();
- keys.add( "key" );
-
- client.getMultipleSetupMap.put( keys, inputMap );
-
- // DO WORK
- Map<String, ICacheElement<String, String>> result = noWait.getMultiple( keys );
-
- // VERIFY
- assertEquals( "elements map", inputMap, result );
- }
-
- /**
- * Simply verify that the client gets updated via the no wait.
- * <p>
- * @throws Exception
- */
- public void testRemove()
- throws Exception
- {
- // SETUP
- MockRemoteCacheClient<String, String> client = new MockRemoteCacheClient<>();
- RemoteCacheNoWait<String, String> noWait = new RemoteCacheNoWait<>( client );
-
- String input = "MyKey";
-
- // DO WORK
- noWait.remove( input );
-
- SleepUtil.sleepAtLeast( 10 );
-
- // VERIFY
- assertEquals( "Wrong number updated.", 1, client.removeList.size() );
- assertEquals( "Wrong key", input, client.removeList.get( 0 ) );
- }
-
- /**
- * Simply verify that the client status is returned in the stats.
- * <p>
- * @throws Exception
- */
- public void testGetStats()
- throws Exception
- {
- // SETUP
- MockRemoteCacheClient<String, String> client = new MockRemoteCacheClient<>();
- client.status = CacheStatus.ALIVE;
- RemoteCacheNoWait<String, String> noWait = new RemoteCacheNoWait<>( client );
-
- // DO WORK
- String result = noWait.getStats();
-
- // VERIFY
- assertTrue( "Status should contain 'ALIVE'", result.indexOf( "ALIVE" ) != -1 );
- }
-
- /**
- * Simply verify that we get a status of error if the cache is in error..
- * <p>
- * @throws Exception
- */
- public void testGetStatus_error()
- throws Exception
- {
- // SETUP
- MockRemoteCacheClient<String, String> client = new MockRemoteCacheClient<>();
- client.status = CacheStatus.ERROR;
- RemoteCacheNoWait<String, String> noWait = new RemoteCacheNoWait<>( client );
-
- // DO WORK
- CacheStatus result = noWait.getStatus();
-
- // VERIFY
- assertEquals( "Wrong status", CacheStatus.ERROR, result );
- }
-
- /**
- * Simply verify that the serviced supplied to fix is passed onto the client. Verify that the
- * original event queue is destroyed. A new event queue willbe plugged in on fix.
- * <p>
- * @throws Exception
- */
- public void testFixCache()
- throws Exception
- {
- // SETUP
- MockRemoteCacheClient<String, String> client = new MockRemoteCacheClient<>();
- client.status = CacheStatus.ALIVE;
- RemoteCacheNoWait<String, String> noWait = new RemoteCacheNoWait<>( client );
-
- MockRemoteCacheService<String, String> service = new MockRemoteCacheService<>();
-
- ICacheElement<String, String> element = new CacheElement<>( "testUpdate", "key", "value" );
-
- // DO WORK
- noWait.update( element );
- SleepUtil.sleepAtLeast( 10 );
- // ICacheEventQueue<String, String> originalQueue = noWait.getCacheEventQueue();
-
- noWait.fixCache( service );
-
- noWait.update( element );
- SleepUtil.sleepAtLeast( 10 );
-
- // VERIFY
- assertEquals( "Wrong status", service, client.fixed );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheUnitTest.java
deleted file mode 100644
index 55090d4..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheUnitTest.java
+++ /dev/null
@@ -1,295 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import java.util.HashSet;
-import java.util.Map;
-
-import junit.framework.TestCase;
-
-import org.apache.commons.jcs.auxiliary.MockCacheEventLogger;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.ZombieCacheServiceNonLocal;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElementSerialized;
-import org.apache.commons.jcs.utils.serialization.SerializationConversionUtil;
-
-/**
- * Unit Tests for the Remote Cache.
- */
-public class RemoteCacheUnitTest
- extends TestCase
-{
- private IRemoteCacheAttributes cattr;
- private MockRemoteCacheService<String, String> service;
- private MockRemoteCacheListener<String, String> listener;
- private RemoteCacheMonitor monitor;
-
- /**
- * @see junit.framework.TestCase#setUp()
- */
- @Override
- protected void setUp() throws Exception
- {
- super.setUp();
- cattr = new RemoteCacheAttributes();
- service = new MockRemoteCacheService<>();
- listener = new MockRemoteCacheListener<>();
- monitor = new RemoteCacheMonitor();
- }
-
- /**
- * Verify that the remote service update method is called. The remote cache serializes the object
- * first.
- * <p>
- * @throws Exception
- */
- public void testUpdate()
- throws Exception
- {
- // SETUP
- long listenerId = 123;
- listener.setListenerId( listenerId );
-
- RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, service, listener, monitor );
-
- String cacheName = "testUpdate";
-
- // DO WORK
- ICacheElement<String, String> element = new CacheElement<>( cacheName, "key", "value" );
- remoteCache.update( element );
-
- // VERIFY
- assertTrue( "The element should be in the serialized wrapper.",
- service.lastUpdate instanceof ICacheElementSerialized );
- ICacheElement<String, String> result = SerializationConversionUtil
- .getDeSerializedCacheElement( (ICacheElementSerialized<String, String>) service.lastUpdate, remoteCache
- .getElementSerializer() );
- assertEquals( "Wrong element updated.", element.getVal(), result.getVal() );
- assertEquals( "Wrong listener id.", Long.valueOf( listenerId ), service.updateRequestIdList.get( 0 ) );
- }
-
- /**
- * Verify that when we call fix events queued in the zombie are propagated to the new service.
- * <p>
- * @throws Exception
- */
- public void testUpdateZombieThenFix()
- throws Exception
- {
- // SETUP
- ZombieCacheServiceNonLocal<String, String> zombie = new ZombieCacheServiceNonLocal<>( 10 );
-
- // set the zombie
- RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, zombie, listener, monitor );
-
- String cacheName = "testUpdate";
-
- // DO WORK
- ICacheElement<String, String> element = new CacheElement<>( cacheName, "key", "value" );
- remoteCache.update( element );
- // set the new service, this should call propagate
- remoteCache.fixCache( service );
-
- // VERIFY
- assertTrue( "The element should be in the serialized warapper.",
- service.lastUpdate instanceof ICacheElementSerialized );
- ICacheElement<String, String> result = SerializationConversionUtil
- .getDeSerializedCacheElement( (ICacheElementSerialized<String, String>) service.lastUpdate, remoteCache
- .getElementSerializer() );
- assertEquals( "Wrong element updated.", element.getVal(), result.getVal() );
- }
-
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testUpdate_simple()
- throws Exception
- {
- RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, service, listener, monitor );
-
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- remoteCache.setCacheEventLogger( cacheEventLogger );
-
- ICacheElement<String, String> item = new CacheElement<>( "region", "key", "value" );
-
- // DO WORK
- remoteCache.update( item );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testGet_simple()
- throws Exception
- {
- RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, service, listener, monitor );
-
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- remoteCache.setCacheEventLogger( cacheEventLogger );
-
- // DO WORK
- remoteCache.get( "key" );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testGetMultiple_simple()
- throws Exception
- {
- RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, service, listener, monitor );
-
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- remoteCache.setCacheEventLogger( cacheEventLogger );
-
- // DO WORK
- remoteCache.getMultiple( new HashSet<>() );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testRemove_simple()
- throws Exception
- {
- RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, service, listener, monitor );
-
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- remoteCache.setCacheEventLogger( cacheEventLogger );
-
- // DO WORK
- remoteCache.remove( "key" );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testRemoveAll_simple()
- throws Exception
- {
- RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, service, listener, monitor );
-
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- remoteCache.setCacheEventLogger( cacheEventLogger );
-
- // DO WORK
- remoteCache.remove( "key" );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testGetMatching_simple()
- throws Exception
- {
- // SETUP
- String pattern = "adsfasdfasd.?";
-
- RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, service, listener, monitor );
-
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- remoteCache.setCacheEventLogger( cacheEventLogger );
-
- // DO WORK
- Map<String, ICacheElement<String, String>> result = remoteCache.getMatching( pattern );
-
- // VERIFY
- assertNotNull( "Should have a map", result );
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testDispose_simple()
- throws Exception
- {
- RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, service, listener, monitor );
-
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- remoteCache.setCacheEventLogger( cacheEventLogger );
-
- // DO WORK
- remoteCache.dispose( );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-
- /**
- * Verify that there is no problem if there is no listener.
- * <p>
- * @throws Exception
- */
- public void testDispose_nullListener()
- throws Exception
- {
- // SETUP
- RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, service, null, monitor );
-
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- remoteCache.setCacheEventLogger( cacheEventLogger );
-
- // DO WORK
- remoteCache.dispose( );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteUtilsUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteUtilsUnitTest.java
deleted file mode 100644
index 344b521..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteUtilsUnitTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import java.rmi.registry.Registry;
-
-import junit.framework.TestCase;
-
-/**
- * Simple tests for remote utils. It is difficult to verify most of the things is does.
- *<p>
- * @author Aaron Smuts
- */
-public class RemoteUtilsUnitTest
- extends TestCase
-{
- /**
- * Call create registry.
- * <p>
- * The exception is in the security manager setting.
- */
- public void testCreateRegistry()
- {
- Registry registry = RemoteUtils.createRegistry( 1102 );
- assertNotNull("Registry should not be null", registry);
- }
-
- public void testGetNamingURL()
- {
- assertEquals("//host:1/servicename", RemoteUtils.getNamingURL("host",1,"servicename"));
- assertEquals("//127.0.0.1:2/servicename", RemoteUtils.getNamingURL("127.0.0.1",2,"servicename"));
- assertEquals("//[0:0:0:0:0:0:0:1%251]:3/servicename", RemoteUtils.getNamingURL("0:0:0:0:0:0:0:1%1",3,"servicename"));
- }
-
- public void testParseServerAndPort()
- {
- RemoteLocation loc = RemoteLocation.parseServerAndPort("server1:1234");
- assertEquals("server1", loc.getHost());
- assertEquals(1234, loc.getPort());
-
- loc = RemoteLocation.parseServerAndPort(" server2 : 4567 ");
- assertEquals("server2", loc.getHost());
- assertEquals(4567, loc.getPort());
-
- loc = RemoteLocation.parseServerAndPort("server2 : port");
- assertNull(loc);
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/TestRemoteCache.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/TestRemoteCache.java
deleted file mode 100644
index f7c9666..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/TestRemoteCache.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-import java.util.Properties;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.MockCacheEventLogger;
-import org.apache.commons.jcs.auxiliary.remote.server.RemoteCacheServerFactory;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.control.MockCompositeCacheManager;
-import org.apache.commons.jcs.engine.control.MockElementSerializer;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/**
- * @author Aaron SMuts
- */
-public class TestRemoteCache
- extends TestCase
-{
- /** The logger */
- private static final Log log = LogManager.getLog( TestRemoteCache.class );
-
- /**
- * Start the cache.
- */
- public TestRemoteCache()
- {
- super();
- try
- {
- System.out.println( "main> creating registry on the localhost" );
- RemoteUtils.createRegistry( 1101 );
- Properties config = RemoteUtils.loadProps("/TestRemoteServer.ccf");
-
- RemoteCacheServerFactory.startup( "localhost", 1101, config);
- }
- catch ( Exception e )
- {
- e.printStackTrace();
- }
- }
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestRemoteClient.ccf" );
- }
-
- /**
- * @throws Exception
- *
- *
- */
- public void skiptestSimpleSend()
- throws Exception
- {
- log.info( "testSimpleSend" );
-
- CacheAccess<String, String> cache = JCS.getInstance( "testCache" );
-
- log.info( "cache = " + cache );
-
- for ( int i = 0; i < 1000; i++ )
- {
-// System.out.println( "puttting " + i );
- cache.put( "key" + i, "data" + i );
-// System.out.println( "put " + i );
- log.info( "put " + i );
- }
- }
-
- /**
- * @throws Exception
- */
- public void testService()
- throws Exception
- {
-
- Thread.sleep( 100 );
-
- ICompositeCacheManager cacheMgr = new MockCompositeCacheManager();
-
- RemoteCacheAttributes rca = new RemoteCacheAttributes();
- rca.setRemoteLocation( "localhost", 1101 );
- rca.setCacheName( "testCache" );
-
- RemoteCacheFactory factory = new RemoteCacheFactory();
- factory.initialize();
- RemoteCacheManager mgr = factory.getManager( rca, cacheMgr, new MockCacheEventLogger(), new MockElementSerializer() );
- AuxiliaryCache<String, String> cache = mgr.getCache( rca );
-
- int numMes = 100;
- for ( int i = 0; i < numMes; i++ )
- {
- String message = "adsfasasfasfasdasf";
- CacheElement<String, String> ce = new CacheElement<>( "key" + 1, "data" + i, message );
- cache.update( ce );
-// System.out.println( "put " + ce );
- }
-
- // Thread.sleep( 2000 );
-
- /*
- * // the receiver instance. JCS cacheReceiver = JCS.getInstance(
- * "testCache" );
- *
- * log.info( "cache = " + cache );
- *
- * for ( int i = 0; i < numMes; i++ ) { System.out.println( "getting " +
- * i ); Object data = cacheReceiver.get( "key" + i );
- * System.out.println( i + " = " + data ); }
- */
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/ZombieRemoteCacheServiceUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/ZombieRemoteCacheServiceUnitTest.java
deleted file mode 100644
index 84ecc3a..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/ZombieRemoteCacheServiceUnitTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.ZombieCacheServiceNonLocal;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-/**
- * Tests for the zombie remote cache service.
- */
-public class ZombieRemoteCacheServiceUnitTest
- extends TestCase
-{
- /**
- * Verify that an update event gets added and then is sent to the service passed to propagate.
- * <p>
- * @throws Exception
- */
- public void testUpdateThenWalk()
- throws Exception
- {
- // SETUP
- MockRemoteCacheService<String, String> service = new MockRemoteCacheService<>();
-
- ZombieCacheServiceNonLocal<String, String> zombie = new ZombieCacheServiceNonLocal<>( 10 );
-
- String cacheName = "testUpdate";
-
- // DO WORK
- ICacheElement<String, String> element = new CacheElement<>( cacheName, "key", "value" );
- zombie.update( element, 123l );
- zombie.propagateEvents( service );
-
- // VERIFY
- assertEquals( "Updated element is not as expected.", element, service.lastUpdate );
- }
-
- /**
- * Verify that nothing is added if the max is set to 0.
- * <p>
- * @throws Exception
- */
- public void testUpdateThenWalk_zeroSize()
- throws Exception
- {
- // SETUP
- MockRemoteCacheService<String, String> service = new MockRemoteCacheService<>();
-
- ZombieCacheServiceNonLocal<String, String> zombie = new ZombieCacheServiceNonLocal<>( 0 );
-
- String cacheName = "testUpdate";
-
- // DO WORK
- ICacheElement<String, String> element = new CacheElement<>( cacheName, "key", "value" );
- zombie.update( element, 123l );
- zombie.propagateEvents( service );
-
- // VERIFY
- assertNull( "Nothing should have been put to the service.", service.lastUpdate );
- }
-
- /**
- * Verify that a remove event gets added and then is sent to the service passed to propagate.
- * <p>
- * @throws Exception
- */
- public void testRemoveThenWalk()
- throws Exception
- {
- // SETUP
- MockRemoteCacheService<String, String> service = new MockRemoteCacheService<>();
-
- ZombieCacheServiceNonLocal<String, String> zombie = new ZombieCacheServiceNonLocal<>( 10 );
-
- String cacheName = "testRemoveThenWalk";
- String key = "myKey";
-
- // DO WORK
- zombie.remove( cacheName, key, 123l );
- zombie.propagateEvents( service );
-
- // VERIFY
- assertEquals( "Updated element is not as expected.", key, service.lastRemoveKey );
- }
-
- /**
- * Verify that a removeAll event gets added and then is sent to the service passed to propagate.
- * <p>
- * @throws Exception
- */
- public void testRemoveAllThenWalk()
- throws Exception
- {
- // SETUP
- MockRemoteCacheService<String, String> service = new MockRemoteCacheService<>();
-
- ZombieCacheServiceNonLocal<String, String> zombie = new ZombieCacheServiceNonLocal<>( 10 );
-
- String cacheName = "testRemoveThenWalk";
-
- // DO WORK
- zombie.removeAll( cacheName, 123l );
- zombie.propagateEvents( service );
-
- // VERIFY
- assertEquals( "Updated element is not as expected.", cacheName, service.lastRemoveAllCacheName);
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/http/client/MockRemoteCacheDispatcher.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/http/client/MockRemoteCacheDispatcher.java
deleted file mode 100644
index e3986db..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/http/client/MockRemoteCacheDispatcher.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.client;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheDispatcher;
-import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheRequest;
-import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheResponse;
-
-import java.io.IOException;
-
-/** For testing the service. */
-public class MockRemoteCacheDispatcher
- implements IRemoteCacheDispatcher
-{
- /** The last request passes to dispatch */
- public RemoteCacheRequest<?, ?> lastRemoteCacheRequest;
-
- /** The response setup */
- public RemoteCacheResponse<?> setupRemoteCacheResponse;
-
- /** Records the last and returns setupRemoteCacheResponse.
- * <p>
- * @param remoteCacheRequest
- * @return RemoteCacheResponse
- * @throws IOException
- */
- @Override
- @SuppressWarnings("unchecked")
- public <K, V, T>
- RemoteCacheResponse<T> dispatchRequest( RemoteCacheRequest<K, V> remoteCacheRequest )
- throws IOException
- {
- this.lastRemoteCacheRequest = remoteCacheRequest;
- return (RemoteCacheResponse<T>)setupRemoteCacheResponse;
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheClientUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheClientUnitTest.java
deleted file mode 100644
index 7d31c70..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheClientUnitTest.java
+++ /dev/null
@@ -1,275 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.client;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheResponse;
-import org.apache.commons.jcs.auxiliary.remote.value.RemoteRequestType;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-/** Unit tests for the client. */
-public class RemoteHttpCacheClientUnitTest
- extends TestCase
-{
- /**
- * Verify get functionality
- * <p>
- * @throws IOException
- */
- public void testGet_nullFromDispatcher()
- throws IOException
- {
- // SETUP
- RemoteHttpCacheAttributes attributes = new RemoteHttpCacheAttributes();
- RemoteHttpCacheClient<String, String> client = new RemoteHttpCacheClient<>( attributes );
-
- MockRemoteCacheDispatcher mockDispatcher = new MockRemoteCacheDispatcher();
- client.setRemoteDispatcher( mockDispatcher );
-
- String cacheName = "test";
- String key = "key";
-
- mockDispatcher.setupRemoteCacheResponse = null;
-
- // DO WORK
- ICacheElement<String, String> result = client.get( cacheName, key );
-
- // VERIFY
- assertNull( "Wrong result.", result );
- assertEquals( "Wrong type.", RemoteRequestType.GET, mockDispatcher.lastRemoteCacheRequest
- .getRequestType() );
- }
-
- /**
- * Verify get functionality
- * <p>
- * @throws IOException
- */
- public void testGet_normal()
- throws IOException
- {
- // SETUP
- RemoteHttpCacheAttributes attributes = new RemoteHttpCacheAttributes();
- RemoteHttpCacheClient<String, String> client = new RemoteHttpCacheClient<>( attributes );
-
- MockRemoteCacheDispatcher mockDispatcher = new MockRemoteCacheDispatcher();
- client.setRemoteDispatcher( mockDispatcher );
-
- String cacheName = "test";
- String key = "key";
-
- ICacheElement<String, String> expected = new CacheElement<>( cacheName, key, "value" );
- RemoteCacheResponse<ICacheElement<String, String>> remoteHttpCacheResponse =
- new RemoteCacheResponse<>();
- remoteHttpCacheResponse.setPayload( expected );
-
- mockDispatcher.setupRemoteCacheResponse = remoteHttpCacheResponse;
-
- // DO WORK
- ICacheElement<String, String> result = client.get( cacheName, key );
-
- // VERIFY
- assertEquals( "Wrong result.", expected, result );
- assertEquals( "Wrong type.", RemoteRequestType.GET, mockDispatcher.lastRemoteCacheRequest
- .getRequestType() );
- }
-
- /**
- * Verify get functionality
- * <p>
- * @throws IOException
- */
- public void testGetMatching_normal()
- throws IOException
- {
- // SETUP
- RemoteHttpCacheAttributes attributes = new RemoteHttpCacheAttributes();
- RemoteHttpCacheClient<String, String> client = new RemoteHttpCacheClient<>( attributes );
-
- MockRemoteCacheDispatcher mockDispatcher = new MockRemoteCacheDispatcher();
- client.setRemoteDispatcher( mockDispatcher );
-
- String cacheName = "test";
- String pattern = "key";
-
- ICacheElement<String, String> expected = new CacheElement<>( cacheName, "key", "value" );
- Map<String, ICacheElement<String, String>> expectedMap = new HashMap<>();
- expectedMap.put( "key", expected );
- RemoteCacheResponse<Map<String, ICacheElement<String, String>>> remoteHttpCacheResponse =
- new RemoteCacheResponse<>();
- remoteHttpCacheResponse.setPayload( expectedMap );
-
- mockDispatcher.setupRemoteCacheResponse = remoteHttpCacheResponse;
-
- // DO WORK
- Map<String, ICacheElement<String, String>> result = client.getMatching( cacheName, pattern );
-
- // VERIFY
- assertEquals( "Wrong result.", expected, result.get( "key" ) );
- assertEquals( "Wrong type.", RemoteRequestType.GET_MATCHING,
- mockDispatcher.lastRemoteCacheRequest.getRequestType() );
- }
-
- /**
- * Verify get functionality
- * <p>
- * @throws IOException
- */
- public void testGetMultiple_normal()
- throws IOException
- {
- // SETUP
- RemoteHttpCacheAttributes attributes = new RemoteHttpCacheAttributes();
- RemoteHttpCacheClient<String, String> client = new RemoteHttpCacheClient<>( attributes );
-
- MockRemoteCacheDispatcher mockDispatcher = new MockRemoteCacheDispatcher();
- client.setRemoteDispatcher( mockDispatcher );
-
- String cacheName = "test";
- Set<String> keys = Collections.emptySet();
-
- ICacheElement<String, String> expected = new CacheElement<>( cacheName, "key", "value" );
- Map<String, ICacheElement<String, String>> expectedMap = new HashMap<>();
- expectedMap.put( "key", expected );
- RemoteCacheResponse<Map<String, ICacheElement<String, String>>> remoteHttpCacheResponse =
- new RemoteCacheResponse<>();
- remoteHttpCacheResponse.setPayload( expectedMap );
-
- mockDispatcher.setupRemoteCacheResponse = remoteHttpCacheResponse;
-
- // DO WORK
- Map<String, ICacheElement<String, String>> result = client.getMultiple( cacheName, keys );
-
- // VERIFY
- assertEquals( "Wrong result.", expected, result.get( "key" ) );
- assertEquals( "Wrong type.", RemoteRequestType.GET_MULTIPLE,
- mockDispatcher.lastRemoteCacheRequest.getRequestType() );
- }
-
- /**
- * Verify remove functionality
- * <p>
- * @throws IOException
- */
- public void testRemove_normal()
- throws IOException
- {
- // SETUP
- RemoteHttpCacheAttributes attributes = new RemoteHttpCacheAttributes();
- RemoteHttpCacheClient<String, String> client = new RemoteHttpCacheClient<>( attributes );
-
- MockRemoteCacheDispatcher mockDispatcher = new MockRemoteCacheDispatcher();
- client.setRemoteDispatcher( mockDispatcher );
-
- String cacheName = "test";
- String key = "key";
-
- // DO WORK
- client.remove( cacheName, key );
-
- // VERIFY
- assertEquals( "Wrong type.", RemoteRequestType.REMOVE, mockDispatcher.lastRemoteCacheRequest
- .getRequestType() );
- }
-
- /**
- * Verify removeall functionality
- * <p>
- * @throws IOException
- */
- public void testRemoveAll_normal()
- throws IOException
- {
- // SETUP
- RemoteHttpCacheAttributes attributes = new RemoteHttpCacheAttributes();
- RemoteHttpCacheClient<String, String> client = new RemoteHttpCacheClient<>( attributes );
-
- MockRemoteCacheDispatcher mockDispatcher = new MockRemoteCacheDispatcher();
- client.setRemoteDispatcher( mockDispatcher );
-
- String cacheName = "test";
-
- // DO WORK
- client.removeAll( cacheName );
-
- // VERIFY
- assertEquals( "Wrong type.", RemoteRequestType.REMOVE_ALL, mockDispatcher.lastRemoteCacheRequest
- .getRequestType() );
- }
-
- /**
- * Verify update functionality
- * <p>
- * @throws IOException
- */
- public void testUpdate_normal()
- throws IOException
- {
- // SETUP
- RemoteHttpCacheAttributes attributes = new RemoteHttpCacheAttributes();
- RemoteHttpCacheClient<String, String> client = new RemoteHttpCacheClient<>( attributes );
-
- MockRemoteCacheDispatcher mockDispatcher = new MockRemoteCacheDispatcher();
- client.setRemoteDispatcher( mockDispatcher );
-
- String cacheName = "test";
-
- ICacheElement<String, String> element = new CacheElement<>( cacheName, "key", "value" );
-
- // DO WORK
- client.update( element );
-
- // VERIFY
- assertEquals( "Wrong type.", RemoteRequestType.UPDATE, mockDispatcher.lastRemoteCacheRequest
- .getRequestType() );
- }
-
- /**
- * Verify dispose functionality
- * <p>
- * @throws IOException
- */
- public void testDispose_normal()
- throws IOException
- {
- // SETUP
- RemoteHttpCacheAttributes attributes = new RemoteHttpCacheAttributes();
- RemoteHttpCacheClient<String, String> client = new RemoteHttpCacheClient<>( attributes );
-
- MockRemoteCacheDispatcher mockDispatcher = new MockRemoteCacheDispatcher();
- client.setRemoteDispatcher( mockDispatcher );
-
- String cacheName = "test";
-
- // DO WORK
- client.dispose( cacheName );
-
- // VERIFY
- assertEquals( "Wrong type.", RemoteRequestType.DISPOSE, mockDispatcher.lastRemoteCacheRequest
- .getRequestType() );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheFactoryUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheFactoryUnitTest.java
deleted file mode 100644
index 0d5c20f..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheFactoryUnitTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.client;
-
-import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.remote.http.client.behavior.IRemoteHttpCacheClient;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.control.MockCompositeCacheManager;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/** Unit tests for the manager. */
-public class RemoteHttpCacheFactoryUnitTest
- extends TestCase
-{
- /** Verify that we get the default. */
- public void testCreateRemoteHttpCacheClient_Bad()
- {
- // SETUP
- String remoteHttpClientClassName = "junk";
- RemoteHttpCacheAttributes cattr = new RemoteHttpCacheAttributes();
- cattr.setRemoteHttpClientClassName( remoteHttpClientClassName );
-
- RemoteHttpCacheFactory factory = new RemoteHttpCacheFactory();
-
- // DO WORK
- IRemoteHttpCacheClient<String, String> result = factory.createRemoteHttpCacheClientForAttributes( cattr );
-
- // VEIFY
- assertNotNull( "Should have a cache.", result );
- assertTrue( "Wrong default.", result instanceof RemoteHttpCacheClient );
- assertTrue( "Should be initialized", ((RemoteHttpCacheClient<String, String>)result).isInitialized() );
- }
-
- /** Verify that we get the default. */
- public void testCreateRemoteHttpCacheClient_default()
- {
- // SETUP
- RemoteHttpCacheAttributes cattr = new RemoteHttpCacheAttributes();
- RemoteHttpCacheFactory factory = new RemoteHttpCacheFactory();
-
- // DO WORK
- IRemoteHttpCacheClient<String, String> result = factory.createRemoteHttpCacheClientForAttributes( cattr );
-
- // VEIFY
- assertNotNull( "Should have a cache.", result );
- assertTrue( "Wrong default.", result instanceof RemoteHttpCacheClient );
- }
-
- /** Verify that we get a cache no wait. */
- public void testGetCache_normal()
- {
- // SETUP
- ICompositeCacheManager cacheMgr = new MockCompositeCacheManager();
- assertNotNull( "Should have a manager.", cacheMgr );
- ICacheEventLogger cacheEventLogger = null;
- IElementSerializer elementSerializer = null;
-
- RemoteHttpCacheAttributes cattr = new RemoteHttpCacheAttributes();
- assertNotNull( "Should have attributes.", cattr );
- RemoteHttpCacheFactory factory = new RemoteHttpCacheFactory();
- assertNotNull( "Should have a factory.", factory );
-
-
- // DO WORK
- AuxiliaryCache<String, String> result = factory.createCache(cattr, cacheMgr, cacheEventLogger, elementSerializer);
-
- // VERIFY
- assertNotNull( "Should have a cache.", result );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheManualTester.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheManualTester.java
deleted file mode 100644
index d65720c..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/http/client/RemoteHttpCacheManualTester.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.client;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-
-/** Manual tester for a JCS instance configured to use the http client. */
-public class RemoteHttpCacheManualTester
- extends TestCase
-{
- /** number to use for the test */
- private static int items = 100;
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestRemoteHttpCache.ccf" );
- }
-
- /**
- * A unit test for JUnit
- * @throws Exception Description of the Exception
- */
- public void testSimpleLoad()
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
-
- jcs.put( "TestKey", "TestValue" );
-
-// System.out.println( jcs.getStats() );
-
- for ( int i = 1; i <= items; i++ )
- {
- jcs.put( i + ":key", "data" + i );
- }
-
- for ( int i = items; i > 0; i-- )
- {
- String res = jcs.get( i + ":key" );
- if ( res == null )
- {
- //assertNotNull( "[" + i + ":key] should not be null", res );
- }
- }
-
- // test removal
- jcs.remove( "300:key" );
- assertNull( jcs.get( "TestKey" ) );
-
-// System.out.println( jcs.getStats() );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheServiceUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheServiceUnitTest.java
deleted file mode 100644
index 6b35897..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheServiceUnitTest.java
+++ /dev/null
@@ -1,181 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.server;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.auxiliary.MockCacheEventLogger;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.control.MockCompositeCacheManager;
-
-import java.util.HashSet;
-
-/** Unit tests for the service. */
-public class RemoteHttpCacheServiceUnitTest
- extends TestCase
-{
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testUpdate_simple()
- throws Exception
- {
- // SETUP
- MockCompositeCacheManager manager = new MockCompositeCacheManager();
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
-
- RemoteHttpCacheServerAttributes rcsa = new RemoteHttpCacheServerAttributes();
- RemoteHttpCacheService<String, String> server =
- new RemoteHttpCacheService<>( manager, rcsa, cacheEventLogger );
-
- String cacheName = "test";
- String key = "key";
- long requesterId = 2;
- CacheElement<String, String> element = new CacheElement<>( cacheName, key, null );
-
- // DO WORK
- server.update( element, requesterId );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testGet_simple()
- throws Exception
- {
- // SETUP
- MockCompositeCacheManager manager = new MockCompositeCacheManager();
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
-
- RemoteHttpCacheServerAttributes rcsa = new RemoteHttpCacheServerAttributes();
- RemoteHttpCacheService<String, String> server =
- new RemoteHttpCacheService<>( manager, rcsa, cacheEventLogger );
-
- // DO WORK
- server.get( "region", "key" );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testGetMatching_simple()
- throws Exception
- {
- // SETUP
- MockCompositeCacheManager manager = new MockCompositeCacheManager();
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
-
- RemoteHttpCacheServerAttributes rcsa = new RemoteHttpCacheServerAttributes();
- RemoteHttpCacheService<String, String> server =
- new RemoteHttpCacheService<>( manager, rcsa, cacheEventLogger );
-
- // DO WORK
- server.getMatching( "region", "pattern", 0 );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testGetMultiple_simple()
- throws Exception
- {
- // SETUP
- MockCompositeCacheManager manager = new MockCompositeCacheManager();
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
-
- RemoteHttpCacheServerAttributes rcsa = new RemoteHttpCacheServerAttributes();
- RemoteHttpCacheService<String, String> server =
- new RemoteHttpCacheService<>( manager, rcsa, cacheEventLogger );
-
- // DO WORK
- server.getMultiple( "region", new HashSet<>() );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testRemove_simple()
- throws Exception
- {
- // SETUP
- MockCompositeCacheManager manager = new MockCompositeCacheManager();
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
-
- RemoteHttpCacheServerAttributes rcsa = new RemoteHttpCacheServerAttributes();
- RemoteHttpCacheService<String, String> server =
- new RemoteHttpCacheService<>( manager, rcsa, cacheEventLogger );
-
- // DO WORK
- server.remove( "region", "key" );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testRemoveAll_simple()
- throws Exception
- {
- // SETUP
- MockCompositeCacheManager manager = new MockCompositeCacheManager();
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
-
- RemoteHttpCacheServerAttributes rcsa = new RemoteHttpCacheServerAttributes();
- RemoteHttpCacheService<String, String> server =
- new RemoteHttpCacheService<>( manager, rcsa, cacheEventLogger );
-
- // DO WORK
- server.removeAll( "region" );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheServletUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheServletUnitTest.java
deleted file mode 100644
index 93cb7c9..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/http/server/RemoteHttpCacheServletUnitTest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.http.server;
-
-/*
- * 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.
- */
-
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.Set;
-
-import junit.framework.TestCase;
-
-import org.apache.commons.jcs.auxiliary.remote.MockRemoteCacheService;
-import org.apache.commons.jcs.auxiliary.remote.util.RemoteCacheRequestFactory;
-import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheRequest;
-import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheResponse;
-import org.apache.commons.jcs.engine.CacheElement;
-
-/** Unit tests for the servlet. */
-public class RemoteHttpCacheServletUnitTest
- extends TestCase
-{
- private RemoteHttpCacheServlet servlet;
- private MockRemoteCacheService<Serializable, Serializable> remoteHttpCacheService;
-
- /**
- * @see junit.framework.TestCase#setUp()
- */
- @Override
- protected void setUp() throws Exception
- {
- super.setUp();
- servlet = new RemoteHttpCacheServlet();
- servlet.init(null);
-
- remoteHttpCacheService = new MockRemoteCacheService<>();
- servlet.setRemoteCacheService( remoteHttpCacheService );
- }
-
- /**
- * @see junit.framework.TestCase#tearDown()
- */
- @Override
- protected void tearDown() throws Exception
- {
- servlet.destroy();
- super.tearDown();
- }
-
- /** Verify that we balk and return an error. */
- public void testProcessRequest_null()
- {
- RemoteCacheRequest<Serializable, Serializable> request = null;
-
- // DO WORK
- RemoteCacheResponse<Object> result = servlet.processRequest( request );
-
- // VERIFY
- assertNotNull( "Should have a result.", result );
- assertTrue( "Should have 'The request is null' in the errorMessage", result.getErrorMessage().indexOf( "The request is null" ) != -1 );
- assertTrue( "Should have 'The request is null' in the toString", result.toString().indexOf( "The request is null" ) != -1 );
- }
-
- /** Verify that the service is called. */
- public void testProcessRequest_Get()
- {
- String cacheName = "test";
- Serializable key = "key";
- long requesterId = 2;
- RemoteCacheRequest<Serializable, Serializable> request = RemoteCacheRequestFactory.createGetRequest( cacheName, key, requesterId );
-
- // DO WORK
- RemoteCacheResponse<Object> result = servlet.processRequest( request );
-
- // VERIFY
- assertNotNull( "Should have a result.", result );
- assertEquals( "Wrong key.", key, remoteHttpCacheService.lastGetKey );
- }
-
- /** Verify that the service is called. */
- public void testProcessRequest_GetMatching()
- {
- String cacheName = "test";
- String pattern = "pattern";
- long requesterId = 2;
- RemoteCacheRequest<Serializable, Serializable> request = RemoteCacheRequestFactory.createGetMatchingRequest( cacheName, pattern,
- requesterId );
-
- // DO WORK
- RemoteCacheResponse<Object> result = servlet.processRequest( request );
-
- // VERIFY
- assertNotNull( "Should have a result.", result );
- assertEquals( "Wrong pattern.", pattern, remoteHttpCacheService.lastGetMatchingPattern );
- }
-
- /** Verify that the service is called. */
- public void testProcessRequest_GetMultiple()
- {
- String cacheName = "test";
- Set<Serializable> keys = Collections.emptySet();
- long requesterId = 2;
- RemoteCacheRequest<Serializable, Serializable> request = RemoteCacheRequestFactory.createGetMultipleRequest( cacheName, keys,
- requesterId );
-
- // DO WORK
- RemoteCacheResponse<Object> result = servlet.processRequest( request );
-
- // VERIFY
- assertNotNull( "Should have a result.", result );
- assertEquals( "Wrong keys.", keys, remoteHttpCacheService.lastGetMultipleKeys );
-
- }
-
- /** Verify that the service is called. */
- public void testProcessRequest_Update()
- {
- String cacheName = "test";
- String key = "key";
- long requesterId = 2;
- CacheElement<Serializable, Serializable> element = new CacheElement<>( cacheName, key, null );
- RemoteCacheRequest<Serializable, Serializable> request = RemoteCacheRequestFactory.createUpdateRequest( element, requesterId );
-
- // DO WORK
- RemoteCacheResponse<Object> result = servlet.processRequest( request );
-
- // VERIFY
- assertNotNull( "Should have a result.", result );
- assertEquals( "Wrong object.", element, remoteHttpCacheService.lastUpdate );
- }
-
- /** Verify that the service is called. */
- public void testProcessRequest_Remove()
- {
- String cacheName = "test";
- Serializable key = "key";
- long requesterId = 2;
- RemoteCacheRequest<Serializable, Serializable> request = RemoteCacheRequestFactory.createRemoveRequest( cacheName, key, requesterId );
-
- // DO WORK
- RemoteCacheResponse<Object> result = servlet.processRequest( request );
-
- // VERIFY
- assertNotNull( "Should have a result.", result );
- assertEquals( "Wrong key.", key, remoteHttpCacheService.lastRemoveKey );
- }
-
- /** Verify that the service is called. */
- public void testProcessRequest_RemoveAll()
- {
- String cacheName = "testRemoveALl";
- long requesterId = 2;
- RemoteCacheRequest<Serializable, Serializable> request = RemoteCacheRequestFactory.createRemoveAllRequest( cacheName, requesterId );
-
- // DO WORK
- RemoteCacheResponse<Object> result = servlet.processRequest( request );
-
- // VERIFY
- assertNotNull( "Should have a result.", result );
- assertEquals( "Wrong cacheName.", cacheName, remoteHttpCacheService.lastRemoveAllCacheName );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/BasicRemoteCacheClientServerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/BasicRemoteCacheClientServerUnitTest.java
deleted file mode 100644
index 21ea4dd..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/BasicRemoteCacheClientServerUnitTest.java
+++ /dev/null
@@ -1,341 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.server;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.util.Enumeration;
-
-import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.MockCacheEventLogger;
-import org.apache.commons.jcs.auxiliary.remote.MockRemoteCacheListener;
-import org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes;
-import org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory;
-import org.apache.commons.jcs.auxiliary.remote.RemoteCacheManager;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.control.MockCompositeCacheManager;
-import org.apache.commons.jcs.engine.control.MockElementSerializer;
-import org.apache.commons.jcs.utils.net.HostNameUtil;
-import org.apache.commons.jcs.utils.timing.SleepUtil;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runners.MethodSorters;
-
-/**
- * These tests startup the remote server and make requests to it.
- * <p>
- *
- * @author Aaron Smuts
- */
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class BasicRemoteCacheClientServerUnitTest extends Assert
-{
- private static final int LOCAL_PORT = 12020;
-
- /**
- * Server instance to use in the tests.
- */
- private static RemoteCacheServer<String, String> server = null;
-
- /**
- * Factory instance to use in the tests.
- */
- private static RemoteCacheFactory factory = null;
-
- /**
- * the remote server port
- */
- private static int remotePort;
-
- /**
- * Starts the server. This is not in a setup, since the server is slow to kill right now.
- */
- @BeforeClass
- public static void setup()
- {
- // Add some debug to try and find out why test fails on Jenkins/Continuum
- try {
- InetAddress lh = InetAddress.getByName("localhost");
- System.out.println("localhost="+lh);
- InetAddress ina=InetAddress.getLocalHost();
- System.out.println("InetAddress.getLocalHost()="+ina);
- // Iterate all NICs (network interface cards)...
- for ( Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); )
- {
- NetworkInterface iface = ifaces.nextElement();
- // Iterate all IP addresses assigned to each card...
- for ( Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); )
- {
- InetAddress inetAddr = inetAddrs.nextElement();
- boolean loopbackAddress = inetAddr.isLoopbackAddress();
- boolean siteLocalAddress = inetAddr.isSiteLocalAddress();
- System.out.println("Found: "+ inetAddr +
- " isLoopback: " + loopbackAddress +
- " isSiteLocal: " + siteLocalAddress +
- ((!loopbackAddress && siteLocalAddress) ? " *" : ""));
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- // end of debug
- String configFile = "TestRemoteCacheClientServer.ccf";
- server = RemoteCacheServerStartupUtil.startServerUsingProperties(configFile);
- factory = new RemoteCacheFactory();
- factory.initialize();
- remotePort = server.remoteCacheServerAttributes.getRemoteLocation().getPort();
- }
-
- @AfterClass
- public static void stop() throws IOException
- {
- if (server != null) { // in case setup failed, no point throwing NPE as well
- server.shutdown("localhost", remotePort);
- }
- // Debug: unfortunately Surefire restarts JVM so log files get overwritten
- // There's probably a better way to fix this ...
- java.io.File jcsLog = new java.io.File("target/jcs.log");
- java.io.File logSave = new java.io.File("target/BasicRemoteCacheClientServerUnitTest_jcs.log");
- System.out.println("Renamed log file? "+jcsLog.renameTo(logSave));
- }
-
- /**
- * Verify that we can start the remote cache server. Send an item to the remote. Verify that the
- * remote put count goes up. If we go through JCS, the manager will be shared and we will get
- * into an endless loop. We will use a mock cache manager instead.
- * <p>
- * The remote server uses the real JCS. We can verify that items are added to JCS behind the
- * server by calling get. We cannot access it directly via JCS since it is serialized.
- * <p>
- * This test uses a mock injected client to test a normal server.
- * <p>
- *
- * @throws Exception
- */
- @Test
- public void test1SinglePut()
- throws Exception
- {
- // SETUP
- MockCompositeCacheManager compositeCacheManager = new MockCompositeCacheManager();
-
- RemoteCacheAttributes attributes = new RemoteCacheAttributes();
- attributes.setRemoteLocation("localhost", remotePort);
- attributes.setLocalPort(LOCAL_PORT);
- attributes.setCacheName("testSinglePut");
-
- RemoteCacheManager remoteCacheManager = factory.getManager(attributes, compositeCacheManager, new MockCacheEventLogger(), new MockElementSerializer());
- AuxiliaryCache<String, String> cache = remoteCacheManager.getCache(attributes);
-
- // DO WORK
- int numPutsPrior = server.getPutCount();
- ICacheElement<String, String> element = new CacheElement<>(cache.getCacheName(), "key", "value");
- cache.update(element);
- SleepUtil.sleepAtLeast(200);
-
- // VERIFY
- try
- {
- assertEquals("Cache is alive", CacheStatus.ALIVE, cache.getStatus());
- assertEquals("Wrong number of puts", 1, server.getPutCount() - numPutsPrior);
- }
- catch (junit.framework.AssertionFailedError e)
- {
- System.out.println(cache.getStats());
- System.out.println(server.getStats());
- throw e;
- }
-
- // DO WORK
- ICacheElement<String, String> result = cache.get("key");
-
- // VERIFY
- assertEquals("Wrong element.", element.getVal(), result.getVal());
- }
-
- /**
- * Verify that we can remove an item via the remote server.
- * <p>
- *
- * @throws Exception
- */
- @Test
- public void test2PutRemove()
- throws Exception
- {
- // SETUP
- MockCompositeCacheManager compositeCacheManager = new MockCompositeCacheManager();
-
- RemoteCacheAttributes attributes = new RemoteCacheAttributes();
- attributes.setRemoteLocation("localhost", remotePort);
- attributes.setLocalPort(LOCAL_PORT);
- attributes.setCacheName("testPutRemove");
-
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
-
- RemoteCacheManager remoteCacheManager = factory.getManager(attributes, compositeCacheManager, cacheEventLogger, null);
- AuxiliaryCache<String, String> cache = remoteCacheManager.getCache(attributes);
-
- // DO WORK
- int numPutsPrior = server.getPutCount();
- ICacheElement<String, String> element = new CacheElement<>(cache.getCacheName(), "key", "value");
- cache.update(element);
- SleepUtil.sleepAtLeast(50);
-
- // VERIFY
- try
- {
- assertEquals("Cache is alive", CacheStatus.ALIVE, cache.getStatus());
- assertEquals("Wrong number of puts", 1, server.getPutCount() - numPutsPrior);
- }
- catch (junit.framework.AssertionFailedError e)
- {
- System.out.println(cache.getStats());
- System.out.println(server.getStats());
- throw e;
- }
-
- // DO WORK
- ICacheElement<String, String> result = cache.get("key");
-
- // VERIFY
- assertEquals("Wrong element.", element.getVal(), result.getVal());
-
- // DO WORK
- cache.remove("key");
- SleepUtil.sleepAtLeast(200);
- ICacheElement<String, String> resultAfterRemote = cache.get("key");
-
- // VERIFY
- assertNull("Element resultAfterRemote should be null.", resultAfterRemote);
- }
-
- /**
- * Register a listener with the server. Send an update. Verify that the listener received it.
- *
- * @throws Exception
- */
- @Test
- public void test3PutAndListen()
- throws Exception
- {
- // SETUP
- MockCompositeCacheManager compositeCacheManager = new MockCompositeCacheManager();
-
- RemoteCacheAttributes attributes = new RemoteCacheAttributes();
- attributes.setRemoteLocation("localhost", remotePort);
- attributes.setLocalPort(LOCAL_PORT);
- attributes.setCacheName("testPutAndListen");
-
- RemoteCacheManager remoteCacheManager = factory.getManager(attributes, compositeCacheManager, new MockCacheEventLogger(), new MockElementSerializer());
- AuxiliaryCache<String, String> cache = remoteCacheManager.getCache(attributes);
-
- MockRemoteCacheListener<String, String> listener = new MockRemoteCacheListener<>();
- server.addCacheListener(cache.getCacheName(), listener);
-
- // DO WORK
- int numPutsPrior = server.getPutCount();
- ICacheElement<String, String> element = new CacheElement<>(cache.getCacheName(), "key", "value");
- cache.update(element);
- SleepUtil.sleepAtLeast(50);
-
- // VERIFY
- try
- {
- assertEquals("Cache is alive", CacheStatus.ALIVE, cache.getStatus());
- assertEquals("Wrong number of puts", 1, server.getPutCount() - numPutsPrior);
- assertEquals("Wrong number of puts to listener.", 1, listener.putCount);
- }
- catch (junit.framework.AssertionFailedError e)
- {
- System.out.println(cache.getStats());
- System.out.println(server.getStats());
- throw e;
- }
- finally
- {
- // remove from all regions.
- server.removeCacheListener(listener);
- }
- }
-
- /**
- * Register a listener with the server. Send an update. Verify that the listener received it.
- *
- * @throws Exception
- */
- @Test
- public void test4PutaMultipleAndListen()
- throws Exception
- {
- // SETUP
- MockCompositeCacheManager compositeCacheManager = new MockCompositeCacheManager();
-
- RemoteCacheAttributes attributes = new RemoteCacheAttributes();
- attributes.setRemoteLocation("localhost", remotePort);
- attributes.setLocalPort(LOCAL_PORT);
- attributes.setCacheName("testPutaMultipleAndListen");
-
- RemoteCacheManager remoteCacheManager = factory.getManager(attributes, compositeCacheManager, new MockCacheEventLogger(), new MockElementSerializer());
- AuxiliaryCache<String, String> cache = remoteCacheManager.getCache(attributes);
-
- MockRemoteCacheListener<String, String> listener = new MockRemoteCacheListener<>();
- server.addCacheListener(cache.getCacheName(), listener);
-
- // DO WORK
- int numPutsPrior = server.getPutCount();
- int numToPut = 100;
- for (int i = 0; i < numToPut; i++)
- {
- ICacheElement<String, String> element = new CacheElement<>(cache.getCacheName(), "key" + 1, "value" + i);
- cache.update(element);
- }
- SleepUtil.sleepAtLeast(500);
-
- // VERIFY
- try
- {
- assertEquals("Cache is alive", CacheStatus.ALIVE, cache.getStatus());
- assertEquals("Wrong number of puts", numToPut, server.getPutCount() - numPutsPrior);
- assertEquals("Wrong number of puts to listener.", numToPut, listener.putCount);
- }
- catch (junit.framework.AssertionFailedError e)
- {
- System.out.println(cache.getStats());
- System.out.println(server.getStats());
- throw e;
- }
- }
-
- @Test
- public void testLocalHost() throws Exception
- {
- final InetAddress byName = InetAddress.getByName("localhost");
- assertTrue("Expected localhost (" + byName.getHostAddress() + ") to be a loopback address", byName.isLoopbackAddress());
- final InetAddress localHost = HostNameUtil.getLocalHostLANAddress();
- assertTrue("Expected getLocalHostLANAddress() (" + localHost + ") to return a site local address", localHost.isSiteLocalAddress());
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/MockRMISocketFactory.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/MockRMISocketFactory.java
deleted file mode 100644
index e007753..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/MockRMISocketFactory.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.server;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.net.InetSocketAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.rmi.server.RMISocketFactory;
-
-/** For testing the custom socket factory configuration */
-public class MockRMISocketFactory
- extends RMISocketFactory
- implements Serializable
-{
- /** Don't change */
- private static final long serialVersionUID = 1056199478581218676L;
-
- /** for testing automatic property configuration. */
- private String testStringProperty;
-
- /**
- * @param host
- * @param port
- * @return Socket
- * @throws IOException
- */
- @Override
- public Socket createSocket( String host, int port )
- throws IOException
- {
-// System.out.println( "Creating socket" );
-
- Socket socket = new Socket();
- socket.setSoTimeout( 1000 );
- socket.setSoLinger( false, 0 );
- socket.connect( new InetSocketAddress( host, port ), 1000 );
- return socket;
- }
-
- /**
- * @param port
- * @return ServerSocket
- * @throws IOException
- */
- @Override
- public ServerSocket createServerSocket( int port )
- throws IOException
- {
-// System.out.println( "Creating server socket" );
-
- return new ServerSocket( port );
- }
-
- /**
- * @param testStringProperty the testStringProperty to set
- */
- public void setTestStringProperty( String testStringProperty )
- {
- this.testStringProperty = testStringProperty;
- }
-
- /**
- * @return the testStringProperty
- */
- public String getTestStringProperty()
- {
- return testStringProperty;
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/RegistryKeepAliveRunnerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/RegistryKeepAliveRunnerUnitTest.java
deleted file mode 100644
index ba07886..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/RegistryKeepAliveRunnerUnitTest.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.server;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.auxiliary.MockCacheEventLogger;
-
-/** Unit tests for the registry keep alive runner. */
-public class RegistryKeepAliveRunnerUnitTest
- extends TestCase
-{
- /** Verify that we get the appropriate event log */
- public void testCheckAndRestoreIfNeeded_failure()
- {
- // SETUP
- String host = "localhost";
- int port = 1234;
- String service = "doesn'texist";
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
-
- RegistryKeepAliveRunner runner = new RegistryKeepAliveRunner( host, port, service );
- runner.setCacheEventLogger( cacheEventLogger );
-
- // DO WORK
- runner.checkAndRestoreIfNeeded();
-
- // VERIFY
- // 1 for the lookup, one for the rebind since the server isn't created yet
- assertEquals( "error tally", 2, cacheEventLogger.errorEventCalls );
- //System.out.println( cacheEventLogger.errorMessages );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerAttributesUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerAttributesUnitTest.java
deleted file mode 100644
index 535f130..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerAttributesUnitTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.server;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType;
-
-/**
- * Tests for the remote cache server attributes.
- * <p>
- * @author Aaron Smuts
- */
-public class RemoteCacheServerAttributesUnitTest
- extends TestCase
-{
-
- /**
- * Verify that we get a string, even if not attributes are set.
- */
- public void testToString()
- {
- RemoteCacheServerAttributes attributes = new RemoteCacheServerAttributes();
- assertNotNull( "Should have a string.", attributes.toString() );
- }
-
- /**
- * Verify that the type is set correctly and that the correct name is returned for the type.
- */
- public void testSetRemoteTypeName_local()
- {
- RemoteCacheServerAttributes attributes = new RemoteCacheServerAttributes();
- attributes.setRemoteTypeName( "LOCAL" );
- assertEquals( "Wrong type.", RemoteType.LOCAL, attributes.getRemoteType() );
- assertEquals( "Wrong name", "LOCAL", attributes.getRemoteTypeName() );
- }
-
- /**
- * Verify that the type is set correctly and that the correct name is returned for the type.
- */
- public void testSetRemoteTypeName_cluster()
- {
- RemoteCacheServerAttributes attributes = new RemoteCacheServerAttributes();
- attributes.setRemoteTypeName( "CLUSTER" );
- assertEquals( "Wrong type.", RemoteType.CLUSTER, attributes.getRemoteType() );
- assertEquals( "Wrong name", "CLUSTER", attributes.getRemoteTypeName() );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerFactoryUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerFactoryUnitTest.java
deleted file mode 100644
index 22ef757..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerFactoryUnitTest.java
+++ /dev/null
@@ -1,202 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.server;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.auxiliary.remote.behavior.ICommonRemoteCacheAttributes;
-import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheConstants;
-
-import java.rmi.server.RMISocketFactory;
-import java.util.Properties;
-
-/** Unit tests for the factory */
-public class RemoteCacheServerFactoryUnitTest
- extends TestCase
-{
- /** verify that we get the timeout value */
- public void testConfigureRemoteCacheServerAttributes_eventQueuePoolName()
- {
- // SETUP
- String eventQueuePoolName = "specialName";
- Properties props = new Properties();
- props.put( IRemoteCacheConstants.CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + ".EventQueuePoolName", eventQueuePoolName );
-
- // DO WORK
- RemoteCacheServerAttributes result = RemoteCacheServerFactory.configureRemoteCacheServerAttributes( props );
-
- // VERIFY
- assertEquals( "Wrong eventQueuePoolName", eventQueuePoolName, result.getEventQueuePoolName() );
- }
-
- /** verify that we get the timeout value */
- public void testConfigureRemoteCacheServerAttributes_timeoutPresent()
- {
- // SETUP
- int timeout = 123245;
- Properties props = new Properties();
- props.put( IRemoteCacheConstants.SOCKET_TIMEOUT_MILLIS, String.valueOf( timeout ) );
-
- // DO WORK
- RemoteCacheServerAttributes result = RemoteCacheServerFactory.configureRemoteCacheServerAttributes( props );
-
- // VERIFY
- assertEquals( "Wrong timeout", timeout, result.getRmiSocketFactoryTimeoutMillis() );
- }
-
- /** verify that we get the timeout value */
- public void testConfigureRemoteCacheServerAttributes_timeoutNotPresent()
- {
- // SETUP
- Properties props = new Properties();
-
- // DO WORK
- RemoteCacheServerAttributes result = RemoteCacheServerFactory.configureRemoteCacheServerAttributes( props );
-
- // VERIFY
- assertEquals( "Wrong timeout", ICommonRemoteCacheAttributes.DEFAULT_RMI_SOCKET_FACTORY_TIMEOUT_MILLIS, result.getRmiSocketFactoryTimeoutMillis() );
- }
-
- /** verify that we get the registryKeepAliveDelayMillis value */
- public void testConfigureRemoteCacheServerAttributes_registryKeepAliveDelayMillisPresent()
- {
- // SETUP
- int registryKeepAliveDelayMillis = 123245;
- Properties props = new Properties();
- props.put( IRemoteCacheConstants.CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + ".registryKeepAliveDelayMillis", String.valueOf( registryKeepAliveDelayMillis ) );
-
- // DO WORK
- RemoteCacheServerAttributes result = RemoteCacheServerFactory.configureRemoteCacheServerAttributes( props );
-
- // VERIFY
- assertEquals( "Wrong registryKeepAliveDelayMillis", registryKeepAliveDelayMillis, result.getRegistryKeepAliveDelayMillis() );
- }
-
- /** verify that we get the useRegistryKeepAlive value */
- public void testConfigureRemoteCacheServerAttributes_useRegistryKeepAlivePresent()
- {
- // SETUP
- boolean useRegistryKeepAlive = false;
- Properties props = new Properties();
- props.put( IRemoteCacheConstants.CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + ".useRegistryKeepAlive", String.valueOf( useRegistryKeepAlive ) );
-
- // DO WORK
- RemoteCacheServerAttributes result = RemoteCacheServerFactory.configureRemoteCacheServerAttributes( props );
-
- // VERIFY
- assertEquals( "Wrong useRegistryKeepAlive", useRegistryKeepAlive, result.isUseRegistryKeepAlive() );
- }
-
- /** verify that we get the startRegistry value */
- public void testConfigureRemoteCacheServerAttributes_startRegistryPresent()
- {
- // SETUP
- boolean startRegistry = false;
- Properties props = new Properties();
- props.put( IRemoteCacheConstants.CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + ".startRegistry", String.valueOf( startRegistry ) );
-
- // DO WORK
- RemoteCacheServerAttributes result = RemoteCacheServerFactory.configureRemoteCacheServerAttributes( props );
-
- // VERIFY
- assertEquals( "Wrong startRegistry", startRegistry, result.isStartRegistry() );
- }
-
- /** verify that we get the registryKeepAliveDelayMillis value */
- public void testConfigureRemoteCacheServerAttributes_rmiSocketFactoryTimeoutMillisPresent()
- {
- // SETUP
- int rmiSocketFactoryTimeoutMillis = 123245;
- Properties props = new Properties();
- props.put( IRemoteCacheConstants.CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + ".rmiSocketFactoryTimeoutMillis", String.valueOf( rmiSocketFactoryTimeoutMillis ) );
-
- // DO WORK
- RemoteCacheServerAttributes result = RemoteCacheServerFactory.configureRemoteCacheServerAttributes( props );
-
- // VERIFY
- assertEquals( "Wrong rmiSocketFactoryTimeoutMillis", rmiSocketFactoryTimeoutMillis, result.getRmiSocketFactoryTimeoutMillis() );
- }
-
- /** verify that we get the startRegistry value */
- public void testConfigureRemoteCacheServerAttributes_allowClusterGetPresent()
- {
- // SETUP
- boolean allowClusterGet = false;
- Properties props = new Properties();
- props.put( IRemoteCacheConstants.CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + ".allowClusterGet", String.valueOf( allowClusterGet ) );
-
- // DO WORK
- RemoteCacheServerAttributes result = RemoteCacheServerFactory.configureRemoteCacheServerAttributes( props );
-
- // VERIFY
- assertEquals( "Wrong allowClusterGet", allowClusterGet, result.isAllowClusterGet() );
- }
-
- /** verify that we get the startRegistry value */
- public void testConfigureRemoteCacheServerAttributes_localClusterConsistencyPresent()
- {
- // SETUP
- boolean localClusterConsistency = false;
- Properties props = new Properties();
- props.put( IRemoteCacheConstants.CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + ".localClusterConsistency", String.valueOf( localClusterConsistency ) );
-
- // DO WORK
- RemoteCacheServerAttributes result = RemoteCacheServerFactory.configureRemoteCacheServerAttributes( props );
-
- // VERIFY
- assertEquals( "Wrong localClusterConsistency", localClusterConsistency, result.isLocalClusterConsistency() );
- }
-
- /** verify that we get the timeout value */
- public void testConfigureObjectSpecificCustomFactory_withProperty()
- {
- // SETUP
- String testValue = "123245";
- Properties props = new Properties();
- props.put( IRemoteCacheConstants.CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX, MockRMISocketFactory.class.getName() );
- props.put( IRemoteCacheConstants.CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX + ".testStringProperty", testValue );
-
- // DO WORK
- RMISocketFactory result = RemoteCacheServerFactory.configureObjectSpecificCustomFactory( props );
-
- // VERIFY
- assertNotNull( "Should have a custom socket factory.", result );
- assertEquals( "Wrong testValue", testValue, ((MockRMISocketFactory)result).getTestStringProperty() );
- }
-
- /** verify that we get the timeout value */
- public void testConfigureObjectSpecificCustomFactory_withProperty_TimeoutConfigurableRMIScoketFactory()
- {
- // SETUP
- int readTimeout = 1234;
- int openTimeout = 1234;
- Properties props = new Properties();
- props.put( IRemoteCacheConstants.CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX, TimeoutConfigurableRMISocketFactory.class.getName() );
- props.put( IRemoteCacheConstants.CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX + ".readTimeout", String.valueOf( readTimeout ) );
- props.put( IRemoteCacheConstants.CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX + ".openTimeout", String.valueOf( openTimeout ) );
-
- // DO WORK
- RMISocketFactory result = RemoteCacheServerFactory.configureObjectSpecificCustomFactory( props );
-
- // VERIFY
- assertNotNull( "Should have a custom socket factory.", result );
- assertEquals( "Wrong readTimeout", readTimeout, ((TimeoutConfigurableRMISocketFactory)result).getReadTimeout() );
- assertEquals( "Wrong readTimeout", openTimeout, ((TimeoutConfigurableRMISocketFactory)result).getOpenTimeout() );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerStartupUtil.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerStartupUtil.java
deleted file mode 100644
index 03a79c1..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerStartupUtil.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.server;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.net.UnknownHostException;
-import java.util.Properties;
-
-import org.apache.commons.jcs.auxiliary.remote.RemoteUtils;
-import org.apache.commons.jcs.utils.net.HostNameUtil;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- *Starts the registry and runs the server via the factory.
- *<p>
- * @author Aaron Smuts
- */
-public class RemoteCacheServerStartupUtil
-{
- /** The logger */
- private static final Log log = LogManager.getLog( RemoteCacheServerStartupUtil.class );
-
- /** Registry to use in the test. */
- private static final int DEFAULT_REGISTRY_PORT = 1101;
-
- /**
- * Starts the registry on port "registry.port"
- * <p>
- * @param propsFileName
- * @return RemoteCacheServer
- */
- public static <K, V> RemoteCacheServer<K, V> startServerUsingProperties( String propsFileName )
- {
- // TODO load from props file or get as init param or get from jndi, or
- // all three
- int registryPort = DEFAULT_REGISTRY_PORT;
-
- Properties props = null;
- try
- {
- props = RemoteUtils.loadProps(propsFileName);
- }
- catch (IOException e)
- {
- log.error( "Problem loading configuration from " + propsFileName, e);
- }
-
- if ( props != null )
- {
- String portS = props.getProperty( "registry.port", String.valueOf( DEFAULT_REGISTRY_PORT ) );
-
- try
- {
- registryPort = Integer.parseInt( portS );
- }
- catch ( NumberFormatException e )
- {
- log.error( "Problem converting port to an int.", e );
- }
- }
-
- // we will always use the local machine for the registry
- try
- {
- String registryHost = HostNameUtil.getLocalHostAddress();
-
- if ( log.isDebugEnabled() )
- {
- log.debug( "registryHost = [" + registryHost + "]" );
- }
-
- if ( "localhost".equals( registryHost ) || "127.0.0.1".equals( registryHost ) )
- {
- log.warn( "The local address [" + registryHost
- + "] is INVALID. Other machines must be able to use the address to reach this server." );
- }
-
- try
- {
- RemoteCacheServerFactory.startup( registryHost, registryPort, props );
- }
- catch ( IOException e )
- {
- log.error( "Problem starting remote cache server.", e );
- }
- }
- catch ( UnknownHostException e )
- {
- log.error( "Could not get local address to use for the registry!", e );
- }
-
- return RemoteCacheServerFactory.getRemoteCacheServer();
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerUnitTest.java
deleted file mode 100644
index d002f80..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/RemoteCacheServerUnitTest.java
+++ /dev/null
@@ -1,465 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.server;
-
-/*
- * 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.
- */
-
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Properties;
-
-import org.apache.commons.jcs.auxiliary.MockCacheEventLogger;
-import org.apache.commons.jcs.auxiliary.remote.MockRemoteCacheListener;
-import org.apache.commons.jcs.auxiliary.remote.RemoteUtils;
-import org.apache.commons.jcs.auxiliary.remote.server.behavior.IRemoteCacheServerAttributes;
-import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.utils.timing.SleepUtil;
-
-import junit.framework.TestCase;
-
-/**
- * Since the server does not know that it is a server, it is easy to unit test. The factory does all
- * the rmi work.
- * <p>
- * @author Aaron Smuts
- */
-public class RemoteCacheServerUnitTest
- extends TestCase
-{
- private static final String expectedIp1 = "adfasdf";
- private static final String expectedIp2 = "adsfadsafaf";
-
- private RemoteCacheServer<String, String> server;
-
- @Override
- protected void setUp() throws Exception
- {
- super.setUp();
-
- IRemoteCacheServerAttributes rcsa = new RemoteCacheServerAttributes();
- rcsa.setConfigFileName( "/TestRemoteCacheServer.ccf" );
- Properties config = RemoteUtils.loadProps(rcsa.getConfigFileName());
- this.server = new RemoteCacheServer<>( rcsa, config );
- }
-
- @Override
- protected void tearDown() throws Exception
- {
- this.server.shutdown();
-
- super.tearDown();
- }
-
- /**
- * Add a listener. Pass the id of 0, verify that the server sets a new listener id. Do another
- * and verify that the second gets an id of 2.
- * <p>
- * @throws Exception
- */
- public void testAddListenerToCache_LOCALtype()
- throws Exception
- {
- MockRemoteCacheListener<String, String> mockListener1 = new MockRemoteCacheListener<>();
- mockListener1.remoteType = RemoteType.LOCAL;
- mockListener1.localAddress = expectedIp1;
- MockRemoteCacheListener<String, String> mockListener2 = new MockRemoteCacheListener<>();
- mockListener1.remoteType = RemoteType.LOCAL;
- mockListener2.localAddress = expectedIp2;
-
- String cacheName = "testAddListener";
-
- // DO WORK
- server.addCacheListener( cacheName, mockListener1 );
- server.addCacheListener( cacheName, mockListener2 );
-
- // VERIFY
- assertEquals( "Wrong listener id.", 1, mockListener1.getListenerId() );
- assertEquals( "Wrong listener id.", 2, mockListener2.getListenerId() );
- assertEquals( "Wrong ip.", expectedIp1, server.getExtraInfoForRequesterId( 1 ) );
- assertEquals( "Wrong ip.", expectedIp2, server.getExtraInfoForRequesterId( 2 ) );
- }
-
- /**
- * Add a listener. Pass the id of 0, verify that the server sets a new listener id. Do another
- * and verify that the second gets an id of 2.
- * <p>
- * @throws Exception
- */
- public void testAddListenerToCache_CLUSTERtype()
- throws Exception
- {
- MockRemoteCacheListener<String, String> mockListener1 = new MockRemoteCacheListener<>();
- mockListener1.remoteType = RemoteType.CLUSTER;
- mockListener1.localAddress = expectedIp1;
- MockRemoteCacheListener<String, String> mockListener2 = new MockRemoteCacheListener<>();
- mockListener1.remoteType = RemoteType.CLUSTER;
- mockListener2.localAddress = expectedIp2;
-
- String cacheName = "testAddListener";
-
- // DO WORK
- server.addCacheListener( cacheName, mockListener1 );
- server.addCacheListener( cacheName, mockListener2 );
-
- // VERIFY
- assertEquals( "Wrong listener id.", 1, mockListener1.getListenerId() );
- assertEquals( "Wrong listener id.", 2, mockListener2.getListenerId() );
- assertEquals( "Wrong ip.", expectedIp1, server.getExtraInfoForRequesterId( 1 ) );
- assertEquals( "Wrong ip.", expectedIp2, server.getExtraInfoForRequesterId( 2 ) );
- }
-
- // TODO: This test only works if preconfigured remote caches exist. Need to fix.
-// /**
-// * Add a listener. Pass the id of 0, verify that the server sets a new listener id. Do another
-// * and verify that the second gets an id of 2.
-// * <p>
-// * @throws Exception
-// */
-// public void testAddListener_ToAll()
-// throws Exception
-// {
-// MockRemoteCacheListener<String, String> mockListener1 = new MockRemoteCacheListener<>();
-// mockListener1.localAddress = expectedIp1;
-// MockRemoteCacheListener<String, String> mockListener2 = new MockRemoteCacheListener<>();
-// mockListener2.localAddress = expectedIp2;
-//
-// // DO WORK
-// // don't specify the cache name
-// server.addCacheListener( mockListener1 );
-// server.addCacheListener( mockListener2 );
-//
-// // VERIFY
-// assertEquals( "Wrong listener id.", 1, mockListener1.getListenerId() );
-// assertEquals( "Wrong listener id.", 2, mockListener2.getListenerId() );
-// assertEquals( "Wrong ip.", expectedIp1, server.getExtraInfoForRequesterId( 1 ) );
-// assertEquals( "Wrong ip.", expectedIp2, server.getExtraInfoForRequesterId( 2 ) );
-// }
-
- /**
- * Add a listener. Pass the id of 0, verify that the server sets a new listener id. Do another
- * and verify that the second gets an id of 2. Call remove Listener and verify that it is
- * removed.
- * <p>
- * @throws Exception
- */
- public void testAddListener_ToAllThenRemove()
- throws Exception
- {
- MockRemoteCacheListener<String, String> mockListener1 = new MockRemoteCacheListener<>();
- MockRemoteCacheListener<String, String> mockListener2 = new MockRemoteCacheListener<>();
-
- String cacheName = "testAddListenerToAllThenRemove";
-
- // DO WORK
- server.addCacheListener( cacheName, mockListener1 );
- server.addCacheListener( cacheName, mockListener2 );
-
- // VERIFY
- assertEquals( "Wrong number of listeners.", 2, server.getCacheListeners( cacheName ).eventQMap.size() );
- assertEquals( "Wrong listener id.", 1, mockListener1.getListenerId() );
- assertEquals( "Wrong listener id.", 2, mockListener2.getListenerId() );
-
- // DO WORK
- server.removeCacheListener( cacheName, mockListener1.getListenerId() );
- assertEquals( "Wrong number of listeners.", 1, server.getCacheListeners( cacheName ).eventQMap.size() );
- }
-
- /**
- * Add a listener. Pass the id of 0, verify that the server sets a new listener id. Do another
- * and verify that the second gets an id of 2. Call remove Listener and verify that it is
- * removed.
- * <p>
- * @throws Exception
- */
- public void testAddListener_ToAllThenRemove_clusterType()
- throws Exception
- {
- MockRemoteCacheListener<String, String> mockListener1 = new MockRemoteCacheListener<>();
- mockListener1.remoteType = RemoteType.CLUSTER;
- MockRemoteCacheListener<String, String> mockListener2 = new MockRemoteCacheListener<>();
- mockListener2.remoteType = RemoteType.CLUSTER;
-
- String cacheName = "testAddListenerToAllThenRemove";
-
- // DO WORK
- server.addCacheListener( cacheName, mockListener1 );
- server.addCacheListener( cacheName, mockListener2 );
-
- // VERIFY
- assertEquals( "Wrong number of listeners.", 0, server.getCacheListeners( cacheName ).eventQMap.size() );
- assertEquals( "Wrong number of listeners.", 2, server.getClusterListeners( cacheName ).eventQMap.size() );
- assertEquals( "Wrong listener id.", 1, mockListener1.getListenerId() );
- assertEquals( "Wrong listener id.", 2, mockListener2.getListenerId() );
-
- // DO WORK
- server.removeCacheListener( cacheName, mockListener1.getListenerId() );
- assertEquals( "Wrong number of listeners.", 1, server.getClusterListeners( cacheName ).eventQMap.size() );
- assertNull( "Should be no entry in the ip map.", server.getExtraInfoForRequesterId( 1 ) );
- }
-
- /**
- * Register a listener and then verify that it is called when we put using a different listener
- * id.
- * @throws Exception
- */
- public void testSimpleRegisterListenerAndPut()
- throws Exception
- {
- IRemoteCacheServerAttributes rcsa = new RemoteCacheServerAttributes();
- rcsa.setConfigFileName( "/TestRemoteCacheServer.ccf" );
-
- Properties config = RemoteUtils.loadProps(rcsa.getConfigFileName());
- MockRemoteCacheListener<String, Long> mockListener = new MockRemoteCacheListener<>();
- RemoteCacheServer<String, Long> server = new RemoteCacheServer<>( rcsa, config );
-
- String cacheName = "testSimpleRegisterListenerAndPut";
- server.addCacheListener( cacheName, mockListener );
-
- // DO WORK
- List<ICacheElement<String, Long>> inputItems = new LinkedList<>();
- int numToPut = 10;
-
- for ( int i = 0; i < numToPut; i++ )
- {
- ICacheElement<String, Long> element = new CacheElement<>( cacheName, String.valueOf( i ), Long.valueOf( i ) );
- inputItems.add( element );
- server.update( element, 9999 );
- }
-
- Thread.sleep( 100 );
- Thread.yield();
- Thread.sleep( 100 );
-
- // VERIFY
- assertEquals( "Wrong number of items put to listener.", numToPut, mockListener.putItems.size() );
- for ( int i = 0; i < numToPut; i++ )
- {
- assertEquals( "Wrong item.", inputItems.get( i ), mockListener.putItems.get( i ) );
- }
-
- server.shutdown();
- }
-
- /**
- * Register a listener and then verify that it is called when we put using a different listener
- * id. The updates should come from a cluster listener and local cluster consistency should be
- * true.
- * <p>
- * @throws Exception
- */
- public void testSimpleRegisterListenerAndPut_FromClusterWithLCC()
- throws Exception
- {
- // SETUP
- IRemoteCacheServerAttributes rcsa = new RemoteCacheServerAttributes();
- rcsa.setLocalClusterConsistency( true );
- rcsa.setConfigFileName( "/TestRemoteCacheServer.ccf" );
- Properties config = RemoteUtils.loadProps(rcsa.getConfigFileName());
- RemoteCacheServer<String, Long> server = new RemoteCacheServer<>( rcsa, config );
-
- // this is to get the listener id for inserts.
- MockRemoteCacheListener<String, Long> clusterListener = new MockRemoteCacheListener<>();
- clusterListener.remoteType = RemoteType.CLUSTER;
-
- // this should get the updates
- MockRemoteCacheListener<String, Long> localListener = new MockRemoteCacheListener<>();
- localListener.remoteType = RemoteType.LOCAL;
-
- String cacheName = "testSimpleRegisterListenerAndPut_FromClusterWithLCC";
- server.addCacheListener( cacheName, clusterListener );
- server.addCacheListener( cacheName, localListener );
-
- // DO WORK
- List<ICacheElement<String, Long>> inputItems = new LinkedList<>();
- int numToPut = 10;
-
- for ( int i = 0; i < numToPut; i++ )
- {
- ICacheElement<String, Long> element = new CacheElement<>( cacheName, String.valueOf( i ), Long.valueOf( i ) );
- inputItems.add( element );
- // update using the cluster listener id
- server.update( element, clusterListener.getListenerId() );
- }
-
- SleepUtil.sleepAtLeast( 200 );
- Thread.yield();
- SleepUtil.sleepAtLeast( 200 );
-
- // VERIFY
- assertEquals( "Wrong number of items put to listener.", numToPut, localListener.putItems.size() );
- for ( int i = 0; i < numToPut; i++ )
- {
- assertEquals( "Wrong item.", inputItems.get( i ), localListener.putItems.get( i ) );
- }
-
- server.shutdown();
- }
-
- /**
- * Register a listener and then verify that it is called when we put using a different listener
- * id.
- * @throws Exception
- */
- public void testSimpleRegisterListenerAndRemove()
- throws Exception
- {
- MockRemoteCacheListener<String, String> mockListener = new MockRemoteCacheListener<>();
-
- String cacheName = "testSimpleRegisterListenerAndPut";
- server.addCacheListener( cacheName, mockListener );
-
- // DO WORK
- int numToPut = 10;
-
- for ( int i = 0; i < numToPut; i++ )
- {
- // use a junk listener id
- server.remove( cacheName, String.valueOf( i ), 9999 );
- }
-
- Thread.sleep( 100 );
- Thread.yield();
- Thread.sleep( 100 );
-
- // VERIFY
- assertEquals( "Wrong number of items removed from listener.", numToPut, mockListener.removedKeys.size() );
- for ( int i = 0; i < numToPut; i++ )
- {
- assertEquals( "Wrong key.", String.valueOf( i ), mockListener.removedKeys.get( i ) );
- }
- }
-
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testUpdate_simple()
- throws Exception
- {
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- server.setCacheEventLogger( cacheEventLogger );
-
- ICacheElement<String, String> item = new CacheElement<>( "region", "key", "value" );
-
- // DO WORK
- server.update( item );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testGet_simple()
- throws Exception
- {
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- server.setCacheEventLogger( cacheEventLogger );
-
- // DO WORK
- server.get( "region", "key" );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testGetMatching_simple()
- throws Exception
- {
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- server.setCacheEventLogger( cacheEventLogger );
-
- // DO WORK
- server.getMatching( "region", "pattern", 0 );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testGetMultiple_simple()
- throws Exception
- {
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- server.setCacheEventLogger( cacheEventLogger );
-
- // DO WORK
- server.getMultiple( "region", new HashSet<>() );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testRemove_simple()
- throws Exception
- {
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- server.setCacheEventLogger( cacheEventLogger );
-
- // DO WORK
- server.remove( "region", "key" );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-
- /**
- * Verify event log calls.
- * <p>
- * @throws Exception
- */
- public void testRemoveAll_simple()
- throws Exception
- {
- MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
- server.setCacheEventLogger( cacheEventLogger );
-
- // DO WORK
- server.removeAll( "region" );
-
- // VERIFY
- assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
- assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/TimeoutConfigurableRMISocketFactoryUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/TimeoutConfigurableRMISocketFactoryUnitTest.java
deleted file mode 100644
index ed76c0a..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/server/TimeoutConfigurableRMISocketFactoryUnitTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.server;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-import java.io.IOException;
-import java.net.ServerSocket;
-import java.net.Socket;
-
-/** Unit tests for the custom factory */
-public class TimeoutConfigurableRMISocketFactoryUnitTest
- extends TestCase
-{
- /**
- * Simple test to see that we can create a server socket and connect.
- * <p>
- * @throws IOException
- */
- public void testCreateAndConnect() throws IOException
- {
- // SETUP
- int port = 3455;
- String host = "localhost";
- TimeoutConfigurableRMISocketFactory factory = new TimeoutConfigurableRMISocketFactory();
-
- // DO WORK
- ServerSocket serverSocket = factory.createServerSocket( port );
- Socket socket = factory.createSocket( host, port );
- socket.close();
- serverSocket.close();
-
- // VERIFY
- // passive, no errors
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/util/RemoteCacheRequestFactoryUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/util/RemoteCacheRequestFactoryUnitTest.java
deleted file mode 100644
index e43688c..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/util/RemoteCacheRequestFactoryUnitTest.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package org.apache.commons.jcs.auxiliary.remote.util;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheRequest;
-import org.apache.commons.jcs.auxiliary.remote.value.RemoteRequestType;
-import org.apache.commons.jcs.engine.CacheElement;
-
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.Set;
-
-/** Unit tests for the request creator. */
-public class RemoteCacheRequestFactoryUnitTest
- extends TestCase
-{
- /** Simple test */
- public void testCreateGetRequest_Normal()
- {
- // SETUP
- String cacheName = "test";
- Serializable key = "key";
- long requesterId = 2;
-
- // DO WORK
- RemoteCacheRequest<Serializable, Serializable> result =
- RemoteCacheRequestFactory.createGetRequest( cacheName, key, requesterId );
-
- // VERIFY
- assertNotNull( "Should have a result", result );
- assertEquals( "Wrong cacheName", cacheName, result.getCacheName() );
- assertEquals( "Wrong type", RemoteRequestType.GET, result.getRequestType() );
- }
-
- /** Simple test */
- public void testCreateGetMatchingRequest_Normal()
- {
- // SETUP
- String cacheName = "test";
- String pattern = "pattern";
- long requesterId = 2;
-
- // DO WORK
- RemoteCacheRequest<Serializable, Serializable> result =
- RemoteCacheRequestFactory.createGetMatchingRequest( cacheName, pattern, requesterId );
-
- // VERIFY
- assertNotNull( "Should have a result", result );
- assertEquals( "Wrong cacheName", cacheName, result.getCacheName() );
- assertEquals( "Wrong type", RemoteRequestType.GET_MATCHING, result.getRequestType() );
- }
-
- /** Simple test */
- public void testCreateGetMultipleRequest_Normal()
- {
- // SETUP
- String cacheName = "test";
- Set<Serializable> keys = Collections.emptySet();
- long requesterId = 2;
-
- // DO WORK
- RemoteCacheRequest<Serializable, Serializable> result =
- RemoteCacheRequestFactory.createGetMultipleRequest( cacheName, keys, requesterId );
-
- // VERIFY
- assertNotNull( "Should have a result", result );
- assertEquals( "Wrong cacheName", cacheName, result.getCacheName() );
- assertEquals( "Wrong type", RemoteRequestType.GET_MULTIPLE, result.getRequestType() );
- }
-
- /** Simple test */
- public void testCreateRemoveRequest_Normal()
- {
- // SETUP
- String cacheName = "test";
- Serializable key = "key";
- long requesterId = 2;
-
- // DO WORK
- RemoteCacheRequest<Serializable, Serializable> result = RemoteCacheRequestFactory
- .createRemoveRequest( cacheName, key, requesterId );
-
- // VERIFY
- assertNotNull( "Should have a result", result );
- assertEquals( "Wrong cacheName", cacheName, result.getCacheName() );
- assertEquals( "Wrong type", RemoteRequestType.REMOVE, result.getRequestType() );
- }
-
- /** Simple test */
- public void testCreateRemoveAllRequest_Normal()
- {
- // SETUP
- String cacheName = "test";
- long requesterId = 2;
-
- // DO WORK
- RemoteCacheRequest<Serializable, Serializable> result =
- RemoteCacheRequestFactory.createRemoveAllRequest( cacheName, requesterId );
-
- // VERIFY
- assertNotNull( "Should have a result", result );
- assertEquals( "Wrong cacheName", cacheName, result.getCacheName() );
- assertEquals( "Wrong type", RemoteRequestType.REMOVE_ALL, result.getRequestType() );
- }
-
- /** Simple test */
- public void testCreateUpdateRequest_Normal()
- {
- // SETUP
- String cacheName = "test";
- Serializable key = "key";
- long requesterId = 2;
-
- CacheElement<Serializable, Serializable> element =
- new CacheElement<>( cacheName, key, null );
-
- // DO WORK
- RemoteCacheRequest<Serializable, Serializable> result =
- RemoteCacheRequestFactory.createUpdateRequest( element, requesterId );
-
- // VERIFY
- assertNotNull( "Should have a result", result );
- assertEquals( "Wrong cacheName", cacheName, result.getCacheName() );
- assertEquals( "Wrong type", RemoteRequestType.UPDATE, result.getRequestType() );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/CacheEventQueueFactoryUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/CacheEventQueueFactoryUnitTest.java
deleted file mode 100644
index b5d3637..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/CacheEventQueueFactoryUnitTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-import org.apache.commons.jcs.auxiliary.remote.MockRemoteCacheListener;
-import org.apache.commons.jcs.engine.behavior.ICacheEventQueue;
-import org.apache.commons.jcs.engine.behavior.ICacheEventQueue.QueueType;
-import org.apache.commons.jcs.engine.behavior.ICacheListener;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/** Unit tests for the CacheEventQueueFactory */
-public class CacheEventQueueFactoryUnitTest
- extends TestCase
-{
- /** Test create */
- public void testCreateCacheEventQueue_Single()
- {
- // SETUP
- QueueType eventQueueType = QueueType.SINGLE;
- ICacheListener<String, String> listener = new MockRemoteCacheListener<>();
- long listenerId = 1;
-
- CacheEventQueueFactory<String, String> factory = new CacheEventQueueFactory<>();
-
- // DO WORK
- ICacheEventQueue<String, String> result = factory.createCacheEventQueue( listener, listenerId, "cacheName", "threadPoolName", eventQueueType );
-
- // VERIFY
- assertNotNull( "Should have a result", result );
- assertTrue( "Wrong type", result.getQueueType() == QueueType.SINGLE );
- }
-
- /** Test create */
- public void testCreateCacheEventQueue_Pooled()
- {
- // SETUP
- QueueType eventQueueType = QueueType.POOLED;
- ICacheListener<String, String> listener = new MockRemoteCacheListener<>();
- long listenerId = 1;
-
- CacheEventQueueFactory<String, String> factory = new CacheEventQueueFactory<>();
-
- // DO WORK
- ICacheEventQueue<String, String> result = factory.createCacheEventQueue( listener, listenerId, "cacheName", "threadPoolName", eventQueueType );
-
- // VERIFY
- assertNotNull( "Should have a result", result );
- assertTrue( "Wrong type", result.getQueueType() == QueueType.POOLED );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/ElementAttributesUtils.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/ElementAttributesUtils.java
deleted file mode 100644
index 5da0af0..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/ElementAttributesUtils.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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.apache.commons.jcs.engine;
-
-/**
- * Allow test access to set last access time without exposing public method
- */
-public class ElementAttributesUtils {
- public static void setLastAccessTime(ElementAttributes ea, long time) {
- ea.setLastAccessTime(time);
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/EventQueueConcurrentLoadTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/EventQueueConcurrentLoadTest.java
deleted file mode 100644
index a38267e..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/EventQueueConcurrentLoadTest.java
+++ /dev/null
@@ -1,358 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheListener;
-
-import junit.extensions.ActiveTestSuite;
-import junit.framework.Test;
-import junit.framework.TestCase;
-
-/**
- * This test case is designed to makes sure there are no deadlocks in the event queue. The time to
- * live should be set to a very short interval to make a deadlock more likely.
- * <p>
- * @author Aaron Smuts
- */
-public class EventQueueConcurrentLoadTest
- extends TestCase
-{
- /** The queue implementation */
- private static CacheEventQueue<String, String> queue = null;
-
- /** The mock listener */
- private static CacheListenerImpl<String, String> listen = null;
-
- /** max failure setting */
- private final int maxFailure = 3;
-
- /** time to wait before retrying on failure. */
- private final int waitBeforeRetry = 100;
-
- /** very small idle time */
- private final int idleTime = 2;
-
- /**
- * Constructor for the TestDiskCache object.
- * @param testName
- */
- public EventQueueConcurrentLoadTest( String testName )
- {
- super( testName );
- }
-
- /**
- * Main method passes this test to the text test runner.
- * @param args
- */
- public static void main( String args[] )
- {
- String[] testCaseName = { EventQueueConcurrentLoadTest.class.getName() };
- junit.textui.TestRunner.main( testCaseName );
- }
-
- /**
- * A unit test suite for JUnit
- * @return The test suite
- */
- public static Test suite()
- {
- ActiveTestSuite suite = new ActiveTestSuite();
-
- suite.addTest( new EventQueueConcurrentLoadTest( "testRunPutTest1" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runPutTest( 200, 200 );
- }
- } );
-
- suite.addTest( new EventQueueConcurrentLoadTest( "testRunPutTest2" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runPutTest( 1200, 1400 );
- }
- } );
-
- suite.addTest( new EventQueueConcurrentLoadTest( "testRunRemoveTest1" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runRemoveTest( 2200 );
- }
- } );
-
- suite.addTest( new EventQueueConcurrentLoadTest( "testRunPutTest4" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runPutTest( 5200, 6600 );
- }
- } );
-
- suite.addTest( new EventQueueConcurrentLoadTest( "testRunRemoveTest2" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runRemoveTest( 5200 );
- }
- } );
-
- suite.addTest( new EventQueueConcurrentLoadTest( "testRunPutDelayTest" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runPutDelayTest( 100, 6700 );
- }
- } );
-
- return suite;
- }
-
- /**
- * Test setup. Create the static queue to be used by all tests
- */
- @Override
- public void setUp()
- {
- listen = new CacheListenerImpl<>();
- queue = new CacheEventQueue<>( listen, 1L, "testCache1", maxFailure, waitBeforeRetry );
-
- queue.setWaitToDieMillis( idleTime );
- }
-
- /**
- * Adds put events to the queue.
- * @param end
- * @param expectedPutCount
- * @throws Exception
- */
- public void runPutTest( int end, int expectedPutCount )
- throws Exception
- {
- for ( int i = 0; i <= end; i++ )
- {
- CacheElement<String, String> elem = new CacheElement<>( "testCache1", i + ":key", i + "data" );
- queue.addPutEvent( elem );
- }
-
- while ( !queue.isEmpty() )
- {
- synchronized ( this )
- {
- System.out.println( "queue is still busy, waiting 250 millis" );
- this.wait( 250 );
- }
- }
- System.out.println( "queue is empty, comparing putCount" );
-
- // this becomes less accurate with each test. It should never fail. If
- // it does things are very off.
- assertTrue( "The put count [" + listen.putCount + "] is below the expected minimum threshold ["
- + expectedPutCount + "]", listen.putCount >= ( expectedPutCount - 1 ) );
-
- }
-
- /**
- * Add remove events to the event queue.
- * @param end
- * @throws Exception
- */
- public void runRemoveTest( int end )
- throws Exception
- {
- for ( int i = 0; i <= end; i++ )
- {
- queue.addRemoveEvent( i + ":key" );
- }
-
- }
-
- /**
- * Test putting and a delay. Waits until queue is empty to start.
- * @param end
- * @param expectedPutCount
- * @throws Exception
- */
- public void runPutDelayTest( int end, int expectedPutCount )
- throws Exception
- {
- while ( !queue.isEmpty() )
- {
- synchronized ( this )
- {
- System.out.println( "queue is busy, waiting 250 millis to begin" );
- this.wait( 250 );
- }
- }
- System.out.println( "queue is empty, begin" );
-
- // get it going
- CacheElement<String, String> elem = new CacheElement<>( "testCache1", "a:key", "adata" );
- queue.addPutEvent( elem );
-
- for ( int i = 0; i <= end; i++ )
- {
- synchronized ( this )
- {
- if ( i % 2 == 0 )
- {
- this.wait( idleTime );
- }
- else
- {
- this.wait( idleTime / 2 );
- }
- }
- CacheElement<String, String> elem2 = new CacheElement<>( "testCache1", i + ":key", i + "data" );
- queue.addPutEvent( elem2 );
- }
-
- while ( !queue.isEmpty() )
- {
- synchronized ( this )
- {
- System.out.println( "queue is still busy, waiting 250 millis" );
- this.wait( 250 );
- }
- }
- System.out.println( "queue is empty, comparing putCount" );
-
- Thread.sleep( 1000 );
-
- // this becomes less accurate with each test. It should never fail. If
- // it does things are very off.
- assertTrue( "The put count [" + listen.putCount + "] is below the expected minimum threshold ["
- + expectedPutCount + "]", listen.putCount >= ( expectedPutCount - 1 ) );
-
- }
-
- /**
- * This is a dummy cache listener to use when testing the event queue.
- */
- protected static class CacheListenerImpl<K, V>
- implements ICacheListener<K, V>
- {
- /**
- * <code>putCount</code>
- */
- protected int putCount = 0;
-
- /**
- * <code>removeCount</code>
- */
- protected int removeCount = 0;
-
- /**
- * @param item
- * @throws IOException
- */
- @Override
- public void handlePut( ICacheElement<K, V> item )
- throws IOException
- {
- synchronized ( this )
- {
- putCount++;
- }
- }
-
- /**
- * @param cacheName
- * @param key
- * @throws IOException
- */
- @Override
- public void handleRemove( String cacheName, K key )
- throws IOException
- {
- synchronized ( this )
- {
- removeCount++;
- }
-
- }
-
- /**
- * @param cacheName
- * @throws IOException
- */
- @Override
- public void handleRemoveAll( String cacheName )
- throws IOException
- {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * @param cacheName
- * @throws IOException
- */
- @Override
- public void handleDispose( String cacheName )
- throws IOException
- {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * @param id
- * @throws IOException
- */
- @Override
- public void setListenerId( long id )
- throws IOException
- {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * @return 0
- * @throws IOException
- */
- @Override
- public long getListenerId()
- throws IOException
- {
- // TODO Auto-generated method stub
- return 0;
- }
-
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/MockCacheServiceNonLocal.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/MockCacheServiceNonLocal.java
deleted file mode 100644
index 662d2d7..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/MockCacheServiceNonLocal.java
+++ /dev/null
@@ -1,245 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
-
-/**
- * This is a mock impl of the non local cache service.
- */
-public class MockCacheServiceNonLocal<K, V>
- implements ICacheServiceNonLocal<K, V>
-{
- /** The key last passed to get */
- public K lastGetKey;
-
- /** The pattern last passed to get */
- public String lastGetMatchingPattern;
-
- /** The keya last passed to getMatching */
- public Set<K> lastGetMultipleKeys;
-
- /** The object that was last passed to update. */
- public ICacheElement<K, V> lastUpdate;
-
- /** List of updates. */
- public List<ICacheElement<K, V>> updateRequestList = new ArrayList<>();
-
- /** List of request ids. */
- public List<Long> updateRequestIdList = new ArrayList<>();
-
- /** The key that was last passed to remove. */
- public K lastRemoveKey;
-
- /** The cache name that was last passed to removeAll. */
- public String lastRemoveAllCacheName;
-
- /**
- * @param cacheName
- * @param key
- * @param requesterId - identity of requester
- * @return null
- */
- @Override
- public ICacheElement<K, V> get( String cacheName, K key, long requesterId )
- {
- lastGetKey = key;
- return null;
- }
-
- /**
- * @param cacheName
- * @return empty set
- */
- @Override
- public Set<K> getKeySet( String cacheName )
- {
- return new HashSet<>();
- }
-
- /**
- * Set the last remove key.
- * <p>
- * @param cacheName
- * @param key
- * @param requesterId - identity of requester
- */
- @Override
- public void remove( String cacheName, K key, long requesterId )
- {
- lastRemoveKey = key;
- }
-
- /**
- * Set the lastRemoveAllCacheName to the cacheName.
- * <p>
- * @param cacheName - region name
- * @param requesterId - identity of requester
- * @throws IOException
- */
- @Override
- public void removeAll( String cacheName, long requesterId )
- throws IOException
- {
- lastRemoveAllCacheName = cacheName;
- }
-
- /**
- * Set the last update item.
- * <p>
- * @param item
- * @param requesterId - identity of requester
- */
- @Override
- public void update( ICacheElement<K, V> item, long requesterId )
- {
- lastUpdate = item;
- updateRequestList.add( item );
- updateRequestIdList.add( Long.valueOf( requesterId ) );
- }
-
- /**
- * Do nothing.
- * <p>
- * @param cacheName
- */
- @Override
- public void dispose( String cacheName )
- {
- return;
- }
-
- /**
- * @param cacheName
- * @param key
- * @return null
- */
- @Override
- public ICacheElement<K, V> get( String cacheName, K key )
- {
- return get( cacheName, key, 0 );
- }
-
- /**
- * Do nothing.
- */
- @Override
- public void release()
- {
- return;
- }
-
- /**
- * Set the last remove key.
- * <p>
- * @param cacheName
- * @param key
- */
- @Override
- public void remove( String cacheName, K key )
- {
- lastRemoveKey = key;
- }
-
- /**
- * Set the last remove all cache name.
- * <p>
- * @param cacheName
- */
- @Override
- public void removeAll( String cacheName )
- {
- lastRemoveAllCacheName = cacheName;
- }
-
- /**
- * Set the last update item.
- * <p>
- * @param item
- */
- @Override
- public void update( ICacheElement<K, V> item )
- {
- lastUpdate = item;
- }
-
- /**
- * @param cacheName
- * @param keys
- * @param requesterId - identity of requester
- * @return empty map
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys, long requesterId )
- {
- lastGetMultipleKeys = keys;
- return new HashMap<>();
- }
-
- /**
- * @param cacheName
- * @param keys
- * @return empty map
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys )
- {
- return getMultiple( cacheName, keys, 0 );
- }
-
- /**
- * Returns an empty map. Zombies have no internal data.
- * <p>
- * @param cacheName
- * @param pattern
- * @return an empty map
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern )
- throws IOException
- {
- return getMatching( cacheName, pattern, 0 );
- }
-
- /**
- * @param cacheName
- * @param pattern
- * @param requesterId
- * @return Map
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern, long requesterId )
- throws IOException
- {
- lastGetMatchingPattern = pattern;
- return new HashMap<>();
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/SystemPropertyUsageUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/SystemPropertyUsageUnitTest.java
deleted file mode 100644
index 3753ea6..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/SystemPropertyUsageUnitTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-import org.apache.commons.jcs.utils.props.PropertyLoader;
-
-import java.util.Properties;
-
-/**
- * Verify that system properties can override.
- */
-public class SystemPropertyUsageUnitTest
- extends TestCase
-{
- private static final String JCS_DEFAULT_CACHEATTRIBUTES_MAX_OBJECTS = "jcs.default.cacheattributes.MaxObjects";
- private static final int testValue = 6789;
-
- private CompositeCacheManager manager = null;
-
- @Override
- protected void setUp() throws Exception
- {
- super.setUp();
- //First shut down any previously running manager.
- manager = CompositeCacheManager.getInstance();
- manager.shutDown();
- }
-
- /**
- * @see junit.framework.TestCase#tearDown()
- */
- @Override
- protected void tearDown() throws Exception
- {
- if (manager != null)
- {
- manager.shutDown();
- }
-
- System.clearProperty(JCS_DEFAULT_CACHEATTRIBUTES_MAX_OBJECTS);
- super.tearDown();
- }
-
- /**
- * Verify that the system properties are used.
- * @throws Exception
- *
- */
- public void testSystemPropertyUsage()
- throws Exception
- {
- System.setProperty( JCS_DEFAULT_CACHEATTRIBUTES_MAX_OBJECTS, String.valueOf(testValue) );
-
- JCS.setConfigFilename( "/TestSystemPropertyUsage.ccf" );
-
- CacheAccess<String, String> jcs = JCS.getInstance( "someCacheNotInFile" );
-
- manager = CompositeCacheManager.getInstance();
-
- assertEquals( "System property value is not reflected.", testValue, jcs.getCacheAttributes().getMaxObjects());
- }
-
- /**
- * Verify that the system properties are not used is specified.
- *
- * @throws Exception
- *
- */
- public void testSystemPropertyUsage_inactive()
- throws Exception
- {
- System.setProperty( JCS_DEFAULT_CACHEATTRIBUTES_MAX_OBJECTS, String.valueOf(testValue) );
-
- manager = CompositeCacheManager.getUnconfiguredInstance();
-
- Properties props = PropertyLoader.loadProperties( "TestSystemPropertyUsage.ccf" );
-
- manager.configure( props, false );
-
- CacheAccess<String, String> jcs = JCS.getInstance( "someCacheNotInFile" );
-
- assertEquals( "System property value should not be reflected",
- Integer.parseInt( props.getProperty( JCS_DEFAULT_CACHEATTRIBUTES_MAX_OBJECTS ) ),
- jcs.getCacheAttributes().getMaxObjects());
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/ZombieCacheServiceNonLocalUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/ZombieCacheServiceNonLocalUnitTest.java
deleted file mode 100644
index 1fa5bb6..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/ZombieCacheServiceNonLocalUnitTest.java
+++ /dev/null
@@ -1,125 +0,0 @@
-package org.apache.commons.jcs.engine;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-
-/**
- * Tests for the zombie remote cache service.
- */
-public class ZombieCacheServiceNonLocalUnitTest
- extends TestCase
-{
- /**
- * Verify that an update event gets added and then is sent to the service passed to propagate.
- * <p>
- * @throws Exception
- */
- public void testUpdateThenWalk()
- throws Exception
- {
- // SETUP
- MockCacheServiceNonLocal<String, String> service = new MockCacheServiceNonLocal<>();
-
- ZombieCacheServiceNonLocal<String, String> zombie = new ZombieCacheServiceNonLocal<>( 10 );
-
- String cacheName = "testUpdate";
-
- // DO WORK
- ICacheElement<String, String> element = new CacheElement<>( cacheName, "key", "value" );
- zombie.update( element, 123l );
- zombie.propagateEvents( service );
-
- // VERIFY
- assertEquals( "Updated element is not as expected.", element, service.lastUpdate );
- }
-
- /**
- * Verify that nothing is added if the max is set to 0.
- * <p>
- * @throws Exception
- */
- public void testUpdateThenWalk_zeroSize()
- throws Exception
- {
- // SETUP
- MockCacheServiceNonLocal<String, String> service = new MockCacheServiceNonLocal<>();
-
- ZombieCacheServiceNonLocal<String, String> zombie = new ZombieCacheServiceNonLocal<>( 0 );
-
- String cacheName = "testUpdate";
-
- // DO WORK
- ICacheElement<String, String> element = new CacheElement<>( cacheName, "key", "value" );
- zombie.update( element, 123l );
- zombie.propagateEvents( service );
-
- // VERIFY
- assertNull( "Nothing should have been put to the service.", service.lastUpdate );
- }
-
- /**
- * Verify that a remove event gets added and then is sent to the service passed to propagate.
- * <p>
- * @throws Exception
- */
- public void testRemoveThenWalk()
- throws Exception
- {
- // SETUP
- MockCacheServiceNonLocal<String, String> service = new MockCacheServiceNonLocal<>();
-
- ZombieCacheServiceNonLocal<String, String> zombie = new ZombieCacheServiceNonLocal<>( 10 );
-
- String cacheName = "testRemoveThenWalk";
- String key = "myKey";
-
- // DO WORK
- zombie.remove( cacheName, key, 123l );
- zombie.propagateEvents( service );
-
- // VERIFY
- assertEquals( "Updated element is not as expected.", key, service.lastRemoveKey );
- }
-
- /**
- * Verify that a removeAll event gets added and then is sent to the service passed to propagate.
- * <p>
- * @throws Exception
- */
- public void testRemoveAllThenWalk()
- throws Exception
- {
- // SETUP
- MockCacheServiceNonLocal<String, String> service = new MockCacheServiceNonLocal<>();
-
- ZombieCacheServiceNonLocal<String, String> zombie = new ZombieCacheServiceNonLocal<>( 10 );
-
- String cacheName = "testRemoveThenWalk";
-
- // DO WORK
- zombie.removeAll( cacheName, 123l );
- zombie.propagateEvents( service );
-
- // VERIFY
- assertEquals( "Updated element is not as expected.", cacheName, service.lastRemoveAllCacheName );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/CacheManagerStatsUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/CacheManagerStatsUnitTest.java
deleted file mode 100644
index 9ae693e..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/CacheManagerStatsUnitTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package org.apache.commons.jcs.engine.control;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.engine.stats.behavior.ICacheStats;
-
-/**
- * @author Aaron Smuts
- *
- */
-public class CacheManagerStatsUnitTest
- extends TestCase
-{
-
- /**
- * Just get the stats after putting a couple entries in the cache.
- *
- * @throws Exception
- */
- public void testSimpleGetStats() throws Exception
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testCache1" );
-
- // 1 miss, 1 hit, 1 put
- cache.get( "testKey" );
- cache.put( "testKey", "testdata" );
- // should have 4 hits
- cache.get( "testKey" );
- cache.get( "testKey" );
- cache.get( "testKey" );
- cache.get( "testKey" );
-
- CompositeCacheManager mgr = CompositeCacheManager.getInstance();
- String statsString = mgr.getStats();
-
-// System.out.println( statsString );
-
- assertTrue( "Should have the cacheName in here.", statsString.indexOf("testCache1") != -1 );
- assertTrue( "Should have the HitCountRam in here.", statsString.indexOf("HitCountRam") != -1 );
- assertTrue( "Should have the 4 in here.", statsString.indexOf("4") != -1 );
-
- ICacheStats[] stats = mgr.getStatistics();
- int statsLen = stats.length;
-// System.out.println( "statsLen = " + statsLen );
- for ( int i = 0; i < statsLen; i++ )
- {
- // TODO finish
- }
- }
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/CompositeCacheConfiguratorUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/CompositeCacheConfiguratorUnitTest.java
deleted file mode 100644
index c05d574..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/CompositeCacheConfiguratorUnitTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package org.apache.commons.jcs.engine.control;
-
-/*
- * 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.
- */
-
-import java.util.Properties;
-
-import junit.framework.TestCase;
-
-import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheConfigurator;
-import org.apache.commons.jcs.auxiliary.MockAuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.MockAuxiliaryCacheAttributes;
-import org.apache.commons.jcs.auxiliary.MockAuxiliaryCacheFactory;
-import org.apache.commons.jcs.engine.logging.MockCacheEventLogger;
-
-/** Unit tests for the configurator. */
-public class CompositeCacheConfiguratorUnitTest
- extends TestCase
-{
- /**
- * Verify that we can parse the event logger correctly
- */
- public void testParseAuxiliary_CacheEventLogger_Normal()
- {
- // SETUP
- String regionName = "MyRegion";
-
- String auxName = "MockAux";
- String auxPrefix = CompositeCacheConfigurator.AUXILIARY_PREFIX + auxName;
- String auxiliaryClassName = MockAuxiliaryCacheFactory.class.getName();
- String eventLoggerClassName = MockCacheEventLogger.class.getName();
- String auxiliaryAttributeClassName = MockAuxiliaryCacheAttributes.class.getName();
-
- Properties props = new Properties();
- props.put( auxPrefix, auxiliaryClassName );
- props.put( auxPrefix + CompositeCacheConfigurator.ATTRIBUTE_PREFIX, auxiliaryAttributeClassName );
- props.put( auxPrefix + AuxiliaryCacheConfigurator.CACHE_EVENT_LOGGER_PREFIX, eventLoggerClassName );
-
-// System.out.print( props );
-
- CompositeCacheManager manager = CompositeCacheManager.getUnconfiguredInstance();
- CompositeCacheConfigurator configurator = new CompositeCacheConfigurator();
-
- // DO WORK
- AuxiliaryCache<String, String> aux = configurator.parseAuxiliary( props, manager, auxName, regionName );
- MockAuxiliaryCache<String, String> result = (MockAuxiliaryCache<String, String>)aux;
-
- // VERIFY
- assertNotNull( "Should have an auxcache.", result );
- assertNotNull( "Should have an event logger.", result.getCacheEventLogger() );
- }
-
- /**
- * Verify that we can parse the spool chunk size
- */
- public void testParseSpoolChunkSize_Normal()
- {
- // SETUP
- String regionName = "MyRegion";
- int chunkSize = 5;
-
- Properties props = new Properties();
- props.put( "jcs.default", "" );
- props.put( "jcs.default.cacheattributes.SpoolChunkSize", String.valueOf( chunkSize ) );
-
- CompositeCacheManager manager = CompositeCacheManager.getUnconfiguredInstance();
-
- // DO WORK
- manager.configure( props );
-
- // VERIFY
- CompositeCache<String, String> cache = manager.getCache( regionName );
- assertEquals( "Wrong chunkSize", cache.getCacheAttributes().getSpoolChunkSize(), chunkSize );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/CompositeCacheDiskUsageUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/CompositeCacheDiskUsageUnitTest.java
deleted file mode 100644
index c965166..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/CompositeCacheDiskUsageUnitTest.java
+++ /dev/null
@@ -1,510 +0,0 @@
-package org.apache.commons.jcs.engine.control;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import junit.framework.TestCase;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.CompositeCacheAttributes;
-import org.apache.commons.jcs.engine.ElementAttributes;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheType.CacheType;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-
-/**
- * Tests of the disk usage settings for the CompositeCache.
- * <p>
- * @author Aaron Smuts
- */
-public class CompositeCacheDiskUsageUnitTest
- extends TestCase
-{
- private static final String CACHE_NAME = "testSpoolAllowed";
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestDiskCacheUsagePattern.ccf" );
- }
-
- /**
- * Verify that the swap region is set to the correct pattern.
- * <p>
- * @throws CacheException
- */
- public void testSwapConfig()
- throws CacheException
- {
- CacheAccess<String, String> swap = JCS.getInstance( "Swap" );
- assertEquals( ICompositeCacheAttributes.DiskUsagePattern.SWAP, swap.getCacheAttributes()
- .getDiskUsagePattern() );
- }
-
- /**
- * Verify that the swap region is set to the correct pattern.
- * <p>
- * @throws CacheException
- */
- public void testUpdateConfig()
- throws CacheException
- {
- CacheAccess<String, String> swap = JCS.getInstance( "Update" );
- assertEquals( ICompositeCacheAttributes.DiskUsagePattern.UPDATE, swap.getCacheAttributes()
- .getDiskUsagePattern() );
- }
-
- /**
- * Setup a disk cache. Configure the disk usage pattern to swap. Call spool. Verify that the
- * item is put to disk.
- */
- public void testSpoolAllowed()
- {
- // SETUP
- ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
- cattr.setCacheName(CACHE_NAME);
- cattr.setDiskUsagePattern( ICompositeCacheAttributes.DiskUsagePattern.SWAP );
-
- IElementAttributes attr = new ElementAttributes();
-
- CompositeCache<String, String> cache = new CompositeCache<>( cattr, attr );
-
- MockAuxCache<String, String> mock = new MockAuxCache<>();
- mock.cacheType = CacheType.DISK_CACHE;
-
- @SuppressWarnings("unchecked")
- AuxiliaryCache<String, String>[] auxArray = new AuxiliaryCache[] { mock };
- cache.setAuxCaches( auxArray );
-
- ICacheElement<String, String> inputElement = new CacheElement<>( CACHE_NAME, "key", "value" );
-
- // DO WORK
- cache.spoolToDisk( inputElement );
-
- // VERIFY
- assertEquals( "Wrong number of calls to the disk cache update.", 1, mock.updateCount );
- assertEquals( "Wrong element updated.", inputElement, mock.lastUpdatedItem );
- }
-
- /**
- * Setup a disk cache. Configure the disk usage pattern to not swap. Call spool. Verify that the
- * item is not put to disk.
- */
- public void testSpoolNotAllowed()
- {
- // SETUP
- ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
- cattr.setCacheName(CACHE_NAME);
- cattr.setDiskUsagePattern( ICompositeCacheAttributes.DiskUsagePattern.UPDATE );
-
- IElementAttributes attr = new ElementAttributes();
-
- CompositeCache<String, String> cache = new CompositeCache<>( cattr, attr );
-
- MockAuxCache<String, String> mock = new MockAuxCache<>();
- mock.cacheType = CacheType.DISK_CACHE;
-
- @SuppressWarnings("unchecked")
- AuxiliaryCache<String, String>[] auxArray = new AuxiliaryCache[] { mock };
- cache.setAuxCaches( auxArray );
-
- ICacheElement<String, String> inputElement = new CacheElement<>( CACHE_NAME, "key", "value" );
-
- // DO WORK
- cache.spoolToDisk( inputElement );
-
- // VERIFY
- assertEquals( "Wrong number of calls to the disk cache update.", 0, mock.updateCount );
- }
-
- /**
- * Setup a disk cache. Configure the disk usage pattern to UPDATE. Call updateAuxiliaries.
- * Verify that the item is put to disk.
- * <p>
- * This tests that the items are put to disk on a normal put when the usage pattern is set
- * appropriately.
- * @throws IOException
- */
- public void testUpdateAllowed()
- throws IOException
- {
- // SETUP
- ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
- cattr.setCacheName(CACHE_NAME);
- cattr.setDiskUsagePattern( ICompositeCacheAttributes.DiskUsagePattern.UPDATE );
-
- IElementAttributes attr = new ElementAttributes();
-
- CompositeCache<String, String> cache = new CompositeCache<>( cattr, attr );
-
- MockAuxCache<String, String> mock = new MockAuxCache<>();
- mock.cacheType = CacheType.DISK_CACHE;
-
- @SuppressWarnings("unchecked")
- AuxiliaryCache<String, String>[] auxArray = new AuxiliaryCache[] { mock };
- cache.setAuxCaches( auxArray );
-
- ICacheElement<String, String> inputElement = new CacheElement<>( CACHE_NAME, "key", "value" );
-
- // DO WORK
- cache.updateAuxiliaries( inputElement, true );
-
- // VERIFY
- assertEquals( "Wrong number of calls to the disk cache update.", 1, mock.updateCount );
- assertEquals( "Wrong element updated.", inputElement, mock.lastUpdatedItem );
- }
-
- /**
- * Setup a disk cache. Configure the disk usage pattern to UPDATE. Call updateAuxiliaries with
- * local only set to false. Verify that the item is put to disk.
- * <p>
- * This tests that the items are put to disk on a normal put when the usage pattern is set
- * appropriately. The local setting should have no impact on whether the item goes to disk.
- * <p>
- * @throws IOException
- */
- public void testUpdateAllowed_localFalse()
- throws IOException
- {
- // SETUP
- ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
- cattr.setCacheName(CACHE_NAME);
- cattr.setDiskUsagePattern( ICompositeCacheAttributes.DiskUsagePattern.UPDATE );
-
- IElementAttributes attr = new ElementAttributes();
-
- CompositeCache<String, String> cache = new CompositeCache<>( cattr, attr );
-
- MockAuxCache<String, String> mock = new MockAuxCache<>();
- mock.cacheType = CacheType.DISK_CACHE;
-
- @SuppressWarnings("unchecked")
- AuxiliaryCache<String, String>[] auxArray = new AuxiliaryCache[] { mock };
- cache.setAuxCaches( auxArray );
-
- ICacheElement<String, String> inputElement = new CacheElement<>( CACHE_NAME, "key", "value" );
-
- // DO WORK
- cache.updateAuxiliaries( inputElement, false );
-
- // VERIFY
- assertEquals( "Wrong number of calls to the disk cache update.", 1, mock.updateCount );
- assertEquals( "Wrong element updated.", inputElement, mock.lastUpdatedItem );
- }
-
- /**
- * Setup a disk cache. Configure the disk usage pattern to SWAP. Call updateAuxiliaries. Verify
- * that the item is not put to disk.
- * <p>
- * This tests that the items are not put to disk on a normal put when the usage pattern is set
- * to SWAP.
- * <p>
- * @throws IOException
- */
- public void testUpdateNotAllowed()
- throws IOException
- {
- // SETUP
- ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
- cattr.setCacheName(CACHE_NAME);
- cattr.setDiskUsagePattern( ICompositeCacheAttributes.DiskUsagePattern.SWAP );
-
- IElementAttributes attr = new ElementAttributes();
-
- CompositeCache<String, String> cache = new CompositeCache<>( cattr, attr );
-
- MockAuxCache<String, String> mock = new MockAuxCache<>();
- mock.cacheType = CacheType.DISK_CACHE;
-
- @SuppressWarnings("unchecked")
- AuxiliaryCache<String, String>[] auxArray = new AuxiliaryCache[] { mock };
- cache.setAuxCaches( auxArray );
-
- ICacheElement<String, String> inputElement = new CacheElement<>( CACHE_NAME, "key", "value" );
-
- // DO WORK
- cache.updateAuxiliaries( inputElement, true );
-
- // VERIFY
- assertEquals( "Wrong number of calls to the disk cache update.", 0, mock.updateCount );
- }
-
- /**
- * Setup a disk cache. Configure the disk usage pattern to UPDATE. Call updateAuxiliaries.
- * Verify that the item is put to disk.
- * <p>
- * This tests that the items are put to disk on a normal put when the usage pattern is set
- * appropriately.
- * @throws IOException
- */
- public void testUpdateAllowed_withOtherCaches()
- throws IOException
- {
- // SETUP
- ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
- cattr.setCacheName(CACHE_NAME);
- cattr.setDiskUsagePattern( ICompositeCacheAttributes.DiskUsagePattern.UPDATE );
-
- IElementAttributes attr = new ElementAttributes();
-
- CompositeCache<String, String> cache = new CompositeCache<>( cattr, attr );
-
- MockAuxCache<String, String> mock = new MockAuxCache<>();
- mock.cacheType = CacheType.DISK_CACHE;
-
- MockAuxCache<String, String> mockLateral = new MockAuxCache<>();
- mockLateral.cacheType = CacheType.LATERAL_CACHE;
-
- @SuppressWarnings("unchecked")
- AuxiliaryCache<String, String>[] auxArray = new AuxiliaryCache[] { mock, mockLateral };
- cache.setAuxCaches( auxArray );
-
- ICacheElement<String, String> inputElement = new CacheElement<>( CACHE_NAME, "key", "value" );
-
- // DO WORK
- cache.updateAuxiliaries( inputElement, false );
-
- // VERIFY
- assertEquals( "Wrong number of calls to the disk cache update.", 1, mock.updateCount );
- assertEquals( "Wrong element updated.", inputElement, mock.lastUpdatedItem );
-
- assertEquals( "Wrong number of calls to the lateral cache update.", 1, mockLateral.updateCount );
- assertEquals( "Wrong element updated with lateral.", inputElement, mockLateral.lastUpdatedItem );
- }
-
- /**
- * Used to test the disk cache functionality.
- * <p>
- * @author Aaron Smuts
- */
- public static class MockAuxCache<K, V>
- extends AbstractAuxiliaryCache<K, V>
- {
- /** The last item passed to update. */
- public ICacheElement<K, V> lastUpdatedItem;
-
- /** The number of times update was called. */
- public int updateCount = 0;
-
- /** The type that should be returned from getCacheType. */
- public CacheType cacheType = CacheType.DISK_CACHE;
-
- /** Resets counters and catchers. */
- public void reset()
- {
- updateCount = 0;
- lastUpdatedItem = null;
- }
-
- /**
- * @param ce
- * @throws IOException
- */
- @Override
- public void update( ICacheElement<K, V> ce )
- throws IOException
- {
- lastUpdatedItem = ce;
- updateCount++;
- }
-
- /**
- * @param key
- * @return ICacheElement
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> get( K key )
- throws IOException
- {
- return null;
- }
-
- /**
- * Gets multiple items from the cache based on the given set of keys.
- * <p>
- * @param keys
- * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is
- * no data in cache for any of these keys
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
- {
- return new HashMap<>();
- }
-
- /**
- * @param key
- * @return false
- * @throws IOException
- */
- @Override
- public boolean remove( K key )
- throws IOException
- {
- return false;
- }
-
- /** @throws IOException */
- @Override
- public void removeAll()
- throws IOException
- {
- // noop
- }
-
- /** @throws IOException */
- @Override
- public void dispose()
- throws IOException
- {
- // noop
- }
-
- /** @return 0 */
- @Override
- public int getSize()
- {
- return 0;
- }
-
- /** @return 0 */
- @Override
- public CacheStatus getStatus()
- {
- return CacheStatus.ALIVE;
- }
-
- /** @return null */
- @Override
- public String getCacheName()
- {
- return null;
- }
-
- /**
- * @return null
- * @throws IOException
- */
- @Override
- public Set<K> getKeySet( )
- throws IOException
- {
- return null;
- }
-
- /** @return null */
- @Override
- public IStats getStatistics()
- {
- return null;
- }
-
- /** @return null */
- @Override
- public String getStats()
- {
- return null;
- }
-
- /**
- * Returns the setup cache type. This allows you to use this mock as multiple cache types.
- * <p>
- * @see org.apache.commons.jcs.engine.behavior.ICacheType#getCacheType()
- * @return cacheType
- */
- @Override
- public CacheType getCacheType()
- {
- return cacheType;
- }
-
- /**
- * @return Returns the AuxiliaryCacheAttributes.
- */
- @Override
- public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
- {
- return null;
- }
-
- /**
- * @param cacheEventLogger
- */
- @Override
- public void setCacheEventLogger( ICacheEventLogger cacheEventLogger )
- {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * @param elementSerializer
- */
- @Override
- public void setElementSerializer( IElementSerializer elementSerializer )
- {
- // TODO Auto-generated method stub
-
- }
-
- /** @return null */
- @Override
- public String getEventLoggingExtraInfo()
- {
- // TODO Auto-generated method stub
- return null;
- }
-
- /**
- * @param pattern
- * @return Collections.EMPTY_MAP;
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMatching(String pattern)
- throws IOException
- {
- return Collections.emptyMap();
- }
-
-
- }
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/CompositeCacheManagerTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/CompositeCacheManagerTest.java
deleted file mode 100644
index 207062c..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/CompositeCacheManagerTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package org.apache.commons.jcs.engine.control;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.CompositeCacheAttributes;
-
-/** Unit tests for the composite cache manager */
-public class CompositeCacheManagerTest
- extends TestCase
-{
-
- /**
- * Verify that calling release, when there are active clients, the caches are correctly disposed or not.
- */
- public void testRelease()
- {
- // See JCS-184
- // create the manager
- CompositeCacheManager manager = CompositeCacheManager.getInstance();
- // add a simple cache
- CompositeCacheAttributes cacheAttributes = new CompositeCacheAttributes();
- CompositeCache<String, String> cache = new CompositeCache<>(cacheAttributes, /* attr */ null);
- manager.addCache("simple_cache", cache);
- // add a client to the cache
- CompositeCacheManager.getUnconfiguredInstance();
- // won't release as there are still clients. Only disposed when release() is called by
- // the last client
- manager.release();
- assertEquals("The cache was disposed during release!", CacheStatus.ALIVE, cache.getStatus());
- manager.release();
- assertEquals("The cache was NOT disposed during release!", CacheStatus.DISPOSED, cache.getStatus());
- }
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/CompositeCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/CompositeCacheUnitTest.java
deleted file mode 100644
index a7b0d3b..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/CompositeCacheUnitTest.java
+++ /dev/null
@@ -1,245 +0,0 @@
-package org.apache.commons.jcs.engine.control;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
-import org.apache.commons.jcs.auxiliary.MockAuxiliaryCache;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.CompositeCacheAttributes;
-import org.apache.commons.jcs.engine.ElementAttributes;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheType.CacheType;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.memory.MockMemoryCache;
-
-import java.io.IOException;
-import java.util.Map;
-
-/**
- * Tests that directly engage the composite cache.
- * <p>
- * @author Aaron Smuts
- */
-public class CompositeCacheUnitTest
- extends TestCase
-{
- /**
- * Verify that the freeMemoryElements method on the memory cache is called on shutdown if there
- * is a disk cache.
- * <p>
- * @throws IOException
- */
- public void testShutdownMemoryFlush()
- throws IOException
- {
- // SETUP
- String cacheName = "testCacheName";
- String mockMemoryCacheClassName = "org.apache.commons.jcs.engine.memory.MockMemoryCache";
- ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
- cattr.setMemoryCacheName( mockMemoryCacheClassName );
-
- IElementAttributes attr = new ElementAttributes();
-
- CompositeCache<String, Integer> cache = new CompositeCache<>( cattr, attr );
-
- MockAuxiliaryCache<String, Integer> diskMock = new MockAuxiliaryCache<>();
- diskMock.cacheType = CacheType.DISK_CACHE;
- @SuppressWarnings("unchecked")
- AuxiliaryCache<String, Integer>[] aux = new AuxiliaryCache[] { diskMock };
- cache.setAuxCaches( aux );
-
- // DO WORK
- int numToInsert = 10;
- for ( int i = 0; i < numToInsert; i++ )
- {
- ICacheElement<String, Integer> element = new CacheElement<>( cacheName, String.valueOf( i ), Integer.valueOf( i ) );
- cache.update( element, false );
- }
-
- cache.dispose();
-
- // VERIFY
- MockMemoryCache<String, Integer> memoryCache = (MockMemoryCache<String, Integer>) cache.getMemoryCache();
- assertEquals( "Wrong number freed.", numToInsert, memoryCache.lastNumberOfFreedElements );
- }
-
- /**
- * Verify that the freeMemoryElements method on the memory cache is NOT called on shutdown if
- * there is NOT a disk cache.
- * <p>
- * @throws IOException
- */
- public void testShutdownMemoryFlush_noDisk()
- throws IOException
- {
- // SETUP
- String cacheName = "testCacheName";
- String mockMemoryCacheClassName = "org.apache.commons.jcs.engine.memory.MockMemoryCache";
- ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
- cattr.setMemoryCacheName( mockMemoryCacheClassName );
-
- IElementAttributes attr = new ElementAttributes();
-
- CompositeCache<String, Integer> cache = new CompositeCache<>( cattr, attr );
-
- MockAuxiliaryCache<String, Integer> diskMock = new MockAuxiliaryCache<>();
- diskMock.cacheType = CacheType.REMOTE_CACHE;
- @SuppressWarnings("unchecked")
- AuxiliaryCache<String, Integer>[] aux = new AuxiliaryCache[] { diskMock };
- cache.setAuxCaches( aux );
-
- // DO WORK
- int numToInsert = 10;
- for ( int i = 0; i < numToInsert; i++ )
- {
- ICacheElement<String, Integer> element = new CacheElement<>( cacheName, String.valueOf( i ), Integer.valueOf( i ) );
- cache.update( element, false );
- }
-
- cache.dispose();
-
- // VERIFY
- MockMemoryCache<String, Integer> memoryCache = (MockMemoryCache<String, Integer>) cache.getMemoryCache();
- assertEquals( "Wrong number freed.", 0, memoryCache.lastNumberOfFreedElements );
- }
-
- /**
- * Verify we can get some matching elements..
- * <p>
- * @throws IOException
- */
- public void testGetMatching_Normal()
- throws IOException
- {
- // SETUP
- int maxMemorySize = 1000;
- String keyprefix1 = "MyPrefix1";
- String keyprefix2 = "MyPrefix2";
- String cacheName = "testGetMatching_Normal";
- String memoryCacheClassName = "org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache";
- ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
- cattr.setMemoryCacheName( memoryCacheClassName );
- cattr.setMaxObjects( maxMemorySize );
-
- IElementAttributes attr = new ElementAttributes();
-
- CompositeCache<String, Integer> cache = new CompositeCache<>( cattr, attr );
-
- MockAuxiliaryCache<String, Integer> diskMock = new MockAuxiliaryCache<>();
- diskMock.cacheType = CacheType.DISK_CACHE;
- @SuppressWarnings("unchecked")
- AuxiliaryCache<String, Integer>[] aux = new AuxiliaryCache[] { diskMock };
- cache.setAuxCaches( aux );
-
- // DO WORK
- int numToInsertPrefix1 = 10;
- // insert with prefix1
- for ( int i = 0; i < numToInsertPrefix1; i++ )
- {
- ICacheElement<String, Integer> element = new CacheElement<>( cacheName, keyprefix1 + String.valueOf( i ), Integer.valueOf( i ) );
- cache.update( element, false );
- }
-
- int numToInsertPrefix2 = 50;
- // insert with prefix1
- for ( int i = 0; i < numToInsertPrefix2; i++ )
- {
- ICacheElement<String, Integer> element = new CacheElement<>( cacheName, keyprefix2 + String.valueOf( i ), Integer.valueOf( i ) );
- cache.update( element, false );
- }
-
- Map<?, ?> result1 = cache.getMatching( keyprefix1 + "\\S+" );
- Map<?, ?> result2 = cache.getMatching( keyprefix2 + "\\S+" );
-
- // VERIFY
- assertEquals( "Wrong number returned 1:", numToInsertPrefix1, result1.size() );
- assertEquals( "Wrong number returned 2:", numToInsertPrefix2, result2.size() );
- }
-
- /**
- * Verify we try a disk aux on a getMatching call.
- * <p>
- * @throws IOException
- */
- public void testGetMatching_NotOnDisk()
- throws IOException
- {
- // SETUP
- int maxMemorySize = 0;
- String cacheName = "testGetMatching_NotOnDisk";
- String memoryCacheClassName = "org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache";
- ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMemoryCacheName( memoryCacheClassName );
- cattr.setMaxObjects( maxMemorySize );
-
- IElementAttributes attr = new ElementAttributes();
-
- CompositeCache<String, Integer> cache = new CompositeCache<>( cattr, attr );
-
- MockAuxiliaryCache<String, Integer> diskMock = new MockAuxiliaryCache<>();
- diskMock.cacheType = CacheType.DISK_CACHE;
- @SuppressWarnings("unchecked")
- AuxiliaryCache<String, Integer>[] aux = new AuxiliaryCache[] { diskMock };
- cache.setAuxCaches( aux );
-
- // DO WORK
- cache.getMatching( "junk" );
-
- // VERIFY
- assertEquals( "Wrong number of calls", 1, diskMock.getMatchingCallCount );
- }
-
- /**
- * Verify we try a remote aux on a getMatching call.
- * <p>
- * @throws IOException
- */
- public void testGetMatching_NotOnRemote()
- throws IOException
- {
- // SETUP
- int maxMemorySize = 0;
- String cacheName = "testGetMatching_NotOnDisk";
- String memoryCacheClassName = "org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache";
- ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
- cattr.setCacheName(cacheName);
- cattr.setMemoryCacheName( memoryCacheClassName );
- cattr.setMaxObjects( maxMemorySize );
-
- IElementAttributes attr = new ElementAttributes();
-
- CompositeCache<String, Integer> cache = new CompositeCache<>( cattr, attr );
-
- MockAuxiliaryCache<String, Integer> diskMock = new MockAuxiliaryCache<>();
- diskMock.cacheType = CacheType.REMOTE_CACHE;
- @SuppressWarnings("unchecked")
- AuxiliaryCache<String, Integer>[] aux = new AuxiliaryCache[] { diskMock };
- cache.setAuxCaches( aux );
-
- // DO WORK
- cache.getMatching( "junk" );
-
- // VERIFY
- assertEquals( "Wrong number of calls", 1, diskMock.getMatchingCallCount );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/MockCompositeCacheManager.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/MockCompositeCacheManager.java
deleted file mode 100644
index 1099919..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/MockCompositeCacheManager.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package org.apache.commons.jcs.engine.control;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
-import org.apache.commons.jcs.engine.CompositeCacheAttributes;
-import org.apache.commons.jcs.engine.ElementAttributes;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
-import org.apache.commons.jcs.engine.behavior.IShutdownObserver;
-
-import java.util.Properties;
-
-/** For testing. */
-public class MockCompositeCacheManager
- implements ICompositeCacheManager
-{
- /** The cache that was returned. */
- private CompositeCache<?, ?> cache;
-
- /** Properties with which this manager was configured. This is exposed for other managers. */
- private Properties configurationProperties;
-
- /**
- * @param cacheName
- * @return Returns a CompositeCache
- */
- @Override
- @SuppressWarnings("unchecked")
- public <K, V> CompositeCache<K, V> getCache( String cacheName )
- {
- if ( cache == null )
- {
-// System.out.println( "Creating mock cache" );
- CompositeCache<K, V> newCache =
- new CompositeCache<>( new CompositeCacheAttributes(), new ElementAttributes() );
- this.setCache( newCache );
- }
-
- return (CompositeCache<K, V>)cache;
- }
-
- @Override
- public <K, V> AuxiliaryCache<K, V> getAuxiliaryCache(String auxName, String cacheName)
- {
- return null;
- }
-
- /**
- * @param cache The cache to set.
- */
- public void setCache( CompositeCache<?, ?> cache )
- {
- this.cache = cache;
- }
-
- /**
- * @return Returns the cache.
- */
- public CompositeCache<?, ?> getCache()
- {
- return cache;
- }
-
- /**
- * This is exposed so other manager can get access to the props.
- * <p>
- * @param props
- */
- public void setConfigurationProperties( Properties props )
- {
- this.configurationProperties = props;
- }
-
- /**
- * This is exposed so other manager can get access to the props.
- * <p>
- * @return the configurationProperties
- */
- @Override
- public Properties getConfigurationProperties()
- {
- return configurationProperties;
- }
-
- /** @return Mock */
- @Override
- public String getStats()
- {
- return "Mock";
- }
-
- /**
- * @see org.apache.commons.jcs.engine.behavior.IShutdownObservable#registerShutdownObserver(org.apache.commons.jcs.engine.behavior.IShutdownObserver)
- */
- @Override
- public void registerShutdownObserver(IShutdownObserver observer)
- {
- // Do nothing
- }
-
- /**
- * @see org.apache.commons.jcs.engine.behavior.IShutdownObservable#deregisterShutdownObserver(org.apache.commons.jcs.engine.behavior.IShutdownObserver)
- */
- @Override
- public void deregisterShutdownObserver(IShutdownObserver observer)
- {
- // Do nothing
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/MockElementSerializer.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/MockElementSerializer.java
deleted file mode 100644
index 49885db..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/MockElementSerializer.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package org.apache.commons.jcs.engine.control;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.utils.serialization.StandardSerializer;
-
-import java.io.IOException;
-
-/** For mocking. */
-public class MockElementSerializer
- implements IElementSerializer
-{
- /** test property */
- private String testProperty;
-
- /** What's used in the background */
- private final StandardSerializer serializer = new StandardSerializer();
-
- /** times out was called */
- public int deSerializeCount = 0;
-
- /** times in was called */
- public int serializeCount = 0;
-
- /**
- * @param bytes
- * @return Object
- * @throws IOException
- * @throws ClassNotFoundException
- *
- */
- @Override
- public <T> T deSerialize( byte[] bytes, ClassLoader loader )
- throws IOException, ClassNotFoundException
- {
- deSerializeCount++;
- return serializer.deSerialize( bytes, loader );
- }
-
- /**
- * @param obj
- * @return byte[]
- * @throws IOException
- *
- */
- @Override
- public <T> byte[] serialize( T obj )
- throws IOException
- {
- serializeCount++;
- return serializer.serialize( obj );
- }
-
- /**
- * @param testProperty
- */
- public void setTestProperty( String testProperty )
- {
- this.testProperty = testProperty;
- }
-
- /**
- * @return testProperty
- */
- public String getTestProperty()
- {
- return testProperty;
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/event/ElementEventHandlerMockImpl.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/event/ElementEventHandlerMockImpl.java
deleted file mode 100644
index 8b56d66..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/event/ElementEventHandlerMockImpl.java
+++ /dev/null
@@ -1,186 +0,0 @@
-package org.apache.commons.jcs.engine.control.event;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.control.event.behavior.ElementEventType;
-import org.apache.commons.jcs.engine.control.event.behavior.IElementEvent;
-import org.apache.commons.jcs.engine.control.event.behavior.IElementEventHandler;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * @author aaronsm
- */
-public class ElementEventHandlerMockImpl
- implements IElementEventHandler
-{
- /** Times called. */
- private int callCount = 0;
-
- /** The logger */
- private static final Log log = LogManager.getLog( ElementEventHandlerMockImpl.class );
-
- /** ELEMENT_EVENT_SPOOLED_DISK_AVAILABLE */
- private int spoolCount = 0;
-
- /** ELEMENT_EVENT_SPOOLED_NOT_ALLOWED */
- private int spoolNotAllowedCount = 0;
-
- /** ELEMENT_EVENT_SPOOLED_DISK_NOT_AVAILABLE */
- private int spoolNoDiskCount = 0;
-
- /** ELEMENT_EVENT_EXCEEDED_MAXLIFE_BACKGROUND */
- private int exceededMaxLifeBackgroundCount = 0;
-
- /** ELEMENT_EVENT_EXCEEDED_IDLETIME_BACKGROUND */
- private int exceededIdleTimeBackgroundCount = 0;
-
- /**
- * @param event
- */
- @Override
- public synchronized <T> void handleElementEvent( IElementEvent<T> event )
- {
- setCallCount( getCallCount() + 1 );
-
- if ( log.isDebugEnabled() )
- {
- log.debug( "HANDLER -- HANDLER -- HANDLER -- ---EVENT CODE = " + event.getElementEvent() );
- log.debug( "/n/n EVENT CODE = " + event.getElementEvent() + " ***************************" );
- }
-
- if ( event.getElementEvent() == ElementEventType.SPOOLED_DISK_AVAILABLE )
- {
- setSpoolCount( getSpoolCount() + 1 );
- }
- else if ( event.getElementEvent() == ElementEventType.SPOOLED_NOT_ALLOWED )
- {
- setSpoolNotAllowedCount( getSpoolNotAllowedCount() + 1 );
- }
- else if ( event.getElementEvent() == ElementEventType.SPOOLED_DISK_NOT_AVAILABLE )
- {
- setSpoolNoDiskCount( getSpoolNoDiskCount() + 1 );
- }
- else if ( event.getElementEvent() == ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND )
- {
- setExceededMaxLifeBackgroundCount( getExceededMaxLifeBackgroundCount() + 1 );
- }
- else if ( event.getElementEvent() == ElementEventType.EXCEEDED_IDLETIME_BACKGROUND )
- {
- setExceededIdleTimeBackgroundCount( getExceededIdleTimeBackgroundCount() + 1 );
- }
- }
-
- /**
- * @param spoolCount The spoolCount to set.
- */
- public void setSpoolCount( int spoolCount )
- {
- this.spoolCount = spoolCount;
- }
-
- /**
- * @return Returns the spoolCount.
- */
- public int getSpoolCount()
- {
- return spoolCount;
- }
-
- /**
- * @param spoolNotAllowedCount The spoolNotAllowedCount to set.
- */
- public void setSpoolNotAllowedCount( int spoolNotAllowedCount )
- {
- this.spoolNotAllowedCount = spoolNotAllowedCount;
- }
-
- /**
- * @return Returns the spoolNotAllowedCount.
- */
- public int getSpoolNotAllowedCount()
- {
- return spoolNotAllowedCount;
- }
-
- /**
- * @param spoolNoDiskCount The spoolNoDiskCount to set.
- */
- public void setSpoolNoDiskCount( int spoolNoDiskCount )
- {
- this.spoolNoDiskCount = spoolNoDiskCount;
- }
-
- /**
- * @return Returns the spoolNoDiskCount.
- */
- public int getSpoolNoDiskCount()
- {
- return spoolNoDiskCount;
- }
-
- /**
- * @param exceededMaxLifeBackground The exceededMaxLifeBackground to set.
- */
- public void setExceededMaxLifeBackgroundCount( int exceededMaxLifeBackground )
- {
- this.exceededMaxLifeBackgroundCount = exceededMaxLifeBackground;
- }
-
- /**
- * @return Returns the exceededMaxLifeBackground.
- */
- public int getExceededMaxLifeBackgroundCount()
- {
- return exceededMaxLifeBackgroundCount;
- }
-
- /**
- * @param callCount The callCount to set.
- */
- public void setCallCount( int callCount )
- {
- this.callCount = callCount;
- }
-
- /**
- * @return Returns the callCount.
- */
- public int getCallCount()
- {
- return callCount;
- }
-
- /**
- * @param exceededIdleTimeBackground The exceededIdleTimeBackground to set.
- */
- public void setExceededIdleTimeBackgroundCount( int exceededIdleTimeBackground )
- {
- this.exceededIdleTimeBackgroundCount = exceededIdleTimeBackground;
- }
-
- /**
- * @return Returns the exceededIdleTimeBackground.
- */
- public int getExceededIdleTimeBackgroundCount()
- {
- return exceededIdleTimeBackgroundCount;
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/event/SimpleEventHandlingUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/event/SimpleEventHandlingUnitTest.java
deleted file mode 100644
index b4ff401..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/control/event/SimpleEventHandlingUnitTest.java
+++ /dev/null
@@ -1,380 +0,0 @@
-package org.apache.commons.jcs.engine.control.event;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.engine.ElementAttributes;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.control.event.behavior.IElementEvent;
-import org.apache.commons.jcs.engine.control.event.behavior.IElementEventHandler;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/**
- * This test suite verifies that the basic ElementEvent are called as they should be.
- */
-public class SimpleEventHandlingUnitTest
- extends TestCase
-{
- /** Items to test with */
- private static int items = 20000;
-
- /**
- * Test setup with expected configuration parameters.
- */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestSimpleEventHandling.ccf" );
- }
-
- /**
- * Verify that the spooled event is called as expected.
- * <p>
- * @throws Exception Description of the Exception
- */
- public void testSpoolEvent()
- throws Exception
- {
- // SETUP
- MyEventHandler meh = new MyEventHandler();
-
- CacheAccess<String, String> jcs = JCS.getInstance( "WithDisk" );
- // this should add the event handler to all items as they are created.
- IElementAttributes attributes = jcs.getDefaultElementAttributes();
- attributes.addElementEventHandler( meh );
- jcs.setDefaultElementAttributes( attributes );
-
- // DO WORK
- // put them in
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", "data" + i );
- }
-
- // wait a bit for it to finish
- Thread.sleep( items / 20 );
-
- // VERIFY
- // test to see if the count is right
- assertTrue( "The number of ELEMENT_EVENT_SPOOLED_DISK_AVAILABLE events [" + meh.getSpoolCount()
- + "] does not equal the number expected [" + items + "]", meh.getSpoolCount() >= items );
- }
-
- /**
- * Test overflow with no disk configured for the region.
- * <p>
- * @throws Exception
- */
- public void testSpoolNoDiskEvent()
- throws Exception
- {
- CacheAccess<String, String> jcs = JCS.getInstance( "NoDisk" );
-
- MyEventHandler meh = new MyEventHandler();
-
- // this should add the event handler to all items as they are created.
- IElementAttributes attributes = jcs.getDefaultElementAttributes();
- attributes.addElementEventHandler( meh );
- jcs.setDefaultElementAttributes( attributes );
-
- // put them in
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", "data" + i );
- }
-
- // wait a bit for it to finish
- Thread.sleep( items / 20 );
-
- // test to see if the count is right
- assertTrue( "The number of ELEMENT_EVENT_SPOOLED_DISK_NOT_AVAILABLE events [" + meh.getSpoolNoDiskCount()
- + "] does not equal the number expected.", meh.getSpoolNoDiskCount() >= items );
-
- }
-
- /**
- * Test the ELEMENT_EVENT_SPOOLED_NOT_ALLOWED event.
- * @throws Exception
- */
- public void testSpoolNotAllowedEvent()
- throws Exception
- {
- MyEventHandler meh = new MyEventHandler();
-
- CacheAccess<String, String> jcs = JCS.getInstance( "DiskButNotAllowed" );
- // this should add the event handler to all items as they are created.
- IElementAttributes attributes = jcs.getDefaultElementAttributes();
- attributes.addElementEventHandler( meh );
- jcs.setDefaultElementAttributes( attributes );
-
- // put them in
- for ( int i = 0; i <= items; i++ )
- {
- jcs.put( i + ":key", "data" + i );
- }
-
- // wait a bit for it to finish
- Thread.sleep( items / 20 );
-
- // test to see if the count is right
- assertTrue( "The number of ELEMENT_EVENT_SPOOLED_NOT_ALLOWED events [" + meh.getSpoolNotAllowedCount()
- + "] does not equal the number expected.", meh.getSpoolNotAllowedCount() >= items );
-
- }
-
- /**
- * Test the ELEMENT_EVENT_SPOOLED_NOT_ALLOWED event.
- * @throws Exception
- */
- public void testSpoolNotAllowedEventOnItem()
- throws Exception
- {
- MyEventHandler meh = new MyEventHandler();
-
- CacheAccess<String, String> jcs = JCS.getInstance( "DiskButNotAllowed" );
- // this should add the event handler to all items as they are created.
- //IElementAttributes attributes = jcs.getDefaultElementAttributes();
- //attributes.addElementEventHandler( meh );
- //jcs.setDefaultElementAttributes( attributes );
-
- // put them in
- for ( int i = 0; i <= items; i++ )
- {
- IElementAttributes attributes = jcs.getDefaultElementAttributes();
- attributes.addElementEventHandler( meh );
- jcs.put( i + ":key", "data" + i, attributes );
- }
-
- // wait a bit for it to finish
- Thread.sleep( items / 20 );
-
- // test to see if the count is right
- assertTrue( "The number of ELEMENT_EVENT_SPOOLED_NOT_ALLOWED events [" + meh.getSpoolNotAllowedCount()
- + "] does not equal the number expected.", meh.getSpoolNotAllowedCount() >= items );
-
- }
-
- /**
- * Test the ELEMENT_EVENT_EXCEEDED_MAXLIFE_ONREQUEST event.
- * @throws Exception
- */
- public void testExceededMaxlifeOnrequestEvent()
- throws Exception
- {
- MyEventHandler meh = new MyEventHandler();
-
- CacheAccess<String, String> jcs = JCS.getInstance( "Maxlife" );
- // this should add the event handler to all items as they are created.
- IElementAttributes attributes = jcs.getDefaultElementAttributes();
- attributes.addElementEventHandler( meh );
- jcs.setDefaultElementAttributes( attributes );
-
- // put them in
- for ( int i = 0; i < 200; i++ )
- {
- jcs.put( i + ":key", "data" + i);
- }
-
- // wait a bit for the items to expire
- Thread.sleep( 3000 );
-
- for ( int i = 0; i < 200; i++ )
- {
- String value = jcs.get( i + ":key");
- assertNull("Item should be null for key " + i + ":key, but is " + value, value);
- }
-
- // wait a bit for it to finish
- Thread.sleep( 100 );
-
- // test to see if the count is right
- assertTrue( "The number of ELEMENT_EVENT_EXCEEDED_MAXLIFE_ONREQUEST events [" + meh.getExceededMaxlifeCount()
- + "] does not equal the number expected.", meh.getExceededMaxlifeCount() >= 200 );
- }
-
- /**
- * Test the ELEMENT_EVENT_EXCEEDED_IDLETIME_ONREQUEST event.
- * @throws Exception
- */
- public void testExceededIdletimeOnrequestEvent()
- throws Exception
- {
- MyEventHandler meh = new MyEventHandler();
-
- CacheAccess<String, String> jcs = JCS.getInstance( "Idletime" );
- // this should add the event handler to all items as they are created.
- IElementAttributes attributes = jcs.getDefaultElementAttributes();
- attributes.addElementEventHandler( meh );
- jcs.setDefaultElementAttributes( attributes );
-
- // put them in
- for ( int i = 0; i < 200; i++ )
- {
- jcs.put( i + ":key", "data" + i);
- }
-
- // update access time
- for ( int i = 0; i < 200; i++ )
- {
- String value = jcs.get( i + ":key");
- assertNotNull("Item should not be null for key " + i + ":key", value);
- }
-
- // wait a bit for the items to expire
- Thread.sleep( 1500 );
-
- for ( int i = 0; i < 200; i++ )
- {
- String value = jcs.get( i + ":key");
- assertNull("Item should be null for key " + i + ":key, but is " + value, value);
- }
-
- // wait a bit for it to finish
- Thread.sleep( 100 );
-
- // test to see if the count is right
- assertTrue( "The number of ELEMENT_EVENT_EXCEEDED_IDLETIME_ONREQUEST events [" + meh.getExceededIdletimeCount()
- + "] does not equal the number expected.", meh.getExceededIdletimeCount() >= 200 );
- }
-
- /**
- * Test that cloned ElementAttributes have different creation times.
- * @throws Exception
- */
- public void testElementAttributesCreationTime()
- throws Exception
- {
- ElementAttributes elem1 = new ElementAttributes();
- long ctime1 = elem1.getCreateTime();
-
- Thread.sleep(10);
-
- IElementAttributes elem2 = elem1.clone();
- long ctime2 = elem2.getCreateTime();
-
- assertFalse("Creation times should be different", ctime1 == ctime2);
- }
-
- /**
- * Simple event counter used to verify test results.
- */
- public static class MyEventHandler
- implements IElementEventHandler
- {
- /** times spool called */
- private int spoolCount = 0;
-
- /** times spool not allowed */
- private int spoolNotAllowedCount = 0;
-
- /** times spool without disk */
- private int spoolNoDiskCount = 0;
-
- /** times exceeded maxlife */
- private int exceededMaxlifeCount = 0;
-
- /** times exceeded idle time */
- private int exceededIdletimeCount = 0;
-
- /**
- * @param event
- */
- @Override
- public synchronized <T> void handleElementEvent( IElementEvent<T> event )
- {
- //System.out.println( "Handling Event of Type " +
- // event.getElementEvent() );
-
- switch (event.getElementEvent())
- {
- case SPOOLED_DISK_AVAILABLE:
- //System.out.println( "Handling Event of Type
- // ELEMENT_EVENT_SPOOLED_DISK_AVAILABLE, " + getSpoolCount() );
- spoolCount++;
- break;
-
- case SPOOLED_NOT_ALLOWED:
- spoolNotAllowedCount++;
- break;
-
- case SPOOLED_DISK_NOT_AVAILABLE:
- spoolNoDiskCount++;
- break;
-
- case EXCEEDED_MAXLIFE_ONREQUEST:
- exceededMaxlifeCount++;
- break;
-
- case EXCEEDED_IDLETIME_ONREQUEST:
- exceededIdletimeCount++;
- break;
-
- case EXCEEDED_IDLETIME_BACKGROUND:
- break;
-
- case EXCEEDED_MAXLIFE_BACKGROUND:
- break;
- }
- }
-
- /**
- * @return Returns the spoolCount.
- */
- protected int getSpoolCount()
- {
- return spoolCount;
- }
-
- /**
- * @return Returns the spoolNotAllowedCount.
- */
- protected int getSpoolNotAllowedCount()
- {
- return spoolNotAllowedCount;
- }
-
- /**
- * @return Returns the spoolNoDiskCount.
- */
- protected int getSpoolNoDiskCount()
- {
- return spoolNoDiskCount;
- }
-
- /**
- * @return the exceededMaxlifeCount
- */
- protected int getExceededMaxlifeCount()
- {
- return exceededMaxlifeCount;
- }
-
- /**
- * @return the exceededIdletimeCount
- */
- protected int getExceededIdletimeCount()
- {
- return exceededIdletimeCount;
- }
- }
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/logging/CacheEventLoggerDebugLoggerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/logging/CacheEventLoggerDebugLoggerUnitTest.java
deleted file mode 100644
index ebfb696..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/logging/CacheEventLoggerDebugLoggerUnitTest.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package org.apache.commons.jcs.engine.logging;
-
-import java.io.StringWriter;
-
-import org.apache.commons.jcs.TestLogConfigurationUtil;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/** Unit tests for the debug implementation */
-public class CacheEventLoggerDebugLoggerUnitTest
- extends TestCase
-{
-
- /** verify that we can log */
- public void testLogICacheEvent_normal()
- {
- // SETUP
- String logCategoryName = "testLogEvent_normal";
-
- String source = "mySource";
- String region = "my region";
- String eventName = "MyEventName";
- String optionalDetails = "SomeExtraData";
- String key = "my key";
-
- StringWriter stringWriter = new StringWriter();
- TestLogConfigurationUtil.configureLogger( stringWriter, logCategoryName );
-
- CacheEventLoggerDebugLogger logger = new CacheEventLoggerDebugLogger();
- logger.setLogCategoryName( logCategoryName );
-
- ICacheEvent<String> event = logger.createICacheEvent( source, region, eventName, optionalDetails, key );
-
- // DO WORK
- logger.logICacheEvent( event );
-
- // VERIFY
- String result = stringWriter.toString();
- assertTrue( "An event with the source should have been logged:" + result, result.indexOf( source ) != -1 );
- assertTrue( "An event with the region should have been logged:" + result, result.indexOf( region ) != -1 );
- assertTrue( "An event with the event name should have been logged:" + result, result.indexOf( eventName ) != -1 );
- assertTrue( "An event with the optionalDetails should have been logged:" + result, result.indexOf( optionalDetails ) != -1 );
- assertTrue( "An event with the key should have been logged:" + result, result.indexOf( key ) != -1 );
- }
-
- /** verify that we can log */
- public void testLogApplicationEvent_normal()
- {
- // SETUP
- String logCategoryName = "testLogApplicationEvent_normal";
-
- String source = "mySource";
- String eventName = "MyEventName";
- String optionalDetails = "SomeExtraData";
-
- StringWriter stringWriter = new StringWriter();
- TestLogConfigurationUtil.configureLogger( stringWriter, logCategoryName );
-
- CacheEventLoggerDebugLogger logger = new CacheEventLoggerDebugLogger();
- logger.setLogCategoryName( logCategoryName );
-
- // DO WORK
- logger.logApplicationEvent( source, eventName, optionalDetails );
-
- // VERIFY
- String result = stringWriter.toString();
- assertTrue( "An event with the source should have been logged:" + result, result.indexOf( source ) != -1 );
- assertTrue( "An event with the event name should have been logged:" + result, result.indexOf( eventName ) != -1 );
- assertTrue( "An event with the optionalDetails should have been logged:" + result, result.indexOf( optionalDetails ) != -1 );
- }
-
- /** verify that we can log */
- public void testLogError_normal()
- {
- // SETUP
- String logCategoryName = "testLogApplicationEvent_normal";
-
- String source = "mySource";
- String eventName = "MyEventName";
- String errorMessage = "SomeExtraData";
-
- StringWriter stringWriter = new StringWriter();
- TestLogConfigurationUtil.configureLogger( stringWriter, logCategoryName );
-
- CacheEventLoggerDebugLogger logger = new CacheEventLoggerDebugLogger();
- logger.setLogCategoryName( logCategoryName );
-
- // DO WORK
- logger.logError( source, eventName, errorMessage );
-
- // VERIFY
- String result = stringWriter.toString();
- assertTrue( "An event with the source should have been logged:" + result, result.indexOf( source ) != -1 );
- assertTrue( "An event with the event name should have been logged:" + result, result.indexOf( eventName ) != -1 );
- assertTrue( "An event with the errorMessage should have been logged:" + result, result.indexOf( errorMessage ) != -1 );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/logging/MockCacheEventLogger.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/logging/MockCacheEventLogger.java
deleted file mode 100644
index b2768c6..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/logging/MockCacheEventLogger.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package org.apache.commons.jcs.engine.logging;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent;
-import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
-
-/**
- * For testing the configurator.
- */
-public class MockCacheEventLogger
- implements ICacheEventLogger
-{
- /** test property */
- private String testProperty;
-
- /**
- * @param source
- * @param eventName
- * @param optionalDetails
- */
- @Override
- public void logApplicationEvent( String source, String eventName, String optionalDetails )
- {
- // TODO Auto-generated method stub
- }
-
- /**
- * @param source
- * @param eventName
- * @param errorMessage
- */
- @Override
- public void logError( String source, String eventName, String errorMessage )
- {
- // TODO Auto-generated method stub
- }
-
- /**
- * @param source
- * @param region
- * @param eventName
- * @param optionalDetails
- * @param key
- * @return ICacheEvent
- */
- @Override
- public <T> ICacheEvent<T> createICacheEvent( String source, String region, String eventName, String optionalDetails,
- T key )
- {
- return new CacheEvent<>();
- }
-
- /**
- * @param event
- */
- @Override
- public <T> void logICacheEvent( ICacheEvent<T> event )
- {
- // TODO Auto-generated method stub
- }
-
- /**
- * @param testProperty
- */
- public void setTestProperty( String testProperty )
- {
- this.testProperty = testProperty;
- }
-
- /**
- * @return testProperty
- */
- public String getTestProperty()
- {
- return testProperty;
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/match/KeyMatcherPatternImpllUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/match/KeyMatcherPatternImpllUnitTest.java
deleted file mode 100644
index 9847b62..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/match/KeyMatcherPatternImpllUnitTest.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package org.apache.commons.jcs.engine.match;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/** Unit tests for the key matcher. */
-public class KeyMatcherPatternImpllUnitTest
- extends TestCase
-{
- /**
- * Verify that the matching method works.
- */
- public void testGetMatchingKeysFromArray_AllMatch()
- {
- // SETUP
- int numToInsertPrefix1 = 10;
- Set<String> keyArray = new HashSet<>();
-
- String keyprefix1 = "MyPrefixC";
-
- // insert with prefix1
- for ( int i = 0; i < numToInsertPrefix1; i++ )
- {
- keyArray.add(keyprefix1 + String.valueOf( i ));
- }
-
- KeyMatcherPatternImpl<String> keyMatcher = new KeyMatcherPatternImpl<>();
-
- // DO WORK
- Set<String> result1 = keyMatcher.getMatchingKeysFromArray( keyprefix1 + ".", keyArray );
-
- // VERIFY
- assertEquals( "Wrong number returned 1: " + result1, numToInsertPrefix1, result1.size() );
- }
-
- /**
- * Verify that the matching method works.
- */
- public void testGetMatchingKeysFromArray_AllMatchFirstNull()
- {
- // SETUP
- int numToInsertPrefix1 = 10;
- Set<String> keyArray = new HashSet<>();
-
- String keyprefix1 = "MyPrefixC";
-
- // insert with prefix1
- for ( int i = 1; i < numToInsertPrefix1 + 1; i++ )
- {
- keyArray.add(keyprefix1 + String.valueOf( i ));
- }
-
- KeyMatcherPatternImpl<String> keyMatcher = new KeyMatcherPatternImpl<>();
-
- // DO WORK
- Set<String> result1 = keyMatcher.getMatchingKeysFromArray( keyprefix1 + "\\S+", keyArray );
-
- // VERIFY
- assertEquals( "Wrong number returned 1: " + result1, numToInsertPrefix1, result1.size() );
- }
-
- /**
- * Verify that the matching method works.
- */
- public void testGetMatchingKeysFromArray_TwoTypes()
- {
- // SETUP
- int numToInsertPrefix1 = 10;
- int numToInsertPrefix2 = 50;
- Set<String> keyArray = new HashSet<>();
-
- String keyprefix1 = "MyPrefixA";
- String keyprefix2 = "MyPrefixB";
-
- // insert with prefix1
- for ( int i = 0; i < numToInsertPrefix1; i++ )
- {
- keyArray.add(keyprefix1 + String.valueOf( i ));
- }
-
- // insert with prefix2
- for ( int i = numToInsertPrefix1; i < numToInsertPrefix2 + numToInsertPrefix1; i++ )
- {
- keyArray.add(keyprefix2 + String.valueOf( i ));
- }
-
- KeyMatcherPatternImpl<String> keyMatcher = new KeyMatcherPatternImpl<>();
-
- // DO WORK
- Set<String> result1 = keyMatcher.getMatchingKeysFromArray( keyprefix1 + ".+", keyArray );
- Set<String> result2 = keyMatcher.getMatchingKeysFromArray( keyprefix2 + ".+", keyArray );
-
- // VERIFY
- assertEquals( "Wrong number returned 1: " + result1, numToInsertPrefix1, result1.size() );
- assertEquals( "Wrong number returned 2: " + result2, numToInsertPrefix2, result2.size() );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/MockMemoryCache.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/MockMemoryCache.java
deleted file mode 100644
index d4ba8ca..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/MockMemoryCache.java
+++ /dev/null
@@ -1,255 +0,0 @@
-package org.apache.commons.jcs.engine.memory;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.memory.behavior.IMemoryCache;
-import org.apache.commons.jcs.engine.stats.behavior.IStats;
-
-/**
- * Mock implementation of a memory cache for testing things like the memory shrinker.
- * <p>
- * @author Aaron Smuts
- */
-public class MockMemoryCache<K, V>
- implements IMemoryCache<K, V>
-{
- /** Config */
- private ICompositeCacheAttributes cacheAttr;
-
- /** Internal map */
- private final HashMap<K, ICacheElement<K, V>> map = new HashMap<>();
-
- /** The number of times waterfall was called. */
- public int waterfallCallCount = 0;
-
- /** The number passed to the last call of free elements. */
- public int lastNumberOfFreedElements = 0;
-
- /**
- * Does nothing
- * @param cache
- */
- @Override
- public void initialize( CompositeCache<K, V> cache )
- {
- // nothing
- }
-
- /**
- * Destroy the memory cache
- * <p>
- * @throws IOException
- */
- @Override
- public void dispose()
- throws IOException
- {
- // nothing
- }
-
- /** @return size */
- @Override
- public int getSize()
- {
- return map.size();
- }
-
- /** @return stats */
- @Override
- public IStats getStatistics()
- {
- return null;
- }
-
- /**
- * @return map.keySet().toArray( */
- @Override
- public Set<K> getKeySet()
- {
- return new LinkedHashSet<>(map.keySet());
- }
-
- /**
- * @param key
- * @return map.remove( key ) != null
- * @throws IOException
- */
- @Override
- public boolean remove( K key )
- throws IOException
- {
- return map.remove( key ) != null;
- }
-
- /**
- * @throws IOException
- */
- @Override
- public void removeAll()
- throws IOException
- {
- map.clear();
- }
-
- /**
- * @param key
- * @return (ICacheElement) map.get( key )
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> get( K key )
- throws IOException
- {
- return map.get( key );
- }
-
- /**
- * @param keys
- * @return elements
- * @throws IOException
- */
- @Override
- public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
- throws IOException
- {
- Map<K, ICacheElement<K, V>> elements = new HashMap<>();
-
- if ( keys != null && !keys.isEmpty() )
- {
- Iterator<K> iterator = keys.iterator();
-
- while ( iterator.hasNext() )
- {
- K key = iterator.next();
-
- ICacheElement<K, V> element = get( key );
-
- if ( element != null )
- {
- elements.put( key, element );
- }
- }
- }
-
- return elements;
- }
-
- /**
- * @param key
- * @return (ICacheElement) map.get( key )
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> getQuiet( K key )
- throws IOException
- {
- return map.get( key );
- }
-
- /**
- * @param ce
- * @throws IOException
- */
- @Override
- public void waterfal( ICacheElement<K, V> ce )
- throws IOException
- {
- waterfallCallCount++;
- }
-
- /**
- * @param ce
- * @throws IOException
- */
- @Override
- public void update( ICacheElement<K, V> ce )
- throws IOException
- {
- if ( ce != null )
- {
- map.put( ce.getKey(), ce );
- }
- }
-
- /**
- * @return ICompositeCacheAttributes
- */
- @Override
- public ICompositeCacheAttributes getCacheAttributes()
- {
- return cacheAttr;
- }
-
- /**
- * @param cattr
- */
- @Override
- public void setCacheAttributes( ICompositeCacheAttributes cattr )
- {
- this.cacheAttr = cattr;
- }
-
- /** @return null */
- @Override
- public CompositeCache<K, V> getCompositeCache()
- {
- return null;
- }
-
- /**
- * @param group
- * @return null
- */
- public Set<K> getGroupKeys( String group )
- {
- return null;
- }
-
- /**
- * @return null
- */
- public Set<String> getGroupNames()
- {
- return null;
- }
-
- /**
- * @param numberToFree
- * @return 0
- * @throws IOException
- */
- @Override
- public int freeElements( int numberToFree )
- throws IOException
- {
- lastNumberOfFreedElements = numberToFree;
- return 0;
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/fifo/FIFOMemoryCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/fifo/FIFOMemoryCacheUnitTest.java
deleted file mode 100644
index 35b6cff..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/fifo/FIFOMemoryCacheUnitTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package org.apache.commons.jcs.engine.memory.fifo;
-
-/*
- * 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.
- */
-
-import java.io.IOException;
-
-import junit.framework.TestCase;
-
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.CompositeCacheAttributes;
-import org.apache.commons.jcs.engine.ElementAttributes;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-
-/** Unit tests for the fifo implementation. */
-public class FIFOMemoryCacheUnitTest
- extends TestCase
-{
- /**
- * Verify that the oldest inserted item is removed
- * <p>
- * @throws IOException
- */
- public void testExpirationPolicy_oneExtra()
- throws IOException
- {
- // SETUP
- int maxObjects = 10;
- String cacheName = "testExpirationPolicy_oneExtra";
-
- ICompositeCacheAttributes attributes = new CompositeCacheAttributes();
- attributes.setCacheName(cacheName);
- attributes.setMaxObjects( maxObjects );
- attributes.setSpoolChunkSize( 1 );
-
- FIFOMemoryCache<String, String> cache = new FIFOMemoryCache<>();
- cache.initialize( new CompositeCache<>( attributes, new ElementAttributes() ) );
-
- for ( int i = 0; i <= maxObjects; i++ )
- {
- CacheElement<String, String> element = new CacheElement<>( cacheName, "key" + i, "value" + i );
- cache.update( element );
- }
-
- CacheElement<String, String> oneMoreElement = new CacheElement<>( cacheName, "onemore", "onemore" );
-
- // DO WORK
- cache.update( oneMoreElement );
-
- // VERIFY
- assertEquals( "Should have max elements", maxObjects, cache.getSize() );
- System.out.println(cache.getKeySet());
- for ( int i = maxObjects; i > 1; i-- )
- {
- assertNotNull( "Should have element " + i, cache.get( "key" + i ) );
- }
- assertNotNull( "Should have oneMoreElement", cache.get( "onemore" ) );
- }
-
- /**
- * Verify that the oldest inserted item is removed
- * <p>
- * @throws IOException
- */
- public void testExpirationPolicy_doubleOver()
- throws IOException
- {
- // SETUP
- int maxObjects = 10;
- String cacheName = "testExpirationPolicy_oneExtra";
-
- ICompositeCacheAttributes attributes = new CompositeCacheAttributes();
- attributes.setCacheName(cacheName);
- attributes.setMaxObjects( maxObjects );
- attributes.setSpoolChunkSize( 1 );
-
- FIFOMemoryCache<String, String> cache = new FIFOMemoryCache<>();
- cache.initialize( new CompositeCache<>( attributes, new ElementAttributes() ) );
-
- // DO WORK
- for ( int i = 0; i <= (maxObjects * 2); i++ )
- {
- CacheElement<String, String> element = new CacheElement<>( cacheName, "key" + i, "value" + i );
- cache.update( element );
- }
-
- // VERIFY
- assertEquals( "Should have max elements", maxObjects, cache.getSize() );
- for ( int i = (maxObjects * 2); i > maxObjects; i-- )
- {
- assertNotNull( "Shjould have elemnt " + i, cache.get( "key" + i ) );
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCacheConcurrentUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCacheConcurrentUnitTest.java
deleted file mode 100644
index e981456..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCacheConcurrentUnitTest.java
+++ /dev/null
@@ -1,175 +0,0 @@
-package org.apache.commons.jcs.engine.memory.lru;
-
-/*
- * 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.
- */
-
-import junit.extensions.ActiveTestSuite;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Test which exercises the LRUMemory cache. This one uses three different
- * regions for three threads.
- */
-public class LHMLRUMemoryCacheConcurrentUnitTest
- extends TestCase
-{
- /**
- * Number of items to cache, twice the configured maxObjects for the memory
- * cache regions.
- */
- private static int items = 200;
-
- /**
- * Constructor for the TestDiskCache object.
- *
- * @param testName
- */
- public LHMLRUMemoryCacheConcurrentUnitTest( String testName )
- {
- super( testName );
- }
-
- /**
- * Main method passes this test to the text test runner.
- *
- * @param args
- */
- public static void main( String args[] )
- {
- String[] testCaseName = { LHMLRUMemoryCacheConcurrentUnitTest.class.getName() };
- junit.textui.TestRunner.main( testCaseName );
- }
-
- /**
- * A unit test suite for JUnit
- * <p>
- * @return The test suite
- */
- public static Test suite()
- {
- ActiveTestSuite suite = new ActiveTestSuite();
-
- suite.addTest( new LHMLRUMemoryCacheConcurrentUnitTest( "testLHMLRUMemoryCache" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "indexedRegion1" );
- }
- } );
-
- return suite;
- }
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- //JCS.setConfigFilename( "/TestLHMLRUCache.ccf" );
- }
-
- /**
- * Adds items to cache, gets them, and removes them. The item count is more
- * than the size of the memory cache, so items should be dumped.
- * <p>
- * @param region
- * Name of the region to access
- *
- * @throws Exception
- * If an error occurs
- */
- public void runTestForRegion( String region )
- throws Exception
- {
- CompositeCacheManager cacheMgr = CompositeCacheManager.getUnconfiguredInstance();
- cacheMgr.configure( "/TestLHMLRUCache.ccf" );
- CompositeCache<String, String> cache = cacheMgr.getCache( region );
-
- LRUMemoryCache<String, String> lru = new LRUMemoryCache<>();
- lru.initialize( cache );
-
- // Add items to cache
-
- for ( int i = 0; i < items; i++ )
- {
- ICacheElement<String, String> ice = new CacheElement<>( cache.getCacheName(), i + ":key", region + " data " + i );
- ice.setElementAttributes( cache.getElementAttributes() );
- lru.update( ice );
- }
-
- // Test that initial items have been purged
- for ( int i = 0; i < 100; i++ )
- {
- assertNull( "Should not have " + i + ":key", lru.get( i + ":key" ) );
- }
-
- // Test that last items are in cache
- for ( int i = 100; i < items; i++ )
- {
- String value = lru.get( i + ":key" ).getVal();
- assertEquals( region + " data " + i, value );
- }
-
- // Test that getMultiple returns all the items remaining in cache and none of the missing ones
- Set<String> keys = new HashSet<>();
- for ( int i = 0; i < items; i++ )
- {
- keys.add( i + ":key" );
- }
-
- Map<String, ICacheElement<String, String>> elements = lru.getMultiple( keys );
- for ( int i = 0; i < 100; i++ )
- {
- assertNull( "Should not have " + i + ":key", elements.get( i + ":key" ) );
- }
- for ( int i = 100; i < items; i++ )
- {
- ICacheElement<String, String> element = elements.get( i + ":key" );
- assertNotNull( "element " + i + ":key is missing", element );
- assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
- }
-
- // Remove all the items
-
- for ( int i = 0; i < items; i++ )
- {
- lru.remove( i + ":key" );
- }
-
- // Verify removal
-
- for ( int i = 0; i < items; i++ )
- {
- assertNull( "Removed key should be null: " + i + ":key", lru.get( i + ":key" ) );
- }
- }
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCacheUnitTest.java
deleted file mode 100644
index 03adb35..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCacheUnitTest.java
+++ /dev/null
@@ -1,312 +0,0 @@
-package org.apache.commons.jcs.engine.memory.lru;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Tests for the test LHMLRU implementation.
- * <p>
- * @author Aaron Smuts
- */
-public class LHMLRUMemoryCacheUnitTest
- extends TestCase
-{
- /** Test setup */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestLHMLRUCache.ccf" );
- }
-
- /**
- * Verify that the mru gets used by a non-defined region when it is set as the default in the
- * default region.
- * <p>
- * @throws CacheException
- */
- public void testLoadFromCCF()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testLoadFromCCF" );
- String memoryCacheName = cache.getCacheAttributes().getMemoryCacheName();
- assertTrue( "Cache name should have LHMLRU in it.", memoryCacheName.indexOf( "LHMLRUMemoryCache" ) != -1 );
- }
-
- /**
- * put twice as many as the max. verify that the second half is in the cache.
- * <p>
- * @throws CacheException
- */
- public void testPutGetThroughHub()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testPutGetThroughHub" );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max * 2;
-
- for ( int i = 0; i < items; i++ )
- {
- cache.put( i + ":key", "myregion" + " data " + i );
- }
-
- // Test that first items are not in the cache
- for ( int i = max -1; i >= 0; i-- )
- {
- String value = cache.get( i + ":key" );
- assertNull( "Should not have value for key [" + i + ":key" + "] in the cache." + cache.getStats(), value );
- }
-
- // Test that last items are in cache
- // skip 2 for the buffer.
- for ( int i = max + 2; i < items; i++ )
- {
- String value = cache.get( i + ":key" );
- assertEquals( "myregion" + " data " + i, value );
- }
-
- // Test that getMultiple returns all the items remaining in cache and none of the missing ones
- Set<String> keys = new HashSet<>();
- for ( int i = 0; i < items; i++ )
- {
- keys.add( i + ":key" );
- }
-
- Map<String, ICacheElement<String, String>> elements = cache.getCacheElements( keys );
- for ( int i = max-1; i >= 0; i-- )
- {
- assertNull( "Should not have value for key [" + i + ":key" + "] in the cache." + cache.getStats(), elements.get( i + ":key" ) );
- }
- for ( int i = max + 2; i < items; i++ )
- {
- ICacheElement<String, String> element = elements.get( i + ":key" );
- assertNotNull( "element " + i + ":key is missing", element );
- assertEquals( "value " + i + ":key", "myregion" + " data " + i, element.getVal() );
- }
- }
-
- /**
- * Put twice as many as the max, twice. verify that the second half is in the cache.
- * <p>
- * @throws CacheException
- */
- public void testPutGetThroughHubTwice()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testPutGetThroughHubTwice" );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max * 2;
-
- for ( int i = 0; i < items; i++ )
- {
- cache.put( i + ":key", "myregion" + " data " + i );
- }
-
- for ( int i = 0; i < items; i++ )
- {
- cache.put( i + ":key", "myregion" + " data " + i );
- }
-
- // Test that first items are not in the cache
- for ( int i = max -1; i >= 0; i-- )
- {
- String value = cache.get( i + ":key" );
- assertNull( "Should not have value for key [" + i + ":key" + "] in the cache.", value );
- }
-
- // Test that last items are in cache
- // skip 2 for the buffer.
- for ( int i = max + 2; i < items; i++ )
- {
- String value = cache.get( i + ":key" );
- assertEquals( "myregion" + " data " + i, value );
- }
-
- }
-
- /**
- * put the max and remove each. verify that they are all null.
- * <p>
- * @throws CacheException
- */
- public void testPutRemoveThroughHub()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testPutRemoveThroughHub" );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max * 2;
-
- for ( int i = 0; i < items; i++ )
- {
- cache.put( i + ":key", "myregion" + " data " + i );
- }
-
- for ( int i = 0; i < items; i++ )
- {
- cache.remove( i + ":key" );
- }
-
- // Test that first items are not in the cache
- for ( int i = max; i >= 0; i-- )
- {
- String value = cache.get( i + ":key" );
- assertNull( "Should not have value for key [" + i + ":key" + "] in the cache.", value );
- }
- }
-
- /**
- * put the max and clear. verify that no elements remain.
- * <p>
- * @throws CacheException
- */
- public void testClearThroughHub()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testClearThroughHub" );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max * 2;
-
- for ( int i = 0; i < items; i++ )
- {
- cache.put( i + ":key", "myregion" + " data " + i );
- }
-
- cache.clear();
-
- // Test that first items are not in the cache
- for ( int i = max; i >= 0; i-- )
- {
- String value = cache.get( i + ":key" );
- assertNull( "Should not have value for key [" + i + ":key" + "] in the cache.", value );
- }
- }
-
- /**
- * Get stats.
- * <p>
- * @throws CacheException
- */
- public void testGetStatsThroughHub()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testGetStatsThroughHub" );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max * 2;
-
- for ( int i = 0; i < items; i++ )
- {
- cache.put( i + ":key", "myregion" + " data " + i );
- }
-
- String stats = cache.getStats();
-
- //System.out.println( stats );
-
- // TODO improve stats check
- assertTrue( "Should have 200 puts" + stats, stats.indexOf( "200" ) != -1 );
- }
-
- /**
- * Put half the max and clear. get the key array and verify that it has the correct number of
- * items.
- * <p>
- * @throws Exception
- */
- public void testGetKeyArray()
- throws Exception
- {
- CompositeCacheManager cacheMgr = CompositeCacheManager.getUnconfiguredInstance();
- cacheMgr.configure( "/TestLHMLRUCache.ccf" );
- CompositeCache<String, String> cache = cacheMgr.getCache( "testGetKeyArray" );
-
- LHMLRUMemoryCache<String, String> mru = new LHMLRUMemoryCache<>();
- mru.initialize( cache );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max / 2;
-
- for ( int i = 0; i < items; i++ )
- {
- ICacheElement<String, String> ice = new CacheElement<>( cache.getCacheName(), i + ":key", cache.getCacheName() + " data " + i );
- ice.setElementAttributes( cache.getElementAttributes() );
- mru.update( ice );
- }
-
- Set<String> keys = mru.getKeySet();
-
- assertEquals( "Wrong number of keys.", items, keys.size() );
- }
-
- /**
- * Add a few keys with the delimiter. Remove them.
- * <p>
- * @throws CacheException
- */
- public void testRemovePartialThroughHub()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testRemovePartialThroughHub" );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max / 2;
-
- cache.put( "test", "data" );
-
- String root = "myroot";
-
- for ( int i = 0; i < items; i++ )
- {
- cache.put( root + ":" + i + ":key", "myregion" + " data " + i );
- }
-
- // Test that last items are in cache
- for ( int i = 0; i < items; i++ )
- {
- String value = cache.get( root + ":" + i + ":key" );
- assertEquals( "myregion" + " data " + i, value );
- }
-
- // remove partial
- cache.remove( root + ":" );
-
- for ( int i = 0; i < items; i++ )
- {
- assertNull( "Should have been removed by partial loop.", cache.get( root + ":" + i + ":key" ) );
- }
-
- assertNotNull( "Other item should be in the cache.", cache.get( "test" ) );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/lru/LRUMemoryCacheConcurrentUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/lru/LRUMemoryCacheConcurrentUnitTest.java
deleted file mode 100644
index 031691d..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/lru/LRUMemoryCacheConcurrentUnitTest.java
+++ /dev/null
@@ -1,171 +0,0 @@
-package org.apache.commons.jcs.engine.memory.lru;
-
-/*
- * 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.
- */
-
-import junit.extensions.ActiveTestSuite;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Test which exercises the LRUMemory cache. This one uses three different
- * regions for three threads.
- */
-public class LRUMemoryCacheConcurrentUnitTest
- extends TestCase
-{
- /**
- * Number of items to cache, twice the configured maxObjects for the memory
- * cache regions.
- */
- private static int items = 200;
-
- /**
- * Constructor for the TestDiskCache object.
- * <p>
- * @param testName
- */
- public LRUMemoryCacheConcurrentUnitTest( String testName )
- {
- super( testName );
- }
-
- /**
- * Main method passes this test to the text test runner.
- * <p>
- * @param args
- */
- public static void main( String args[] )
- {
- String[] testCaseName = { LRUMemoryCacheConcurrentUnitTest.class.getName() };
- junit.textui.TestRunner.main( testCaseName );
- }
-
- /**
- * A unit test suite for JUnit
- * <p>
- * @return The test suite
- */
- public static Test suite()
- {
- ActiveTestSuite suite = new ActiveTestSuite();
-
- suite.addTest( new LRUMemoryCacheConcurrentUnitTest( "testLRUMemoryCache" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runTestForRegion( "testRegion1" );
- }
- } );
-
- return suite;
- }
-
- /**
- * Test setup
- */
- @Override
- public void setUp()
- {
- //JCS.setConfigFilename( "/TestDiskCache.ccf" );
- }
-
- /**
- * Adds items to cache, gets them, and removes them. The item count is more
- * than the size of the memory cache, so items should be dumped.
- * <p>
- * @param region
- * Name of the region to access
- * @throws Exception
- * If an error occurs
- */
- public void runTestForRegion( String region )
- throws Exception
- {
- CompositeCacheManager cacheMgr = CompositeCacheManager.getUnconfiguredInstance();
- cacheMgr.configure( "/TestDiskCache.ccf" );
- CompositeCache<String, String> cache = cacheMgr.getCache( region );
-
- LRUMemoryCache<String, String> lru = new LRUMemoryCache<>();
- lru.initialize( cache );
-
- // Add items to cache
-
- for ( int i = 0; i < items; i++ )
- {
- ICacheElement<String, String> ice = new CacheElement<>( cache.getCacheName(), i + ":key", region + " data " + i );
- ice.setElementAttributes( cache.getElementAttributes() );
- lru.update( ice );
- }
-
- // Test that initial items have been purged
- for ( int i = 0; i < 100; i++ )
- {
- assertNull( "Should not have " + i + ":key", lru.get( i + ":key" ) );
- }
-
- // Test that last items are in cache
- for ( int i = 100; i < items; i++ )
- {
- String value = lru.get( i + ":key" ).getVal();
- assertEquals( region + " data " + i, value );
- }
-
- // Test that getMultiple returns all the items remaining in cache and none of the missing ones
- Set<String> keys = new HashSet<>();
- for ( int i = 0; i < items; i++ )
- {
- keys.add( i + ":key" );
- }
-
- Map<String, ICacheElement<String, String>> elements = lru.getMultiple( keys );
- for ( int i = 0; i < 100; i++ )
- {
- assertNull( "Should not have " + i + ":key", elements.get( i + ":key" ) );
- }
- for ( int i = 100; i < items; i++ )
- {
- ICacheElement<String, String> element = elements.get( i + ":key" );
- assertNotNull( "element " + i + ":key is missing", element );
- assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
- }
-
- // Remove all the items
- for ( int i = 0; i < items; i++ )
- {
- lru.remove( i + ":key" );
- }
-
- // Verify removal
- for ( int i = 0; i < items; i++ )
- {
- assertNull( "Removed key should be null: " + i + ":key", lru.get( i + ":key" ) );
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/mru/LRUvsMRUPerformanceTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/mru/LRUvsMRUPerformanceTest.java
deleted file mode 100644
index 8d3343b..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/mru/LRUvsMRUPerformanceTest.java
+++ /dev/null
@@ -1,183 +0,0 @@
-package org.apache.commons.jcs.engine.memory.mru;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache;
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-/**
- * Tests the performance difference between the LRU and the MRU. There should be very little.
- */
-public class LRUvsMRUPerformanceTest
- extends TestCase
-{
- /** ration we want */
- float ratioPut = 0;
-
- /** ration we want */
- float ratioGet = 0;
-
- /** ration we want */
- float target = 1.20f;
-
- /** times to run */
- int loops = 20;
-
- /** item per run */
- int tries = 10000;
-
- /**
- * A unit test for JUnit
- * @throws Exception Description of the Exception
- */
- public void testSimpleLoad()
- throws Exception
- {
- Log log1 = LogManager.getLog( LRUMemoryCache.class );
- if ( log1.isDebugEnabled() )
- {
- System.out.println( "The log level must be at info or above for the a performance test." );
- return;
- }
- Log log2 = LogManager.getLog( MRUMemoryCache.class );
- if ( log2.isDebugEnabled() )
- {
- System.out.println( "The log level must be at info or above for the a performance test." );
- return;
- }
- doWork();
-
- // these were when the mru was implemented with the jdk linked list
- //assertTrue( "Ratio is unacceptible.", this.ratioPut < target );
- ///assertTrue( "Ratio is unacceptible.", this.ratioGet < target );
- }
-
- /**
- * Runs the test
- */
- public void doWork()
- {
-
- long start = 0;
- long end = 0;
- long time = 0;
- float tPer = 0;
-
- long putTotalLRU = 0;
- long getTotalLRU = 0;
- long putTotalMRU = 0;
- long getTotalMRU = 0;
-
- try
- {
-
- JCS.setConfigFilename( "/TestMRUCache.ccf" );
- CacheAccess<String, String> cache = JCS.getInstance( "lruDefined" );
- CacheAccess<String, String> mru = JCS.getInstance( "mruDefined" );
-
- System.out.println( "LRU = " + cache );
-
- for ( int j = 0; j < loops; j++ )
- {
-
- System.out.println( "Beginning loop " + j );
-
- String name = "LRU ";
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- cache.put( "key:" + i, "data" + i );
- }
- end = System.currentTimeMillis();
- time = end - start;
- putTotalLRU += time;
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( name + " put time for " + tries + " = " + time + "; millis per = " + tPer );
-
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- cache.get( "key:" + i );
- }
- end = System.currentTimeMillis();
- time = end - start;
- getTotalLRU += time;
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
-
- // /////////////////////////////////////////////////////////////
- name = "MRU";
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- mru.put( "key:" + i, "data" + i );
- }
- end = System.currentTimeMillis();
- time = end - start;
- putTotalMRU += time;
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( name + " put time for " + tries + " = " + time + "; millis per = " + tPer );
-
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- mru.get( "key:" + i );
- }
- end = System.currentTimeMillis();
- time = end - start;
- getTotalMRU += time;
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
-
- System.out.println( "\n" );
- }
-
- }
- catch ( Exception e )
- {
- e.printStackTrace( System.out );
- System.out.println( e );
- }
-
- long putAvJCS = putTotalLRU / loops;
- long getAvJCS = getTotalLRU / loops;
- long putAvHashtable = putTotalMRU / loops;
- long getAvHashtable = getTotalMRU / loops;
-
- System.out.println( "Finished " + loops + " loops of " + tries + " gets and puts" );
-
- System.out.println( "\n" );
- System.out.println( "Put average for JCS = " + putAvJCS );
- System.out.println( "Put average for MRU = " + putAvHashtable );
- ratioPut = Float.intBitsToFloat( (int) putAvJCS ) / Float.intBitsToFloat( (int) putAvHashtable );
- System.out.println( "JCS puts took " + ratioPut + " times the Hashtable, the goal is <" + target + "x" );
-
- System.out.println( "\n" );
- System.out.println( "Get average for JCS = " + getAvJCS );
- System.out.println( "Get average for MRU = " + getAvHashtable );
- ratioGet = Float.intBitsToFloat( (int) getAvJCS ) / Float.intBitsToFloat( (int) getAvHashtable );
- System.out.println( "JCS gets took " + ratioGet + " times the Hashtable, the goal is <" + target + "x" );
- }
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/mru/MRUMemoryCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/mru/MRUMemoryCacheUnitTest.java
deleted file mode 100644
index 7b427d2..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/mru/MRUMemoryCacheUnitTest.java
+++ /dev/null
@@ -1,312 +0,0 @@
-package org.apache.commons.jcs.engine.memory.mru;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Tests for the test MRU implementation.
- * <p>
- * @author Aaron Smuts
- */
-public class MRUMemoryCacheUnitTest
- extends TestCase
-{
- /** Test setup */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestMRUCache.ccf" );
- }
-
- /**
- * Verify that the mru gets used by a non-defined region when it is set as the default in the
- * default region.
- * <p>
- * @throws CacheException
- */
- public void testLoadFromCCF()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testPutGet" );
- String memoryCacheName = cache.getCacheAttributes().getMemoryCacheName();
- assertTrue( "Cache name should have MRU in it.", memoryCacheName.indexOf( "MRUMemoryCache" ) != -1 );
- }
-
- /**
- * put twice as many as the max. verify that the second half is in the cache.
- * <p>
- * @throws CacheException
- */
- public void testPutGetThroughHub()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testPutGetThroughHub" );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max * 2;
-
- for ( int i = 0; i < items; i++ )
- {
- cache.put( i + ":key", "myregion" + " data " + i );
- }
-
- // Test that first items are not in the cache
- for ( int i = max -1; i >= 0; i-- )
- {
- String value = cache.get( i + ":key" );
- assertNull( "Should not have value for key [" + i + ":key" + "] in the cache." + cache.getStats(), value );
- }
-
- // Test that last items are in cache
- // skip 2 for the buffer.
- for ( int i = max + 2; i < items; i++ )
- {
- String value = cache.get( i + ":key" );
- assertEquals( "myregion" + " data " + i, value );
- }
-
- // Test that getMultiple returns all the items remaining in cache and none of the missing ones
- Set<String> keys = new HashSet<>();
- for ( int i = 0; i < items; i++ )
- {
- keys.add( i + ":key" );
- }
-
- Map<String, ICacheElement<String, String>> elements = cache.getCacheElements( keys );
- for ( int i = max-1; i >= 0; i-- )
- {
- assertNull( "Should not have value for key [" + i + ":key" + "] in the cache." + cache.getStats(), elements.get( i + ":key" ) );
- }
- for ( int i = max + 2; i < items; i++ )
- {
- ICacheElement<String, String> element = elements.get( i + ":key" );
- assertNotNull( "element " + i + ":key is missing", element );
- assertEquals( "value " + i + ":key", "myregion" + " data " + i, element.getVal() );
- }
- }
-
- /**
- * Put twice as many as the max, twice. verify that the second half is in the cache.
- * <p>
- * @throws CacheException
- */
- public void testPutGetThroughHubTwice()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testPutGetThroughHub" );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max * 2;
-
- for ( int i = 0; i < items; i++ )
- {
- cache.put( i + ":key", "myregion" + " data " + i );
- }
-
- for ( int i = 0; i < items; i++ )
- {
- cache.put( i + ":key", "myregion" + " data " + i );
- }
-
- // Test that first items are not in the cache
- for ( int i = max-1; i >= 0; i-- )
- {
- String value = cache.get( i + ":key" );
- assertNull( "Should not have value for key [" + i + ":key" + "] in the cache.", value );
- }
-
- // Test that last items are in cache
- // skip 2 for the buffer.
- for ( int i = max + 2; i < items; i++ )
- {
- String value = cache.get( i + ":key" );
- assertEquals( "myregion" + " data " + i, value );
- }
-
- }
-
- /**
- * put the max and remove each. verify that they are all null.
- * <p>
- * @throws CacheException
- */
- public void testPutRemoveThroughHub()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testPutGetThroughHub" );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max * 2;
-
- for ( int i = 0; i < items; i++ )
- {
- cache.put( i + ":key", "myregion" + " data " + i );
- }
-
- for ( int i = 0; i < items; i++ )
- {
- cache.remove( i + ":key" );
- }
-
- // Test that first items are not in the cache
- for ( int i = max; i >= 0; i-- )
- {
- String value = cache.get( i + ":key" );
- assertNull( "Should not have value for key [" + i + ":key" + "] in the cache.", value );
- }
- }
-
- /**
- * put the max and clear. verify that no elements remain.
- * <p>
- * @throws CacheException
- */
- public void testClearThroughHub()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testPutGetThroughHub" );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max * 2;
-
- for ( int i = 0; i < items; i++ )
- {
- cache.put( i + ":key", "myregion" + " data " + i );
- }
-
- cache.clear();
-
- // Test that first items are not in the cache
- for ( int i = max; i >= 0; i-- )
- {
- String value = cache.get( i + ":key" );
- assertNull( "Should not have value for key [" + i + ":key" + "] in the cache.", value );
- }
- }
-
- /**
- * Get stats.
- * <p>
- * @throws CacheException
- */
- public void testGetStatsThroughHub()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testGetStatsThroughHub" );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max * 2;
-
- for ( int i = 0; i < items; i++ )
- {
- cache.put( i + ":key", "myregion" + " data " + i );
- }
-
- String stats = cache.getStats();
-
-// System.out.println( stats );
-
- // TODO improve stats check
- assertTrue( "Should have 200 puts", stats.indexOf( "2000" ) != -1 );
- }
-
- /**
- * Put half the max and clear. get the key array and verify that it has the correct number of
- * items.
- * <p>
- * @throws Exception
- */
- public void testGetKeyArray()
- throws Exception
- {
- CompositeCacheManager cacheMgr = CompositeCacheManager.getUnconfiguredInstance();
- cacheMgr.configure( "/TestMRUCache.ccf" );
- CompositeCache<String, String> cache = cacheMgr.getCache( "testGetKeyArray" );
-
- MRUMemoryCache<String, String> mru = new MRUMemoryCache<>();
- mru.initialize( cache );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max / 2;
-
- for ( int i = 0; i < items; i++ )
- {
- ICacheElement<String, String> ice = new CacheElement<>( cache.getCacheName(), i + ":key", cache.getCacheName() + " data " + i );
- ice.setElementAttributes( cache.getElementAttributes() );
- mru.update( ice );
- }
-
- Set<String> keys = mru.getKeySet();
-
- assertEquals( "Wrong number of keys.", items, keys.size() );
- }
-
- /**
- * Add a few keys with the delimiter. Remove them.
- * <p>
- * @throws CacheException
- */
- public void testRemovePartialThroughHub()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testGetStatsThroughHub" );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max / 2;
-
- cache.put( "test", "data" );
-
- String root = "myroot";
-
- for ( int i = 0; i < items; i++ )
- {
- cache.put( root + ":" + i + ":key", "myregion" + " data " + i );
- }
-
- // Test that last items are in cache
- for ( int i = 0; i < items; i++ )
- {
- String value = cache.get( root + ":" + i + ":key" );
- assertEquals( "myregion" + " data " + i, value );
- }
-
- // remove partial
- cache.remove( root + ":" );
-
- for ( int i = 0; i < items; i++ )
- {
- assertNull( "Should have been removed by partial loop.", cache.get( root + ":" + i + ":key" ) );
- }
-
- assertNotNull( "Other item should be in the cache.", cache.get( "test" ) );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/shrinking/ShrinkerThreadUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/shrinking/ShrinkerThreadUnitTest.java
deleted file mode 100644
index 97511fe..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/shrinking/ShrinkerThreadUnitTest.java
+++ /dev/null
@@ -1,336 +0,0 @@
-package org.apache.commons.jcs.engine.memory.shrinking;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.CompositeCacheAttributes;
-import org.apache.commons.jcs.engine.ElementAttributes;
-import org.apache.commons.jcs.engine.ElementAttributesUtils;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.control.event.ElementEventHandlerMockImpl;
-import org.apache.commons.jcs.engine.control.event.behavior.ElementEventType;
-import org.apache.commons.jcs.engine.memory.MockMemoryCache;
-
-import java.io.IOException;
-
-/**
- * This tests the functionality of the shrinker thread.
- * <p>
- * @author Aaron Smuts
- */
-public class ShrinkerThreadUnitTest
- extends TestCase
-{
- /** verify the check for removal
- * <p>
- * @throws IOException */
- public void testCheckForRemoval_Expired() throws IOException
- {
- // SETUP
- CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
- cacheAttr.setCacheName("testRegion");
- cacheAttr.setMaxMemoryIdleTimeSeconds( 10 );
- cacheAttr.setMaxSpoolPerRun( 10 );
-
- CompositeCache<String, String> cache = new CompositeCache<>(cacheAttr, new ElementAttributes());
-
- String key = "key";
- String value = "value";
-
- ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value );
- ElementAttributes elementAttr = new ElementAttributes();
- elementAttr.setIsEternal( false );
- element.setElementAttributes( elementAttr );
- element.getElementAttributes().setMaxLife(1);
-
- long now = System.currentTimeMillis();
- // add two seconds
- now += 2000;
-
- // DO WORK
- boolean result = cache.isExpired( element, now,
- ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND,
- ElementEventType.EXCEEDED_IDLETIME_BACKGROUND );
-
- // VERIFY
- assertTrue( "Item should have expired.", result );
- }
-
- /** verify the check for removal
- * <p>
- * @throws IOException */
- public void testCheckForRemoval_NotExpired() throws IOException
- {
- // SETUP
- CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
- cacheAttr.setCacheName("testRegion");
- cacheAttr.setMaxMemoryIdleTimeSeconds( 10 );
- cacheAttr.setMaxSpoolPerRun( 10 );
-
- CompositeCache<String, String> cache = new CompositeCache<>(cacheAttr, new ElementAttributes());
-
- String key = "key";
- String value = "value";
-
- ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value );
- ElementAttributes elementAttr = new ElementAttributes();
- elementAttr.setIsEternal( false );
- element.setElementAttributes( elementAttr );
- element.getElementAttributes().setMaxLife(1);
-
- long now = System.currentTimeMillis();
- // subtract two seconds
- now -= 2000;
-
- // DO WORK
- boolean result = cache.isExpired( element, now,
- ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND,
- ElementEventType.EXCEEDED_IDLETIME_BACKGROUND );
-
- // VERIFY
- assertFalse( "Item should not have expired.", result );
- }
-
- /** verify the check for removal
- * <p>
- * @throws IOException */
- public void testCheckForRemoval_IdleTooLong() throws IOException
- {
- // SETUP
- CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
- cacheAttr.setCacheName("testRegion");
- cacheAttr.setMaxMemoryIdleTimeSeconds( 10 );
- cacheAttr.setMaxSpoolPerRun( 10 );
-
- CompositeCache<String, String> cache = new CompositeCache<>(cacheAttr, new ElementAttributes());
-
- String key = "key";
- String value = "value";
-
- ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value );
- ElementAttributes elementAttr = new ElementAttributes();
- elementAttr.setIsEternal( false );
- element.setElementAttributes( elementAttr );
- element.getElementAttributes().setMaxLife(100);
- element.getElementAttributes().setIdleTime( 1 );
-
- long now = System.currentTimeMillis();
- // add two seconds
- now += 2000;
-
- // DO WORK
- boolean result = cache.isExpired( element, now,
- ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND,
- ElementEventType.EXCEEDED_IDLETIME_BACKGROUND );
-
- // VERIFY
- assertTrue( "Item should have expired.", result );
- }
-
- /** verify the check for removal
- * <p>
- * @throws IOException */
- public void testCheckForRemoval_NotIdleTooLong() throws IOException
- {
- // SETUP
- CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
- cacheAttr.setCacheName("testRegion");
- cacheAttr.setMaxMemoryIdleTimeSeconds( 10 );
- cacheAttr.setMaxSpoolPerRun( 10 );
-
- CompositeCache<String, String> cache = new CompositeCache<>(cacheAttr, new ElementAttributes());
-
- String key = "key";
- String value = "value";
-
- ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value );
- ElementAttributes elementAttr = new ElementAttributes();
- elementAttr.setIsEternal( false );
- element.setElementAttributes( elementAttr );
- element.getElementAttributes().setMaxLife(100);
- element.getElementAttributes().setIdleTime( 1 );
-
- long now = System.currentTimeMillis();
- // subtract two seconds
- now -= 2000;
-
- // DO WORK
- boolean result = cache.isExpired( element, now,
- ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND,
- ElementEventType.EXCEEDED_IDLETIME_BACKGROUND );
-
- // VERIFY
- assertFalse( "Item should not have expired.", result );
- }
-
- /**
- * Setup cache attributes in mock. Create the shrinker with the mock. Add some elements into the
- * mock memory cache see that they get spooled.
- * <p>
- * @throws Exception
- */
- public void testSimpleShrink()
- throws Exception
- {
- // SETUP
- CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
- cacheAttr.setCacheName("testRegion");
- cacheAttr.setMemoryCacheName("org.apache.commons.jcs.engine.memory.MockMemoryCache");
- cacheAttr.setMaxMemoryIdleTimeSeconds( 1 );
- cacheAttr.setMaxSpoolPerRun( 10 );
-
- CompositeCache<String, String> cache = new CompositeCache<>(cacheAttr, new ElementAttributes());
- MockMemoryCache<String, String> memory = (MockMemoryCache<String, String>)cache.getMemoryCache();
-
- String key = "key";
- String value = "value";
-
- ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value );
-
- ElementAttributes elementAttr = new ElementAttributes();
- elementAttr.setIsEternal( false );
- element.setElementAttributes( elementAttr );
- element.getElementAttributes().setMaxLife(1);
- memory.update( element );
-
- ICacheElement<String, String> returnedElement1 = memory.get( key );
- assertNotNull( "We should have received an element", returnedElement1 );
-
- // set this to 2 seconds ago.
- ElementAttributesUtils.setLastAccessTime( elementAttr, System.currentTimeMillis() - 2000 );
-
- // DO WORK
- ShrinkerThread<String, String> shrinker = new ShrinkerThread<>( cache );
- shrinker.run();
-
- Thread.sleep( 500 );
-
- // VERIFY
- ICacheElement<String, String> returnedElement2 = memory.get( key );
- assertTrue( "Waterfall should have been called.", memory.waterfallCallCount > 0 );
- assertNull( "We not should have received an element. It should have been spooled.", returnedElement2 );
- }
-
- /**
- * Add 10 to the memory cache. Set the spool per run limit to 3.
- * <p>
- * @throws Exception
- */
- public void testSimpleShrinkMultiple()
- throws Exception
- {
- // SETUP
- CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
- cacheAttr.setCacheName("testRegion");
- cacheAttr.setMemoryCacheName("org.apache.commons.jcs.engine.memory.MockMemoryCache");
- cacheAttr.setMaxMemoryIdleTimeSeconds( 1 );
- cacheAttr.setMaxSpoolPerRun( 3 );
-
- CompositeCache<String, String> cache = new CompositeCache<>(cacheAttr, new ElementAttributes());
- MockMemoryCache<String, String> memory = (MockMemoryCache<String, String>)cache.getMemoryCache();
-
- for ( int i = 0; i < 10; i++ )
- {
- String key = "key" + i;
- String value = "value";
-
- ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value );
-
- ElementAttributes elementAttr = new ElementAttributes();
- elementAttr.setIsEternal( false );
- element.setElementAttributes( elementAttr );
- element.getElementAttributes().setMaxLife(1);
- memory.update( element );
-
- ICacheElement<String, String> returnedElement1 = memory.get( key );
- assertNotNull( "We should have received an element", returnedElement1 );
-
- // set this to 2 seconds ago.
- ElementAttributesUtils.setLastAccessTime( elementAttr, System.currentTimeMillis() - 2000 );
- }
-
- // DO WORK
- ShrinkerThread<String, String> shrinker = new ShrinkerThread<>( cache );
- shrinker.run();
-
- // VERIFY
- Thread.sleep( 500 );
- assertEquals( "Waterfall called the wrong number of times.", 3, memory.waterfallCallCount );
- assertEquals( "Wrong number of elements remain.", 7, memory.getSize() );
- }
-
- /**
- * Add a mock event handler to the items. Verify that it gets called.
- * <p>
- * This is only testing the spooled background event
- * <p>
- * @throws Exception
- */
- public void testSimpleShrinkMultipleWithEventHandler()
- throws Exception
- {
- // SETUP
- CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
- cacheAttr.setCacheName("testRegion");
- cacheAttr.setMemoryCacheName("org.apache.commons.jcs.engine.memory.MockMemoryCache");
- cacheAttr.setMaxMemoryIdleTimeSeconds( 1 );
- cacheAttr.setMaxSpoolPerRun( 3 );
-
- CompositeCache<String, String> cache = new CompositeCache<>(cacheAttr, new ElementAttributes());
- MockMemoryCache<String, String> memory = (MockMemoryCache<String, String>)cache.getMemoryCache();
-
- ElementEventHandlerMockImpl handler = new ElementEventHandlerMockImpl();
-
- for ( int i = 0; i < 10; i++ )
- {
- String key = "key" + i;
- String value = "value";
-
- ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value );
-
- ElementAttributes elementAttr = new ElementAttributes();
- elementAttr.addElementEventHandler( handler );
- elementAttr.setIsEternal( false );
- element.setElementAttributes( elementAttr );
- element.getElementAttributes().setMaxLife(1);
- memory.update( element );
-
- ICacheElement<String, String> returnedElement1 = memory.get( key );
- assertNotNull( "We should have received an element", returnedElement1 );
-
- // set this to 2 seconds ago.
- ElementAttributesUtils.setLastAccessTime( elementAttr, System.currentTimeMillis() - 2000 );
- }
-
- // DO WORK
- ShrinkerThread<String, String> shrinker = new ShrinkerThread<>( cache );
- shrinker.run();
-
- // VERIFY
- Thread.sleep( 500 );
- assertEquals( "Waterfall called the wrong number of times.", 3, memory.waterfallCallCount );
- // the shrinker delegates the the composite cache on the memory cache to put the
- // event on the queue. This make it hard to test. TODO we need to change this to make it easier to verify.
- //assertEquals( "Event handler ExceededIdleTimeBackground called the wrong number of times.", 3, handler.getExceededIdleTimeBackgroundCount() );
- assertEquals( "Wrong number of elements remain.", 7, memory.getSize() );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/soft/SoftReferenceMemoryCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/soft/SoftReferenceMemoryCacheUnitTest.java
deleted file mode 100644
index 3a96d68..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/memory/soft/SoftReferenceMemoryCacheUnitTest.java
+++ /dev/null
@@ -1,247 +0,0 @@
-package org.apache.commons.jcs.engine.memory.soft;
-
-/*
- * 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.
- */
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import junit.framework.TestCase;
-
-import org.apache.commons.jcs.JCS;
-import org.apache.commons.jcs.access.CacheAccess;
-import org.apache.commons.jcs.access.exception.CacheException;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-
-/**
- * Tests for the test Soft reference implementation.
- * <p>
- * @author Aaron Smuts
- */
-public class SoftReferenceMemoryCacheUnitTest
- extends TestCase
-{
- /** Test setup */
- @Override
- public void setUp()
- {
- JCS.setConfigFilename( "/TestSoftReferenceCache.ccf" );
- }
-
- /**
- * @see junit.framework.TestCase#tearDown()
- */
- @Override
- protected void tearDown() throws Exception
- {
- CompositeCacheManager.getInstance().shutDown();
- }
-
- /**
- * Verify that the cache gets used by a non-defined region when it is set as the default in the
- * default region.
- * <p>
- * @throws CacheException
- */
- public void testLoadFromCCF()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testPutGet" );
- String memoryCacheName = cache.getCacheAttributes().getMemoryCacheName();
- assertTrue( "Cache name should have SoftReference in it.",
- memoryCacheName.indexOf( "SoftReferenceMemoryCache" ) != -1 );
- }
-
- /**
- * put twice as many as the max. verify that all are in the cache.
- * <p>
- * @throws CacheException
- */
- public void testPutGetThroughHub()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testPutGetThroughHub" );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max * 2;
-
- for ( int i = 0; i < items; i++ )
- {
- cache.put( i + ":key", "myregion" + " data " + i );
- }
-
- // Test that all items are in cache
- for ( int i = 0; i < items; i++ )
- {
- String value = cache.get( i + ":key" );
- assertEquals( "myregion" + " data " + i, value );
- }
-
- // Test that getMultiple returns all the items remaining in cache and none of the missing ones
- Set<String> keys = new HashSet<>();
- for ( int i = 0; i < items; i++ )
- {
- keys.add( i + ":key" );
- }
-
- Map<String, ICacheElement<String, String>> elements = cache.getCacheElements( keys );
- for ( int i = 0; i < items; i++ )
- {
- ICacheElement<String, String> element = elements.get( i + ":key" );
- assertNotNull( "element " + i + ":key is missing", element );
- assertEquals( "value " + i + ":key", "myregion" + " data " + i, element.getVal() );
- }
-
- // System.out.println(cache.getStats());
- }
-
- /**
- * put the max and remove each. verify that they are all null.
- * <p>
- * @throws CacheException
- */
- public void testPutRemoveThroughHub()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testPutGetThroughHub" );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max * 2;
-
- for ( int i = 0; i < items; i++ )
- {
- cache.put( i + ":key", "myregion" + " data " + i );
- }
-
- for ( int i = 0; i < items; i++ )
- {
- cache.remove( i + ":key" );
- }
-
- // Test that first items are not in the cache
- for ( int i = max; i >= 0; i-- )
- {
- String value = cache.get( i + ":key" );
- assertNull( "Should not have value for key [" + i + ":key" + "] in the cache.", value );
- }
- }
-
- /**
- * put the max and clear. verify that no elements remain.
- * <p>
- * @throws CacheException
- */
- public void testClearThroughHub()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testPutGetThroughHub" );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max * 2;
-
- for ( int i = 0; i < items; i++ )
- {
- cache.put( i + ":key", "myregion" + " data " + i );
- }
-
- cache.clear();
-
- // Test that first items are not in the cache
- for ( int i = max; i >= 0; i-- )
- {
- String value = cache.get( i + ":key" );
- assertNull( "Should not have value for key [" + i + ":key" + "] in the cache.", value );
- }
- }
-
- /**
- * Put half the max and clear. get the key array and verify that it has the correct number of
- * items.
- * <p>
- * @throws Exception
- */
- public void testGetKeyArray()
- throws Exception
- {
- CompositeCacheManager cacheMgr = CompositeCacheManager.getUnconfiguredInstance();
- cacheMgr.configure( "/TestSoftReferenceCache.ccf" );
- CompositeCache<String, String> cache = cacheMgr.getCache( "testGetKeyArray" );
-
- SoftReferenceMemoryCache<String, String> srmc = new SoftReferenceMemoryCache<>();
- srmc.initialize( cache );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max / 2;
-
- for ( int i = 0; i < items; i++ )
- {
- ICacheElement<String, String> ice = new CacheElement<>( cache.getCacheName(), i + ":key", cache.getCacheName() + " data " + i );
- ice.setElementAttributes( cache.getElementAttributes() );
- srmc.update( ice );
- }
-
- Set<String> keys = srmc.getKeySet();
-
- assertEquals( "Wrong number of keys.", items, keys.size() );
- }
-
- /**
- * Add a few keys with the delimiter. Remove them.
- * <p>
- * @throws CacheException
- */
- public void testRemovePartialThroughHub()
- throws CacheException
- {
- CacheAccess<String, String> cache = JCS.getInstance( "testGetStatsThroughHub" );
-
- int max = cache.getCacheAttributes().getMaxObjects();
- int items = max / 2;
-
- cache.put( "test", "data" );
-
- String root = "myroot";
-
- for ( int i = 0; i < items; i++ )
- {
- cache.put( root + ":" + i + ":key", "myregion" + " data " + i );
- }
-
- // Test that last items are in cache
- for ( int i = 0; i < items; i++ )
- {
- String value = cache.get( root + ":" + i + ":key" );
- assertEquals( "myregion" + " data " + i, value );
- }
-
- // remove partial
- cache.remove( root + ":" );
-
- for ( int i = 0; i < items; i++ )
- {
- assertNull( "Should have been removed by partial loop.", cache.get( root + ":" + i + ":key" ) );
- }
-
- assertNotNull( "Other item should be in the cache.", cache.get( "test" ) );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/access/JCSWorkerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/access/JCSWorkerUnitTest.java
deleted file mode 100644
index 7dec5d3..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/access/JCSWorkerUnitTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package org.apache.commons.jcs.utils.access;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/**
- * Test cases for the JCS worker.
- *
- * @author Aaron Smuts
- *
- */
-public class JCSWorkerUnitTest
- extends TestCase
-{
-
- /**
- * Test basic worker functionality. This is a serial not a concurrent test.
- * <p>
- * Just verify that the worker will go to the cache before asking the helper.
- *
- * @throws Exception
- *
- */
- public void testSimpleGet()
- throws Exception
- {
- JCSWorker<String, Long> cachingWorker = new JCSWorker<>( "example region" );
-
- // This is the helper.
- JCSWorkerHelper<Long> helper = new AbstractJCSWorkerHelper<Long>()
- {
- int timesCalled = 0;
-
- @Override
- public Long doWork()
- {
- return Long.valueOf( ++timesCalled );
- }
- };
-
- String key = "abc";
-
- Long result = cachingWorker.getResult( key, helper );
- assertEquals( "Called the wrong number of times", Long.valueOf( 1 ), result );
-
- // should get it from the cache.
- Long result2 = cachingWorker.getResult( key, helper );
- assertEquals( "Called the wrong number of times", Long.valueOf( 1 ), result2 );
- }
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/config/PropertySetterUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/config/PropertySetterUnitTest.java
deleted file mode 100644
index bb363f7..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/config/PropertySetterUnitTest.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.apache.commons.jcs.utils.config;
-
-/*
- * 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.
- */
-
-import static org.junit.Assert.*;
-
-import java.io.File;
-
-import org.junit.Test;
-
-/**
- * Test property settings
- *
- * @author Thomas Vandahl
- *
- */
-public class PropertySetterUnitTest
-{
- enum EnumTest { ONE, TWO, THREE };
-
- @Test
- public void testConvertArg()
- {
- PropertySetter ps = new PropertySetter(this);
- Object s = ps.convertArg("test", String.class);
- assertEquals("Should be a string", "test", s);
-
- Object i = ps.convertArg("1", Integer.TYPE);
- assertEquals("Should be an integer", Integer.valueOf(1), i);
-
- Object l = ps.convertArg("1", Long.TYPE);
- assertEquals("Should be a long", Long.valueOf(1), l);
-
- Object b = ps.convertArg("true", Boolean.TYPE);
- assertEquals("Should be a boolean", Boolean.TRUE, b);
-
- Object e = ps.convertArg("TWO", EnumTest.class);
- assertEquals("Should be an enum", EnumTest.TWO, e);
-
- Object f = ps.convertArg("test.conf", File.class);
- assertTrue("Should be a file", f instanceof File);
- }
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/discovery/MockDiscoveryListener.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/discovery/MockDiscoveryListener.java
deleted file mode 100644
index 746639a..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/discovery/MockDiscoveryListener.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.apache.commons.jcs.utils.discovery;
-
-/*
- * 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.
- */
-
-import org.apache.commons.jcs.utils.discovery.behavior.IDiscoveryListener;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** Mock listener, for testing. */
-public class MockDiscoveryListener
- implements IDiscoveryListener
-{
- /** discovered services. */
- public List<DiscoveredService> discoveredServices = new ArrayList<>();
-
- /**
- * Adds the entry to a list. I'm not using a set. I want to see if we get dupes.
- * <p>
- * @param service
- */
- @Override
- public void addDiscoveredService( DiscoveredService service )
- {
- discoveredServices.add( service );
- }
-
- /**
- * Removes it from the list.
- * <p>
- * @param service
- */
- @Override
- public void removeDiscoveredService( DiscoveredService service )
- {
- discoveredServices.remove( service );
- }
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/discovery/UDPDiscoverySenderUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/discovery/UDPDiscoverySenderUnitTest.java
deleted file mode 100644
index c28f805..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/discovery/UDPDiscoverySenderUnitTest.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package org.apache.commons.jcs.utils.discovery;
-
-import java.util.ArrayList;
-
-import org.apache.commons.jcs.utils.discovery.UDPDiscoveryMessage.BroadcastType;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/**
- * Tests for the sender.
- */
-public class UDPDiscoverySenderUnitTest
- extends TestCase
-{
- /** multicast address to send/receive on */
- private static final String ADDRESS = "228.4.5.9";
-
- /** multicast address to send/receive on */
- private static final int PORT = 5556;
-
- /** imaginary host address for sending */
- private static final String SENDING_HOST = "imaginary host address";
-
- /** imaginary port for sending */
- private static final int SENDING_PORT = 1;
-
- /** receiver instance for tests */
- private UDPDiscoveryReceiver receiver;
-
- /** sender instance for tests */
- private UDPDiscoverySender sender;
-
- /**
- * Set up the receiver. Maybe better to just code sockets here? Set up the sender for sending
- * the message.
- * <p>
- * @throws Exception on error
- */
- @Override
- protected void setUp()
- throws Exception
- {
- super.setUp();
- receiver = new UDPDiscoveryReceiver( null, null, ADDRESS, PORT );
- sender = new UDPDiscoverySender( ADDRESS, PORT, 0 );
- }
-
- /**
- * Kill off the sender and receiver.
- * <p>
- * @throws Exception on error
- */
- @Override
- protected void tearDown()
- throws Exception
- {
- receiver.shutdown();
- sender.close();
- super.tearDown();
- }
-
- /**
- * Test sending a live messages.
- * <p>
- * @throws Exception on error
- */
- public void testPassiveBroadcast()
- throws Exception
- {
- // SETUP
- ArrayList<String> cacheNames = new ArrayList<>();
-
- // DO WORK
- sender.passiveBroadcast( SENDING_HOST, SENDING_PORT, cacheNames, 1L );
-
- // VERIFY
- // grab the sent message
- Object obj = receiver.waitForMessage() ;
-
- assertTrue( "unexpected crap received", obj instanceof UDPDiscoveryMessage );
-
- UDPDiscoveryMessage msg = (UDPDiscoveryMessage) obj;
- // disabled test because of JCS-89
- // assertEquals( "wrong host", SENDING_HOST, msg.getHost() );
- assertEquals( "wrong port", SENDING_PORT, msg.getPort() );
- assertEquals( "wrong message type", BroadcastType.PASSIVE, msg.getMessageType() );
- }
-
- /**
- * Test sending a remove broadcast.
- * <p>
- * @throws Exception on error
- */
- public void testRemoveBroadcast()
- throws Exception
- {
- // SETUP
- ArrayList<String> cacheNames = new ArrayList<>();
-
- // DO WORK
- sender.removeBroadcast( SENDING_HOST, SENDING_PORT, cacheNames, 1L );
-
- // VERIFY
- // grab the sent message
- Object obj = receiver.waitForMessage();
-
- assertTrue( "unexpected crap received", obj instanceof UDPDiscoveryMessage );
-
- UDPDiscoveryMessage msg = (UDPDiscoveryMessage) obj;
- // disabled test because of JCS-89
- // assertEquals( "wrong host", SENDING_HOST, msg.getHost() );
- assertEquals( "wrong port", SENDING_PORT, msg.getPort() );
- assertEquals( "wrong message type", BroadcastType.REMOVE, msg.getMessageType() );
- }
-
- /**
- * Test sending a request broadcast.
- * <p>
- * @throws Exception on error
- */
- public void testRequestBroadcast()
- throws Exception
- {
- // DO WORK
- sender.requestBroadcast();
-
- // VERIFY
- // grab the sent message
- Object obj = receiver.waitForMessage();
-
- assertTrue( "unexpected crap received", obj instanceof UDPDiscoveryMessage );
-
- UDPDiscoveryMessage msg = (UDPDiscoveryMessage) obj;
- assertEquals( "wrong message type", BroadcastType.REQUEST, msg.getMessageType() );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryServiceUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryServiceUnitTest.java
deleted file mode 100644
index 054c152..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryServiceUnitTest.java
+++ /dev/null
@@ -1,226 +0,0 @@
-package org.apache.commons.jcs.utils.discovery;
-
-/*
- * 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.
- */
-
-import java.util.ArrayList;
-
-import junit.framework.TestCase;
-
-/** Unit tests for the service. */
-public class UDPDiscoveryServiceUnitTest
- extends TestCase
-{
- /** Verify that the list is updated. */
- public void testAddOrUpdateService_NotInList()
- {
- // SETUP
- String host = "228.5.6.7";
- int port = 6789;
- UDPDiscoveryAttributes attributes = new UDPDiscoveryAttributes();
- attributes.setUdpDiscoveryAddr( host );
- attributes.setUdpDiscoveryPort( port );
- attributes.setServicePort( 1000 );
-
- // create the service
- UDPDiscoveryService service = new UDPDiscoveryService( attributes );
- service.startup();
- service.addParticipatingCacheName( "testCache1" );
-
- MockDiscoveryListener discoveryListener = new MockDiscoveryListener();
- service.addDiscoveryListener( discoveryListener );
-
- DiscoveredService discoveredService = new DiscoveredService();
- discoveredService.setServiceAddress( host );
- discoveredService.setCacheNames( new ArrayList<>() );
- discoveredService.setServicePort( 1000 );
- discoveredService.setLastHearFromTime( 100 );
-
- // DO WORK
- service.addOrUpdateService( discoveredService );
-
- // VERIFY
- assertTrue( "Service should be in the service list.", service.getDiscoveredServices()
- .contains( discoveredService ) );
- assertTrue( "Service should be in the listener list.", discoveryListener.discoveredServices
- .contains( discoveredService ) );
- }
-
- /** Verify that the list is updated. */
- public void testAddOrUpdateService_InList_NamesDoNotChange()
- {
- // SETUP
- String host = "228.5.6.7";
- int port = 6789;
- UDPDiscoveryAttributes attributes = new UDPDiscoveryAttributes();
- attributes.setUdpDiscoveryAddr( host );
- attributes.setUdpDiscoveryPort( port );
- attributes.setServicePort( 1000 );
-
- // create the service
- UDPDiscoveryService service = new UDPDiscoveryService( attributes );
- service.startup();
- service.addParticipatingCacheName( "testCache1" );
-
- MockDiscoveryListener discoveryListener = new MockDiscoveryListener();
- service.addDiscoveryListener( discoveryListener );
-
- ArrayList<String> sametCacheNames = new ArrayList<>();
- sametCacheNames.add( "name1" );
-
- DiscoveredService discoveredService = new DiscoveredService();
- discoveredService.setServiceAddress( host );
- discoveredService.setCacheNames( sametCacheNames );
- discoveredService.setServicePort( 1000 );
- discoveredService.setLastHearFromTime( 100 );
-
-
- DiscoveredService discoveredService2 = new DiscoveredService();
- discoveredService2.setServiceAddress( host );
- discoveredService2.setCacheNames( sametCacheNames );
- discoveredService2.setServicePort( 1000 );
- discoveredService2.setLastHearFromTime( 500 );
-
- // DO WORK
- service.addOrUpdateService( discoveredService );
- // again
- service.addOrUpdateService( discoveredService2 );
-
- // VERIFY
- assertEquals( "Should only be one in the set.", 1, service.getDiscoveredServices().size() );
- assertTrue( "Service should be in the service list.", service.getDiscoveredServices()
- .contains( discoveredService ) );
- assertTrue( "Service should be in the listener list.", discoveryListener.discoveredServices
- .contains( discoveredService ) );
-
- // need to update the time this sucks. add has no effect convert to a map
- for (DiscoveredService service1 : service.getDiscoveredServices())
- {
- if ( discoveredService.equals( service1 ) )
- {
- assertEquals( "The match should have the new last heard from time.", service1.getLastHearFromTime(),
- discoveredService2.getLastHearFromTime() );
- }
- }
- // the mock has a list from all add calls.
- // it should have been called when the list changed.
- //assertEquals( "Mock should have been called once.", 1, discoveryListener.discoveredServices.size() );
- // logic changed. it's called every time.
- assertEquals( "Mock should have been called twice.", 2, discoveryListener.discoveredServices.size() );
- }
-
- /** Verify that the list is updated. */
- public void testAddOrUpdateService_InList_NamesChange()
- {
- // SETUP
- String host = "228.5.6.7";
- int port = 6789;
- UDPDiscoveryAttributes attributes = new UDPDiscoveryAttributes();
- attributes.setUdpDiscoveryAddr( host );
- attributes.setUdpDiscoveryPort( port );
- attributes.setServicePort( 1000 );
-
- // create the service
- UDPDiscoveryService service = new UDPDiscoveryService( attributes );
- service.startup();
- service.addParticipatingCacheName( "testCache1" );
-
- MockDiscoveryListener discoveryListener = new MockDiscoveryListener();
- service.addDiscoveryListener( discoveryListener );
-
- DiscoveredService discoveredService = new DiscoveredService();
- discoveredService.setServiceAddress( host );
- discoveredService.setCacheNames( new ArrayList<>() );
- discoveredService.setServicePort( 1000 );
- discoveredService.setLastHearFromTime( 100 );
-
- ArrayList<String> differentCacheNames = new ArrayList<>();
- differentCacheNames.add( "name1" );
- DiscoveredService discoveredService2 = new DiscoveredService();
- discoveredService2.setServiceAddress( host );
- discoveredService2.setCacheNames( differentCacheNames );
- discoveredService2.setServicePort( 1000 );
- discoveredService2.setLastHearFromTime( 500 );
-
- // DO WORK
- service.addOrUpdateService( discoveredService );
- // again
- service.addOrUpdateService( discoveredService2 );
-
- // VERIFY
- assertEquals( "Should only be one in the set.", 1, service.getDiscoveredServices().size() );
- assertTrue( "Service should be in the service list.", service.getDiscoveredServices()
- .contains( discoveredService ) );
- assertTrue( "Service should be in the listener list.", discoveryListener.discoveredServices
- .contains( discoveredService ) );
-
- // need to update the time this sucks. add has no effect convert to a map
- for (DiscoveredService service1 : service.getDiscoveredServices())
- {
- if ( discoveredService.equals( service1 ) )
- {
- assertEquals( "The match should have the new last heard from time.", service1.getLastHearFromTime(),
- discoveredService2.getLastHearFromTime() );
- assertEquals( "The names should be updated.", service1.getCacheNames() + "", differentCacheNames + "" );
- }
- }
- // the mock has a list from all add calls.
- // it should have been called when the list changed.
- assertEquals( "Mock should have been called twice.", 2, discoveryListener.discoveredServices.size() );
- assertEquals( "The second mock listener add should be discoveredService2", discoveredService2,
- discoveryListener.discoveredServices.get( 1 ) );
- }
-
- /** Verify that the list is updated. */
- public void testRemoveDiscoveredService()
- {
- // SETUP
- String host = "228.5.6.7";
- int port = 6789;
- UDPDiscoveryAttributes attributes = new UDPDiscoveryAttributes();
- attributes.setUdpDiscoveryAddr( host );
- attributes.setUdpDiscoveryPort( port );
- attributes.setServicePort( 1000 );
-
- // create the service
- UDPDiscoveryService service = new UDPDiscoveryService( attributes );
- service.startup();
- service.addParticipatingCacheName( "testCache1" );
-
- MockDiscoveryListener discoveryListener = new MockDiscoveryListener();
- service.addDiscoveryListener( discoveryListener );
-
- DiscoveredService discoveredService = new DiscoveredService();
- discoveredService.setServiceAddress( host );
- discoveredService.setCacheNames( new ArrayList<>() );
- discoveredService.setServicePort( 1000 );
- discoveredService.setLastHearFromTime( 100 );
-
- service.addOrUpdateService( discoveredService );
-
- // DO WORK
- service.removeDiscoveredService( discoveredService );
-
- // VERIFY
- assertFalse( "Service should not be in the service list.", service.getDiscoveredServices()
- .contains( discoveredService ) );
- assertFalse( "Service should not be in the listener list.", discoveryListener.discoveredServices
- .contains( discoveredService ) );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryUnitTest.java
deleted file mode 100644
index 0f85cb1..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryUnitTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package org.apache.commons.jcs.utils.discovery;
-
-/*
- * 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.
- */
-
-import java.util.ArrayList;
-
-import org.apache.commons.jcs.utils.timing.SleepUtil;
-
-import junit.framework.TestCase;
-
-/**
- * Unit tests for discovery
- */
-public class UDPDiscoveryUnitTest
- extends TestCase
-{
- /**
- * <p>
- * @throws Exception
- */
- public void testSimpleUDPDiscovery()
- throws Exception
- {
- UDPDiscoveryAttributes attributes = new UDPDiscoveryAttributes();
- attributes.setUdpDiscoveryAddr( /*"FF7E:230::1234"*/ "228.5.6.7" );
- attributes.setUdpDiscoveryPort( 6789 );
- attributes.setServicePort( 1000 );
-
- // create the service
- UDPDiscoveryService service = new UDPDiscoveryService( attributes );
- service.startup();
- service.addParticipatingCacheName( "testCache1" );
-
- MockDiscoveryListener discoveryListener = new MockDiscoveryListener();
- service.addDiscoveryListener( discoveryListener );
-
- // create a receiver with the service
- UDPDiscoveryReceiver receiver = new UDPDiscoveryReceiver( service,
- null,
- attributes.getUdpDiscoveryAddr(),
- attributes.getUdpDiscoveryPort() );
- Thread t = new Thread( receiver );
- t.start();
-
- // create a sender
- UDPDiscoverySender sender = new UDPDiscoverySender(
- attributes.getUdpDiscoveryAddr(),
- attributes.getUdpDiscoveryPort(),
- 4 /* datagram TTL */);
-
- // create more names than we have no wait facades for
- // the only one that gets added should be testCache1
- ArrayList<String> cacheNames = new ArrayList<>();
- int numJunk = 10;
- for ( int i = 0; i < numJunk; i++ )
- {
- cacheNames.add( "junkCacheName" + i );
- }
- cacheNames.add( "testCache1" );
-
- // send max messages
- int max = 10;
- int cnt = 0;
- for ( ; cnt < max; cnt++ )
- {
- sender.passiveBroadcast( "localhost", 1111, cacheNames, 1 );
- SleepUtil.sleepAtLeast( 20 );
- }
-
- SleepUtil.sleepAtLeast( 200 );
-
- // check to see that we got 10 messages
- //System.out.println( "Receiver count = " + receiver.getCnt() );
-
- // request braodcasts change things.
- assertTrue( "Receiver count [" + receiver.getCnt() + "] should be the at least the number sent [" + cnt + "].",
- cnt <= receiver.getCnt() );
- sender.close();
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/net/HostNameUtilUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/net/HostNameUtilUnitTest.java
deleted file mode 100644
index 4f45704..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/net/HostNameUtilUnitTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.apache.commons.jcs.utils.net;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-import java.net.UnknownHostException;
-
-/** Tests for the host name util. */
-public class HostNameUtilUnitTest
- extends TestCase
-{
- /**
- * It's nearly impossible to unit test the getLocalHostLANAddress method.
- * <p>
- * @throws UnknownHostException
- */
- public void testGetLocalHostAddress_Simple() throws UnknownHostException
- {
- // DO WORK
- String result = HostNameUtil.getLocalHostAddress();
-
- // VERIFY
- //System.out.print( result );
- assertNotNull( "Should have a host address.", result );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/props/PropertyLoader.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/props/PropertyLoader.java
deleted file mode 100644
index 99311b8..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/props/PropertyLoader.java
+++ /dev/null
@@ -1,160 +0,0 @@
-package org.apache.commons.jcs.utils.props;
-
-import java.io.IOException;
-
-/*
- * 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.
- */
-
-import java.io.InputStream;
-import java.util.Properties;
-
-/**
- * I modified this class to work with .ccf files in particular. I also removed
- * the resource bundle functionality.
- * <p>
- * A simple class for loading java.util.Properties backed by .ccf files deployed
- * as classpath resources. See individual methods for details.
- * <p>
- * The original source is from:
- * <p>
- * @author (C) <a
- * href="http://www.javaworld.com/columns/jw-qna-index.shtml">Vlad
- * Roubtsov </a>, 2003
- */
-public abstract class PropertyLoader
-{
- /** throw an error if we can load the file */
- private static final boolean THROW_ON_LOAD_FAILURE = true;
-
- /** File suffix. */
- private static final String SUFFIX = ".ccf";
-
- /** property suffix */
- private static final String SUFFIX_PROPERTIES = ".properties";
-
- /**
- * Looks up a resource named 'name' in the classpath. The resource must map
- * to a file with .ccf extention. The name is assumed to be absolute and can
- * use either "/" or "." for package segment separation with an optional
- * leading "/" and optional ".ccf" suffix.
- * <p>
- * The suffix ".ccf" will be appended if it is not set. This can also handle
- * .properties files
- * <p>
- * Thus, the following names refer to the same resource:
- *
- * <pre>
- *
- * some.pkg.Resource
- * some.pkg.Resource.ccf
- * some/pkg/Resource
- * some/pkg/Resource.ccf
- * /some/pkg/Resource
- * /some/pkg/Resource.ccf
- * </pre>
- *
- * @param name
- * classpath resource name [may not be null]
- * @param loader
- * classloader through which to load the resource [null is
- * equivalent to the application loader]
- * @return resource converted to java.util.properties [may be null if the
- * resource was not found and THROW_ON_LOAD_FAILURE is false]
- * @throws IllegalArgumentException
- * if the resource was not found and THROW_ON_LOAD_FAILURE is
- * true
- */
- public static Properties loadProperties( String name, ClassLoader loader )
- {
- boolean isCCFSuffix = true;
-
- if ( name == null )
- {
- throw new IllegalArgumentException( "null input: name" );
- }
-
- ClassLoader classLoader = ( loader == null ) ? ClassLoader.getSystemClassLoader() : loader;
-
- String fileName = name.startsWith( "/" ) ? name.substring( 1 ) : name;
-
- if ( fileName.endsWith( SUFFIX ) )
- {
- fileName = fileName.substring( 0, fileName.length() - SUFFIX.length() );
- }
-
- if ( fileName.endsWith( SUFFIX_PROPERTIES ) )
- {
- fileName = fileName.substring( 0, fileName.length() - SUFFIX_PROPERTIES.length() );
- isCCFSuffix = false;
- }
-
- fileName = fileName.replace( '.', '/' );
-
- if ( !fileName.endsWith( SUFFIX ) && isCCFSuffix )
- {
- fileName = fileName.concat( SUFFIX );
- }
- else if ( !fileName.endsWith( SUFFIX_PROPERTIES ) && !isCCFSuffix )
- {
- fileName = fileName.concat( SUFFIX_PROPERTIES );
- }
-
- Properties result = null;
-
- try (InputStream in = classLoader.getResourceAsStream( fileName ))
- {
- result = new Properties();
- result.load( in ); // can throw IOException
- }
- catch ( IOException e )
- {
- result = null;
- }
-
- if ( THROW_ON_LOAD_FAILURE && result == null )
- {
- throw new IllegalArgumentException( "could not load [" + fileName + "]" + " as " + "a classloader resource" );
- }
-
- return result;
- }
-
- /**
- * A convenience overload of {@link #loadProperties(String, ClassLoader)}
- * that uses the current thread's context classloader. A better strategy
- * would be to use techniques shown in
- * http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html
- * <p>
- * @param name
- * @return Properties
- */
- public static Properties loadProperties( final String name )
- {
- return loadProperties( name, Thread.currentThread().getContextClassLoader() );
- }
-
- /**
- * Can't use this one.
- */
- private PropertyLoader()
- {
- super();
- } // this class is not extentible
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/serialization/CompressingSerializerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/serialization/CompressingSerializerUnitTest.java
deleted file mode 100644
index 6b09dca..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/serialization/CompressingSerializerUnitTest.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package org.apache.commons.jcs.utils.serialization;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-import java.io.IOException;
-
-/**
- * Tests the compressing serializer.
- */
-public class CompressingSerializerUnitTest
- extends TestCase
-{
- /**
- * Verify that we don't get any erorrs for null input.
- * <p>
- * @throws ClassNotFoundException
- * @throws IOException
- */
- public void testDeserialize_NullInput()
- throws IOException, ClassNotFoundException
- {
- // SETUP
- CompressingSerializer serializer = new CompressingSerializer();
-
- // DO WORK
- Object result = serializer.deSerialize( null, null );
-
- // VERIFY
- assertNull( "Should have nothing.", result );
- }
-
- /**
- * Test simple back and forth with a string.
- * <p>
- * ))<=>((
- * <p>
- * @throws Exception on error
- */
- public void testSimpleBackAndForth()
- throws Exception
- {
- // SETUP
- CompressingSerializer serializer = new CompressingSerializer();
-
- // DO WORK
- String before = "adsfdsafdsafdsafdsafdsafdsafdsagfdsafdsafdsfdsafdsafsa333 31231";
- String after = (String) serializer.deSerialize( serializer.serialize( before ), null );
-
- // VERIFY
- assertEquals( "Before and after should be the same.", before, after );
- }
-
- /**
- * Test serialization with a null object. Verify that we don't get an error.
- * <p>
- * @throws Exception on error
- */
- public void testSerialize_NullInput()
- throws Exception
- {
- // SETUP
- CompressingSerializer serializer = new CompressingSerializer();
-
- String before = null;
-
- // DO WORK
- byte[] serialized = serializer.serialize( before );
- String after = (String) serializer.deSerialize( serialized, null );
-
- // VERIFY
- assertNull( "Should have nothing. after =" + after, after );
- }
-
- /**
- * Verify that the compressed is smaller.
- * <p>
- * @throws Exception on error
- */
- public void testSerialize_CompareCompressedAndUncompressed()
- throws Exception
- {
- // SETUP
- CompressingSerializer serializer = new CompressingSerializer();
-
- // I hate for loops.
- String before = "adsfdsafdsafdsafdsafdsafdsafdsagfdsafdsafdssaf dsaf sadf dsaf dsaf dsaf "
- + "dsafdsa fdsaf dsaf dsafdsa dsaf dsaf dsaf dsaf dsafdsa76f dsa798f dsa6fdsa 087f "
- + "gh 987dsahb dsahbuhbfnui nufdsa hbv87 f8vhdsgbnfv h8fdg8dfjvn8fdwgj fdsgjb9fdsjbv"
- + "jvhjv hg98f-dsaghj j9fdsb gfsb 9fdshjbgb987fdsbfdwgh ujbhjbhb hbfdsgh fdshb "
- + "Ofdsgyfesgyfdsafdsafsa333 31231";
-
- // DO WORK
- byte[] compressed = serializer.serialize( before );
- byte[] nonCompressed = new StandardSerializer().serialize( before );
-
- // VERIFY
- assertTrue( "Compressed should be smaller. compressed size = " + compressed.length + "nonCompressed size = "
- + nonCompressed.length, compressed.length < nonCompressed.length );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/serialization/SerializationConversionUtilUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/serialization/SerializationConversionUtilUnitTest.java
deleted file mode 100644
index 9f8b6a1..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/serialization/SerializationConversionUtilUnitTest.java
+++ /dev/null
@@ -1,195 +0,0 @@
-package org.apache.commons.jcs.utils.serialization;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.ElementAttributes;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheElementSerialized;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-
-import java.io.IOException;
-
-/**
- * Tests the serialization conversion util.
- * <p>
- * @author Aaron Smuts
- */
-public class SerializationConversionUtilUnitTest
- extends TestCase
-{
- /**
- * Verify null for null.
- * <p>
- * @throws IOException
- */
- public void testgGetSerializedCacheElement_null()
- throws IOException
- {
- // SETUP
- IElementSerializer elementSerializer = new StandardSerializer();
- ICacheElement<String, String> before = null;
-
- // DO WORK
- ICacheElementSerialized<String, String> result =
- SerializationConversionUtil.getSerializedCacheElement( before, elementSerializer );
-
- // VERIFY
- assertNull( "Should get null for null", result );
- }
-
- /**
- * Verify null for null.
- * <p>
- * @throws Exception
- */
- public void testgGetDeSerializedCacheElement_null()
- throws Exception
- {
- // SETUP
- IElementSerializer elementSerializer = new StandardSerializer();
- ICacheElementSerialized<String, String> before = null;
-
- // DO WORK
- ICacheElement<String, String> result =
- SerializationConversionUtil.getDeSerializedCacheElement( before, elementSerializer );
-
- // VERIFY
- assertNull( "Should get null for null", result );
- }
-
- /**
- * Verify that we can go back and forth with the simplest of objects.
- * <p>
- * @throws Exception
- */
- public void testSimpleConversion()
- throws Exception
- {
- // SETUP
- String cacheName = "testName";
- String key = "key";
- String value = "value fdsadf dsafdsa fdsaf dsafdsaf dsafdsaf dsaf dsaf dsaf dsafa dsaf dsaf dsafdsaf";
-
- IElementSerializer elementSerializer = new StandardSerializer();
-
- IElementAttributes attr = new ElementAttributes();
- attr.setMaxLife(34);
-
- ICacheElement<String, String> before = new CacheElement<>( cacheName, key, value );
- before.setElementAttributes( attr );
-
- // DO WORK
- ICacheElementSerialized<String, String> serialized =
- SerializationConversionUtil.getSerializedCacheElement( before, elementSerializer );
-
- // VERIFY
- assertNotNull( "Should have a serialized object.", serialized );
-
- // DO WORK
- ICacheElement<String, String> after =
- SerializationConversionUtil.getDeSerializedCacheElement( serialized, elementSerializer );
-
- // VERIFY
- assertNotNull( "Should have a deserialized object.", after );
- assertEquals( "Values should be the same.", before.getVal(), after.getVal() );
- assertEquals( "Attributes should be the same.", before.getElementAttributes().getMaxLife(), after
- .getElementAttributes().getMaxLife() );
- assertEquals( "Keys should be the same.", before.getKey(), after.getKey() );
- assertEquals( "Cache name should be the same.", before.getCacheName(), after.getCacheName() );
- }
-
- /**
- * Verify that we can go back and forth with the simplest of objects.
- *<p>
- * @throws Exception
- */
- public void testAccidentalDoubleConversion()
- throws Exception
- {
- // SETUP
- String cacheName = "testName";
- String key = "key";
- String value = "value fdsadf dsafdsa fdsaf dsafdsaf dsafdsaf dsaf dsaf dsaf dsafa dsaf dsaf dsafdsaf";
-
- IElementSerializer elementSerializer = new StandardSerializer();
-
- IElementAttributes attr = new ElementAttributes();
- attr.setMaxLife(34);
-
- ICacheElement<String, String> before = new CacheElement<>( cacheName, key, value );
- before.setElementAttributes( attr );
-
- // DO WORK
- ICacheElementSerialized<String, String> alreadySerialized =
- SerializationConversionUtil.getSerializedCacheElement( before, elementSerializer );
- ICacheElementSerialized<String, String> serialized =
- SerializationConversionUtil.getSerializedCacheElement( alreadySerialized, elementSerializer );
-
- // VERIFY
- assertNotNull( "Should have a serialized object.", serialized );
-
- // DO WORK
- ICacheElement<String, String> after =
- SerializationConversionUtil.getDeSerializedCacheElement( serialized, elementSerializer );
-
- // VERIFY
- assertNotNull( "Should have a deserialized object.", after );
- assertEquals( "Values should be the same.", before.getVal(), after.getVal() );
- assertEquals( "Attributes should be the same.", before.getElementAttributes().getMaxLife(), after
- .getElementAttributes().getMaxLife() );
- assertEquals( "Keys should be the same.", before.getKey(), after.getKey() );
- assertEquals( "Cache name should be the same.", before.getCacheName(), after.getCacheName() );
- }
-
- /**
- * Verify that we get an IOException for a null serializer.
- */
- public void testNullSerializerConversion()
- {
- // SETUP
- String cacheName = "testName";
- String key = "key";
- String value = "value fdsadf dsafdsa fdsaf dsafdsaf dsafdsaf dsaf dsaf dsaf dsafa dsaf dsaf dsafdsaf";
-
- IElementSerializer elementSerializer = null;// new StandardSerializer();
-
- IElementAttributes attr = new ElementAttributes();
- attr.setMaxLife(34);
-
- ICacheElement<String, String> before = new CacheElement<>( cacheName, key, value );
- before.setElementAttributes( attr );
-
- // DO WORK
- try
- {
- SerializationConversionUtil.getSerializedCacheElement( before, elementSerializer );
-
- // VERIFY
- fail( "We should have received an IOException." );
- }
- catch ( IOException e )
- {
- // expected
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/serialization/StandardSerializerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/serialization/StandardSerializerUnitTest.java
deleted file mode 100644
index 0411fec..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/serialization/StandardSerializerUnitTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package org.apache.commons.jcs.utils.serialization;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/**
- * Tests the standard serializer.
- *<p>
- * @author Aaron Smuts
- */
-public class StandardSerializerUnitTest
- extends TestCase
-{
- /**
- * Test simple back and forth with a string.
- *<p>
- * @throws Exception
- */
- public void testSimpleBackAndForth()
- throws Exception
- {
- // SETUP
- StandardSerializer serializer = new StandardSerializer();
-
- String before = "adsfdsafdsafdsafdsafdsafdsafdsagfdsafdsafdsfdsafdsafsa333 31231";
-
- // DO WORK
- String after = (String) serializer.deSerialize( serializer.serialize( before ), null );
-
- // VERIFY
- assertEquals( "Before and after should be the same.", before, after );
- }
-
- /**
- * Test serialization with a null object. Verify that we don't get an error.
- *<p>
- * @throws Exception
- */
- public void testNullInput()
- throws Exception
- {
- // SETUP
- StandardSerializer serializer = new StandardSerializer();
-
- String before = null;
-
- // DO WORK
- byte[] serialized = serializer.serialize( before );
- //System.out.println( "testNullInput " + serialized );
-
- String after = (String) serializer.deSerialize( serialized, null );
- //System.out.println( "testNullInput " + after );
-
- // VERIFY
- assertNull( "Should have nothing.", after );
- }
-
- /**
- * Test simple back and forth with a string.
- *<p>
- * @throws Exception
- */
- public void testBigStringBackAndForth()
- throws Exception
- {
- // SETUP
- StandardSerializer serializer = new StandardSerializer();
-
- String string = "This is my big string ABCDEFGH";
- StringBuilder sb = new StringBuilder();
- sb.append( string );
- for ( int i = 0; i < 4; i++ )
- {
- sb.append( " " + i + sb.toString() ); // big string
- }
- String before = sb.toString();
-
- // DO WORK
- String after = (String) serializer.deSerialize( serializer.serialize( before ), null );
-
- // VERIFY
- assertEquals( "Before and after should be the same.", before, after );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/DoubleLinkedListDumpUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/DoubleLinkedListDumpUnitTest.java
deleted file mode 100644
index 644e4c3..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/DoubleLinkedListDumpUnitTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package org.apache.commons.jcs.utils.struct;
-
-import java.io.StringWriter;
-
-import org.apache.commons.jcs.TestLogConfigurationUtil;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/** Unit tests for the double linked list. */
-public class DoubleLinkedListDumpUnitTest
- extends TestCase
-{
- /** verify that the entries are dumped. */
- public void testDumpEntries_DebugTrue()
- {
- // SETUP
- StringWriter stringWriter = new StringWriter();
- TestLogConfigurationUtil.configureLogger( stringWriter, DoubleLinkedList.class.getName() );
-
- DoubleLinkedList<DoubleLinkedListNode<String>> list = new DoubleLinkedList<>();
-
- String payload1 = "payload1";
- DoubleLinkedListNode<String> node1 = new DoubleLinkedListNode<>( payload1 );
-
- String payload2 = "payload2";
- DoubleLinkedListNode<String> node2 = new DoubleLinkedListNode<>( payload2 );
-
- list.addLast( node1 );
- list.addLast( node2 );
- list.debugDumpEntries();
-
- // WO WORK
- String result = stringWriter.toString();
-
- // VERIFY
- assertTrue( "Missing node in log dump", result.indexOf( payload1 ) != -1 );
- assertTrue( "Missing node in log dump", result.indexOf( payload2 ) != -1 );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/DoubleLinkedListUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/DoubleLinkedListUnitTest.java
deleted file mode 100644
index a215598..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/DoubleLinkedListUnitTest.java
+++ /dev/null
@@ -1,159 +0,0 @@
-package org.apache.commons.jcs.utils.struct;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-/** Unit tests for the double linked list. */
-public class DoubleLinkedListUnitTest
- extends TestCase
-{
- /** verify that the last is added when the list is empty. */
- public void testAddLast_Empty()
- {
- // SETUP
- DoubleLinkedList<DoubleLinkedListNode<String>> list = new DoubleLinkedList<>();
-
- String payload1 = "payload1";
- DoubleLinkedListNode<String> node1 = new DoubleLinkedListNode<>( payload1 );
-
- // WO WORK
- list.addLast( node1 );
-
- // VERIFY
- assertEquals( "Wrong last", node1, list.getLast() );
- }
-
- /** verify that the last is added when the list is empty. */
- public void testAddLast_NotEmpty()
- {
- // SETUP
- DoubleLinkedList<DoubleLinkedListNode<String>> list = new DoubleLinkedList<>();
-
- String payload1 = "payload1";
- DoubleLinkedListNode<String> node1 = new DoubleLinkedListNode<>( payload1 );
-
- String payload2 = "payload2";
- DoubleLinkedListNode<String> node2 = new DoubleLinkedListNode<>( payload2 );
-
- // WO WORK
- list.addLast( node1 );
- list.addLast( node2 );
-
- // VERIFY
- assertEquals( "Wrong last", node2, list.getLast() );
- }
-
- /** verify that it's added last. */
- public void testMakeLast_wasFirst()
- {
- // SETUP
- DoubleLinkedList<DoubleLinkedListNode<String>> list = new DoubleLinkedList<>();
-
- String payload1 = "payload1";
- DoubleLinkedListNode<String> node1 = new DoubleLinkedListNode<>( payload1 );
-
- String payload2 = "payload2";
- DoubleLinkedListNode<String> node2 = new DoubleLinkedListNode<>( payload2 );
-
- list.addFirst( node2 );
- list.addFirst( node1 );
-
- // DO WORK
- list.makeLast( node1 );
-
- // VERIFY
- assertEquals( "Wrong size", 2, list.size() );
- assertEquals( "Wrong last", node1, list.getLast() );
- assertEquals( "Wrong first", node2, list.getFirst() );
- }
-
- /** verify that it's added last. */
- public void testMakeLast_wasLast()
- {
- // SETUP
- DoubleLinkedList<DoubleLinkedListNode<String>> list = new DoubleLinkedList<>();
-
- String payload1 = "payload1";
- DoubleLinkedListNode<String> node1 = new DoubleLinkedListNode<>( payload1 );
-
- String payload2 = "payload2";
- DoubleLinkedListNode<String> node2 = new DoubleLinkedListNode<>( payload2 );
-
- list.addFirst( node1 );
- list.addFirst( node2 );
-
- // DO WORK
- list.makeLast( node1 );
-
- // VERIFY
- assertEquals( "Wrong size", 2, list.size() );
- assertEquals( "Wrong last", node1, list.getLast() );
- assertEquals( "Wrong first", node2, list.getFirst() );
- }
-
- /** verify that it's added last. */
- public void testMakeLast_wasAlone()
- {
- // SETUP
- DoubleLinkedList<DoubleLinkedListNode<String>> list = new DoubleLinkedList<>();
-
- String payload1 = "payload1";
- DoubleLinkedListNode<String> node1 = new DoubleLinkedListNode<>( payload1 );
-
- list.addFirst( node1 );
-
- // DO WORK
- list.makeLast( node1 );
-
- // VERIFY
- assertEquals( "Wrong size", 1, list.size() );
- assertEquals( "Wrong last", node1, list.getLast() );
- assertEquals( "Wrong first", node1, list.getFirst() );
- }
-
- /** verify that it's added last. */
- public void testMakeLast_wasInMiddle()
- {
- // SETUP
- DoubleLinkedList<DoubleLinkedListNode<String>> list = new DoubleLinkedList<>();
-
- String payload1 = "payload1";
- DoubleLinkedListNode<String> node1 = new DoubleLinkedListNode<>( payload1 );
-
- String payload2 = "payload2";
- DoubleLinkedListNode<String> node2 = new DoubleLinkedListNode<>( payload2 );
-
- String payload3 = "payload3";
- DoubleLinkedListNode<String> node3 = new DoubleLinkedListNode<>( payload3 );
-
- list.addFirst( node2 );
- list.addFirst( node1 );
- list.addFirst( node3 );
-
- // DO WORK
- list.makeLast( node1 );
-
- // VERIFY
- assertEquals( "Wrong size", 3, list.size() );
- assertEquals( "Wrong last", node1, list.getLast() );
- assertEquals( "Wrong first", node3, list.getFirst() );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/JCSvsCommonsLRUMapPerformanceTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/JCSvsCommonsLRUMapPerformanceTest.java
deleted file mode 100644
index eca6224..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/JCSvsCommonsLRUMapPerformanceTest.java
+++ /dev/null
@@ -1,179 +0,0 @@
-package org.apache.commons.jcs.utils.struct;
-
-/*
- * 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.
- */
-
-import java.util.Map;
-
-import org.apache.commons.jcs.log.Log;
-import org.apache.commons.jcs.log.LogManager;
-
-import junit.framework.TestCase;
-
-/**
- * This ensures that the jcs version of the LRU map is as fast as the commons
- * version. It has been testing at .6 to .7 times the commons LRU.
- *
- */
-public class JCSvsCommonsLRUMapPerformanceTest
- extends TestCase
-{
- /** jcs / commons */
- float ratioPut = 0;
-
- /** jcs / commons */
- float ratioGet = 0;
-
- /** goal */
- float target = 1.0f;
-
- /** loops */
- int loops = 20;
-
- /** number to test with */
- int tries = 100000;
-
- /**
- * A unit test for JUnit
- *
- * @throws Exception
- * Description of the Exception
- */
- public void testSimpleLoad()
- throws Exception
- {
- Log log = LogManager.getLog( LRUMap.class );
- if ( log.isDebugEnabled() )
- {
- System.out.println( "The log level must be at info or above for the a performance test." );
- return;
- }
-
- doWork();
- assertTrue( this.ratioPut < target );
- assertTrue( this.ratioGet < target );
- }
-
- /**
- *
- */
- public void doWork()
- {
- long start = 0;
- long end = 0;
- long time = 0;
- float tPer = 0;
-
- long putTotalJCS = 0;
- long getTotalJCS = 0;
- long putTotalHashtable = 0;
- long getTotalHashtable = 0;
-
- String name = "LRUMap";
- String cache2Name = "";
-
- try
- {
- Map<String, String> cache = new LRUMap<>( tries );
-
- for ( int j = 0; j < loops; j++ )
- {
- name = "JCS ";
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- cache.put( "key:" + i, "data" + i );
- }
- end = System.currentTimeMillis();
- time = end - start;
- putTotalJCS += time;
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( name + " put time for " + tries + " = " + time + "; millis per = " + tPer );
-
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- cache.get( "key:" + i );
- }
- end = System.currentTimeMillis();
- time = end - start;
- getTotalJCS += time;
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
-
- // /////////////////////////////////////////////////////////////
- cache2Name = "Commons ";
- // or LRUMapJCS
- Map<String, String> cache2 = new org.apache.commons.collections4.map.LRUMap<String, String>( tries );
- // cache2Name = "Hashtable";
- // Hashtable cache2 = new Hashtable();
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- cache2.put( "key:" + i, "data" + i );
- }
- end = System.currentTimeMillis();
- time = end - start;
- putTotalHashtable += time;
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( cache2Name + " put time for " + tries + " = " + time + "; millis per = " + tPer );
-
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- cache2.get( "key:" + i );
- }
- end = System.currentTimeMillis();
- time = end - start;
- getTotalHashtable += time;
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( cache2Name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
-
- System.out.println( "\n" );
- }
-
- }
- catch ( Exception e )
- {
- e.printStackTrace( System.out );
- System.out.println( e );
- }
-
- long putAvJCS = putTotalJCS / loops;
- long getAvJCS = getTotalJCS / loops;
- long putAvHashtable = putTotalHashtable / loops;
- long getAvHashtable = getTotalHashtable / loops;
-
- System.out.println( "Finished " + loops + " loops of " + tries + " gets and puts" );
-
- System.out.println( "\n" );
- System.out.println( "Put average for LRUMap = " + putAvJCS );
- System.out.println( "Put average for " + cache2Name + " = " + putAvHashtable );
- ratioPut = Float.intBitsToFloat( (int) putAvJCS ) / Float.intBitsToFloat( (int) putAvHashtable );
- System.out.println( name + " puts took " + ratioPut + " times the " + cache2Name + ", the goal is <" + target
- + "x" );
-
- System.out.println( "\n" );
- System.out.println( "Get average for LRUMap = " + getAvJCS );
- System.out.println( "Get average for " + cache2Name + " = " + getAvHashtable );
- ratioGet = Float.intBitsToFloat( (int) getAvJCS ) / Float.intBitsToFloat( (int) getAvHashtable );
- System.out.println( name + " gets took " + ratioGet + " times the " + cache2Name + ", the goal is <" + target
- + "x" );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapConcurrentUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapConcurrentUnitTest.java
deleted file mode 100644
index 5894fe4..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapConcurrentUnitTest.java
+++ /dev/null
@@ -1,282 +0,0 @@
-package org.apache.commons.jcs.utils.struct;
-
-/*
- * 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.
- */
-
-import java.util.Iterator;
-
-/*
- * 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.
- */
-
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
-
-/**
- * Tests the LRUMap
- *
- */
-public class LRUMapConcurrentUnitTest
- extends TestCase
-{
- /** number to test with */
- private static int items = 20000;
-
- /**
- * Constructor for the TestSimpleLoad object
- * <p>
- * @param testName
- * Description of the Parameter
- */
- public LRUMapConcurrentUnitTest( String testName )
- {
- super( testName );
- }
-
- /**
- * A unit test suite for JUnit
- * <p>
- * @return The test suite
- */
- public static Test suite()
- {
- // run the basic tests
- TestSuite suite = new TestSuite( LRUMapConcurrentUnitTest.class );
-
- // run concurrent tests
- final LRUMap<String, String> map = new LRUMap<>( 2000 );
- suite.addTest( new LRUMapConcurrentUnitTest( "conc1" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runConcurrentPutGetTests( map, 2000 );
- }
- } );
- suite.addTest( new LRUMapConcurrentUnitTest( "conc2" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runConcurrentPutGetTests( map, 2000 );
- }
- } );
- suite.addTest( new LRUMapConcurrentUnitTest( "conc3" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runConcurrentPutGetTests( map, 2000 );
- }
- } );
-
- // run more concurrent tests
- final int max2 = 20000;
- final LRUMap<String, String> map2 = new LRUMap<>( max2 );
- suite.addTest( new LRUMapConcurrentUnitTest( "concB1" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runConcurrentRangeTests( map2, 10000, max2 );
- }
- } );
- suite.addTest( new LRUMapConcurrentUnitTest( "concB1" )
- {
- @Override
- public void runTest()
- throws Exception
- {
- this.runConcurrentRangeTests( map2, 0, 9999 );
- }
- } );
-
- return suite;
- }
-
- /**
- * Just test that we can put, get and remove as expected.
- * <p>
- * @throws Exception
- * Description of the Exception
- */
- public void testSimpleLoad()
- throws Exception
- {
- LRUMap<String, String> map = new LRUMap<>( items );
-
- for ( int i = 0; i < items; i++ )
- {
- map.put( i + ":key", "data" + i );
- }
-
- for ( int i = items - 1; i >= 0; i-- )
- {
- String res = map.get( i + ":key" );
- assertNotNull( "[" + i + ":key] should not be null", res );
- }
-
- // test removal
- map.remove( "300:key" );
- assertNull( map.get( "300:key" ) );
-
- }
-
- /**
- * Just make sure that the LRU functions in he most simple case.
- *
- * @throws Exception
- * Description of the Exception
- */
- public void testLRURemoval()
- throws Exception
- {
- int total = 10;
- LRUMap<String, String> map = new LRUMap<>( total );
-
- // put the max in
- for ( int i = 0; i < total; i++ )
- {
- map.put( i + ":key", "data" + i );
- }
-
- Iterator<?> it = map.entrySet().iterator();
- while ( it.hasNext() )
- {
- assertNotNull( it.next() );
- }
-// System.out.println( map.getStatistics() );
-
- // get the max out backwards
- for ( int i = total - 1; i >= 0; i-- )
- {
- String res = map.get( i + ":key" );
- assertNotNull( "[" + i + ":key] should not be null", res );
- }
-
-// System.out.println( map.getStatistics() );
-
- //since we got them backwards the total should be at the end.
- // add one confirm that total is gone.
- map.put( ( total ) + ":key", "data" + ( total ) );
- assertNull( map.get( ( total - 1 ) + ":key" ) );
-
- }
-
- /**
- * @throws Exception
- */
- public void testLRURemovalAgain()
- throws Exception
- {
- int total = 10000;
- LRUMap<String, String> map = new LRUMap<>( total );
-
- // put the max in
- for ( int i = 0; i < total * 2; i++ )
- {
- map.put( i + ":key", "data" + i );
- }
-
- // get the total number, these should be null
- for ( int i = total - 1; i >= 0; i-- )
- {
- assertNull( map.get( i + ":key" ) );
- }
-
- // get the total to total *2 items out, these should be found.
- for ( int i = ( total * 2 ) - 1; i >= total; i-- )
- {
- String res = map.get( i + ":key" );
- assertNotNull( "[" + i + ":key] should not be null", res );
- }
-
-// System.out.println( map.getStatistics() );
- }
-
- /**
- * Just make sure that we can put and get concurrently
- *
- * @param map
- * @param items
- * @throws Exception
- */
- public void runConcurrentPutGetTests( LRUMap<String, String> map, int items )
- throws Exception
- {
- for ( int i = 0; i < items; i++ )
- {
- map.put( i + ":key", "data" + i );
- }
-
- for ( int i = items - 1; i >= 0; i-- )
- {
- String res = map.get( i + ":key" );
- assertNotNull( "[" + i + ":key] should not be null", res );
- }
- }
-
- /**
- * Put, get, and remove from a range. This should occur at a range that is
- * not touched by other tests.
- * <p>
- * @param map
- * @param start
- * @param end
- * @throws Exception
- */
- public void runConcurrentRangeTests( LRUMap<String, String> map, int start, int end )
- throws Exception
- {
- for ( int i = start; i < end; i++ )
- {
- map.put( i + ":key", "data" + i );
- }
-
- for ( int i = end - 1; i >= start; i-- )
- {
- String res = map.get( i + ":key" );
- assertNotNull( "[" + i + ":key] should not be null", res );
- }
-
- // test removal
- map.remove( start + ":key" );
- assertNull( map.get( start + ":key" ) );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapPerformanceTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapPerformanceTest.java
deleted file mode 100644
index fd57f82..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapPerformanceTest.java
+++ /dev/null
@@ -1,176 +0,0 @@
-package org.apache.commons.jcs.utils.struct;
-
-/*
- * 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.
- */
-
-import java.util.Map;
-
-import junit.framework.TestCase;
-
-/**
- * This ensures that the jcs version of the LRU map is as fast as the commons
- * version. It has been testing at .6 to .7 times the commons LRU.
- * <p>
- * @author aaronsm
- *
- */
-public class LRUMapPerformanceTest
- extends TestCase
-{
- /** The put put ration after the test */
- float ratioPut = 0;
-
- /** The ratio after the test */
- float ratioGet = 0;
-
- /** put jcs / commons ratio */
- float targetPut = 1.2f;
-
- /** get jcs / commons ratio */
- float targetGet = .5f;
-
- /** Time to loop */
- int loops = 20;
-
- /** items to put and get per loop */
- int tries = 100000;
-
- /**
- * A unit test for JUnit
- *
- * @throws Exception
- * Description of the Exception
- */
- public void testSimpleLoad()
- throws Exception
- {
- doWork();
- assertTrue( this.ratioPut < targetPut );
- assertTrue( this.ratioGet < targetGet );
- }
-
- /**
- *
- */
- public void doWork()
- {
- long start = 0;
- long end = 0;
- long time = 0;
- float tPer = 0;
-
- long putTotalJCS = 0;
- long getTotalJCS = 0;
- long putTotalHashtable = 0;
- long getTotalHashtable = 0;
-
- String name = "LRUMap";
- String cache2Name = "";
-
- try
- {
- LRUMap<String, String> cache = new LRUMap<>( tries );
-
- for ( int j = 0; j < loops; j++ )
- {
- name = "JCS ";
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- cache.put( "key:" + i, "data" + i );
- }
- end = System.currentTimeMillis();
- time = end - start;
- putTotalJCS += time;
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( name + " put time for " + tries + " = " + time + "; millis per = " + tPer );
-
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- cache.get( "key:" + i );
- }
- end = System.currentTimeMillis();
- time = end - start;
- getTotalJCS += time;
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
-
- ///////////////////////////////////////////////////////////////
- cache2Name = "LRUMap (commons)";
- //or LRUMapJCS
- Map<String, String> cache2 = new org.apache.commons.collections4.map.LRUMap<String, String>( tries );
-// Map<String, String> cache2 = new ConcurrentLinkedHashMap.Builder<String, String>()
-// .maximumWeightedCapacity( tries )
-// .build();
- //cache2Name = "Hashtable";
- //Hashtable cache2 = new Hashtable();
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- cache2.put( "key:" + i, "data" + i );
- }
- end = System.currentTimeMillis();
- time = end - start;
- putTotalHashtable += time;
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( cache2Name + " put time for " + tries + " = " + time + "; millis per = " + tPer );
-
- start = System.currentTimeMillis();
- for ( int i = 0; i < tries; i++ )
- {
- cache2.get( "key:" + i );
- }
- end = System.currentTimeMillis();
- time = end - start;
- getTotalHashtable += time;
- tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
- System.out.println( cache2Name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
-
- System.out.println( "\n" );
- }
- }
- catch ( Exception e )
- {
- e.printStackTrace( System.out );
- System.out.println( e );
- }
-
- long putAvJCS = putTotalJCS / loops;
- long getAvJCS = getTotalJCS / loops;
- long putAvHashtable = putTotalHashtable / loops;
- long getAvHashtable = getTotalHashtable / loops;
-
- System.out.println( "Finished " + loops + " loops of " + tries + " gets and puts" );
-
- System.out.println( "\n" );
- System.out.println( "Put average for LRUMap = " + putAvJCS );
- System.out.println( "Put average for " + cache2Name + " = " + putAvHashtable );
- ratioPut = Float.intBitsToFloat( (int) putAvJCS ) / Float.intBitsToFloat( (int) putAvHashtable );
- System.out.println( name + " puts took " + ratioPut + " times the " + cache2Name + ", the goal is <" + targetPut
- + "x" );
-
- System.out.println( "\n" );
- System.out.println( "Get average for LRUMap = " + getAvJCS );
- System.out.println( "Get average for " + cache2Name + " = " + getAvHashtable );
- ratioGet = Float.intBitsToFloat( (int) getAvJCS ) / Float.intBitsToFloat( (int) getAvHashtable );
- System.out.println( name + " gets took " + ratioGet + " times the " + cache2Name + ", the goal is <" + targetGet
- + "x" );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapUnitTest.java
deleted file mode 100644
index 3d33c95..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapUnitTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-package org.apache.commons.jcs.utils.struct;
-
-/*
- * 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.
- */
-
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import junit.framework.TestCase;
-
-/**
- * Basic unit tests for the LRUMap
- *
- * @author Aaron Smuts
- *
- */
-public class LRUMapUnitTest
- extends TestCase
-{
-
- /**
- * Put up to the size limit and then make sure they are all there.
- *
- */
- public void testPutWithSizeLimit()
- {
- int size = 10;
- Map<String, String> cache = new LRUMap<>( size );
-
- for ( int i = 0; i < size; i++ )
- {
- cache.put( "key:" + i, "data:" + i );
- }
-
- for ( int i = 0; i < size; i++ )
- {
- String data = cache.get( "key:" + i );
- assertEquals( "Data is wrong.", "data:" + i, data );
- }
- }
-
- /**
- * Put into the lru with no limit and then make sure they are all there.
- *
- */
- public void testPutWithNoSizeLimit()
- {
- int size = 10;
- Map<String, String> cache = new LRUMap<>( );
-
- for ( int i = 0; i < size; i++ )
- {
- cache.put( "key:" + i, "data:" + i );
- }
-
- for ( int i = 0; i < size; i++ )
- {
- String data = cache.get( "key:" + i );
- assertEquals( "Data is wrong.", "data:" + i, data );
- }
- }
-
- /**
- * Put and then remove. Make sure the element is returned.
- *
- */
- public void testPutAndRemove()
- {
- int size = 10;
- Map<String, String> cache = new LRUMap<>( size );
-
- cache.put( "key:" + 1, "data:" + 1 );
- String data = cache.remove( "key:" + 1 );
- assertEquals( "Data is wrong.", "data:" + 1, data );
- }
-
- /**
- * Call remove on an empty map
- *
- */
- public void testRemoveEmpty()
- {
- int size = 10;
- Map<String, String> cache = new LRUMap<>( size );
-
- Object returned = cache.remove( "key:" + 1 );
- assertNull( "Shouldn't hvae anything.", returned );
- }
-
-
- /**
- * Add items to the map and then test to see that they come back in the entry set.
- *
- */
- public void testGetEntrySet()
- {
- int size = 10;
- Map<String, String> cache = new LRUMap<>( size );
-
- for ( int i = 0; i < size; i++ )
- {
- cache.put( "key:" + i, "data:" + i );
- }
-
- Set<Entry<String, String>> entries = cache.entrySet();
- assertEquals( "Set contains the wrong number of items.", size, entries.size() );
-
- // check minimal correctness
- for (Entry<String, String> data : entries)
- {
- assertTrue( "Data is wrong.", data.getValue().indexOf( "data:") != -1 );
- }
- }
-
-
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManagerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManagerUnitTest.java
deleted file mode 100644
index 3831954..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManagerUnitTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package org.apache.commons.jcs.utils.threadpool;
-
-/*
- * 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.
- */
-
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-
-import org.apache.commons.jcs.utils.props.PropertyLoader;
-
-import junit.framework.TestCase;
-
-/**
- * Verify that the manager can create pools as intended by the default and
- * specified file names.
- *
- * @author asmuts
- */
-public class ThreadPoolManagerUnitTest
- extends TestCase
-{
-
- /**
- * Make sure it can load a default cache.ccf file
- */
- public void testDefaultConfig()
- {
- Properties props = PropertyLoader.loadProperties( "thread_pool.properties" );
- ThreadPoolManager.setProps( props );
- ThreadPoolManager mgr = ThreadPoolManager.getInstance();
- assertNotNull( mgr );
-
- ExecutorService pool = mgr.getExecutorService( "test1" );
- assertNotNull( pool );
- }
-
- /**
- * Make sure it can load a certain configuration
- */
- public void testSpecialConfig()
- {
- Properties props = PropertyLoader.loadProperties( "thread_pool.properties" );
- ThreadPoolManager.setProps( props );
- ThreadPoolManager mgr = ThreadPoolManager.getInstance();
- assertNotNull( mgr );
-
- ExecutorService pool = mgr.getExecutorService( "aborttest" );
- assertNotNull( pool );
- }
-
- /**
- * Get a couple pools by name and then see if they are in the list.
- *
- */
- public void testGetPoolNames()
- {
- ThreadPoolManager mgr = ThreadPoolManager.getInstance();
- assertNotNull( mgr );
-
- String poolName1 = "testGetPoolNames1";
- mgr.getExecutorService( poolName1 );
-
- String poolName2 = "testGetPoolNames2";
- mgr.getExecutorService( poolName2 );
-
- Set<String> names = mgr.getPoolNames();
- assertTrue( "Should have name in list.", names.contains( poolName1 ) );
- assertTrue( "Should have name in list.", names.contains( poolName2 ) );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/timing/SleepUtil.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/timing/SleepUtil.java
deleted file mode 100644
index e1c09cd..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/timing/SleepUtil.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package org.apache.commons.jcs.utils.timing;
-
-/*
- * 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.
- */
-
-/**
- * Utility methods to help deal with thread issues.
- */
-public class SleepUtil
-{
- /**
- * Sleep for a specified duration in milliseconds. This method is a
- * platform-specific workaround for Windows due to its inability to resolve
- * durations of time less than approximately 10 - 16 ms.
- * <p>
- * @param milliseconds the number of milliseconds to sleep
- */
- public static void sleepAtLeast( long milliseconds )
- {
- long endTime = System.currentTimeMillis() + milliseconds;
-
- while ( System.currentTimeMillis() <= endTime )
- {
- try
- {
- Thread.sleep( milliseconds );
- }
- catch ( InterruptedException e )
- {
- // TODO - Do something here?
- }
- }
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/zip/CompressionUtilUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/zip/CompressionUtilUnitTest.java
deleted file mode 100644
index 1c390f7..0000000
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/zip/CompressionUtilUnitTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package org.apache.commons.jcs.utils.zip;
-
-/*
- * 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.
- */
-
-import junit.framework.TestCase;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.zip.GZIPOutputStream;
-
-/** Unit tests for the compression util */
-public class CompressionUtilUnitTest
- extends TestCase
-{
- /** Test method for decompressByteArray. */
- public final void testDecompressByteArray_failure()
- {
- try
- {
- // DO WORK
- CompressionUtil.decompressByteArray( null );
-
- // VERIFY
- fail( "excepted an IllegalArgumentException" );
- }
- catch ( IllegalArgumentException exception )
- {
- // expected
- return;
- }
- }
-
- /**
- * Test method for decompressByteArray.
- * <p>
- * @throws IOException
- */
- public final void testCompressDecompressByteArray_success()
- throws IOException
- {
- // SETUP
- String text = "This is some text to compress, not a lot, just a bit ";
-
- // DO WORK
- byte[] compressedText = CompressionUtil.compressByteArray( text.getBytes() );
- byte[] output = CompressionUtil.decompressByteArray( compressedText );
-
- // VERIFY
- String result = new String( output );
- assertNotNull( "decompressed output stream shouldn't have been null ", output );
- assertEquals( text, result );
- }
-
- /**
- * Test method for decompressByteArray.
- * <p>
- * @throws IOException
- */
- public final void testCompressDecompressGzipByteArray_success()
- throws IOException
- {
- // SETUP
- String text = " This is some text to compress, not a lot, just a bit ";
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- GZIPOutputStream os = new GZIPOutputStream( baos );
-
- os.write( text.getBytes() );
- os.flush();
- os.close();
-
- // DO WORK
- byte[] output = CompressionUtil.decompressGzipByteArray( baos.toByteArray() );
-
- // VERIFY
- String result = new String( output );
- assertNotNull( "decompressed output stream shouldn't have been null ", output );
- assertEquals( text, result );
- }
-}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/ConcurrentRemovalLoadTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/ConcurrentRemovalLoadTest.java
new file mode 100644
index 0000000..5ff05c0
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/ConcurrentRemovalLoadTest.java
@@ -0,0 +1,139 @@
+package org.apache.commons.jcs3;
+
+import org.apache.commons.jcs3.JCS;
+
+/*
+ * 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.
+ */
+
+import junit.extensions.ActiveTestSuite;
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+/**
+ * Test which exercises the hierarchical removal when the cache is active.
+ */
+public class ConcurrentRemovalLoadTest
+ extends TestCase
+{
+ /**
+ * A unit test suite for JUnit. This verifies that we can remove hierarchically while the region
+ * is active.
+ * @return The test suite
+ */
+ public static Test suite()
+ {
+ ActiveTestSuite suite = new ActiveTestSuite();
+
+ suite.addTest( new RemovalTestUtil( "testRemoveCache1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ runTestPutThenRemoveCategorical( 0, 200 );
+ }
+ } );
+
+ suite.addTest( new RemovalTestUtil( "testPutCache1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ runPutInRange( 300, 400 );
+ }
+ } );
+
+ suite.addTest( new RemovalTestUtil( "testPutCache2" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ runPutInRange( 401, 600 );
+ }
+ } );
+
+ // stomp on previous put
+ suite.addTest( new RemovalTestUtil( "testPutCache3" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ runPutInRange( 401, 600 );
+ }
+ } );
+
+ suite.addTest( new RemovalTestUtil( "testRemoveCache1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ runTestPutThenRemoveCategorical( 601, 700 );
+ }
+ } );
+
+ suite.addTest( new RemovalTestUtil( "testRemoveCache1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ runTestPutThenRemoveCategorical( 701, 800 );
+ }
+ } );
+
+ suite.addTest( new RemovalTestUtil( "testRemoveCache1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ runTestPutThenRemoveCategorical( 901, 1000 );
+ }
+ } );
+
+ suite.addTest( new RemovalTestUtil( "testPutCache2" )
+ {
+ // verify that there are no errors with concurrent gets.
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ runGetInRange( 0, 1000, false );
+ }
+ } );
+ return suite;
+ }
+
+ /**
+ * Test setup
+ * <p>
+ * @throws Exception
+ */
+ @Override
+ public void setUp()
+ throws Exception
+ {
+ JCS.setConfigFilename( "/TestRemoval.ccf" );
+ JCS.getInstance( "testCache1" );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSCacheElementRetrievalUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSCacheElementRetrievalUnitTest.java
new file mode 100644
index 0000000..75f1c5c
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSCacheElementRetrievalUnitTest.java
@@ -0,0 +1,54 @@
+package org.apache.commons.jcs3;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * @author Aaron Smuts
+ *
+ */
+public class JCSCacheElementRetrievalUnitTest
+ extends TestCase
+{
+ /**
+ *
+ * @throws Exception
+ */
+ public void testSimpleElementRetrieval()
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
+
+ jcs.put( "test_key", "test_data" );
+
+ long now = System.currentTimeMillis();
+ ICacheElement<String, String> elem = jcs.getCacheElement( "test_key" );
+ assertEquals( "Name wasn't right", "testCache1", elem.getCacheName() );
+
+ long diff = now - elem.getElementAttributes().getCreateTime();
+ assertTrue( "Create time should have been at or after the call", diff >= 0 );
+
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSConcurrentCacheAccessUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSConcurrentCacheAccessUnitTest.java
new file mode 100644
index 0000000..0777f0c
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSConcurrentCacheAccessUnitTest.java
@@ -0,0 +1,183 @@
+package org.apache.commons.jcs3;
+
+/*
+ * 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.
+ */
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.GroupCacheAccess;
+import org.apache.commons.jcs3.access.exception.CacheException;
+
+import junit.framework.TestCase;
+
+/**
+ * Test Case for JCS-73, modeled after the Groovy code by Alexander Kleymenov
+ *
+ * @author Thomas Vandahl
+ *
+ */
+public class JCSConcurrentCacheAccessUnitTest extends TestCase
+{
+ private final static int THREADS = 20;
+ private final static int LOOPS = 10000;
+
+ /**
+ * the cache instance
+ */
+ protected GroupCacheAccess<Integer, String> cache;
+
+ /**
+ * the group name
+ */
+ protected String group = "group";
+
+ /**
+ * the error count
+ */
+ protected AtomicInteger errcount;
+
+ /**
+ * Collect all value mismatches
+ */
+ protected List<String> valueMismatchList;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ JCS.setConfigFilename( "/TestJCS-73.ccf" );
+ cache = JCS.getGroupCacheInstance( "cache" );
+ errcount = new AtomicInteger(0);
+ valueMismatchList = new CopyOnWriteArrayList<>();
+ }
+
+ @Override
+ protected void tearDown()
+ throws Exception
+ {
+ super.tearDown();
+ cache.clear();
+ cache.dispose();
+ }
+
+ /**
+ * Worker thread
+ */
+ protected class Worker extends Thread
+ {
+ @Override
+ public void run()
+ {
+ String name = getName();
+
+ for (int idx = 0; idx < LOOPS; idx++)
+ {
+ if (idx > 0)
+ {
+ // get previously stored value
+ String res = cache.getFromGroup(Integer.valueOf(idx-1), group);
+
+ if (res == null)
+ {
+ // null value got inspite of the fact it was placed in cache!
+ System.out.println("ERROR: for " + idx + " in " + name);
+ errcount.incrementAndGet();
+
+ // try to get the value again:
+ int n = 5;
+ while (n-- > 0)
+ {
+ res = cache.getFromGroup(Integer.valueOf(idx-1), group);
+ if (res != null)
+ {
+ // the value finally appeared in cache
+ System.out.println("ERROR FIXED for " + idx + ": " + res + " " + name);
+ errcount.decrementAndGet();
+ break;
+ }
+
+ System.out.println("ERROR STILL PERSISTS for " + idx + " in " + name);
+ try
+ {
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException e)
+ {
+ // continue
+ }
+ }
+ }
+
+ if (!String.valueOf(idx-1).equals(res))
+ {
+ valueMismatchList.add(String.format("Values do not match: %s - %s", String.valueOf(idx-1), res));
+ }
+ }
+
+ // put value in the cache
+ try
+ {
+ cache.putInGroup(Integer.valueOf(idx), group, String.valueOf(idx));
+ }
+ catch (CacheException e)
+ {
+ // continue
+ }
+
+// if ((idx % 1000) == 0)
+// {
+// System.out.println(name + " " + idx);
+// }
+ }
+
+ }
+ }
+
+ /**
+ *
+ * @throws Exception
+ */
+ public void testConcurrentAccess()
+ throws Exception
+ {
+ Worker[] worker = new Worker[THREADS];
+
+ for (int i = 0; i < THREADS; i++)
+ {
+ worker[i] = new Worker();
+ worker[i].start();
+ }
+
+ for (int i = 0; i < THREADS; i++)
+ {
+ worker[i].join();
+ }
+
+ assertEquals("Error count should be 0", 0, errcount.intValue());
+ for (String msg : valueMismatchList)
+ {
+ System.out.println(msg);
+ }
+ assertEquals("Value mismatch count should be 0", 0, valueMismatchList.size());
+ }
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSLightLoadUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSLightLoadUnitTest.java
new file mode 100644
index 0000000..be5a06c
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSLightLoadUnitTest.java
@@ -0,0 +1,75 @@
+package org.apache.commons.jcs3;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+
+import junit.framework.TestCase;
+
+/**
+ * Runs a few thousand queries.
+ */
+public class JCSLightLoadUnitTest
+ extends TestCase
+{
+ /** number to use for the test */
+ private static int items = 20000;
+
+ /**
+ * Test setup
+ * @throws Exception
+ */
+ @Override
+ public void setUp()
+ throws Exception
+ {
+ JCS.setConfigFilename( "/TestSimpleLoad.ccf" );
+ JCS.getInstance( "testCache1" );
+ }
+
+ /**
+ * A unit test for JUnit
+ * @throws Exception Description of the Exception
+ */
+ public void testSimpleLoad()
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
+ // ICompositeCacheAttributes cattr = jcs.getCacheAttributes();
+ // cattr.setMaxObjects( 20002 );
+ // jcs.setCacheAttributes( cattr );
+
+ for ( int i = 1; i <= items; i++ )
+ {
+ jcs.put( i + ":key", "data" + i );
+ }
+
+ for ( int i = items; i > 0; i-- )
+ {
+ String res = jcs.get( i + ":key" );
+ assertNotNull( "[" + i + ":key] should not be null", res );
+ }
+
+ // test removal
+ jcs.remove( "300:key" );
+ assertNull( jcs.get( "300:key" ) );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSRemovalSimpleConcurrentTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSRemovalSimpleConcurrentTest.java
new file mode 100644
index 0000000..eab03e6
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSRemovalSimpleConcurrentTest.java
@@ -0,0 +1,194 @@
+package org.apache.commons.jcs3;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Verify that basic removal functionality works.
+ */
+public class JCSRemovalSimpleConcurrentTest
+ extends TestCase
+{
+ /**
+ * @param testName
+ */
+ public JCSRemovalSimpleConcurrentTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * Test setup
+ * <p>
+ * @throws Exception
+ */
+ @Override
+ public void setUp()
+ throws Exception
+ {
+ JCS.setConfigFilename( "/TestRemoval.ccf" );
+ JCS.getInstance( "testCache1" );
+ }
+
+ /**
+ * Main method passes this test to the text test runner.
+ * <p>
+ * @param args
+ */
+ public static void main( String args[] )
+ {
+ String[] testCaseName = { JCSRemovalSimpleConcurrentTest.class.getName() };
+ junit.textui.TestRunner.main( testCaseName );
+ }
+
+ /**
+ * Verify that 2 level deep hierchical removal works.
+ * <p>
+ * @throws Exception
+ */
+ public void testTwoDeepRemoval()
+ throws Exception
+ {
+ int count = 500;
+ CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
+
+ for ( int i = 0; i <= count; i++ )
+ {
+ jcs.put( "key:" + i + ":anotherpart", "data" + i );
+ }
+
+ for ( int i = count; i >= 0; i-- )
+ {
+ String res = jcs.get( "key:" + i + ":anotherpart" );
+ assertNotNull( "[key:" + i + ":anotherpart] should not be null, " + jcs.getStats(), res );
+ }
+
+ for ( int i = 0; i <= count; i++ )
+ {
+ jcs.remove( "key:" + i + ":" );
+ assertNull( jcs.getStats(), jcs.get( "key:" + i + ":anotherpart" ) );
+ }
+
+ }
+
+ /**
+ * Verify that 1 level deep hierchical removal works.
+ *
+ * @throws Exception
+ */
+ public void testSingleDepthRemoval()
+ throws Exception
+ {
+
+ int count = 500;
+ CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
+
+ for ( int i = 0; i <= count; i++ )
+ {
+ jcs.put( i + ":key", "data" + i );
+ }
+
+ for ( int i = count; i >= 0; i-- )
+ {
+ String res = jcs.get( i + ":key" );
+ assertNotNull( "[" + i + ":key] should not be null", res );
+ }
+
+ for ( int i = 0; i <= count; i++ )
+ {
+ jcs.remove( i + ":" );
+ assertNull( jcs.get( i + ":key" ) );
+ }
+ }
+
+ /**
+ * Verify that clear removes everyting as it should.
+ * <p>
+ * @throws Exception
+ */
+ public void testClear()
+ throws Exception
+ {
+
+ int count = 500;
+ CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
+
+ for ( int i = 0; i <= count; i++ )
+ {
+ jcs.put( i + ":key", "data" + i );
+ }
+
+ for ( int i = count; i >= 0; i-- )
+ {
+ String res = jcs.get( i + ":key" );
+ assertNotNull( "[" + i + ":key] should not be null", res );
+ }
+ jcs.clear();
+
+ for ( int i = count; i >= 0; i-- )
+ {
+ String res = jcs.get( i + ":key" );
+ if ( res != null )
+ {
+ assertNull( "[" + i + ":key] should be null after remvoeall" + jcs.getStats(), res );
+ }
+ }
+ }
+
+ /**
+ * Verify that we can clear repeatedly without error.
+ *
+ * @throws Exception
+ */
+ public void testClearRepeatedlyWithoutError()
+ throws Exception
+ {
+ int count = 500;
+ CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
+
+ jcs.clear();
+
+ for ( int i = 0; i <= count; i++ )
+ {
+ jcs.put( i + ":key", "data" + i );
+ }
+
+ for ( int i = count; i >= 0; i-- )
+ {
+ String res = jcs.get( i + ":key" );
+ assertNotNull( "[" + i + ":key] should not be null", res );
+ }
+
+ for ( int i = count; i >= 0; i-- )
+ {
+ jcs.put( i + ":key", "data" + i );
+ jcs.clear();
+ String res = jcs.get( i + ":key" );
+ if ( res != null )
+ {
+ assertNull( "[" + i + ":key] should be null after remvoeall" + jcs.getStats(), res );
+ }
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSThrashTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSThrashTest.java
new file mode 100644
index 0000000..7a7988c
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSThrashTest.java
@@ -0,0 +1,307 @@
+package org.apache.commons.jcs3;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+import junit.framework.TestCase;
+
+/**
+ * This is based on a test that was posted to the user's list:
+ * <p>
+ * http://www.opensubscriber.com/message/jcs-users@jakarta.apache.org/2435965.html
+ */
+public class JCSThrashTest
+ extends TestCase
+{
+ /** The logger. */
+ private static final Log LOG = LogManager.getLog( JCSThrashTest.class.getName() );
+
+ /**
+ * the cache instance
+ */
+ protected CacheAccess<String, Serializable> jcs;
+
+ /**
+ * Sets up the test
+ * @throws Exception
+ */
+ @Override
+ protected void setUp()
+ throws Exception
+ {
+ super.setUp();
+ JCS.setConfigFilename( "/TestThrash.ccf" );
+ jcs = JCS.getInstance( "testcache" );
+ }
+
+ /**
+ * @throws Exception
+ */
+ @Override
+ protected void tearDown()
+ throws Exception
+ {
+ super.tearDown();
+ jcs.clear();
+ jcs.dispose();
+ }
+
+ /**
+ * Tests adding an entry.
+ * @throws Exception
+ */
+ public void testPut()
+ throws Exception
+ {
+ final String value = "value";
+ final String key = "key";
+
+ // Make sure the element is not found
+ assertEquals( 0, getListSize() );
+
+ assertNull( jcs.get( key ) );
+
+ jcs.put( key, value );
+
+ // Get the element
+ LOG.info( "jcs.getStats(): " + jcs.getStatistics() );
+ assertEquals( 1, getListSize() );
+ assertNotNull( jcs.get( key ) );
+ assertEquals( value, jcs.get( key ) );
+ }
+
+ /**
+ * Test elements can be removed from the store
+ * @throws Exception
+ */
+ public void testRemove()
+ throws Exception
+ {
+ jcs.put( "key1", "value1" );
+ assertEquals( 1, getListSize() );
+
+ jcs.remove( "key1" );
+ assertEquals( 0, getListSize() );
+
+ jcs.put( "key2", "value2" );
+ jcs.put( "key3", "value3" );
+ assertEquals( 2, getListSize() );
+
+ jcs.remove( "key2" );
+ assertEquals( 1, getListSize() );
+
+ // Try to remove an object that is not there in the store
+ jcs.remove( "key4" );
+ assertEquals( 1, getListSize() );
+ }
+
+ /**
+ * This does a bunch of work and then verifies that the memory has not grown by much. Most of
+ * the time the amount of memory used after the test is less.
+ * @throws Exception
+ */
+ public void testForMemoryLeaks()
+ throws Exception
+ {
+ long differenceMemoryCache = thrashCache();
+ LOG.info( "Memory Difference is: " + differenceMemoryCache );
+ assertTrue( differenceMemoryCache < 500000 );
+
+ //LOG.info( "Memory Used is: " + measureMemoryUse() );
+ }
+
+ /**
+ * @return time
+ * @throws Exception
+ */
+ protected long thrashCache()
+ throws Exception
+ {
+ long startingSize = measureMemoryUse();
+ LOG.info( "Memory Used is: " + startingSize );
+
+ final String value = "value";
+ final String key = "key";
+
+ // Add the entry
+ jcs.put( key, value );
+
+ // Create 15 threads that read the keys;
+ final List<Executable> executables = new ArrayList<>();
+ for ( int i = 0; i < 15; i++ )
+ {
+ final JCSThrashTest.Executable executable = () ->
+ {
+ for ( int j = 0; j < 500; j++ )
+ {
+ final String keyj = "key" + j;
+ jcs.get( keyj );
+ }
+ jcs.get( "key" );
+ };
+ executables.add( executable );
+ }
+
+ // Create 15 threads that are insert 500 keys with large byte[] as
+ // values
+ for ( int i = 0; i < 15; i++ )
+ {
+ final JCSThrashTest.Executable executable = () ->
+ {
+
+ // Add a bunch of entries
+ for ( int j = 0; j < 500; j++ )
+ {
+ // Use a random length value
+ final String keyj = "key" + j;
+ byte[] valuej = new byte[10000];
+ jcs.put( keyj, valuej );
+ }
+ };
+ executables.add( executable );
+ }
+
+ runThreads( executables );
+ jcs.clear();
+
+ long finishingSize = measureMemoryUse();
+ LOG.info( "Memory Used is: " + finishingSize );
+ return finishingSize - startingSize;
+ }
+
+ /**
+ * Runs a set of threads, for a fixed amount of time.
+ * <p>
+ * @param executables
+ * @throws Exception
+ */
+ protected void runThreads( final List<Executable> executables )
+ throws Exception
+ {
+
+ final long endTime = System.currentTimeMillis() + 10000;
+ final Throwable[] errors = new Throwable[1];
+
+ // Spin up the threads
+ final Thread[] threads = new Thread[executables.size()];
+ for ( int i = 0; i < threads.length; i++ )
+ {
+ final JCSThrashTest.Executable executable = executables.get( i );
+ threads[i] = new Thread()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ // Run the thread until the given end time
+ while ( System.currentTimeMillis() < endTime )
+ {
+ executable.execute();
+ }
+ }
+ catch ( Throwable t )
+ {
+ // Hang on to any errors
+ errors[0] = t;
+ }
+ }
+ };
+ threads[i].start();
+ }
+
+ // Wait for the threads to finish
+ for ( int i = 0; i < threads.length; i++ )
+ {
+ threads[i].join();
+ }
+
+ // Throw any error that happened
+ if ( errors[0] != null )
+ {
+ throw new Exception( "Test thread failed.", errors[0] );
+ }
+ }
+
+ /**
+ * Measure memory used by the VM.
+ * <p>
+ * @return bytes
+ * @throws InterruptedException
+ */
+ protected long measureMemoryUse()
+ throws InterruptedException
+ {
+ System.gc();
+ Thread.sleep( 3000 );
+ System.gc();
+ return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
+ }
+
+ /**
+ * A runnable, that can throw an exception.
+ */
+ protected interface Executable
+ {
+ /**
+ * Executes this object.
+ * @throws Exception
+ */
+ void execute()
+ throws Exception;
+ }
+
+ /**
+ * @return size
+ */
+ private int getListSize()
+ {
+ final String listSize = "List Size";
+ final String lruMemoryCache = "LRU Memory Cache";
+ String result = "0";
+ List<IStats> istats = jcs.getStatistics().getAuxiliaryCacheStats();
+ for ( IStats istat : istats )
+ {
+ List<IStatElement<?>> statElements = istat.getStatElements();
+ if ( lruMemoryCache.equals( istat.getTypeName() ) )
+ {
+ for ( IStatElement<?> statElement : statElements )
+ {
+ if ( listSize.equals( statElement.getName() ) )
+ {
+ result = statElement.getData().toString();
+ break;
+ }
+ }
+ }
+ }
+ return Integer.parseInt( result );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSUnitTest.java
new file mode 100644
index 0000000..b7af360
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSUnitTest.java
@@ -0,0 +1,90 @@
+package org.apache.commons.jcs3;
+
+/*
+ * 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.
+ */
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Random;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+
+import junit.framework.TestCase;
+
+/**
+ * Simple test for the JCS class.
+ */
+public class JCSUnitTest
+ extends TestCase
+{
+ /** A random for key generation. */
+ Random random = new Random();
+
+ /**
+ * @throws Exception
+ */
+ public void testJCS()
+ throws Exception
+ {
+ CacheAccess<String, LinkedList<HashMap<String, String>>> jcs = JCS.getInstance( "testCache1" );
+
+ LinkedList<HashMap<String, String>> list = buildList();
+
+ jcs.put( "some:key", list );
+
+ assertEquals( list, jcs.get( "some:key" ) );
+ }
+
+ /**
+ * @return builds a list
+ */
+ private LinkedList<HashMap<String, String>> buildList()
+ {
+ LinkedList<HashMap<String, String>> list = new LinkedList<>();
+
+ for ( int i = 0; i < 100; i++ )
+ {
+ list.add( buildMap() );
+ }
+
+ return list;
+ }
+
+ /**
+ * @return a map
+ */
+ private HashMap<String, String> buildMap()
+ {
+ HashMap<String, String> map = new HashMap<>();
+
+ byte[] keyBytes = new byte[32];
+ byte[] valBytes = new byte[128];
+
+ for ( int i = 0; i < 10; i++ )
+ {
+ random.nextBytes( keyBytes );
+ random.nextBytes( valBytes );
+
+ map.put( new String( keyBytes ), new String( valBytes ) );
+ }
+
+ return map;
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSvsHashtablePerformanceTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSvsHashtablePerformanceTest.java
new file mode 100644
index 0000000..ef207d2
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/JCSvsHashtablePerformanceTest.java
@@ -0,0 +1,181 @@
+package org.apache.commons.jcs3;
+
+/*
+ * 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.
+ */
+
+import java.util.Hashtable;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+import junit.framework.TestCase;
+
+/**
+ * This test ensures that basic memory operations are with a specified order of magnitude of the
+ * java.util.Hashtable.
+ * <p>
+ * Currently JCS is under 2x a hashtable for gets, and under 1.2x for puts.
+ */
+public class JCSvsHashtablePerformanceTest
+ extends TestCase
+{
+ /** jcs / hashtable */
+ float ratioPut = 0;
+
+ /** jcs / hashtable */
+ float ratioGet = 0;
+
+ /** ration goal */
+ float target = 3.50f;
+
+ /** Times to run the test */
+ int loops = 20;
+
+ /** how many puts and gets to run */
+ int tries = 50000;
+
+ /**
+ * A unit test for JUnit
+ * @throws Exception Description of the Exception
+ */
+ public void testSimpleLoad()
+ throws Exception
+ {
+ Log log1 = LogManager.getLog( LRUMemoryCache.class );
+ if ( log1.isDebugEnabled() )
+ {
+ System.out.println( "The log level must be at info or above for the a performance test." );
+ return;
+ }
+ Log log2 = LogManager.getLog( JCS.class );
+ if ( log2.isDebugEnabled() )
+ {
+ System.out.println( "The log level must be at info or above for the a performance test." );
+ return;
+ }
+ doWork();
+ assertTrue( this.ratioPut < target );
+ assertTrue( this.ratioGet < target );
+ }
+
+ /**
+ *
+ */
+ public void doWork()
+ {
+ long start = 0;
+ long end = 0;
+ long time = 0;
+ float tPer = 0;
+
+ long putTotalJCS = 0;
+ long getTotalJCS = 0;
+ long putTotalHashtable = 0;
+ long getTotalHashtable = 0;
+
+ try
+ {
+
+ JCS.setConfigFilename( "/TestJCSvHashtablePerf.ccf" );
+ CacheAccess<String, String> cache = JCS.getInstance( "testCache1" );
+
+ for ( int j = 0; j < loops; j++ )
+ {
+
+ String name = "JCS ";
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ cache.put( "key:" + i, "data" + i );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ putTotalJCS += time;
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( name + " put time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ cache.get( "key:" + i );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ getTotalJCS += time;
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ // /////////////////////////////////////////////////////////////
+ name = "Hashtable";
+ Hashtable<String, String> cache2 = new Hashtable<>();
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ cache2.put( "key:" + i, "data" + i );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ putTotalHashtable += time;
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( name + " put time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ cache2.get( "key:" + i );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ getTotalHashtable += time;
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ System.out.println( "\n" );
+ }
+
+ }
+ catch ( Exception e )
+ {
+ e.printStackTrace( System.out );
+ System.out.println( e );
+ }
+
+ long putAvJCS = putTotalJCS / loops;
+ long getAvJCS = getTotalJCS / loops;
+ long putAvHashtable = putTotalHashtable / loops;
+ long getAvHashtable = getTotalHashtable / loops;
+
+ System.out.println( "Finished " + loops + " loops of " + tries + " gets and puts" );
+
+ System.out.println( "\n" );
+ System.out.println( "Put average for JCS = " + putAvJCS );
+ System.out.println( "Put average for Hashtable = " + putAvHashtable );
+ ratioPut = Float.intBitsToFloat( (int) putAvJCS ) / Float.intBitsToFloat( (int) putAvHashtable );
+ System.out.println( "JCS puts took " + ratioPut + " times the Hashtable, the goal is <" + target + "x" );
+
+ System.out.println( "\n" );
+ System.out.println( "Get average for JCS = " + getAvJCS );
+ System.out.println( "Get average for Hashtable = " + getAvHashtable );
+ ratioGet = Float.intBitsToFloat( (int) getAvJCS ) / Float.intBitsToFloat( (int) getAvHashtable );
+ System.out.println( "JCS gets took " + ratioGet + " times the Hashtable, the goal is <" + target + "x" );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/RemovalTestUtil.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/RemovalTestUtil.java
new file mode 100644
index 0000000..1d363e3
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/RemovalTestUtil.java
@@ -0,0 +1,131 @@
+package org.apache.commons.jcs3;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Simple methods to be run by active test suites that test removal.
+ *
+ */
+public class RemovalTestUtil
+ extends TestCase
+{
+ /**
+ * Constructor for the TestSimpleLoad object
+ *
+ * @param testName
+ * Description of the Parameter
+ */
+ public RemovalTestUtil( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * Adds elements in the range specified and then removes them using the
+ * categorical or substring removal method.
+ *
+ * @param start
+ * @param end
+ *
+ * @throws Exception
+ * Description of the Exception
+ */
+ public void runTestPutThenRemoveCategorical( int start, int end )
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
+
+ for ( int i = start; i <= end; i++ )
+ {
+ jcs.put( i + ":key", "data" + i );
+ }
+
+ for ( int i = end; i >= start; i-- )
+ {
+ String res = jcs.get( i + ":key" );
+ assertNotNull( "[" + i + ":key] should not be null", res );
+ }
+
+ for ( int i = start; i <= end; i++ )
+ {
+ jcs.remove( i + ":" );
+ assertNull( jcs.get( i + ":key" ) );
+ }
+ }
+
+ /**
+ * Put items in the cache in this key range. Can be used to verify that
+ * concurrent operations are not effected by things like hierchical removal.
+ *
+ * @param start
+ * int
+ * @param end
+ * int
+ * @throws Exception
+ */
+ public void runPutInRange( int start, int end )
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
+
+ for ( int i = start; i <= end; i++ )
+ {
+ jcs.put( i + ":key", "data" + i );
+ }
+
+ for ( int i = end; i >= start; i-- )
+ {
+ String res = jcs.get( i + ":key" );
+ assertNotNull( "[" + i + ":key] should not be null", res );
+ }
+ }
+
+ /**
+ * Just get from start to end.
+ *
+ * @param start
+ * int
+ * @param end
+ * int
+ * @param check
+ * boolean -- check to see if the items are in the cache.
+ * @throws Exception
+ */
+ public void runGetInRange( int start, int end, boolean check )
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
+
+ // don't care if they are found
+ for ( int i = end; i >= start; i-- )
+ {
+ String res = jcs.get( i + ":key" );
+ if ( check )
+ {
+ assertNotNull( "[" + i + ":key] should not be null", res );
+ }
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/TestLogConfigurationUtil.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/TestLogConfigurationUtil.java
new file mode 100644
index 0000000..e7ebce2
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/TestLogConfigurationUtil.java
@@ -0,0 +1,85 @@
+package org.apache.commons.jcs3;
+
+import java.io.StringWriter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+import org.apache.commons.jcs3.log.LogManager;
+
+/*
+ * 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.
+ */
+
+/** Utility for testing log messages. */
+public class TestLogConfigurationUtil
+{
+ /**
+ * Configures a logger for the given name. This allows us to check the log output.
+ * <p>
+ * @param stringWriter string writer
+ * @param loggerName logger name
+ */
+ public static void configureLogger( StringWriter stringWriter, String loggerName )
+ {
+ LogManager.setLogSystem("jul");
+ java.util.logging.LogManager.getLogManager().reset();
+ Logger rootLogger = java.util.logging.LogManager.getLogManager().getLogger("");
+
+ rootLogger.addHandler(new MockLogHandler(stringWriter));
+ rootLogger.setLevel(Level.FINE);
+ }
+
+ private static class MockLogHandler extends Handler
+ {
+ private final StringWriter writer;
+
+ public MockLogHandler(StringWriter writer)
+ {
+ super();
+ this.writer = writer;
+ }
+
+ @Override
+ public void publish(LogRecord record)
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append(record.getMillis())
+ .append(" - ")
+ .append(record.getSourceClassName())
+ .append("#")
+ .append(record.getSourceMethodName())
+ .append(" - ")
+ .append(record.getMessage())
+ .append('\n');
+ writer.append(sb.toString());
+ }
+
+ @Override
+ public void flush()
+ {
+ writer.flush();
+ }
+
+ @Override
+ public void close() throws SecurityException
+ {
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/TestTCPLateralCache.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/TestTCPLateralCache.java
new file mode 100644
index 0000000..2418ab4
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/TestTCPLateralCache.java
@@ -0,0 +1,146 @@
+package org.apache.commons.jcs3;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+
+/*
+ * 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.
+ */
+
+import junit.extensions.ActiveTestSuite;
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+/**
+ * Test which exercises the indexed disk cache. This one uses three different
+ * regions for thre threads.
+ *
+ * @version $Id$
+ */
+public class TestTCPLateralCache
+ extends TestCase
+{
+ /**
+ * Number of items to cache, twice the configured maxObjects for the memory
+ * cache regions.
+ */
+ private static int items = 200;
+
+ /**
+ * Constructor for the TestTCPLateralCache object.
+ *
+ * @param testName
+ */
+ public TestTCPLateralCache( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * A unit test suite for JUnit
+ *
+ * @return The test suite
+ */
+ public static Test suite()
+ {
+ ActiveTestSuite suite = new ActiveTestSuite();
+
+ suite.addTest( new TestTCPLateralCache( "testTcpRegion1_no_receiver" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "testTcpRegion1" );
+ }
+ } );
+
+ // suite.addTest( new TestTCPLateralCache( "testIndexedDiskCache2" )
+ // {
+ // public void runTest() throws Exception
+ // {
+ // this.runTestForRegion( "indexedRegion2" );
+ // }
+ // } );
+ //
+ // suite.addTest( new TestTCPLateralCache( "testIndexedDiskCache3" )
+ // {
+ // public void runTest() throws Exception
+ // {
+ // this.runTestForRegion( "indexedRegion3" );
+ // }
+ // } );
+
+ return suite;
+ }
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestTCPLateralCache.ccf" );
+ }
+
+ /**
+ * Adds items to cache, gets them, and removes them. The item count is more
+ * than the size of the memory cache, so items should spool to disk.
+ *
+ * @param region
+ * Name of the region to access
+ *
+ * @throws Exception
+ * If an error occurs
+ */
+ public void runTestForRegion( String region )
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+
+ // Add items to cache
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+
+ // Test that all items are in cache
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ String value = jcs.get( i + ":key" );
+
+ assertEquals( region + " data " + i, value );
+ }
+
+ // Remove all the items
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.remove( i + ":key" );
+ }
+
+ // Verify removal
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ assertNull( "Removed key should be null: " + i + ":key", jcs.get( i + ":key" ) );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/ZeroSizeCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/ZeroSizeCacheUnitTest.java
new file mode 100644
index 0000000..a277d57
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/ZeroSizeCacheUnitTest.java
@@ -0,0 +1,92 @@
+package org.apache.commons.jcs3;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ *
+ * @author Aaron Smuts
+ *
+ */
+public class ZeroSizeCacheUnitTest
+ extends TestCase
+{
+ /** number to get each loop */
+ private static int items = 20000;
+
+ /**
+ * Test setup
+ * <p>
+ * @throws Exception
+ */
+ @Override
+ public void setUp()
+ throws Exception
+ {
+ JCS.setConfigFilename( "/TestZeroSizeCache.ccf" );
+ JCS.getInstance( "testCache1" );
+ }
+
+ /**
+ * Verify that a 0 size cache does not result in errors. You should be able
+ * to disable a region this way.
+ * @throws Exception
+ *
+ */
+ public void testPutGetRemove()
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", "data" + i );
+ }
+
+ // all the gets should be null
+ for ( int i = items; i >= 0; i-- )
+ {
+ String res = jcs.get( i + ":key" );
+ assertNull( "[" + i + ":key] should be null", res );
+ }
+
+ // test removal, should be no exceptions
+ jcs.remove( "300:key" );
+
+ // allow the shrinker to run
+ Thread.sleep( 500 );
+
+ // do it again.
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", "data" + i );
+ }
+
+ for ( int i = items; i >= 0; i-- )
+ {
+ String res = jcs.get( i + ":key" );
+ assertNull( "[" + i + ":key] should be null", res );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/access/CacheAccessUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/access/CacheAccessUnitTest.java
new file mode 100644
index 0000000..ba8dbf2
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/access/CacheAccessUnitTest.java
@@ -0,0 +1,367 @@
+package org.apache.commons.jcs3.access;
+
+/*
+ * 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.
+ */
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.access.exception.ObjectExistsException;
+import org.apache.commons.jcs3.engine.CompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.ElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests the methods of the cache access class.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class CacheAccessUnitTest
+ extends TestCase
+{
+ /**
+ * Verify that we get an object exists exception if the item is in the cache.
+ * @throws Exception
+ */
+ public void testPutSafe()
+ throws Exception
+ {
+ CacheAccess<String, String> access = JCS.getInstance( "test" );
+ assertNotNull( "We should have an access class", access );
+
+ String key = "mykey";
+ String value = "myvalue";
+
+ access.put( key, value );
+
+ String returnedValue1 = access.get( key );
+ assertEquals( "Wrong value returned.", value, returnedValue1 );
+
+ try
+ {
+ access.putSafe( key, "someothervalue" );
+ fail( "We should have received an exception since this key is already in the cache." );
+ }
+ catch ( CacheException e )
+ {
+ assertTrue( "Wrong type of exception.", e instanceof ObjectExistsException );
+ assertTrue( "Should have the key in the error message.", e.getMessage().indexOf( "[" + key + "]" ) != -1 );
+ }
+
+ String returnedValue2 = access.get( key );
+ assertEquals( "Wrong value returned. Should still be the original.", value, returnedValue2 );
+ }
+
+ /**
+ * Try to put a null key and verify that we get an exception.
+ * @throws Exception
+ */
+ public void testPutNullKey()
+ throws Exception
+ {
+ CacheAccess<String, String> access = JCS.getInstance( "test" );
+ assertNotNull( "We should have an access class", access );
+
+ String key = null;
+ String value = "myvalue";
+
+ try
+ {
+ access.put( key, value );
+ fail( "Should not have been able to put a null key." );
+ }
+ catch ( CacheException e )
+ {
+ assertTrue( "Should have the word null in the error message.", e.getMessage().indexOf( "null" ) != -1 );
+ }
+ }
+
+ /**
+ * Try to put a null value and verify that we get an exception.
+ * @throws Exception
+ */
+ public void testPutNullValue()
+ throws Exception
+ {
+ CacheAccess<String, String> access = JCS.getInstance( "test" );
+ assertNotNull( "We should have an access class", access );
+
+ String key = "myKey";
+ String value = null;
+
+ try
+ {
+ access.put( key, value );
+ fail( "Should not have been able to put a null object." );
+ }
+ catch ( CacheException e )
+ {
+ assertTrue( "Should have the word null in the error message.", e.getMessage().indexOf( "null" ) != -1 );
+ }
+ }
+
+ /**
+ * Verify that elements that go in the region after this call take the new attributes.
+ * @throws Exception
+ */
+ public void testSetDefaultElementAttributes()
+ throws Exception
+ {
+ CacheAccess<String, String> access = JCS.getInstance( "test" );
+ assertNotNull( "We should have an access class", access );
+
+ long maxLife = 9876;
+ IElementAttributes attr = new ElementAttributes();
+ attr.setMaxLife(maxLife);
+
+ access.setDefaultElementAttributes( attr );
+
+ assertEquals( "Wrong element attributes.", attr.getMaxLife(), access.getDefaultElementAttributes()
+ .getMaxLife() );
+
+ String key = "mykey";
+ String value = "myvalue";
+
+ access.put( key, value );
+
+ ICacheElement<String, String> element = access.getCacheElement( key );
+
+ assertEquals( "Wrong max life. Should have the new value.", maxLife, element.getElementAttributes()
+ .getMaxLife() );
+ }
+
+ /**
+ * Verify that getCacheElements returns the elements requested based on the key.
+ * @throws Exception
+ */
+ public void testGetCacheElements()
+ throws Exception
+ {
+ //SETUP
+ CacheAccess<String, String> access = JCS.getInstance( "test" );
+ assertNotNull( "We should have an access class", access );
+
+ String keyOne = "mykeyone";
+ String keyTwo = "mykeytwo";
+ String keyThree = "mykeythree";
+ String keyFour = "mykeyfour";
+ String valueOne = "myvalueone";
+ String valueTwo = "myvaluetwo";
+ String valueThree = "myvaluethree";
+ String valueFour = "myvaluefour";
+
+ access.put( keyOne, valueOne );
+ access.put( keyTwo, valueTwo );
+ access.put( keyThree, valueThree );
+
+ Set<String> input = new HashSet<>();
+ input.add( keyOne );
+ input.add( keyTwo );
+
+ //DO WORK
+ Map<String, ICacheElement<String, String>> result = access.getCacheElements( input );
+
+ //VERIFY
+ assertEquals( "map size", 2, result.size() );
+ ICacheElement<String, String> elementOne = result.get( keyOne );
+ assertEquals( "value one", keyOne, elementOne.getKey() );
+ assertEquals( "value one", valueOne, elementOne.getVal() );
+ ICacheElement<String, String> elementTwo = result.get( keyTwo );
+ assertEquals( "value two", keyTwo, elementTwo.getKey() );
+ assertEquals( "value two", valueTwo, elementTwo.getVal() );
+
+ assertNull(access.get(keyFour));
+ String suppliedValue1 = access.get(keyFour, () -> valueFour);
+ assertNotNull( "value four", suppliedValue1);
+ assertEquals( "value four", valueFour, suppliedValue1);
+ String suppliedValue2 = access.get(keyFour);
+ assertNotNull( "value four", suppliedValue2);
+ assertEquals( "value four", suppliedValue1, suppliedValue2);
+ }
+
+ /**
+ * Verify that we can get a region using the define region method.
+ * @throws Exception
+ */
+ public void testRegionDefiniton()
+ throws Exception
+ {
+ CacheAccess<String, String> access = JCS.getInstance( "test" );
+ assertNotNull( "We should have an access class", access );
+ }
+
+ /**
+ * Verify that we can get a region using the define region method with cache attributes.
+ * @throws Exception
+ */
+ public void testRegionDefinitonWithAttributes()
+ throws Exception
+ {
+ ICompositeCacheAttributes ca = new CompositeCacheAttributes();
+
+ long maxIdleTime = 8765;
+ ca.setMaxMemoryIdleTimeSeconds( maxIdleTime );
+
+ CacheAccess<String, String> access = JCS.getInstance( "testRegionDefinitonWithAttributes", ca );
+ assertNotNull( "We should have an access class", access );
+
+ ICompositeCacheAttributes ca2 = access.getCacheAttributes();
+ assertEquals( "Wrong idle time setting.", ca.getMaxMemoryIdleTimeSeconds(), ca2.getMaxMemoryIdleTimeSeconds() );
+ }
+
+ /**
+ * Verify that we can get a region using the define region method with cache attributes and
+ * element attributes.
+ * @throws Exception
+ */
+ public void testRegionDefinitonWithBothAttributes()
+ throws Exception
+ {
+ ICompositeCacheAttributes ca = new CompositeCacheAttributes();
+
+ long maxIdleTime = 8765;
+ ca.setMaxMemoryIdleTimeSeconds( maxIdleTime );
+
+ long maxLife = 9876;
+ IElementAttributes attr = new ElementAttributes();
+ attr.setMaxLife(maxLife);
+
+ CacheAccess<String, String> access = JCS.getInstance( "testRegionDefinitonWithAttributes", ca, attr );
+ assertNotNull( "We should have an access class", access );
+
+ ICompositeCacheAttributes ca2 = access.getCacheAttributes();
+ assertEquals( "Wrong idle time setting.", ca.getMaxMemoryIdleTimeSeconds(), ca2.getMaxMemoryIdleTimeSeconds() );
+ }
+
+ /**
+ * Verify we can get some matching elements..
+ * <p>
+ * @throws Exception
+ */
+ public void testGetMatching_Normal()
+ throws Exception
+ {
+ // SETUP
+ int maxMemorySize = 1000;
+ String keyprefix1 = "MyPrefix1";
+ String keyprefix2 = "MyPrefix2";
+ String memoryCacheClassName = "org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache";
+ ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
+ cattr.setMemoryCacheName( memoryCacheClassName );
+ cattr.setMaxObjects( maxMemorySize );
+
+ long maxLife = 9876;
+ IElementAttributes attr = new ElementAttributes();
+ attr.setMaxLife(maxLife);
+
+ CacheAccess<String, Integer> access = JCS.getInstance( "testGetMatching_Normal", cattr, attr );
+
+ // DO WORK
+ int numToInsertPrefix1 = 10;
+ // insert with prefix1
+ for ( int i = 0; i < numToInsertPrefix1; i++ )
+ {
+ access.put( keyprefix1 + String.valueOf( i ), Integer.valueOf( i ) );
+ }
+
+ int numToInsertPrefix2 = 50;
+ // insert with prefix1
+ for ( int i = 0; i < numToInsertPrefix2; i++ )
+ {
+ access.put( keyprefix2 + String.valueOf( i ), Integer.valueOf( i ) );
+ }
+
+ Map<String, Integer> result1 = access.getMatching( keyprefix1 + ".+" );
+ Map<String, Integer> result2 = access.getMatching( keyprefix2 + "\\S+" );
+
+ // VERIFY
+ assertEquals( "Wrong number returned 1:", numToInsertPrefix1, result1.size() );
+ assertEquals( "Wrong number returned 2:", numToInsertPrefix2, result2.size() );
+ //System.out.println( result1 );
+
+ // verify that the elements are unwrapped
+ for (Map.Entry<String, Integer> entry : result1.entrySet())
+ {
+ Object value = entry.getValue();
+ assertFalse( "Should not be a cache element.", value instanceof ICacheElement );
+ }
+ }
+
+ /**
+ * Verify we can get some matching elements..
+ * <p>
+ * @throws Exception
+ */
+ public void testGetMatchingElements_Normal()
+ throws Exception
+ {
+ // SETUP
+ int maxMemorySize = 1000;
+ String keyprefix1 = "MyPrefix1";
+ String keyprefix2 = "MyPrefix2";
+ String memoryCacheClassName = "org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache";
+ ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
+ cattr.setMemoryCacheName( memoryCacheClassName );
+ cattr.setMaxObjects( maxMemorySize );
+
+ long maxLife = 9876;
+ IElementAttributes attr = new ElementAttributes();
+ attr.setMaxLife(maxLife);
+
+ CacheAccess<String, Integer> access = JCS.getInstance( "testGetMatching_Normal", cattr, attr );
+
+ // DO WORK
+ int numToInsertPrefix1 = 10;
+ // insert with prefix1
+ for ( int i = 0; i < numToInsertPrefix1; i++ )
+ {
+ access.put( keyprefix1 + String.valueOf( i ), Integer.valueOf( i ) );
+ }
+
+ int numToInsertPrefix2 = 50;
+ // insert with prefix1
+ for ( int i = 0; i < numToInsertPrefix2; i++ )
+ {
+ access.put( keyprefix2 + String.valueOf( i ), Integer.valueOf( i ) );
+ }
+
+ Map<String, ICacheElement<String, Integer>> result1 = access.getMatchingCacheElements( keyprefix1 + "\\S+" );
+ Map<String, ICacheElement<String, Integer>> result2 = access.getMatchingCacheElements( keyprefix2 + ".+" );
+
+ // VERIFY
+ assertEquals( "Wrong number returned 1:", numToInsertPrefix1, result1.size() );
+ assertEquals( "Wrong number returned 2:", numToInsertPrefix2, result2.size() );
+ //System.out.println( result1 );
+
+ // verify that the elements are wrapped
+ for (Map.Entry<String, ICacheElement<String, Integer>> entry : result1.entrySet())
+ {
+ Object value = entry.getValue();
+ assertTrue( "Should be a cache element.", value instanceof ICacheElement );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/access/GroupCacheAccessUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/access/GroupCacheAccessUnitTest.java
new file mode 100644
index 0000000..c690b76
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/access/GroupCacheAccessUnitTest.java
@@ -0,0 +1,241 @@
+package org.apache.commons.jcs3.access;
+
+/*
+ * 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.
+ */
+
+import java.util.Set;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.GroupCacheAccess;
+import org.apache.commons.jcs3.access.exception.CacheException;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests the methods of the group cache access class.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class GroupCacheAccessUnitTest
+ extends TestCase
+{
+ /**
+ * Verify that we can put and get an object
+ * @throws Exception
+ */
+ public void testPutAndGet()
+ throws Exception
+ {
+ GroupCacheAccess<String, String> access = JCS.getGroupCacheInstance( "test" );
+ assertNotNull( "We should have an access class", access );
+
+ String key = "mykey";
+ String group = "mygroup";
+ String value = "myvalue";
+
+ access.putInGroup(key, group, value);
+
+ String returnedValue1 = access.getFromGroup(key, group);
+ assertEquals( "Wrong value returned.", value, returnedValue1 );
+ }
+
+ /**
+ * Try to put a null key and verify that we get an exception.
+ * @throws Exception
+ */
+ public void testPutNullKey()
+ throws Exception
+ {
+ GroupCacheAccess<String, String> access = JCS.getGroupCacheInstance( "test" );
+ assertNotNull( "We should have an access class", access );
+
+ String key = null;
+ String group = "mygroup";
+ String value = "myvalue";
+
+ try
+ {
+ access.putInGroup(key, group, value);
+ fail( "Should not have been able to put a null key." );
+ }
+ catch ( CacheException e )
+ {
+ assertTrue( "Should have the word null in the error message.", e.getMessage().indexOf( "null" ) != -1 );
+ }
+ }
+
+ /**
+ * Try to put a null value and verify that we get an exception.
+ * @throws Exception
+ */
+ public void testPutNullValue()
+ throws Exception
+ {
+ GroupCacheAccess<String, String> access = JCS.getGroupCacheInstance( "test" );
+ assertNotNull( "We should have an access class", access );
+
+ String key = "myKey";
+ String group = "mygroup";
+ String value = null;
+
+ try
+ {
+ access.putInGroup(key, group, value);
+ fail( "Should not have been able to put a null object." );
+ }
+ catch ( CacheException e )
+ {
+ assertTrue( "Should have the word null in the error message.", e.getMessage().indexOf( "null" ) != -1 );
+ }
+ }
+
+ /**
+ * Verify that we can remove items from the cache
+ * @throws Exception
+ */
+ public void testRemove()
+ throws Exception
+ {
+ GroupCacheAccess<String, String> access = JCS.getGroupCacheInstance( "test" );
+ assertNotNull( "We should have an access class", access );
+
+ String key = "mykey";
+ String group = "mygroup";
+ String value = "myvalue";
+
+ for (int i = 0; i < 10; i++)
+ {
+ access.putInGroup(key + i, group, value + i);
+ }
+
+ // Make sure cache contains some data
+ for (int i = 0; i < 10; i++)
+ {
+ String returnedValue1 = access.getFromGroup(key + i, group);
+ assertEquals( "Wrong value returned.", value + i, returnedValue1 );
+ }
+
+ access.removeFromGroup(key + 0, group);
+
+ assertNull("Should not be in cache", access.getFromGroup(key + 0, group));
+
+ for (int i = 1; i < 10; i++)
+ {
+ String returnedValue1 = access.getFromGroup(key + i, group);
+ assertEquals( "Wrong value returned.", value + i, returnedValue1 );
+ }
+ }
+
+ /**
+ * Verify that we can invalidate the group
+ * @throws Exception
+ */
+ public void testInvalidate()
+ throws Exception
+ {
+ GroupCacheAccess<String, String> access = JCS.getGroupCacheInstance( "test" );
+ assertNotNull( "We should have an access class", access );
+
+ String key = "mykey";
+ String group = "mygroup";
+ String value = "myvalue";
+
+ for (int i = 0; i < 10; i++)
+ {
+ access.putInGroup(key + i, group + 0, value + i);
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ access.putInGroup(key + i, group + 1, value + i);
+ }
+
+ // Make sure cache contains some data
+ for (int i = 0; i < 10; i++)
+ {
+ String returnedValue1 = access.getFromGroup(key + i, group + 0);
+ assertEquals( "Wrong value returned.", value + i, returnedValue1 );
+ String returnedValue2 = access.getFromGroup(key + i, group + 1);
+ assertEquals( "Wrong value returned.", value + i, returnedValue2 );
+ }
+
+ access.invalidateGroup(group + 0);
+
+ for (int i = 0; i < 10; i++)
+ {
+ assertNull("Should not be in cache", access.getFromGroup(key + i, group + 0));
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ String returnedValue1 = access.getFromGroup(key + i, group + 1);
+ assertEquals( "Wrong value returned.", value + i, returnedValue1 );
+ }
+ }
+
+ /**
+ * Verify we can use the group cache.
+ * <p>
+ * @throws Exception
+ */
+ public void testGroupCache()
+ throws Exception
+ {
+ GroupCacheAccess<String, Integer> access = JCS.getGroupCacheInstance( "testGroup" );
+ String groupName1 = "testgroup1";
+ String groupName2 = "testgroup2";
+
+ Set<String> keys1 = access.getGroupKeys( groupName1 );
+ assertNotNull(keys1);
+ assertEquals(0, keys1.size());
+
+ Set<String> keys2 = access.getGroupKeys( groupName2 );
+ assertNotNull(keys2);
+ assertEquals(0, keys2.size());
+
+ // DO WORK
+ int numToInsertGroup1 = 10;
+ // insert with prefix1
+ for ( int i = 0; i < numToInsertGroup1; i++ )
+ {
+ access.putInGroup(String.valueOf( i ), groupName1, Integer.valueOf( i ) );
+ }
+
+ int numToInsertGroup2 = 50;
+ // insert with prefix1
+ for ( int i = 0; i < numToInsertGroup2; i++ )
+ {
+ access.putInGroup(String.valueOf( i ), groupName2, Integer.valueOf( i + 1 ) );
+ }
+
+ keys1 = access.getGroupKeys( groupName1 ); // Test for JCS-102
+ assertNotNull(keys1);
+ assertEquals("Wrong number returned 1:", 10, keys1.size());
+
+ keys2 = access.getGroupKeys( groupName2 );
+ assertNotNull(keys2);
+ assertEquals("Wrong number returned 2:", 50, keys2.size());
+
+ assertEquals(Integer.valueOf(5), access.getFromGroup("5", groupName1));
+ assertEquals(Integer.valueOf(6), access.getFromGroup("5", groupName2));
+
+ assertTrue(access.getGroupNames().contains(groupName1));
+ assertTrue(access.getGroupNames().contains(groupName2));
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/access/SystemPropertyUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/access/SystemPropertyUnitTest.java
new file mode 100644
index 0000000..f5878b6
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/access/SystemPropertyUnitTest.java
@@ -0,0 +1,90 @@
+package org.apache.commons.jcs3.access;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+
+/**
+ * This test is for the system property usage in configuration values.
+ *
+ * @author Aaron Smuts
+ *
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class SystemPropertyUnitTest
+ extends TestCase
+{
+
+ /**
+ * Verify that we use a system property for a ${FOO} string in a value.
+ *
+ * @throws Exception
+ *
+ */
+ public void test1SystemPropertyInValueDelimiter()
+ throws Exception
+ {
+
+ int maxMemory = 1234;
+ System.getProperties().setProperty( "MY_SYSTEM_PROPERTY_DISK_DIR", "system_set" );
+ System.getProperties().setProperty( "MY_SYSTEM_PROPERTY_MAX_SIZE", String.valueOf( maxMemory ) );
+
+ JCS.setConfigFilename( "/TestSystemProperties.ccf" );
+
+ CacheAccess<String, String> cache = JCS.getInstance( "test1" );
+ assertEquals( "We should have used the system property for the memory size", maxMemory, cache
+ .getCacheAttributes().getMaxObjects() );
+
+ System.clearProperty("MY_SYSTEM_PROPERTY_DISK_DIR");
+ System.clearProperty("MY_SYSTEM_PROPERTY_MAX_SIZE");
+ }
+
+ /**
+ * Verify that we use a system property for a ${FOO} string in a value. We
+ * define a propety in the cache.ccf file, but we do not have it as a system
+ * property. The default value should be used, if one exists.
+ *
+ * @throws Exception
+ *
+ */
+ public void test2SystemPropertyMissingInValueDelimeter()
+ throws Exception
+ {
+ System.getProperties().setProperty( "MY_SYSTEM_PROPERTY_DISK_DIR", "system_set" );
+
+ CompositeCacheManager mgr = CompositeCacheManager.getUnconfiguredInstance();
+ mgr.configure( "/TestSystemProperties.ccf" );
+
+ CacheAccess<String, String> cache = JCS.getInstance( "missing" );
+ // TODO check against the actual default def
+ assertEquals( "We should have used the default property for the memory size", 100, cache.getCacheAttributes()
+ .getMaxObjects() );
+
+ System.clearProperty("MY_SYSTEM_PROPERTY_DISK_DIR");
+
+ }
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/access/TestCacheAccess.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/access/TestCacheAccess.java
new file mode 100644
index 0000000..c08f64a
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/access/TestCacheAccess.java
@@ -0,0 +1,959 @@
+package org.apache.commons.jcs3.access;
+
+/*
+ * 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.
+ */
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Random;
+import java.util.StringTokenizer;
+
+import org.apache.commons.jcs3.engine.control.event.ElementEventHandlerMockImpl;
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.access.GroupCacheAccess;
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.engine.ElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * Allows the user to run common cache commands from the command line for a test cache. This also
+ * provide basic methods for use in unit tests.
+ */
+public class TestCacheAccess
+{
+ /** log instance */
+ private static final Log log = LogManager.getLog( TestCacheAccess.class );
+
+ /** cache instance to use in testing */
+ private CacheAccess<String, String> cache_control = null;
+
+ /** cache instance to use in testing */
+ private GroupCacheAccess<String, String> group_cache_control = null;
+
+ /** do we use system.out.println to print out debug data? */
+ private static boolean isSysOut = false;
+
+ /** Construct and initialize the cachecontrol based on the config file. */
+ public TestCacheAccess()
+ {
+ this( "testCache1" );
+ }
+
+ /**
+ * @param regionName the name of the region.
+ */
+ public TestCacheAccess( String regionName )
+ {
+ try
+ {
+ cache_control = JCS.getInstance( regionName );
+ group_cache_control = JCS.getGroupCacheInstance( regionName );
+ }
+ catch ( Exception e )
+ {
+ log.error( "Problem getting cache instance", e );
+ p( e.toString() );
+ }
+ }
+
+ /**
+ * This is the main loop called by the main method.
+ */
+ public void runLoop()
+ {
+ try
+ {
+ // process user input till done
+ boolean notDone = true;
+ String message = null;
+ // wait to dispose
+ BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) );
+
+ help();
+
+ while ( notDone )
+ {
+ p( "enter command:" );
+
+ message = br.readLine();
+
+ if ( message == null || message.startsWith( "help" ) )
+ {
+ help();
+ }
+ else if ( message.startsWith( "gc" ) )
+ {
+ System.gc();
+ }
+ else if ( message.startsWith( "getAttributeNames" ) )
+ {
+ long n_start = System.currentTimeMillis();
+ String groupName = null;
+ StringTokenizer toke = new StringTokenizer( message );
+ int tcnt = 0;
+ while ( toke.hasMoreElements() )
+ {
+ tcnt++;
+ String t = (String) toke.nextElement();
+ if ( tcnt == 2 )
+ {
+ groupName = t.trim();
+ }
+ }
+ getAttributeNames( groupName );
+ long n_end = System.currentTimeMillis();
+ p( "---got attrNames for " + groupName + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
+ }
+ else if ( message.startsWith( "shutDown" ) )
+ {
+ CompositeCacheManager.getInstance().shutDown();
+ //cache_control.dispose();
+ notDone = false;
+ //System.exit( -1 );
+ return;
+ }
+ /////////////////////////////////////////////////////////////////////
+ // get multiple from a region
+ else if ( message.startsWith( "getm" ) )
+ {
+ processGetMultiple( message );
+ }
+ else if ( message.startsWith( "getg" ) )
+ {
+ processGetGroup( message );
+ }
+ else if ( message.startsWith( "getag" ) )
+ {
+ processGetAutoGroup( message );
+ }
+ else if ( message.startsWith( "getMatching" ) )
+ {
+ processGetMatching( message );
+ }
+ else if ( message.startsWith( "get" ) )
+ {
+ processGet( message );
+ }
+ else if ( message.startsWith( "putg" ) )
+ {
+ processPutGroup( message );
+ }
+ // put automatically
+ else if ( message.startsWith( "putag" ) )
+ {
+ processPutAutoGroup( message );
+ }
+ else if ( message.startsWith( "putm" ) )
+ {
+ String numS = message.substring( message.indexOf( " " ) + 1, message.length() );
+ if ( numS == null )
+ {
+ p( "usage: putm numbertoput" );
+ }
+ else
+ {
+ int num = Integer.parseInt( numS.trim() );
+ putMultiple( num );
+ }
+ }
+ else if ( message.startsWith( "pute" ) )
+ {
+ String numS = message.substring( message.indexOf( " " ) + 1, message.length() );
+ if ( numS == null )
+ {
+ p( "usage: putme numbertoput" );
+ }
+ else
+ {
+ int num = Integer.parseInt( numS.trim() );
+ long n_start = System.currentTimeMillis();
+ for ( int n = 0; n < num; n++ )
+ {
+ IElementAttributes attrp = cache_control.getDefaultElementAttributes();
+ ElementEventHandlerMockImpl hand = new ElementEventHandlerMockImpl();
+ attrp.addElementEventHandler( hand );
+ cache_control.put( "key" + n, "data" + n + " put from ta = junk", attrp );
+ }
+ long n_end = System.currentTimeMillis();
+ p( "---put " + num + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
+ }
+ }
+ else if ( message.startsWith( "put" ) )
+ {
+ processPut( message );
+ }
+ else if ( message.startsWith( "removem" ) )
+ {
+ String numS = message.substring( message.indexOf( " " ) + 1, message.length() );
+ if ( numS == null )
+ {
+ p( "usage: removem numbertoremove" );
+ }
+ else
+ {
+ int num = Integer.parseInt( numS.trim() );
+ removeMultiple( num );
+ }
+ }
+ else if ( message.startsWith( "removeall" ) )
+ {
+ cache_control.clear();
+ p( "removed all" );
+ }
+ else if ( message.startsWith( "remove" ) )
+ {
+ String key = message.substring( message.indexOf( " " ) + 1, message.length() );
+ cache_control.remove( key );
+ p( "removed " + key );
+ }
+ else if ( message.startsWith( "deattr" ) )
+ {
+ IElementAttributes ae = cache_control.getDefaultElementAttributes();
+ p( "Default IElementAttributes " + ae );
+ }
+ else if ( message.startsWith( "cloneattr" ) )
+ {
+ String numS = message.substring( message.indexOf( " " ) + 1, message.length() );
+ if ( numS == null )
+ {
+ p( "usage: put numbertoput" );
+ }
+ else
+ {
+ int num = Integer.parseInt( numS.trim() );
+ IElementAttributes attrp = new ElementAttributes();
+ long n_start = System.currentTimeMillis();
+ for ( int n = 0; n < num; n++ )
+ {
+ attrp.clone();
+ }
+ long n_end = System.currentTimeMillis();
+ p( "---cloned attr " + num + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
+ }
+ }
+ else if ( message.startsWith( "switch" ) )
+ {
+ String name = message.substring( message.indexOf( " " ) + 1, message.length() );
+
+ setRegion( name );
+ p( "switched to cache = " + name );
+ p( cache_control.toString() );
+ }
+ else if ( message.startsWith( "stats" ) )
+ {
+ p( cache_control.getStats() );
+ }
+ else if ( message.startsWith( "gc" ) )
+ {
+ System.gc();
+ p( "Called system.gc()" );
+ }
+ else if ( message.startsWith( "random" ) )
+ {
+ processRandom( message );
+ }
+ }
+ }
+ catch ( CacheException | IOException e )
+ {
+ p( e.toString() );
+ e.printStackTrace( System.out );
+ }
+ }
+
+ /**
+ * @param message
+ */
+ private void processGetMultiple( String message )
+ {
+ int num = 0;
+ boolean show = true;
+
+ StringTokenizer toke = new StringTokenizer( message );
+ int tcnt = 0;
+ while ( toke.hasMoreElements() )
+ {
+ tcnt++;
+ String t = (String) toke.nextElement();
+ if ( tcnt == 2 )
+ {
+ try
+ {
+ num = Integer.parseInt( t.trim() );
+ }
+ catch ( NumberFormatException nfe )
+ {
+ p( t + "not a number" );
+ }
+ }
+ else if ( tcnt == 3 )
+ {
+ show = Boolean.valueOf( t ).booleanValue();
+ }
+ }
+
+ if ( tcnt < 2 )
+ {
+ p( "usage: get numbertoget show values[true|false]" );
+ }
+ else
+ {
+ getMultiple( num, show );
+ }
+ }
+
+ /**
+ * @param message
+ */
+ private void processGetGroup( String message )
+ {
+ String key = null;
+ String group = null;
+ boolean show = true;
+
+ StringTokenizer toke = new StringTokenizer( message );
+ int tcnt = 0;
+ while ( toke.hasMoreElements() )
+ {
+ tcnt++;
+ String t = (String) toke.nextElement();
+ if ( tcnt == 2 )
+ {
+ key = t.trim();
+ }
+ else if ( tcnt == 3 )
+ {
+ group = t.trim();
+ }
+ else if ( tcnt == 4 )
+ {
+ show = Boolean.valueOf( t ).booleanValue();
+ }
+ }
+
+ if ( tcnt < 2 )
+ {
+ p( "usage: get key show values[true|false]" );
+ }
+ else
+ {
+ long n_start = System.currentTimeMillis();
+ try
+ {
+ Object obj = group_cache_control.getFromGroup( key, group );
+ if ( show && obj != null )
+ {
+ p( obj.toString() );
+ }
+ }
+ catch ( Exception e )
+ {
+ log.error( e );
+ }
+ long n_end = System.currentTimeMillis();
+ p( "---got " + key + " from group " + group + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
+ }
+ }
+
+ /**
+ * @param message
+ */
+ private void processGetAutoGroup( String message )
+ {
+ // get auto from group
+
+ int num = 0;
+ String group = null;
+ boolean show = true;
+
+ StringTokenizer toke = new StringTokenizer( message );
+ int tcnt = 0;
+ while ( toke.hasMoreElements() )
+ {
+ tcnt++;
+ String t = (String) toke.nextElement();
+ if ( tcnt == 2 )
+ {
+ num = Integer.parseInt( t.trim() );
+ }
+ else if ( tcnt == 3 )
+ {
+ group = t.trim();
+ }
+ else if ( tcnt == 4 )
+ {
+ show = Boolean.valueOf( t ).booleanValue();
+ }
+ }
+
+ if ( tcnt < 2 )
+ {
+ p( "usage: get key show values[true|false]" );
+ }
+ else
+ {
+ long n_start = System.currentTimeMillis();
+ try
+ {
+ for ( int a = 0; a < num; a++ )
+ {
+ Object obj = group_cache_control.getFromGroup( "keygr" + a, group );
+ if ( show && obj != null )
+ {
+ p( obj.toString() );
+ }
+ }
+ }
+ catch ( Exception e )
+ {
+ log.error( e );
+ }
+ long n_end = System.currentTimeMillis();
+ p( "---got " + num + " from group " + group + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
+ }
+ }
+
+ /**
+ * @param message
+ * @throws CacheException
+ */
+ private void processPutGroup( String message )
+ throws CacheException
+ {
+ String group = null;
+ String key = null;
+ StringTokenizer toke = new StringTokenizer( message );
+ int tcnt = 0;
+ while ( toke.hasMoreElements() )
+ {
+ tcnt++;
+ String t = (String) toke.nextElement();
+ if ( tcnt == 2 )
+ {
+ key = t.trim();
+ }
+ else if ( tcnt == 3 )
+ {
+ group = t.trim();
+ }
+ }
+
+ if ( tcnt < 3 )
+ {
+ p( "usage: putg key group" );
+ }
+ else
+ {
+ long n_start = System.currentTimeMillis();
+ group_cache_control.putInGroup( key, group, "data from putg ----asdfasfas-asfasfas-asfas in group " + group );
+ long n_end = System.currentTimeMillis();
+ p( "---put " + key + " in group " + group + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
+ }
+ }
+
+ /**
+ * @param message
+ * @throws CacheException
+ */
+ private void processPutAutoGroup( String message )
+ throws CacheException
+ {
+ String group = null;
+ int num = 0;
+ StringTokenizer toke = new StringTokenizer( message );
+ int tcnt = 0;
+ while ( toke.hasMoreElements() )
+ {
+ tcnt++;
+ String t = (String) toke.nextElement();
+ if ( tcnt == 2 )
+ {
+ num = Integer.parseInt( t.trim() );
+ }
+ else if ( tcnt == 3 )
+ {
+ group = t.trim();
+ }
+ }
+
+ if ( tcnt < 3 )
+ {
+ p( "usage: putag num group" );
+ }
+ else
+ {
+ long n_start = System.currentTimeMillis();
+ for ( int a = 0; a < num; a++ )
+ {
+ group_cache_control.putInGroup( "keygr" + a, group, "data " + a
+ + " from putag ----asdfasfas-asfasfas-asfas in group " + group );
+ }
+ long n_end = System.currentTimeMillis();
+ p( "---put " + num + " in group " + group + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
+ }
+ }
+
+ /**
+ * @param message
+ * @throws CacheException
+ */
+ private void processPut( String message )
+ throws CacheException
+ {
+ String key = null;
+ String val = null;
+ StringTokenizer toke = new StringTokenizer( message );
+ int tcnt = 0;
+ while ( toke.hasMoreElements() )
+ {
+ tcnt++;
+ String t = (String) toke.nextElement();
+ if ( tcnt == 2 )
+ {
+ key = t.trim();
+ }
+ else if ( tcnt == 3 )
+ {
+ val = t.trim();
+ }
+ }
+
+ if ( tcnt < 3 )
+ {
+ p( "usage: put key val" );
+ }
+ else
+ {
+
+ long n_start = System.currentTimeMillis();
+ cache_control.put( key, val );
+ long n_end = System.currentTimeMillis();
+ p( "---put " + key + " | " + val + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
+ }
+ }
+
+ /**
+ * @param message
+ */
+ private void processRandom( String message )
+ {
+ String rangeS = "";
+ String numOpsS = "";
+ boolean show = true;
+
+ StringTokenizer toke = new StringTokenizer( message );
+ int tcnt = 0;
+ while ( toke.hasMoreElements() )
+ {
+ tcnt++;
+ String t = (String) toke.nextElement();
+ if ( tcnt == 2 )
+ {
+ rangeS = t.trim();
+ }
+ else if ( tcnt == 3 )
+ {
+ numOpsS = t.trim();
+ }
+ else if ( tcnt == 4 )
+ {
+ show = Boolean.valueOf( t ).booleanValue();
+ }
+ }
+
+ String numS = message.substring( message.indexOf( " " ) + 1, message.length() );
+
+ int range = 0;
+ int numOps = 0;
+ try
+ {
+ range = Integer.parseInt( rangeS.trim() );
+ numOps = Integer.parseInt( numOpsS.trim() );
+ }
+ catch ( Exception e )
+ {
+ p( "usage: random range numOps show" );
+ p( "ex. random 100 1000 false" );
+ }
+ if ( numS == null )
+ {
+ p( "usage: random range numOps show" );
+ p( "ex. random 100 1000 false" );
+ }
+ else
+ {
+ random( range, numOps, show );
+ }
+ }
+
+ /**
+ * @param message
+ */
+ private void processGet( String message )
+ {
+ // plain old get
+
+ String key = null;
+ boolean show = true;
+
+ StringTokenizer toke = new StringTokenizer( message );
+ int tcnt = 0;
+ while ( toke.hasMoreElements() )
+ {
+ tcnt++;
+ String t = (String) toke.nextElement();
+ if ( tcnt == 2 )
+ {
+ key = t.trim();
+ }
+ else if ( tcnt == 3 )
+ {
+ show = Boolean.valueOf( t ).booleanValue();
+ }
+ }
+
+ if ( tcnt < 2 )
+ {
+ p( "usage: get key show values[true|false]" );
+ }
+ else
+ {
+ long n_start = System.currentTimeMillis();
+ try
+ {
+ Object obj = cache_control.get( key );
+ if ( show && obj != null )
+ {
+ p( obj.toString() );
+ }
+ }
+ catch ( Exception e )
+ {
+ log.error( e );
+ }
+ long n_end = System.currentTimeMillis();
+ p( "---got " + key + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
+ }
+ }
+
+ /**
+ * @param message
+ */
+ private void processGetMatching( String message )
+ {
+ // plain old get
+
+ String pattern = null;
+ boolean show = true;
+
+ StringTokenizer toke = new StringTokenizer( message );
+ int tcnt = 0;
+ while ( toke.hasMoreElements() )
+ {
+ tcnt++;
+ String t = (String) toke.nextElement();
+ if ( tcnt == 2 )
+ {
+ pattern = t.trim();
+ }
+ else if ( tcnt == 3 )
+ {
+ show = Boolean.valueOf( t ).booleanValue();
+ }
+ }
+
+ if ( tcnt < 2 )
+ {
+ p( "usage: getMatching key show values[true|false]" );
+ }
+ else
+ {
+ long n_start = System.currentTimeMillis();
+ try
+ {
+ Map<String, String> results = cache_control.getMatching( pattern );
+ if ( show && results != null )
+ {
+ p( results.toString() );
+ }
+ }
+ catch ( Exception e )
+ {
+ log.error( e );
+ }
+ long n_end = System.currentTimeMillis();
+ p( "---gotMatching [" + pattern + "] in " + String.valueOf( n_end - n_start ) + " millis ---" );
+ }
+ }
+
+ /**
+ * Test harness.
+ * @param args The command line arguments
+ */
+ public static void main( String[] args )
+ {
+ isSysOut = true;
+ String ccfFileName = args[0];
+ if ( ccfFileName != null )
+ {
+ JCS.setConfigFilename( ccfFileName );
+ }
+ TestCacheAccess tca = new TestCacheAccess( "testCache1" );
+ tca.runLoop();
+ }
+
+ // end main
+ /////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Gets multiple items from the cache with keys of the form key1, key2, key3 up to key[num].
+ * @param num int
+ */
+ public void getMultiple( int num )
+ {
+ getMultiple( num, false );
+ }
+
+ /**
+ * @param num
+ * @param show
+ */
+ public void getMultiple( int num, boolean show )
+ {
+ long n_start = System.currentTimeMillis();
+ for ( int n = 0; n < num; n++ )
+ {
+ try
+ {
+ Object obj = cache_control.get( "key" + n );
+ if ( show && obj != null )
+ {
+ p( obj.toString() );
+ }
+ }
+ catch ( Exception e )
+ {
+ log.error( e );
+ }
+ }
+ long n_end = System.currentTimeMillis();
+ p( "---got " + num + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
+ }
+
+ /**
+ * Puts multiple items into the cache.
+ * @param num int
+ */
+ public void putMultiple( int num )
+ {
+ try
+ {
+ long n_start = System.currentTimeMillis();
+ for ( int n = 0; n < num; n++ )
+ {
+ cache_control.put( "key" + n, "data" + n + " put from ta = junk" );
+ }
+ long n_end = System.currentTimeMillis();
+ p( "---put " + num + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
+ }
+ catch ( Exception e )
+ {
+ log.error( e );
+ }
+ }
+
+ /**
+ * Removes multiple items from the cache.
+ * @param num int
+ */
+ public void removeMultiple( int num )
+ {
+ try
+ {
+ long n_start = System.currentTimeMillis();
+ for ( int n = 0; n < num; n++ )
+ {
+ cache_control.remove( "key" + n );
+ }
+ long n_end = System.currentTimeMillis();
+ p( "---removed " + num + " in " + String.valueOf( n_end - n_start ) + " millis ---" );
+ }
+ catch ( Exception e )
+ {
+ log.error( e );
+ }
+ }
+
+ /**
+ * The random method performs numOps number of operations. The operations will be a mix of puts,
+ * gets, and removes. The key range will be from 0 to range.
+ * @param range int The end of the key range.
+ * @param numOps int The number of operations to perform
+ */
+ public void random( int range, int numOps )
+ {
+ random( range, numOps, false );
+ }
+
+ /**
+ * @param range
+ * @param numOps
+ * @param show
+ */
+ public void random( int range, int numOps, boolean show )
+ {
+ try
+ {
+ for ( int i = 1; i < numOps; i++ )
+ {
+ Random ran = new Random( i );
+ int n = ran.nextInt( 4 );
+ int kn = ran.nextInt( range );
+ String key = "key" + kn;
+ if ( n == 1 )
+ {
+ cache_control.put( key, "data" + i + " junk asdfffffffadfasdfasf " + kn + ":" + n );
+ if ( show )
+ {
+ p( "put " + key );
+ }
+ }
+ else if ( n == 2 )
+ {
+ cache_control.remove( key );
+ if ( show )
+ {
+ p( "removed " + key );
+ }
+ }
+ else
+ {
+ // slightly greater chance of get
+ Object obj = cache_control.get( key );
+ if ( show && obj != null )
+ {
+ p( obj.toString() );
+ }
+ }
+
+ if ( i % 10000 == 0 )
+ {
+ p( cache_control.getStats() );
+ }
+
+ }
+ p( "Finished random cycle of " + numOps );
+ }
+ catch ( Exception e )
+ {
+ p( e.toString() );
+ e.printStackTrace( System.out );
+ }
+ }
+
+ /**
+ * Sets the region to be used by test methods.
+ * @param name String -- Name of region
+ */
+ public void setRegion( String name )
+ {
+ try
+ {
+ cache_control = JCS.getInstance( name );
+ }
+ catch ( Exception e )
+ {
+ p( e.toString() );
+ e.printStackTrace( System.out );
+ }
+
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * The tester will print to the console if isSysOut is true, else it will log. It is false by
+ * default. When run via the main method, isSysOut will be set to true
+ * @param s String to print or log
+ */
+ public static void p( String s )
+ {
+ if ( isSysOut )
+ {
+ System.out.println( s );
+ }
+ else
+ {
+ if ( log.isDebugEnabled() )
+ {
+ log.debug( s );
+ }
+ }
+ }
+
+ /**
+ * Displays usage information for command line testing.
+ */
+ public static void help()
+ {
+ p( "\n\n\n\n" );
+ p( "type 'shutDown' to shutdown the cache" );
+ p( "type 'getm num show[false|true]' to get num automatically from a region" );
+ p( "type 'putm num' to put num automatically to a region" );
+ p( "type 'removeall' to remove all items in a region" );
+ p( "type 'remove key' to remove" );
+ p( "type 'removem num' to remove a number automatically" );
+ p( "type 'getMatching pattern show' to getMatching" );
+ p( "type 'get key show' to get" );
+ p( "type 'getg key group show' to get" );
+ p( "type 'getag num group show' to get automatically from a group" );
+ p( "type 'getAttributeNames group' to get a list og the group elements" );
+ p( "type 'putg key group val' to put" );
+ p( "type 'putag num group' to put automatically from a group" );
+ p( "type 'put key val' to put" );
+ p( "type 'stats' to get stats" );
+ p( "type 'deattr' to get the default element attributes" );
+ p( "type 'cloneattr num' to clone attr" );
+ p( "type 'random range numOps' to put, get, and remove randomly" );
+ p( "type 'switch name' to switch to this region name" );
+ p( "type 'gc' to call System.gc()" );
+ p( "type 'help' for commands" );
+
+ }
+
+ /**
+ * Gets the attributeNames attribute of the TestCacheAccess class
+ * @param groupName
+ */
+ public void getAttributeNames( String groupName )
+ {
+ Iterator<String> iter = group_cache_control.getGroupKeys( groupName ).iterator();
+
+ while ( iter.hasNext() )
+ {
+ p( "=" + iter.next() );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/admin/AdminBeanUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/admin/AdminBeanUnitTest.java
new file mode 100644
index 0000000..ef7a0bb
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/admin/AdminBeanUnitTest.java
@@ -0,0 +1,176 @@
+package org.apache.commons.jcs3.admin;
+
+/*
+ * 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.
+ */
+
+import java.util.List;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.admin.CacheElementInfo;
+import org.apache.commons.jcs3.admin.CacheRegionInfo;
+import org.apache.commons.jcs3.admin.JCSAdminBean;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Test the admin bean that is used by the JCSAdmin.jsp
+ *
+ * @author Aaron Smuts
+ *
+ */
+public class AdminBeanUnitTest
+ extends TestCase
+{
+
+ /**
+ * Create a test region and then verify that we get it from the list.
+ *
+ * @throws Exception
+ *
+ */
+ public void testGetRegionInfo()
+ throws Exception
+ {
+ String regionName = "myRegion";
+ CacheAccess<String, String> cache = JCS.getInstance( regionName );
+
+ cache.put( "key", "value" );
+
+ JCSAdminBean admin = new JCSAdminBean();
+
+ List<CacheRegionInfo> regions = admin.buildCacheInfo();
+
+ boolean foundRegion = false;
+
+ for (CacheRegionInfo info : regions)
+ {
+
+ if ( info.getCacheName().equals( regionName ) )
+ {
+ foundRegion = true;
+
+ assertTrue( "Byte count should be greater than 5.", info.getByteCount() > 5 );
+
+ assertNotNull( "Should have stats.", info.getCacheStatistics() );
+ }
+ }
+
+ assertTrue( "Should have found the region we just created.", foundRegion );
+ }
+
+ /**
+ * Put a value in a region and verify that it shows up.
+ *
+ * @throws Exception
+ */
+ public void testGetElementForRegionInfo()
+ throws Exception
+ {
+ String regionName = "myRegion";
+ CacheAccess<String, String> cache = JCS.getInstance( regionName );
+
+ // clear the region
+ cache.clear();
+
+ String key = "myKey";
+ cache.put( key, "value" );
+
+ JCSAdminBean admin = new JCSAdminBean();
+
+ List<CacheElementInfo> elements = admin.buildElementInfo( regionName );
+ assertEquals( "Wrong number of elements in the region.", 1, elements.size() );
+
+ CacheElementInfo elementInfo = elements.get(0);
+ assertEquals( "Wrong key." + elementInfo, key, elementInfo.getKey() );
+ }
+
+ /**
+ * Remove an item via the remove method.
+ *
+ * @throws Exception
+ */
+ public void testRemove()
+ throws Exception
+ {
+ JCSAdminBean admin = new JCSAdminBean();
+
+ String regionName = "myRegion";
+ CacheAccess<String, String> cache = JCS.getInstance( regionName );
+
+ // clear the region
+ cache.clear();
+ admin.clearRegion( regionName );
+
+ String key = "myKey";
+ cache.put( key, "value" );
+
+ List<CacheElementInfo> elements = admin.buildElementInfo( regionName );
+ assertEquals( "Wrong number of elements in the region.", 1, elements.size() );
+
+ CacheElementInfo elementInfo = elements.get(0);
+ assertEquals( "Wrong key.", key, elementInfo.getKey() );
+
+ admin.removeItem( regionName, key );
+
+ List<CacheElementInfo> elements2 = admin.buildElementInfo( regionName );
+ assertEquals( "Wrong number of elements in the region after remove.", 0, elements2.size() );
+ }
+
+ /**
+ * Add an item to a region. Call clear all and verify that it doesn't exist.
+ *
+ * @throws Exception
+ */
+ public void testClearAll()
+ throws Exception
+ {
+ JCSAdminBean admin = new JCSAdminBean();
+
+ String regionName = "myRegion";
+ CacheAccess<String, String> cache = JCS.getInstance( regionName );
+
+ String key = "myKey";
+ cache.put( key, "value" );
+
+ admin.clearAllRegions();
+
+ List<CacheElementInfo> elements2 = admin.buildElementInfo( regionName );
+ assertEquals( "Wrong number of elements in the region after remove.", 0, elements2.size() );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/admin/CountingStreamUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/admin/CountingStreamUnitTest.java
new file mode 100644
index 0000000..ddd4722
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/admin/CountingStreamUnitTest.java
@@ -0,0 +1,79 @@
+package org.apache.commons.jcs3.admin;
+
+import org.apache.commons.jcs3.admin.CountingOnlyOutputStream;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for the counting only output stream.
+ *
+ * @author Aaron Smuts
+ *
+ */
+public class CountingStreamUnitTest
+ extends TestCase
+{
+
+ /**
+ * Write a single byte and verify the count.
+ *
+ * @throws Exception
+ */
+ public void testSingleByte() throws Exception
+ {
+ CountingOnlyOutputStream out = new CountingOnlyOutputStream();
+ out.write( 1 );
+ assertEquals( "Wrong number of bytes written.", 1, out.getCount() );
+ out.write( 1 );
+ assertEquals( "Wrong number of bytes written.", 2, out.getCount() );
+ out.close();
+ }
+
+ /**
+ * This should count the size of the array.
+ *
+ * @throws Exception
+ */
+ public void testByteArray() throws Exception
+ {
+ CountingOnlyOutputStream out = new CountingOnlyOutputStream();
+ byte[] array = new byte[]{1,2,3,4,5};
+ out.write( array );
+ assertEquals( "Wrong number of bytes written.", array.length, out.getCount() );
+ out.close();
+ }
+
+ /**
+ * This should count the len -- the third arg
+ *
+ * @throws Exception
+ */
+ public void testByteArrayLenCount() throws Exception
+ {
+ CountingOnlyOutputStream out = new CountingOnlyOutputStream();
+ byte[] array = new byte[]{1,2,3,4,5};
+ int len = 3;
+ out.write( array, 0, len );
+ assertEquals( "Wrong number of bytes written.", len, out.getCount() );
+ out.close();
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/admin/TestJMX.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/admin/TestJMX.java
new file mode 100644
index 0000000..2f1c518
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/admin/TestJMX.java
@@ -0,0 +1,38 @@
+package org.apache.commons.jcs3.admin;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+
+/**
+ * Helper class to test the JMX registration
+ */
+public class TestJMX
+{
+ public static void main(String[] args) throws Exception
+ {
+ CacheAccess<String, String> cache = JCS.getInstance("test");
+
+ cache.put("key", "value");
+ System.out.println("Waiting...");
+ Thread.sleep(Long.MAX_VALUE);
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/AuxiliaryCacheConfiguratorUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/AuxiliaryCacheConfiguratorUnitTest.java
new file mode 100644
index 0000000..cd0dee0
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/AuxiliaryCacheConfiguratorUnitTest.java
@@ -0,0 +1,131 @@
+package org.apache.commons.jcs3.auxiliary;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import org.apache.commons.jcs3.engine.control.MockElementSerializer;
+import org.apache.commons.jcs3.engine.logging.MockCacheEventLogger;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheConfigurator;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+
+import java.util.Properties;
+
+/** Unit tests for the auxiliary cache configurator. */
+public class AuxiliaryCacheConfiguratorUnitTest
+ extends TestCase
+{
+ /**
+ * Verify that we don't get an error.
+ */
+ public void testParseCacheEventLogger_Null()
+ {
+ // SETUP
+ Properties props = new Properties();
+
+ // DO WORK
+ MockCacheEventLogger result = (MockCacheEventLogger) AuxiliaryCacheConfigurator.parseCacheEventLogger( props,
+ "junk" );
+
+ // VERIFY
+ assertNull( "Should not have a logger.", result );
+ }
+
+ /**
+ * Verify that we don't get an error.
+ */
+ public void testParseCacheEventLogger_NullName()
+ {
+ // SETUP
+ Properties props = new Properties();
+
+ // DO WORK
+ MockCacheEventLogger result = (MockCacheEventLogger) AuxiliaryCacheConfigurator.parseCacheEventLogger( props,
+ null );
+
+ // VERIFY
+ assertNull( "Should not have a logger.", result );
+ }
+
+ /**
+ * Verify that we can parse the event logger.
+ */
+ public void testParseCacheEventLogger_Normal()
+ {
+ // SETUP
+ String auxPrefix = "jcs.auxiliary." + "MYAux";
+ String testPropertyValue = "This is the value";
+ String className = MockCacheEventLogger.class.getName();
+
+ Properties props = new Properties();
+ props.put( auxPrefix + AuxiliaryCacheConfigurator.CACHE_EVENT_LOGGER_PREFIX, className );
+ props.put( auxPrefix + AuxiliaryCacheConfigurator.CACHE_EVENT_LOGGER_PREFIX
+ + AuxiliaryCacheConfigurator.ATTRIBUTE_PREFIX + ".testProperty", testPropertyValue );
+
+ // DO WORK
+ MockCacheEventLogger result = (MockCacheEventLogger) AuxiliaryCacheConfigurator
+ .parseCacheEventLogger( props, auxPrefix );
+
+ // VERIFY
+ assertNotNull( "Should have a logger.", result );
+ assertEquals( "Property should be set.", testPropertyValue, result.getTestProperty() );
+ }
+
+ /**
+ * Verify that we can parse the ElementSerializer.
+ */
+ public void testParseElementSerializer_Normal()
+ {
+ // SETUP
+ String auxPrefix = "jcs.auxiliary." + "MYAux";
+ String testPropertyValue = "This is the value";
+ String className = MockElementSerializer.class.getName();
+
+ Properties props = new Properties();
+ props.put( auxPrefix + AuxiliaryCacheConfigurator.SERIALIZER_PREFIX, className );
+ props.put( auxPrefix + AuxiliaryCacheConfigurator.SERIALIZER_PREFIX
+ + AuxiliaryCacheConfigurator.ATTRIBUTE_PREFIX + ".testProperty", testPropertyValue );
+
+ // DO WORK
+ MockElementSerializer result = (MockElementSerializer) AuxiliaryCacheConfigurator
+ .parseElementSerializer( props, auxPrefix );
+
+ // VERIFY
+ assertNotNull( "Should have a Serializer.", result );
+ assertEquals( "Property should be set.", testPropertyValue, result.getTestProperty() );
+ }
+
+ /**
+ * Verify that we can parse the ElementSerializer.
+ */
+ public void testParseElementSerializer_Null()
+ {
+ // SETUP
+ Properties props = new Properties();
+
+ // DO WORK
+ IElementSerializer result = AuxiliaryCacheConfigurator
+ .parseElementSerializer( props, "junk" );
+
+ // VERIFY
+ assertTrue( "Should have the default Serializer.", result instanceof StandardSerializer );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/MockAuxiliaryCache.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/MockAuxiliaryCache.java
new file mode 100644
index 0000000..73faea3
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/MockAuxiliaryCache.java
@@ -0,0 +1,217 @@
+package org.apache.commons.jcs3.auxiliary;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+
+/**
+ * Mock auxiliary for unit tests.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class MockAuxiliaryCache<K, V>
+ extends AbstractAuxiliaryCache<K, V>
+{
+ /** Can setup the cache type */
+ public CacheType cacheType = CacheType.DISK_CACHE;
+
+ /** Can setup status */
+ public CacheStatus status = CacheStatus.ALIVE;
+
+ /** Times getMatching was Called */
+ public int getMatchingCallCount = 0;
+
+ /**
+ * @param ce
+ * @throws IOException
+ */
+ @Override
+ public void update( ICacheElement<K, V> ce )
+ throws IOException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * @param key
+ * @return ICacheElement
+ * @throws IOException
+ */
+ @Override
+ public ICacheElement<K, V> get( K key )
+ throws IOException
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /**
+ * @param pattern
+ * @return Map
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching(String pattern)
+ throws IOException
+ {
+ getMatchingCallCount++;
+ return new HashMap<>();
+ }
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * @param keys
+ * @return a map of K key to ICacheElement<String, String> element, or an empty map if there is no
+ * data in cache for any of these keys
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
+ {
+ return new HashMap<>();
+ }
+
+ /**
+ * @param key
+ * @return boolean
+ * @throws IOException
+ */
+ @Override
+ public boolean remove( K key )
+ throws IOException
+ {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ /**
+ * @throws IOException
+ */
+ @Override
+ public void removeAll()
+ throws IOException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * @throws IOException
+ */
+ @Override
+ public void dispose()
+ throws IOException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * @return int
+ */
+ @Override
+ public int getSize()
+ {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ /**
+ * @return int
+ */
+ @Override
+ public CacheStatus getStatus()
+ {
+ return status;
+ }
+
+ /**
+ * @return null
+ */
+ @Override
+ public String getCacheName()
+ {
+ return null;
+ }
+
+ /**
+ * Return the keys in this cache.
+ * <p>
+ * @see org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache#getKeySet()
+ */
+ @Override
+ public Set<K> getKeySet() throws IOException
+ {
+ return null;
+ }
+
+ /**
+ * @return null
+ */
+ @Override
+ public IStats getStatistics()
+ {
+ return null;
+ }
+
+ /**
+ * @return null
+ */
+ @Override
+ public String getStats()
+ {
+ return null;
+ }
+
+ /**
+ * @return cacheType
+ */
+ @Override
+ public CacheType getCacheType()
+ {
+ return cacheType;
+ }
+
+ /**
+ * @return Returns the AuxiliaryCacheAttributes.
+ */
+ @Override
+ public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
+ {
+ return null;
+ }
+
+ /** @return null */
+ @Override
+ public String getEventLoggingExtraInfo()
+ {
+ return null;
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/MockAuxiliaryCacheAttributes.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/MockAuxiliaryCacheAttributes.java
new file mode 100644
index 0000000..5eaa7fe
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/MockAuxiliaryCacheAttributes.java
@@ -0,0 +1,31 @@
+package org.apache.commons.jcs3.auxiliary;
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheAttributes;
+
+/*
+ * 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.
+ */
+
+/** For testing. */
+public class MockAuxiliaryCacheAttributes
+ extends AbstractAuxiliaryCacheAttributes
+{
+ /** Don't change. */
+ private static final long serialVersionUID = 1091238902450504108L;
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/MockAuxiliaryCacheFactory.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/MockAuxiliaryCacheFactory.java
new file mode 100644
index 0000000..dc79ffb
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/MockAuxiliaryCacheFactory.java
@@ -0,0 +1,73 @@
+package org.apache.commons.jcs3.auxiliary;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheFactory;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+
+/** For testing */
+public class MockAuxiliaryCacheFactory
+ extends AbstractAuxiliaryCacheFactory
+{
+ /** the name of the aux */
+ public String name = "MockAuxiliaryCacheFactory";
+
+ /**
+ * Creates a mock aux.
+ * <p>
+ * @param attr
+ * @param cacheMgr
+ * @param cacheEventLogger
+ * @param elementSerializer
+ * @return AuxiliaryCache
+ */
+ @Override
+ public <K, V> AuxiliaryCache<K, V>
+ createCache( AuxiliaryCacheAttributes attr, ICompositeCacheManager cacheMgr,
+ ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
+ {
+ MockAuxiliaryCache<K, V> auxCache = new MockAuxiliaryCache<>();
+ auxCache.setCacheEventLogger( cacheEventLogger );
+ auxCache.setElementSerializer( elementSerializer );
+ return auxCache;
+ }
+
+ /**
+ * @return String
+ */
+ @Override
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * @param s
+ */
+ @Override
+ public void setName( String s )
+ {
+ this.name = s;
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/MockCacheEventLogger.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/MockCacheEventLogger.java
new file mode 100644
index 0000000..a70bd28
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/MockCacheEventLogger.java
@@ -0,0 +1,98 @@
+package org.apache.commons.jcs3.auxiliary;
+
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.jcs3.engine.logging.CacheEvent;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEvent;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+
+/**
+ * For testing auxiliary event logging. Improve later so we can test the details. This is very
+ * crude.
+ */
+public class MockCacheEventLogger
+ implements ICacheEventLogger
+{
+ /** times called */
+ public int applicationEventCalls = 0;
+
+ /** times called */
+ public int startICacheEventCalls = 0;
+
+ /** times called */
+ public int endICacheEventCalls = 0;
+
+ /** times called */
+ public int errorEventCalls = 0;
+
+ /** list of messages */
+ public List<String> errorMessages = new ArrayList<>();
+
+ /**
+ * @param source
+ * @param eventName
+ * @param optionalDetails
+ */
+ @Override
+ public void logApplicationEvent( String source, String eventName, String optionalDetails )
+ {
+ applicationEventCalls++;
+ }
+
+ /**
+ * @param event
+ */
+ @Override
+ public <T> void logICacheEvent( ICacheEvent<T> event )
+ {
+ endICacheEventCalls++;
+ }
+
+ /**
+ * @param source
+ * @param eventName
+ * @param errorMessage
+ */
+ @Override
+ public void logError( String source, String eventName, String errorMessage )
+ {
+ errorEventCalls++;
+ errorMessages.add( errorMessage );
+ }
+
+ /**
+ * @param source
+ * @param region
+ * @param eventName
+ * @param optionalDetails
+ * @param key
+ * @return ICacheEvent
+ */
+ @Override
+ public <T> ICacheEvent<T> createICacheEvent( String source, String region,
+ String eventName, String optionalDetails, T key )
+ {
+ startICacheEventCalls++;
+ return new CacheEvent<>();
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/AbstractDiskCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/AbstractDiskCacheUnitTest.java
new file mode 100644
index 0000000..1ec3488
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/AbstractDiskCacheUnitTest.java
@@ -0,0 +1,302 @@
+package org.apache.commons.jcs3.auxiliary.disk;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.jcs3.TestLogConfigurationUtil;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache;
+import org.apache.commons.jcs3.auxiliary.disk.behavior.IDiskCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.ElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+
+/** Tests for the abstract disk cache. It's largely tested by actual instances. */
+public class AbstractDiskCacheUnitTest
+ extends TestCase
+{
+ /**
+ * Verify that update and get work.
+ * <p>
+ * @throws IOException
+ */
+ public void testUpdateGet_allowed()
+ throws IOException
+ {
+ // SETUP
+ String cacheName = "testUpdateGet_allowed";
+ IDiskCacheAttributes diskCacheAttributes = new IndexedDiskCacheAttributes();
+ diskCacheAttributes.setCacheName( cacheName );
+
+ AbstractDiskCacheTestInstance<String, String> diskCache = new AbstractDiskCacheTestInstance<>( diskCacheAttributes );
+
+ String key = "myKey";
+ String value = "myValue";
+ IElementAttributes elementAttributes = new ElementAttributes();
+ ICacheElement<String, String> cacheElement = new CacheElement<>( cacheName, key, value, elementAttributes );
+
+ diskCache.update( cacheElement );
+
+ // DO WORK
+ ICacheElement<String, String> result = diskCache.get( key );
+
+ // VERIFY
+ //System.out.println( diskCache.getStats() );
+ assertNotNull( "Item should be in the map.", result );
+ }
+
+ /**
+ * Verify that alive is set to false..
+ * <p>
+ * @throws IOException
+ */
+ public void testDispose()
+ throws IOException
+ {
+ // SETUP
+ String cacheName = "testDispose";
+ IDiskCacheAttributes diskCacheAttributes = new IndexedDiskCacheAttributes();
+ diskCacheAttributes.setCacheName( cacheName );
+
+ AbstractDiskCacheTestInstance<String, String> diskCache = new AbstractDiskCacheTestInstance<>( diskCacheAttributes );
+
+ String key = "myKey";
+ String value = "myValue";
+ IElementAttributes elementAttributes = new ElementAttributes();
+ ICacheElement<String, String> cacheElement = new CacheElement<>( cacheName, key, value, elementAttributes );
+
+ diskCache.update( cacheElement );
+
+ // DO WORK
+ diskCache.dispose();
+
+ // VERIFY
+ assertFalse( "disk cache should not be alive.", diskCache.isAlive() );
+ assertEquals( "Status should be disposed", CacheStatus.DISPOSED, diskCache.getStatus() );
+ }
+
+ /**
+ * Verify that removeAll is prohibited.
+ * <p>
+ * @throws IOException
+ */
+ public void testRemoveAll_notAllowed()
+ throws IOException
+ {
+ // SETUP
+ StringWriter stringWriter = new StringWriter();
+ TestLogConfigurationUtil.configureLogger( stringWriter, AbstractDiskCache.class.getName() );
+
+ IDiskCacheAttributes diskCacheAttributes = new IndexedDiskCacheAttributes();
+ diskCacheAttributes.setAllowRemoveAll( false );
+
+ AbstractDiskCacheTestInstance<String, String> diskCache = new AbstractDiskCacheTestInstance<>( diskCacheAttributes );
+
+ String cacheName = "testRemoveAll_notAllowed";
+ String key = "myKey";
+ String value = "myValue";
+ IElementAttributes elementAttributes = new ElementAttributes();
+ ICacheElement<String, String> cacheElement = new CacheElement<>( cacheName, key, value, elementAttributes );
+
+ diskCache.update( cacheElement );
+
+ // DO WORK
+ diskCache.removeAll();
+ String result = stringWriter.toString();
+
+ // VERIFY
+ assertTrue( "Should say not allowed.", result.indexOf( "set to false" ) != -1 );
+ assertNotNull( "Item should be in the map.", diskCache.get( key ) );
+ }
+
+ /**
+ * Verify that removeAll is allowed.
+ * <p>
+ * @throws IOException
+ */
+ public void testRemoveAll_allowed()
+ throws IOException
+ {
+ // SETUP
+ IDiskCacheAttributes diskCacheAttributes = new IndexedDiskCacheAttributes();
+ diskCacheAttributes.setAllowRemoveAll( true );
+
+ AbstractDiskCacheTestInstance<String, String> diskCache = new AbstractDiskCacheTestInstance<>( diskCacheAttributes );
+
+ String cacheName = "testRemoveAll_allowed";
+ String key = "myKey";
+ String value = "myValue";
+ IElementAttributes elementAttributes = new ElementAttributes();
+ ICacheElement<String, String> cacheElement = new CacheElement<>( cacheName, key, value, elementAttributes );
+
+ diskCache.update( cacheElement );
+
+ // DO WORK
+ diskCache.removeAll();
+
+ // VERIFY
+ assertNull( "Item should not be in the map.", diskCache.get( key ) );
+ }
+
+ /** Concrete, testable instance. */
+ protected static class AbstractDiskCacheTestInstance<K, V>
+ extends AbstractDiskCache<K, V>
+ {
+ /** Internal map */
+ protected Map<K, ICacheElement<K, V>> map = new HashMap<>();
+
+ /** used by the abstract aux class */
+ protected IDiskCacheAttributes diskCacheAttributes;
+
+ /**
+ * Creates the disk cache.
+ * <p>
+ * @param attr
+ */
+ public AbstractDiskCacheTestInstance( IDiskCacheAttributes attr )
+ {
+ super( attr );
+ diskCacheAttributes = attr;
+ setAlive(true);
+ }
+
+ /**
+ * The location on disk
+ * <p>
+ * @return "memory"
+ */
+ @Override
+ protected String getDiskLocation()
+ {
+ return "memory";
+ }
+
+ /**
+ * Return the keys in this cache.
+ * <p>
+ * @see org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache#getKeySet()
+ */
+ @Override
+ public Set<K> getKeySet() throws IOException
+ {
+ return new HashSet<>(map.keySet());
+ }
+
+ /**
+ * @return map.size()
+ */
+ @Override
+ public int getSize()
+ {
+ return map.size();
+ }
+
+ /**
+ * @throws IOException
+ */
+ @Override
+ protected void processDispose()
+ throws IOException
+ {
+ //System.out.println( "processDispose" );
+ }
+
+ /**
+ * @param key
+ * @return ICacheElement
+ * @throws IOException
+ */
+ @Override
+ protected ICacheElement<K, V> processGet( K key )
+ throws IOException
+ {
+ //System.out.println( "processGet: " + key );
+ return map.get( key );
+ }
+
+ /**
+ * @param pattern
+ * @return Collections.EMPTY_MAP
+ * @throws IOException
+ */
+ @Override
+ protected Map<K, ICacheElement<K, V>> processGetMatching( String pattern )
+ throws IOException
+ {
+ return Collections.emptyMap();
+ }
+
+ /**
+ * @param key
+ * @return false
+ * @throws IOException
+ */
+ @Override
+ protected boolean processRemove( K key )
+ throws IOException
+ {
+ return map.remove( key ) != null;
+ }
+
+ /**
+ * @throws IOException
+ */
+ @Override
+ protected void processRemoveAll()
+ throws IOException
+ {
+ //System.out.println( "processRemoveAll" );
+ map.clear();
+ }
+
+ /**
+ * @param cacheElement
+ * @throws IOException
+ */
+ @Override
+ protected void processUpdate( ICacheElement<K, V> cacheElement )
+ throws IOException
+ {
+ //System.out.println( "processUpdate: " + cacheElement );
+ map.put( cacheElement.getKey(), cacheElement );
+ }
+
+ /**
+ * @return null
+ */
+ @Override
+ public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
+ {
+ return diskCacheAttributes;
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/DiskTestObject.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/DiskTestObject.java
new file mode 100644
index 0000000..bc97648
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/DiskTestObject.java
@@ -0,0 +1,78 @@
+package org.apache.commons.jcs3.auxiliary.disk;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+import java.util.Arrays;
+
+/**
+ * Resembles a cached image.
+ */
+public class DiskTestObject implements Serializable
+{
+ /** don't change */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Key
+ */
+ public Integer id;
+
+ /**
+ * Byte size
+ */
+ public byte[] imageBytes;
+
+ /**
+ * @param id
+ * @param imageBytes
+ */
+ public DiskTestObject(Integer id, byte[] imageBytes)
+ {
+ this.id = id;
+ this.imageBytes = imageBytes;
+ }
+
+ /**
+ * @see java.lang.Object#equals(Object other)
+ */
+ @Override
+ public boolean equals(Object other)
+ {
+ if (other instanceof DiskTestObject)
+ {
+ DiskTestObject o = (DiskTestObject) other;
+ if (id != null)
+ return id.equals(o.id) && Arrays.equals(imageBytes, o.imageBytes);
+ else if (id == null && o.id == null) return Arrays.equals(imageBytes, o.imageBytes);
+ }
+ return false;
+ }
+
+ /**
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode()
+ {
+ return id.hashCode();
+ }
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/PurgatoryElementUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/PurgatoryElementUnitTest.java
new file mode 100644
index 0000000..adb3b8f
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/PurgatoryElementUnitTest.java
@@ -0,0 +1,92 @@
+package org.apache.commons.jcs3.auxiliary.disk;
+
+import org.apache.commons.jcs3.auxiliary.disk.PurgatoryElement;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.ElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/** Simple unit tests for the Purgatory Element. */
+public class PurgatoryElementUnitTest
+ extends TestCase
+{
+ /** Verify basic data */
+ public void testSpoolable_normal()
+ {
+ // SETUP
+ String cacheName = "myCacheName";
+ String key = "myKey";
+ String value = "myValue";
+ IElementAttributes elementAttributes = new ElementAttributes();
+ ICacheElement<String, String> cacheElement = new CacheElement<>( cacheName, key, value, elementAttributes );
+ PurgatoryElement<String, String> purgatoryElement = new PurgatoryElement<>( cacheElement );
+ purgatoryElement.setSpoolable( false );
+
+ // DO WORK
+ boolean result = purgatoryElement.isSpoolable();
+
+ // VERIFY
+ assertFalse( "Should not be spoolable.", result );
+ }
+
+ /** Verify basic data */
+ public void testElementAttributes_normal()
+ {
+ // SETUP
+ String cacheName = "myCacheName";
+ String key = "myKey";
+ String value = "myValue";
+ IElementAttributes elementAttributes = new ElementAttributes();
+
+ ICacheElement<String, String> cacheElement = new CacheElement<>( cacheName, key, value );
+ PurgatoryElement<String, String> purgatoryElement = new PurgatoryElement<>( cacheElement );
+ purgatoryElement.setElementAttributes( elementAttributes );
+
+ // DO WORK
+ IElementAttributes result = cacheElement.getElementAttributes();
+
+ // VERIFY
+ assertEquals( "Should have set the attributes on the element", elementAttributes, result );
+ }
+
+ /** Verify basic data */
+ public void testToString_normal()
+ {
+ // SETUP
+ String cacheName = "myCacheName";
+ String key = "myKey";
+ String value = "myValue";
+ IElementAttributes elementAttributes = new ElementAttributes();
+ ICacheElement<String, String> cacheElement = new CacheElement<>( cacheName, key, value, elementAttributes );
+ PurgatoryElement<String, String> purgatoryElement = new PurgatoryElement<>( cacheElement );
+
+ // DO WORK
+ String result = purgatoryElement.toString();
+
+ // VERIFY
+ assertTrue( "Should have the cacheName.", result.indexOf( cacheName ) != -1 );
+ assertTrue( "Should have the key.", result.indexOf( key ) != -1 );
+ assertTrue( "Should have the value.", result.indexOf( value ) != -1 );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheConcurrentUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheConcurrentUnitTest.java
new file mode 100644
index 0000000..fc78205
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheConcurrentUnitTest.java
@@ -0,0 +1,259 @@
+package org.apache.commons.jcs3.auxiliary.disk.block;
+
+/*
+ * 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.
+ */
+
+import junit.extensions.ActiveTestSuite;
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/**
+ * Test which exercises the block disk cache. This one uses three different
+ * regions for three threads.
+ */
+public class BlockDiskCacheConcurrentUnitTest
+ extends TestCase
+{
+ /**
+ * Number of items to cache, twice the configured maxObjects for the memory
+ * cache regions.
+ */
+ private static int items = 200;
+
+ /**
+ * Constructor for the TestDiskCache object.
+ *
+ * @param testName
+ * @throws Exception
+ */
+ public BlockDiskCacheConcurrentUnitTest( String testName )
+ throws Exception
+ {
+ super( testName );
+ }
+
+ /**
+ * Main method passes this test to the text test runner.
+ *
+ * @param args
+ */
+ public static void main( String args[] )
+ {
+ String[] testCaseName = { BlockDiskCacheConcurrentUnitTest.class.getName() };
+ junit.textui.TestRunner.main( testCaseName );
+ }
+
+ /**
+ * A unit test suite for JUnit
+ *
+ * @return The test suite
+ * @throws Exception
+ */
+ public static Test suite()
+ throws Exception
+ {
+ ActiveTestSuite suite = new ActiveTestSuite();
+
+ JCS.setConfigFilename( "/TestBlockDiskCache.ccf" );
+ JCS.getInstance( "indexedRegion1" ).clear();
+ JCS.getInstance( "indexedRegion2" ).clear();
+ JCS.getInstance( "indexedRegion3" ).clear();
+
+ suite.addTest( new BlockDiskCacheConcurrentUnitTest( "testBlockDiskCache1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion1" );
+ }
+ } );
+
+ suite.addTest( new BlockDiskCacheConcurrentUnitTest( "testBlockDiskCache2" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion2" );
+ }
+ } );
+
+ suite.addTest( new BlockDiskCacheConcurrentUnitTest( "testBlockDiskCache3" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion3" );
+ }
+ } );
+
+ suite.addTest( new BlockDiskCacheConcurrentUnitTest( "testBlockDiskCache4" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegionInRange( "indexedRegion3", 300, 600 );
+ }
+ } );
+
+ return suite;
+ }
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestBlockDiskCache.ccf" );
+ }
+
+ /**
+ * Adds items to cache, gets them, and removes them. The item count is more
+ * than the size of the memory cache, so items should spool to disk.
+ *
+ * @param region
+ * Name of the region to access
+ *
+ * @throws Exception
+ * If an error occurs
+ */
+ public void runTestForRegion( String region )
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+
+ // Add items to cache
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+
+ // Test that all items are in cache
+ for ( int i = 0; i <= items; i++ )
+ {
+ String value = jcs.get( i + ":key" );
+
+ assertEquals( region + " data " + i, value );
+ }
+
+ // Test that getElements returns all the expected values
+ Set<String> keys = new HashSet<>();
+ for ( int i = 0; i <= items; i++ )
+ {
+ keys.add( i + ":key" );
+ }
+
+ Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
+ for ( int i = 0; i <= items; i++ )
+ {
+ ICacheElement<String, String> element = elements.get( i + ":key" );
+ assertNotNull( "element " + i + ":key is missing", element );
+ assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
+ }
+
+ // Remove all the items
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.remove( i + ":key" );
+ }
+
+ // Verify removal
+ // another thread may have inserted since
+ for ( int i = 0; i <= items; i++ )
+ {
+ assertNull( "Removed key should be null: " + i + ":key" + "\n stats " + jcs.getStats(), jcs
+ .get( i + ":key" ) );
+ }
+ }
+
+ /**
+ * Adds items to cache, gets them, and removes them. The item count is more
+ * than the size of the memory cache, so items should spool to disk.
+ *
+ * @param region
+ * Name of the region to access
+ * @param start
+ * @param end
+ *
+ * @throws Exception
+ * If an error occurs
+ */
+ public void runTestForRegionInRange( String region, int start, int end )
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+
+ // Add items to cache
+ for ( int i = start; i <= end; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+
+ // Test that all items are in cache
+ for ( int i = start; i <= end; i++ )
+ {
+ String value = jcs.get( i + ":key" );
+
+ assertEquals( region + " data " + i, value );
+ }
+
+ // Test that getElements returns all the expected values
+ Set<String> keys = new HashSet<>();
+ for ( int i = start; i <= end; i++ )
+ {
+ keys.add( i + ":key" );
+ }
+
+ Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
+ for ( int i = start; i <= end; i++ )
+ {
+ ICacheElement<String, String> element = elements.get( i + ":key" );
+ assertNotNull( "element " + i + ":key is missing", element );
+ assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
+ }
+
+ // Remove all the items
+ for ( int i = start; i <= end; i++ )
+ {
+ jcs.remove( i + ":key" );
+ }
+
+// System.out.println( jcs.getStats() );
+
+ // Verify removal
+ // another thread may have inserted since
+ for ( int i = start; i <= end; i++ )
+ {
+ assertNull( "Removed key should be null: " + i + ":key " + "\n stats " + jcs.getStats(), jcs.get( i
+ + ":key" ) );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheCountUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheCountUnitTest.java
new file mode 100644
index 0000000..df8f109
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheCountUnitTest.java
@@ -0,0 +1,36 @@
+package org.apache.commons.jcs3.auxiliary.disk.block;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
+import org.apache.commons.jcs3.auxiliary.disk.block.BlockDiskCacheAttributes;
+
+public class BlockDiskCacheCountUnitTest extends BlockDiskCacheUnitTestAbstract
+{
+
+ @Override
+ public BlockDiskCacheAttributes getCacheAttributes()
+ {
+ BlockDiskCacheAttributes ret = new BlockDiskCacheAttributes();
+ ret.setDiskLimitType(DiskLimitType.COUNT);
+ return ret;
+ }
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheKeyStoreUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheKeyStoreUnitTest.java
new file mode 100644
index 0000000..8c190df
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheKeyStoreUnitTest.java
@@ -0,0 +1,193 @@
+package org.apache.commons.jcs3.auxiliary.disk.block;
+
+import org.apache.commons.jcs3.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
+import org.apache.commons.jcs3.auxiliary.disk.block.BlockDiskCache;
+import org.apache.commons.jcs3.auxiliary.disk.block.BlockDiskCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.disk.block.BlockDiskKeyStore;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for the keyStore.
+ * <p>
+ *
+ * @author Aaron Smuts
+ */
+public class BlockDiskCacheKeyStoreUnitTest
+ extends TestCase
+{
+ /** Directory name */
+ private final String rootDirName = "target/test-sandbox/block";
+
+ /**
+ * Put a bunch of keys in the key store and verify that they are present.
+ * <p>
+ *
+ * @throws Exception
+ */
+ public void testPutKeys()
+ throws Exception
+ {
+ // SETUP
+ BlockDiskCacheAttributes attributes = new BlockDiskCacheAttributes();
+ attributes.setCacheName("testPutKeys");
+ attributes.setDiskPath(rootDirName);
+ attributes.setMaxKeySize(1000);
+ attributes.setBlockSizeBytes(2000);
+
+ innerTestPutKeys(attributes);
+ }
+
+ public void testPutKeysSize()
+ throws Exception
+ {
+ // SETUP
+ BlockDiskCacheAttributes attributes = new BlockDiskCacheAttributes();
+ attributes.setCacheName("testPutKeys");
+ attributes.setDiskPath(rootDirName);
+ attributes.setMaxKeySize(100000);
+ attributes.setBlockSizeBytes(1024);
+ attributes.setDiskLimitType(DiskLimitType.SIZE);
+
+ innerTestPutKeys(attributes);
+ }
+
+ private void innerTestPutKeys(BlockDiskCacheAttributes attributes)
+ {
+ BlockDiskCache<String, String> blockDiskCache = new BlockDiskCache<>(attributes);
+ BlockDiskKeyStore<String> keyStore = new BlockDiskKeyStore<>(attributes, blockDiskCache);
+
+ // DO WORK
+ int numElements = 100;
+ for (int i = 0; i < numElements; i++)
+ {
+ keyStore.put(String.valueOf(i), new int[i]);
+ }
+ // System.out.println( "testPutKeys " + keyStore );
+
+ // VERIFY
+ assertEquals("Wrong number of keys", numElements, keyStore.size());
+ for (int i = 0; i < numElements; i++)
+ {
+ int[] result = keyStore.get(String.valueOf(i));
+ assertEquals("Wrong array returned.", i, result.length);
+ }
+ }
+
+ /**
+ * Verify that we can load keys that we saved. Add a bunch. Save them. Clear
+ * the memory key hash. Load the keys. Verify.
+ * <p>
+ *
+ * @throws Exception
+ */
+ public void testSaveLoadKeys()
+ throws Exception
+ {
+ // SETUP
+ BlockDiskCacheAttributes attributes = new BlockDiskCacheAttributes();
+ attributes.setCacheName("testSaveLoadKeys");
+ attributes.setDiskPath(rootDirName);
+ attributes.setMaxKeySize(10000);
+ attributes.setBlockSizeBytes(2000);
+
+ testSaveLoadKeysInner(attributes);
+ }
+
+ public void testSaveLoadKeysSize()
+ throws Exception
+ {
+ // SETUP
+ BlockDiskCacheAttributes attributes = new BlockDiskCacheAttributes();
+ attributes.setCacheName("testSaveLoadKeys");
+ attributes.setDiskPath(rootDirName);
+ attributes.setMaxKeySize(10000);
+ attributes.setBlockSizeBytes(2000);
+
+ testSaveLoadKeysInner(attributes);
+ }
+
+ private void testSaveLoadKeysInner(BlockDiskCacheAttributes attributes)
+ {
+ BlockDiskKeyStore<String> keyStore = new BlockDiskKeyStore<>(attributes, null);
+
+ // DO WORK
+ int numElements = 1000;
+ int blockIndex = 0;
+ // Random random = new Random( 89 );
+ for (int i = 0; i < numElements; i++)
+ {
+ int blocks = i;// random.nextInt( 10 );
+
+ // fill with reasonable data to make verify() happy
+ int[] block1 = new int[blocks];
+ int[] block2 = new int[blocks];
+ for (int j = 0; j < blocks; j++)
+ {
+ block1[j] = blockIndex++;
+ block2[j] = blockIndex++;
+ }
+ keyStore.put(String.valueOf(i), block1);
+ keyStore.put(String.valueOf(i), block2);
+ }
+ // System.out.println( "testSaveLoadKeys " + keyStore );
+
+ // VERIFY
+ assertEquals("Wrong number of keys", numElements, keyStore.size());
+
+ // DO WORK
+ keyStore.saveKeys();
+ keyStore.clearMemoryMap();
+
+ // VERIFY
+ assertEquals("Wrong number of keys after clearing memory", 0, keyStore.size());
+
+ // DO WORK
+ keyStore.loadKeys();
+
+ // VERIFY
+ assertEquals("Wrong number of keys after loading", numElements, keyStore.size());
+ for (int i = 0; i < numElements; i++)
+ {
+ int[] result = keyStore.get(String.valueOf(i));
+ assertEquals("Wrong array returned.", i, result.length);
+ }
+ }
+
+ public void testObjectLargerThanMaxSize()
+ {
+ BlockDiskCacheAttributes attributes = new BlockDiskCacheAttributes();
+ attributes.setCacheName("testObjectLargerThanMaxSize");
+ attributes.setDiskPath(rootDirName);
+ attributes.setMaxKeySize(1000);
+ attributes.setBlockSizeBytes(2000);
+ attributes.setDiskLimitType(DiskLimitType.SIZE);
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ BlockDiskKeyStore<String> keyStore = new BlockDiskKeyStore<>(attributes, new BlockDiskCache(attributes));
+
+ keyStore.put("1", new int[1000]);
+ keyStore.put("2", new int[1000]);
+ assertNull(keyStore.get("1"));
+ assertNotNull(keyStore.get("2"));
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheRandomConcurrentTestUtil.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheRandomConcurrentTestUtil.java
new file mode 100644
index 0000000..3d7f1ef
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheRandomConcurrentTestUtil.java
@@ -0,0 +1,91 @@
+package org.apache.commons.jcs3.auxiliary.disk.block;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import org.apache.commons.jcs3.access.TestCacheAccess;
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.junit.Test;
+
+/**
+ * This is used by other tests to generate a random load on the disk cache.
+ */
+public class BlockDiskCacheRandomConcurrentTestUtil
+ extends TestCase
+{
+ /**
+ * Constructor for the TestDiskCache object.
+ *
+ * @param testName
+ */
+ public BlockDiskCacheRandomConcurrentTestUtil( String testName )
+ {
+ super( testName );
+ }
+
+ @Test
+ public void test()
+ {
+
+ }
+
+ /**
+ * Randomly adds items to cache, gets them, and removes them. The range
+ * count is more than the size of the memory cache, so items should spool to
+ * disk.
+ * <p>
+ * @param region
+ * Name of the region to access
+ * @param range
+ * @param numOps
+ * @param testNum
+ *
+ * @throws Exception
+ * If an error occurs
+ */
+ public void runTestForRegion( String region, int range, int numOps, int testNum )
+ throws Exception
+ {
+ // run a rondom operation test to detect deadlocks
+ TestCacheAccess tca = new TestCacheAccess( "/TestBlockDiskCacheCon.ccf" );
+ tca.setRegion( region );
+ tca.random( range, numOps );
+
+ // make sure a simple put then get works
+ // this may fail if the other tests are flooding the disk cache
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+ String key = "testKey" + testNum;
+ String data = "testData" + testNum;
+ jcs.put( key, data );
+ String value = jcs.get( key );
+ assertEquals( data, value );
+ }
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestBlockDiskCacheCon.ccf" );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheSameRegionConcurrentUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheSameRegionConcurrentUnitTest.java
new file mode 100644
index 0000000..ee79176
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheSameRegionConcurrentUnitTest.java
@@ -0,0 +1,173 @@
+package org.apache.commons.jcs3.auxiliary.disk.block;
+
+/*
+ * 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.
+ */
+
+import junit.extensions.ActiveTestSuite;
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/**
+ * Test which exercises the block disk cache. Runs three threads against the same region.
+ */
+public class BlockDiskCacheSameRegionConcurrentUnitTest
+ extends TestCase
+{
+ /**
+ * Constructor for the TestDiskCache object.
+ * <p>
+ * @param testName
+ */
+ public BlockDiskCacheSameRegionConcurrentUnitTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * Main method passes this test to the text test runner.
+ * <p>
+ * @param args
+ * @throws InterruptedException
+ */
+ public static void main( String args[] ) throws InterruptedException
+ {
+ String[] testCaseName = { BlockDiskCacheSameRegionConcurrentUnitTest.class.getName() };
+ junit.textui.TestRunner.main( testCaseName );
+
+ // Give test threads some time to finish
+ Thread.sleep(2000);
+ }
+
+ /**
+ * A unit test suite for JUnit
+ * @return The test suite
+ */
+ public static Test suite()
+ {
+ ActiveTestSuite suite = new ActiveTestSuite();
+
+ suite.addTest( new BlockDiskCacheSameRegionConcurrentUnitTest( "testBlockDiskCache1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "blockRegion4", 0, 200 );
+ }
+ } );
+
+ suite.addTest( new BlockDiskCacheSameRegionConcurrentUnitTest( "testBlockDiskCache2" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "blockRegion4", 1000, 1200 );
+ }
+ } );
+
+ suite.addTest( new BlockDiskCacheSameRegionConcurrentUnitTest( "testBlockDiskCache3" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "blockRegion4", 2000, 2200 );
+ }
+ } );
+
+ suite.addTest( new BlockDiskCacheSameRegionConcurrentUnitTest( "testBlockDiskCache4" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "blockRegion4", 2200, 5200 );
+ }
+ } );
+
+ return suite;
+ }
+
+ /**
+ * Test setup. Sets the config name and clears the region.
+ * <p>
+ * @throws Exception
+ */
+ @Override
+ public void setUp()
+ throws Exception
+ {
+ JCS.setConfigFilename( "/TestBlockDiskCacheCon.ccf" );
+ }
+
+ /**
+ * Adds items to cache, gets them, and removes them. The item count is more than the size of the
+ * memory cache, so items should spool to disk.
+ * @param region Name of the region to access
+ * @param start
+ * @param end
+ * @throws Exception If an error occurs
+ */
+ public void runTestForRegion( String region, int start, int end )
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+
+ // Add items to cache
+
+ for ( int i = start; i <= end; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i + "-" + region );
+ }
+
+ // Test that all items are in cache
+
+ for ( int i = start; i <= end; i++ )
+ {
+ String key = i + ":key";
+ String value = jcs.get( key );
+
+ assertEquals( "Wrong value for key [" + key + "]", region + " data " + i + "-" + region, value );
+ }
+
+ // Test that getElements returns all the expected values
+ Set<String> keys = new HashSet<>();
+ for ( int i = start; i <= end; i++ )
+ {
+ keys.add( i + ":key" );
+ }
+
+ Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
+ for ( int i = start; i <= end; i++ )
+ {
+ ICacheElement<String, String> element = elements.get( i + ":key" );
+ assertNotNull( "element " + i + ":key is missing", element );
+ assertEquals( "value " + i + ":key", region + " data " + i + "-" + region, element.getVal() );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheSizeUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheSizeUnitTest.java
new file mode 100644
index 0000000..04f3fe7
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheSizeUnitTest.java
@@ -0,0 +1,36 @@
+package org.apache.commons.jcs3.auxiliary.disk.block;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
+import org.apache.commons.jcs3.auxiliary.disk.block.BlockDiskCacheAttributes;
+
+public class BlockDiskCacheSizeUnitTest extends BlockDiskCacheUnitTestAbstract
+{
+
+ @Override
+ public BlockDiskCacheAttributes getCacheAttributes()
+ {
+ BlockDiskCacheAttributes ret = new BlockDiskCacheAttributes();
+ ret.setDiskLimitType(DiskLimitType.SIZE);
+ return ret;
+ }
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheSteadyLoadTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheSteadyLoadTest.java
new file mode 100644
index 0000000..7c10dd4
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheSteadyLoadTest.java
@@ -0,0 +1,161 @@
+package org.apache.commons.jcs3.auxiliary.disk.block;
+
+/*
+ * 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.
+ */
+
+import java.text.DecimalFormat;
+import java.util.Random;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.jcs3.auxiliary.disk.DiskTestObject;
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+
+/**
+ * This allows you to put thousands of large objects into the disk cache and to force removes to
+ * trigger optimizations along the way.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class BlockDiskCacheSteadyLoadTest
+ extends TestCase
+{
+ /** String for separating log entries. */
+ private static final String LOG_DIVIDER = "---------------------------";
+
+ /** the runtime. */
+ private static Runtime rt = Runtime.getRuntime();
+
+ /** The decimal format to use int he logs. */
+ private static DecimalFormat format = new DecimalFormat( "#,###" );
+
+ /**
+ * Insert 2000 wait 1 second, repeat. Average 1000 / sec.
+ * <p>
+ * @throws Exception
+ */
+ public void testRunSteadyLoadTest()
+ throws Exception
+ {
+ JCS.setConfigFilename( "/TestBlockDiskCacheSteadyLoad.ccf" );
+
+ logMemoryUsage();
+
+ int numPerRun = 250;
+ long pauseBetweenRuns = 1000;
+ int runCount = 0;
+ int runs = 1000;
+ int upperKB = 50;
+
+ CacheAccess<String, DiskTestObject> jcs = JCS.getInstance( ( numPerRun / 2 ) + "aSecond" );
+
+// ElapsedTimer timer = new ElapsedTimer();
+ int numToGet = numPerRun * ( runs / 10 );
+ for ( int i = 0; i < numToGet; i++ )
+ {
+ jcs.get( String.valueOf( i ) );
+ }
+// System.out.println( LOG_DIVIDER );
+// System.out.println( "After getting " + numToGet );
+// System.out.println( "Elapsed " + timer.getElapsedTimeString() );
+ logMemoryUsage();
+
+ jcs.clear();
+ Thread.sleep( 3000 );
+// System.out.println( LOG_DIVIDER );
+// System.out.println( "Start putting" );
+
+// long totalSize = 0;
+ int totalPut = 0;
+
+ Random random = new Random( 89 );
+ while ( runCount < runs )
+ {
+ runCount++;
+ for ( int i = 0; i < numPerRun; i++ )
+ {
+ // 1/2 upper to upperKB-4 KB
+ int kiloBytes = Math.max( upperKB / 2, random.nextInt( upperKB ) );
+ int bytes = ( kiloBytes ) * 1024;
+// totalSize += bytes;
+ totalPut++;
+ DiskTestObject object = new DiskTestObject( Integer.valueOf( i ), new byte[bytes] );
+ jcs.put( String.valueOf( totalPut ), object );
+ }
+
+ // get half of those inserted the previous run
+ if ( runCount > 1 )
+ {
+ for ( int j = ( ( totalPut - numPerRun ) - ( numPerRun / 2 ) ); j < ( totalPut - numPerRun ); j++ )
+ {
+ jcs.get( String.valueOf( j ) );
+ }
+ }
+
+ // remove half of those inserted the previous run
+ if ( runCount > 1 )
+ {
+ for ( int j = ( ( totalPut - numPerRun ) - ( numPerRun / 2 ) ); j < ( totalPut - numPerRun ); j++ )
+ {
+ jcs.remove( String.valueOf( j ) );
+ }
+ }
+
+
+ Thread.sleep( pauseBetweenRuns );
+ if ( runCount % 100 == 0 )
+ {
+// System.out.println( LOG_DIVIDER );
+// System.out.println( "Elapsed " + timer.getElapsedTimeString() );
+// System.out.println( "Run count: " + runCount + " Average size: " + ( totalSize / totalPut ) + "\n"
+// + jcs.getStats() );
+ logMemoryUsage();
+ }
+ }
+
+ Thread.sleep( 3000 );
+// System.out.println( jcs.getStats() );
+ logMemoryUsage();
+
+ Thread.sleep( 10000 );
+// System.out.println( jcs.getStats() );
+ logMemoryUsage();
+
+ System.gc();
+ Thread.sleep( 3000 );
+ System.gc();
+// System.out.println( jcs.getStats() );
+ logMemoryUsage();
+ }
+
+ /**
+ * Logs the memory usage.
+ */
+ private static void logMemoryUsage()
+ {
+ long byte2MB = 1024 * 1024;
+ long total = rt.totalMemory() / byte2MB;
+ long free = rt.freeMemory() / byte2MB;
+ long used = total - free;
+ System.out.println( LOG_DIVIDER );
+ System.out.println( "Memory:" + " Used:" + format.format( used ) + "MB" + " Free:" + format.format( free )
+ + "MB" + " Total:" + format.format( total ) + "MB" );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheUnitTestAbstract.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheUnitTestAbstract.java
new file mode 100644
index 0000000..4c07f6c
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskCacheUnitTestAbstract.java
@@ -0,0 +1,574 @@
+package org.apache.commons.jcs3.auxiliary.disk.block;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+import org.apache.commons.jcs3.auxiliary.disk.block.BlockDisk;
+import org.apache.commons.jcs3.auxiliary.disk.block.BlockDiskCache;
+import org.apache.commons.jcs3.auxiliary.disk.block.BlockDiskCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.ElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.control.group.GroupAttrName;
+import org.apache.commons.jcs3.engine.control.group.GroupId;
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+
+import junit.framework.TestCase;
+
+/** Unit tests for the Block Disk Cache */
+public abstract class BlockDiskCacheUnitTestAbstract extends TestCase
+{
+ public abstract BlockDiskCacheAttributes getCacheAttributes();
+
+ public void testPutGetMatching_SmallWait() throws Exception
+ {
+ // SETUP
+ int items = 200;
+
+ String cacheName = "testPutGetMatching_SmallWait";
+ BlockDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
+ BlockDiskCache<String, String> diskCache = new BlockDiskCache<>(cattr);
+
+ // DO WORK
+ for (int i = 0; i <= items; i++)
+ {
+ diskCache.update(new CacheElement<>(cacheName, i + ":key", cacheName + " data " + i));
+ }
+ Thread.sleep(500);
+
+ Map<String, ICacheElement<String, String>> matchingResults = diskCache.getMatching("1.8.+");
+
+ // VERIFY
+ assertEquals("Wrong number returned", 10, matchingResults.size());
+ // System.out.println( "matchingResults.keySet() " + matchingResults.keySet() );
+ // System.out.println( "\nAFTER TEST \n" + diskCache.getStats() );
+ }
+
+ /**
+ * Test the basic get matching. With no wait this will all come from purgatory.
+ * <p>
+ *
+ * @throws Exception
+ */
+ public void testPutGetMatching_NoWait() throws Exception
+ {
+ // SETUP
+ int items = 200;
+
+ String cacheName = "testPutGetMatching_NoWait";
+ BlockDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
+ BlockDiskCache<String, String> diskCache = new BlockDiskCache<>(cattr);
+
+ // DO WORK
+ for (int i = 0; i <= items; i++)
+ {
+ diskCache.update(new CacheElement<>(cacheName, i + ":key", cacheName + " data " + i));
+ }
+
+ Map<String, ICacheElement<String, String>> matchingResults = diskCache.getMatching("1.8.+");
+
+ // VERIFY
+ assertEquals("Wrong number returned", 10, matchingResults.size());
+ // System.out.println( "matchingResults.keySet() " + matchingResults.keySet() );
+ // System.out.println( "\nAFTER TEST \n" + diskCache.getStats() );
+ }
+
+ /**
+ * Verify that the block disk cache can handle a big string.
+ * <p>
+ *
+ * @throws Exception
+ */
+ public void testChunk_BigString() throws Exception
+ {
+ String string = "This is my big string ABCDEFGH";
+ StringBuilder sb = new StringBuilder();
+ sb.append(string);
+ for (int i = 0; i < 4; i++)
+ {
+ sb.append("|" + i + ":" + sb.toString()); // big string
+ }
+ string = sb.toString();
+
+ StandardSerializer elementSerializer = new StandardSerializer();
+ byte[] data = elementSerializer.serialize(string);
+
+ File file = new File("target/test-sandbox/BlockDiskCacheUnitTest/testChunk_BigString.data");
+
+ BlockDisk blockDisk = new BlockDisk(file, 200, elementSerializer);
+
+ int numBlocksNeeded = blockDisk.calculateTheNumberOfBlocksNeeded(data);
+ // System.out.println( numBlocksNeeded );
+
+ // get the individual sub arrays.
+ byte[][] chunks = blockDisk.getBlockChunks(data, numBlocksNeeded);
+
+ byte[] resultData = new byte[0];
+
+ for (short i = 0; i < chunks.length; i++)
+ {
+ byte[] chunk = chunks[i];
+ byte[] newTotal = new byte[data.length + chunk.length];
+ // copy data into the new array
+ System.arraycopy(data, 0, newTotal, 0, data.length);
+ // copy the chunk into the new array
+ System.arraycopy(chunk, 0, newTotal, data.length, chunk.length);
+ // swap the new and old.
+ resultData = newTotal;
+ }
+
+ Serializable result = elementSerializer.deSerialize(resultData, null);
+ // System.out.println( result );
+ assertEquals("wrong string after retrieval", string, result);
+ blockDisk.close();
+ }
+
+ /**
+ * Verify that the block disk cache can handle a big string.
+ * <p>
+ *
+ * @throws Exception
+ */
+ public void testPutGet_BigString() throws Exception
+ {
+ String string = "This is my big string ABCDEFGH";
+ StringBuilder sb = new StringBuilder();
+ sb.append(string);
+ for (int i = 0; i < 4; i++)
+ {
+ sb.append(" " + i + sb.toString()); // big string
+ }
+ string = sb.toString();
+
+ String cacheName = "testPutGet_BigString";
+
+ BlockDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMaxKeySize(100);
+ cattr.setBlockSizeBytes(200);
+ cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
+ BlockDiskCache<String, String> diskCache = new BlockDiskCache<>(cattr);
+
+ // DO WORK
+ diskCache.update(new CacheElement<>(cacheName, "x", string));
+
+ // VERIFY
+ assertNotNull(diskCache.get("x"));
+ Thread.sleep(1000);
+ ICacheElement<String, String> afterElement = diskCache.get("x");
+ assertNotNull(afterElement);
+ // System.out.println( "afterElement = " + afterElement );
+ String after = afterElement.getVal();
+
+ assertNotNull(after);
+ assertEquals("wrong string after retrieval", string, after);
+ }
+
+ /**
+ * Verify that the block disk cache can handle utf encoded strings.
+ * <p>
+ *
+ * @throws Exception
+ */
+ public void testUTF8String() throws Exception
+ {
+ String string = "IÒtÎrn‚tiÙn‡lizÊti¯n";
+ StringBuilder sb = new StringBuilder();
+ sb.append(string);
+ for (int i = 0; i < 4; i++)
+ {
+ sb.append(sb.toString()); // big string
+ }
+ string = sb.toString();
+
+ // System.out.println( "The string contains " + string.length() + " characters" );
+
+ String cacheName = "testUTF8String";
+
+ BlockDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMaxKeySize(100);
+ cattr.setBlockSizeBytes(200);
+ cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
+ BlockDiskCache<String, String> diskCache = new BlockDiskCache<>(cattr);
+
+ // DO WORK
+ diskCache.update(new CacheElement<>(cacheName, "x", string));
+
+ // VERIFY
+ assertNotNull(diskCache.get("x"));
+ Thread.sleep(1000);
+ ICacheElement<String, String> afterElement = diskCache.get("x");
+ assertNotNull(afterElement);
+ // System.out.println( "afterElement = " + afterElement );
+ String after = afterElement.getVal();
+
+ assertNotNull(after);
+ assertEquals("wrong string after retrieval", string, after);
+ }
+
+ /**
+ * Verify that the block disk cache can handle utf encoded strings.
+ * <p>
+ *
+ * @throws Exception
+ */
+ public void testUTF8ByteArray() throws Exception
+ {
+ String string = "IÒtÎrn‚tiÙn‡lizÊti¯n";
+ StringBuilder sb = new StringBuilder();
+ sb.append(string);
+ for (int i = 0; i < 4; i++)
+ {
+ sb.append(sb.toString()); // big string
+ }
+ string = sb.toString();
+ // System.out.println( "The string contains " + string.length() + " characters" );
+ byte[] bytes = string.getBytes(StandardCharsets.UTF_8);
+
+ String cacheName = "testUTF8ByteArray";
+
+ BlockDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMaxKeySize(100);
+ cattr.setBlockSizeBytes(200);
+ cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
+ BlockDiskCache<String, byte[]> diskCache = new BlockDiskCache<>(cattr);
+
+ // DO WORK
+ diskCache.update(new CacheElement<>(cacheName, "x", bytes));
+
+ // VERIFY
+ assertNotNull(diskCache.get("x"));
+ Thread.sleep(1000);
+ ICacheElement<String, byte[]> afterElement = diskCache.get("x");
+ assertNotNull(afterElement);
+ // System.out.println( "afterElement = " + afterElement );
+ byte[] after = afterElement.getVal();
+
+ assertNotNull(after);
+ assertEquals("wrong bytes after retrieval", bytes.length, after.length);
+ // assertEquals( "wrong bytes after retrieval", bytes, after );
+ // assertEquals( "wrong bytes after retrieval", string, new String( after, StandardCharsets.UTF_8 ) );
+
+ }
+
+ /**
+ * Verify that the block disk cache can handle utf encoded strings.
+ * <p>
+ *
+ * @throws Exception
+ */
+ public void testUTF8StringAndBytes() throws Exception
+ {
+ X before = new X();
+ String string = "IÒtÎrn‚tiÙn‡lizÊti¯n";
+ StringBuilder sb = new StringBuilder();
+ sb.append(string);
+ for (int i = 0; i < 4; i++)
+ {
+ sb.append(sb.toString()); // big string
+ }
+ string = sb.toString();
+ // System.out.println( "The string contains " + string.length() + " characters" );
+ before.string = string;
+ before.bytes = string.getBytes(StandardCharsets.UTF_8);
+
+ String cacheName = "testUTF8StringAndBytes";
+
+ BlockDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMaxKeySize(100);
+ cattr.setBlockSizeBytes(500);
+ cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
+ BlockDiskCache<String, X> diskCache = new BlockDiskCache<>(cattr);
+
+ // DO WORK
+ diskCache.update(new CacheElement<>(cacheName, "x", before));
+
+ // VERIFY
+ assertNotNull(diskCache.get("x"));
+ Thread.sleep(1000);
+ ICacheElement<String, X> afterElement = diskCache.get("x");
+ // System.out.println( "afterElement = " + afterElement );
+ X after = (afterElement.getVal());
+
+ assertNotNull(after);
+ assertEquals("wrong string after retrieval", string, after.string);
+ assertEquals("wrong bytes after retrieval", string, new String(after.bytes, StandardCharsets.UTF_8));
+
+ }
+
+ public void testLoadFromDisk() throws Exception
+ {
+ for (int i = 0; i < 20; i++)
+ { // usually after 2 time it fails
+ oneLoadFromDisk();
+ }
+ }
+
+ public void testAppendToDisk() throws Exception
+ {
+ String cacheName = "testAppendToDisk";
+ BlockDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMaxKeySize(100);
+ cattr.setBlockSizeBytes(500);
+ cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
+ BlockDiskCache<String, X> diskCache = new BlockDiskCache<>(cattr);
+ diskCache.removeAll();
+ X value1 = new X();
+ value1.string = "1234567890";
+ X value2 = new X();
+ value2.string = "0987654321";
+ diskCache.update(new CacheElement<>(cacheName, "1", value1));
+ diskCache.dispose();
+ diskCache = new BlockDiskCache<>(cattr);
+ diskCache.update(new CacheElement<>(cacheName, "2", value2));
+ diskCache.dispose();
+ diskCache = new BlockDiskCache<>(cattr);
+ assertTrue(diskCache.verifyDisk());
+ assertEquals(2, diskCache.getKeySet().size());
+ assertEquals(value1.string, diskCache.get("1").getVal().string);
+ assertEquals(value2.string, diskCache.get("2").getVal().string);
+ }
+
+ public void oneLoadFromDisk() throws Exception
+ {
+ // initialize object to be stored
+ X before = new X();
+ String string = "IÒtÎrn‚tiÙn‡lizÊti¯n";
+ StringBuilder sb = new StringBuilder();
+ sb.append(string);
+ for (int i = 0; i < 4; i++)
+ {
+ sb.append(sb.toString()); // big string
+ }
+ string = sb.toString();
+ before.string = string;
+ before.bytes = string.getBytes(StandardCharsets.UTF_8);
+
+ // initialize cache
+ String cacheName = "testLoadFromDisk";
+ BlockDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMaxKeySize(100);
+ cattr.setBlockSizeBytes(500);
+ cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
+ BlockDiskCache<String, X> diskCache = new BlockDiskCache<>(cattr);
+
+ // DO WORK
+ for (int i = 0; i < 50; i++)
+ {
+ diskCache.update(new CacheElement<>(cacheName, "x" + i, before));
+ }
+ diskCache.dispose();
+
+ // VERIFY
+ diskCache = new BlockDiskCache<>(cattr);
+
+ for (int i = 0; i < 50; i++)
+ {
+ ICacheElement<String, X> afterElement = diskCache.get("x" + i);
+ assertNotNull("Missing element from cache. Cache size: " + diskCache.getSize() + " element: x" + i, afterElement);
+ X after = (afterElement.getVal());
+
+ assertNotNull(after);
+ assertEquals("wrong string after retrieval", string, after.string);
+ assertEquals("wrong bytes after retrieval", string, new String(after.bytes, StandardCharsets.UTF_8));
+ }
+
+ diskCache.dispose();
+ }
+
+ /**
+ * Add some items to the disk cache and then remove them one by one.
+ *
+ * @throws IOException
+ */
+ public void testRemoveItems() throws IOException
+ {
+ BlockDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName("testRemoveItems");
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
+ BlockDiskCache<String, String> disk = new BlockDiskCache<>(cattr);
+
+ disk.processRemoveAll();
+
+ int cnt = 25;
+ for (int i = 0; i < cnt; i++)
+ {
+ IElementAttributes eAttr = new ElementAttributes();
+ eAttr.setIsSpool(true);
+ ICacheElement<String, String> element = new CacheElement<>("testRemoveItems", "key:" + i, "data:" + i);
+ element.setElementAttributes(eAttr);
+ disk.processUpdate(element);
+ }
+
+ // remove each
+ for (int i = 0; i < cnt; i++)
+ {
+ disk.remove("key:" + i);
+ ICacheElement<String, String> element = disk.processGet("key:" + i);
+ assertNull("Should not have received an element.", element);
+ }
+ }
+
+ /**
+ * Add some items to the disk cache and then remove them one by one.
+ * <p>
+ *
+ * @throws IOException
+ */
+ public void testRemove_PartialKey() throws IOException
+ {
+ BlockDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName("testRemove_PartialKey");
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
+ BlockDiskCache<String, String> disk = new BlockDiskCache<>(cattr);
+
+ disk.processRemoveAll();
+
+ int cnt = 25;
+ for (int i = 0; i < cnt; i++)
+ {
+ IElementAttributes eAttr = new ElementAttributes();
+ eAttr.setIsSpool(true);
+ ICacheElement<String, String> element = new CacheElement<>("testRemove_PartialKey", i + ":key", "data:"
+ + i);
+ element.setElementAttributes(eAttr);
+ disk.processUpdate(element);
+ }
+
+ // verify each
+ for (int i = 0; i < cnt; i++)
+ {
+ ICacheElement<String, String> element = disk.processGet(i + ":key");
+ assertNotNull("Shoulds have received an element.", element);
+ }
+
+ // remove each
+ for (int i = 0; i < cnt; i++)
+ {
+ disk.remove(i + ":");
+ ICacheElement<String, String> element = disk.processGet(i + ":key");
+ assertNull("Should not have received an element.", element);
+ }
+ }
+
+
+ /**
+ * Verify that group members are removed if we call remove with a group.
+ *
+ * @throws IOException
+ */
+ public void testRemove_Group() throws IOException
+ {
+ // SETUP
+ BlockDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName("testRemove_Group");
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
+ BlockDiskCache<GroupAttrName<String>, String> disk = new BlockDiskCache<>(cattr);
+
+ disk.processRemoveAll();
+
+ String cacheName = "testRemove_Group_Region";
+ String groupName = "testRemove_Group";
+
+ int cnt = 25;
+ for (int i = 0; i < cnt; i++)
+ {
+ GroupAttrName<String> groupAttrName = getGroupAttrName(cacheName, groupName, i + ":key");
+ CacheElement<GroupAttrName<String>, String> element = new CacheElement<>(cacheName,
+ groupAttrName, "data:" + i);
+
+ IElementAttributes eAttr = new ElementAttributes();
+ eAttr.setIsSpool(true);
+ element.setElementAttributes(eAttr);
+
+ disk.processUpdate(element);
+ }
+
+ // verify each
+ for (int i = 0; i < cnt; i++)
+ {
+ GroupAttrName<String> groupAttrName = getGroupAttrName(cacheName, groupName, i + ":key");
+ ICacheElement<GroupAttrName<String>, String> element = disk.processGet(groupAttrName);
+ assertNotNull("Should have received an element.", element);
+ }
+
+ // DO WORK
+ // remove the group
+ disk.remove(getGroupAttrName(cacheName, groupName, null));
+
+ for (int i = 0; i < cnt; i++)
+ {
+ GroupAttrName<String> groupAttrName = getGroupAttrName(cacheName, groupName, i + ":key");
+ ICacheElement<GroupAttrName<String>, String> element = disk.processGet(groupAttrName);
+
+ // VERIFY
+ assertNull("Should not have received an element.", element);
+ }
+
+ }
+
+ /**
+ * Internal method used for group functionality.
+ * <p>
+ *
+ * @param cacheName
+ * @param group
+ * @param name
+ * @return GroupAttrName
+ */
+ private GroupAttrName<String> getGroupAttrName(String cacheName, String group, String name)
+ {
+ GroupId gid = new GroupId(cacheName, group);
+ return new GroupAttrName<>(gid, name);
+ }
+
+ /** Holder for a string and byte array. */
+ static class X implements Serializable
+ {
+ /** ignore */
+ private static final long serialVersionUID = 1L;
+
+ /** Test string */
+ String string;
+
+ /*** test byte array. */
+ byte[] bytes;
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskUnitTest.java
new file mode 100644
index 0000000..a09bdb0
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/BlockDiskUnitTest.java
@@ -0,0 +1,369 @@
+package org.apache.commons.jcs3.auxiliary.disk.block;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Random;
+
+import org.apache.commons.jcs3.auxiliary.disk.block.BlockDisk;
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Test for the disk access layer of the Block Disk Cache.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class BlockDiskUnitTest
+ extends TestCase
+{
+ /** data file. */
+ private File rafDir;
+ private BlockDisk disk;
+
+ /**
+ * @see junit.framework.TestCase#setUp()
+ * Creates the base directory
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ String rootDirName = "target/test-sandbox/block";
+ this.rafDir = new File( rootDirName );
+ this.rafDir.mkdirs();
+ }
+
+ private void setUpBlockDisk(String fileName) throws IOException
+ {
+ File file = new File(rafDir, fileName + ".data");
+ file.delete();
+ this.disk = new BlockDisk(file, new StandardSerializer());
+ }
+
+ private void setUpBlockDisk(String fileName, int blockSize) throws IOException
+ {
+ File file = new File(rafDir, fileName + ".data");
+ file.delete();
+ this.disk = new BlockDisk(file, blockSize, new StandardSerializer());
+ }
+
+ /**
+ * @see junit.framework.TestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception
+ {
+ disk.close();
+ super.tearDown();
+ }
+
+ /**
+ * Test writing a null object within a single block size.
+ * <p>
+ * @throws Exception
+ */
+ public void testWrite_NullBlockElement()
+ throws Exception
+ {
+ // SETUP
+ setUpBlockDisk("testWrite_NullBlockElement");
+
+ // DO WORK
+ int[] blocks = disk.write( null );
+
+ // VERIFY
+ assertEquals( "Wrong number of blocks recorded.", 1, disk.getNumberOfBlocks() );
+ assertEquals( "Wrong number of blocks returned.", 1, blocks.length );
+ assertEquals( "Wrong block returned.", 0, blocks[0] );
+ }
+
+ /**
+ * Test writing an element within a single block size.
+ * <p>
+ * @throws Exception
+ */
+ public void testWrite_SingleBlockElement()
+ throws Exception
+ {
+ // SETUP
+ setUpBlockDisk("testWrite_SingleBlockElement");
+
+ // DO WORK
+ int bytes = 1 * 1024;
+ int[] blocks = disk.write( new byte[bytes] );
+
+ // VERIFY
+ assertEquals( "Wrong number of blocks recorded.", 1, disk.getNumberOfBlocks() );
+ assertEquals( "Wrong number of blocks returned.", 1, blocks.length );
+ assertEquals( "Wrong block returned.", 0, blocks[0] );
+ }
+
+ /**
+ * Test writing and reading an element within a single block size.
+ * <p>
+ * @throws Exception
+ */
+ public void testWriteAndRead_SingleBlockElement()
+ throws Exception
+ {
+ // SETUP
+ setUpBlockDisk("testWriteAndRead_SingleBlockElement");
+
+ // DO WORK
+ int bytes = 1 * 1024;
+ int[] blocks = disk.write( new byte[bytes] );
+
+ byte[] result = (byte[]) disk.read( blocks );
+
+ // VERIFY
+ assertEquals( "Wrong item retured.", new byte[bytes].length, result.length );
+ }
+
+ /**
+ * Test writing two elements that each fit within a single block size.
+ * <p>
+ * @throws Exception
+ */
+ public void testWrite_TwoSingleBlockElements()
+ throws Exception
+ {
+ // SETUP
+ setUpBlockDisk("testWrite_TwoSingleBlockElements");
+
+ // DO WORK
+ int bytes = 1 * 1024;
+ int[] blocks1 = disk.write( new byte[bytes] );
+ int[] blocks2 = disk.write( new byte[bytes] );
+
+ // VERIFY
+ assertEquals( "Wrong number of blocks recorded.", 2, disk.getNumberOfBlocks() );
+ assertEquals( "Wrong number of blocks returned.", 1, blocks1.length );
+ assertEquals( "Wrong block returned.", 0, blocks1[0] );
+ assertEquals( "Wrong number of blocks returned.", 1, blocks2.length );
+ assertEquals( "Wrong block returned.", 1, blocks2[0] );
+ }
+
+ /**
+ * Verify that it says we need two blocks if the total size will fit.
+ * <p>
+ * @throws Exception
+ */
+ public void testCalculateBlocksNeededDouble()
+ throws Exception
+ {
+ // SETUP
+ setUpBlockDisk("testCalculateBlocksNeededDouble");
+
+ // DO WORK
+ int result = disk.calculateTheNumberOfBlocksNeeded( new byte[disk.getBlockSizeBytes() * 2
+ - ( 2 * BlockDisk.HEADER_SIZE_BYTES )] );
+
+ // Verify
+ assertEquals( "Wrong number of blocks", 2, result );
+ }
+
+ /**
+ * Test writing an element that takes two blocks.
+ * <p>
+ * @throws Exception
+ */
+ public void testWrite_DoubleBlockElement()
+ throws Exception
+ {
+ // SETUP
+ setUpBlockDisk("testWriteDoubleBlockElement");
+
+ // DO WORK
+ // byte arrays encur 27 bytes of serialization overhead.
+ int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), 2 );
+ int[] blocks = disk.write( new byte[bytes] );
+
+ // VERIFY
+ assertEquals( "Wrong number of blocks recorded.", 2, disk.getNumberOfBlocks() );
+ assertEquals( "Wrong number of blocks returned.", 2, blocks.length );
+ assertEquals( "Wrong block returned.", 0, blocks[0] );
+ }
+
+ /**
+ * Test writing an element that takes 128 blocks. There was a byte in a for loop that limited the number to 127. I fixed this.
+ * <p>
+ * @throws Exception
+ */
+ public void testWrite_128BlockElement()
+ throws Exception
+ {
+ // SETUP
+ int numBlocks = 128;
+
+ setUpBlockDisk("testWrite_128BlockElement");
+
+ // DO WORK
+ // byte arrays encur 27 bytes of serialization overhead.
+ int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), numBlocks );
+ int[] blocks = disk.write( new byte[bytes] );
+
+ // VERIFY
+ assertEquals( "Wrong number of blocks recorded.", numBlocks, disk.getNumberOfBlocks() );
+ assertEquals( "Wrong number of blocks returned.", numBlocks, blocks.length );
+ assertEquals( "Wrong block returned.", 0, blocks[0] );
+ }
+
+ /**
+ * Test writing and reading elements that do not fit within a single block.
+ * <p>
+ * @throws Exception
+ */
+ public void testWriteAndReadMultipleMultiBlockElement()
+ throws Exception
+ {
+ // SETUP
+ setUpBlockDisk("testWriteAndReadSingleBlockElement");
+
+ // DO WORK
+ int numBlocksPerElement = 4;
+ int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), numBlocksPerElement );
+
+ int numElements = 100;
+ for ( int i = 0; i < numElements; i++ )
+ {
+ int[] blocks = disk.write( new byte[bytes] );
+ byte[] result = (byte[]) disk.read( blocks );
+
+ // VERIFY
+ assertEquals( "Wrong item retured.", new byte[bytes].length, result.length );
+ assertEquals( "Wrong number of blocks returned.", numBlocksPerElement, blocks.length );
+ }
+ }
+
+ /**
+ * Test writing and reading elements that do not fit within a single block.
+ * <p>
+ * @throws Exception
+ */
+ public void testWriteAndReadMultipleMultiBlockElement_setSize()
+ throws Exception
+ {
+ // SETUP
+ setUpBlockDisk("testWriteAndReadSingleBlockElement", 1024);
+
+ // DO WORK
+ int numBlocksPerElement = 4;
+ int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), numBlocksPerElement );
+
+ int numElements = 100;
+ Random r = new Random(System.currentTimeMillis());
+ final byte[] src = new byte[bytes];
+ for ( int i = 0; i < numElements; i++ )
+ {
+ r.nextBytes(src); // Ensure we don't just write zeros out
+ int[] blocks = disk.write( src );
+ byte[] result = (byte[]) disk.read( blocks );
+
+ // VERIFY
+ assertEquals( "Wrong item length retured.", src.length, result.length );
+ assertEquals( "Wrong number of blocks returned.", numBlocksPerElement, blocks.length );
+
+ // We check the array contents, too, to ensure we read back what we wrote out
+ for (int j = 0 ; j < src.length ; j++) {
+ assertEquals( "Mismatch at offset " + j + " in attempt # " + (i + 1), src[j], result[j] );
+ }
+ }
+ assertEquals( "Wrong number of elements. "+disk, numBlocksPerElement * numElements, disk.getNumberOfBlocks() );
+ }
+
+ /**
+ * Used to get the size for byte arrays that will take up the number of blocks specified.
+ * <p>
+ * @param blockSize
+ * @param numBlocks
+ * @return num bytes.
+ */
+ private int getBytesForBlocksOfByteArrays( int blockSize, int numBlocks )
+ {
+ // byte arrays encur some bytes of serialization overhead.
+ return blockSize * numBlocks - ( numBlocks * BlockDisk.HEADER_SIZE_BYTES ) - ( numBlocks * 14 );
+ }
+
+ /**
+ * Verify that the block disk can handle a big string.
+ * <p>
+ * @throws Exception
+ */
+ public void testWriteAndRead_BigString()
+ throws Exception
+ {
+ // SETUP
+ setUpBlockDisk("testWriteAndRead_BigString", 4096); //1024
+
+ String string = "This is my big string ABCDEFGH";
+ StringBuilder sb = new StringBuilder();
+ sb.append( string );
+ for ( int i = 0; i < 8; i++ )
+ {
+ sb.append( " " + i + sb.toString() ); // big string
+ }
+ string = sb.toString();
+
+ // DO WORK
+ int[] blocks = disk.write( string );
+ String result = (String) disk.read( blocks );
+
+ // VERIFY
+// System.out.println( string );
+// System.out.println( result );
+// System.out.println( disk );
+ assertEquals( "Wrong item retured.", string, result );
+ }
+
+ /**
+ * Verify that the block disk can handle a big string.
+ * <p>
+ * @throws Exception
+ */
+ public void testWriteAndRead_BigString2()
+ throws Exception
+ {
+ // SETUP
+ setUpBlockDisk("testWriteAndRead_BigString", 47); //4096;//1024
+
+ String string = "abcdefghijklmnopqrstuvwxyz1234567890";
+ string += string;
+ string += string;
+
+ // DO WORK
+ int[] blocks = disk.write( string );
+ String result = (String) disk.read( blocks );
+
+ // VERIFY
+ assertEquals( "Wrong item retured.", string, result );
+ }
+
+ public void testJCS156() throws Exception
+ {
+ // SETUP
+ setUpBlockDisk("testJCS156", 4096);
+ long offset = disk.calculateByteOffsetForBlockAsLong(Integer.MAX_VALUE);
+ assertTrue("Must not wrap round", offset > 0);
+ assertEquals(Integer.MAX_VALUE*4096L,offset);
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/HugeQuantityBlockDiskCacheLoadTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/HugeQuantityBlockDiskCacheLoadTest.java
new file mode 100644
index 0000000..aee9b5e
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/block/HugeQuantityBlockDiskCacheLoadTest.java
@@ -0,0 +1,136 @@
+package org.apache.commons.jcs3.auxiliary.disk.block;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import org.apache.commons.jcs3.utils.timing.SleepUtil;
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.utils.timing.ElapsedTimer;
+
+/**
+ * Put a few hundred thousand entries in the block disk cache.
+ * @author Aaron Smuts
+ */
+public class HugeQuantityBlockDiskCacheLoadTest
+ extends TestCase
+{
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestBlockDiskCacheHuge.ccf" );
+ }
+
+ /**
+ * Adds items to cache, gets them, and removes them. The item count is more than the size of the
+ * memory cache, so items should spool to disk.
+ * <p>
+ * @throws Exception If an error occurs
+ */
+ public void testLargeNumberOfItems()
+ throws Exception
+ {
+ int items = 300000;
+ String region = "testCache1";
+
+ System.out.println( "--------------------------" );
+ long initialMemory = measureMemoryUse();
+ System.out.println( "Before getting JCS: " + initialMemory );
+
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+ jcs.clear();
+
+ try
+ {
+ ElapsedTimer timer = new ElapsedTimer();
+ System.out.println( "Start: " + measureMemoryUse() );
+
+ // Add items to cache
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+
+ System.out.println( jcs.getStats() );
+ System.out.println( "--------------------------" );
+ System.out.println( "After put: " + measureMemoryUse() );
+
+ Thread.sleep( 5000 );
+
+ System.out.println( jcs.getStats() );
+ System.out.println( "--------------------------" );
+ System.out.println( "After wait: " + measureMemoryUse() );
+
+ for ( int i = 0; i < 10; i++ )
+ {
+ SleepUtil.sleepAtLeast( 3000 );
+ System.out.println( "--------------------------" );
+ System.out.println( "After sleep. " + timer.getElapsedTimeString() + " memory used = "
+ + measureMemoryUse() );
+ System.out.println( jcs.getStats() );
+ }
+
+ // Test that all items are in cache
+ System.out.println( "--------------------------" );
+ System.out.println( "Retrieving all." );
+ for ( int i = 0; i <= items; i++ )
+ {
+ //System.out.print( "\033[s" );
+ String value = jcs.get( i + ":key" );
+ if ( i % 1000 == 0 )
+ {
+ //System.out.print( "\033[r" );
+ System.out.println( i + " " );
+ }
+ assertEquals( "Wrong value returned.", region + " data " + i, value );
+ }
+ long aftetGet = measureMemoryUse();
+ System.out.println( "After get: " + aftetGet + " diff = " + ( aftetGet - initialMemory ) );
+
+ }
+ finally
+ {
+ // dump the stats to the report
+ System.out.println( jcs.getStats() );
+ System.out.println( "--------------------------" );
+ long endMemory = measureMemoryUse();
+ System.out.println( "End: " + endMemory + " diff = " + ( endMemory - initialMemory ) );
+ }
+ }
+
+ /**
+ * Measure memory used by the VM.
+ * @return long
+ * @throws InterruptedException
+ */
+ protected long measureMemoryUse()
+ throws InterruptedException
+ {
+ System.gc();
+ Thread.sleep( 3000 );
+ System.gc();
+ return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/DiskTestObjectUtil.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/DiskTestObjectUtil.java
new file mode 100644
index 0000000..779ba3c
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/DiskTestObjectUtil.java
@@ -0,0 +1,144 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.Random;
+
+import org.apache.commons.jcs3.auxiliary.disk.DiskTestObject;
+import org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDisk;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+
+/**
+ * Utility for dealing with test objects.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class DiskTestObjectUtil
+{
+ /**
+ * Total from the start to the endPostion.
+ * <p>
+ * @param testObjects
+ * @param endPosition
+ * @return size
+ * @throws IOException
+ */
+ public static long totalSize( DiskTestObject[] testObjects, int endPosition )
+ throws IOException
+ {
+ StandardSerializer serializer = new StandardSerializer();
+ long total = 0;
+ for ( int i = 0; i < endPosition; i++ )
+ {
+ int tileSize = serializer.serialize( testObjects[i] ).length + IndexedDisk.HEADER_SIZE_BYTES;
+ total += tileSize;
+ }
+ return total;
+ }
+
+ /**
+ * Total from the start to the endPostion.
+ * <p>
+ * @param elements
+ * @param endPosition
+ * @return size
+ * @throws IOException
+ */
+ public static <K, V> long totalSize( ICacheElement<K, V>[] elements, int endPosition )
+ throws IOException
+ {
+ return totalSize( elements, 0, endPosition );
+ }
+
+ /**
+ * Total from the start to the endPostion.
+ * <p>
+ * @param elements
+ * @param startPosition
+ * @param endPosition
+ * @return size
+ * @throws IOException
+ */
+ public static <K, V> long totalSize( ICacheElement<K, V>[] elements, int startPosition, int endPosition )
+ throws IOException
+ {
+ StandardSerializer serializer = new StandardSerializer();
+ long total = 0;
+ for ( int i = startPosition; i < endPosition; i++ )
+ {
+ int tileSize = serializer.serialize( elements[i] ).length + IndexedDisk.HEADER_SIZE_BYTES;
+ total += tileSize;
+ }
+ return total;
+ }
+
+ /**
+ * Creates an array of ICacheElements with DiskTestObjects with payloads the byte size.
+ * <p>
+ * @param numToCreate
+ * @param bytes
+ * @param cacheName
+ * @return ICacheElement[]
+ */
+ public static ICacheElement<Integer, DiskTestObject>[] createCacheElementsWithTestObjects( int numToCreate, int bytes, String cacheName )
+ {
+ @SuppressWarnings("unchecked")
+ ICacheElement<Integer, DiskTestObject>[] elements = new ICacheElement[numToCreate];
+ for ( int i = 0; i < numToCreate; i++ )
+ {
+ // 24 KB
+ int size = bytes * 1024;
+ DiskTestObject tile = new DiskTestObject( Integer.valueOf( i ), new byte[size] );
+
+ ICacheElement<Integer, DiskTestObject> element = new CacheElement<>( cacheName, tile.id, tile );
+ elements[i] = element;
+ }
+ return elements;
+ }
+
+ /**
+ * Creates an array of ICacheElements with DiskTestObjects with payloads the byte size.
+ * <p>
+ * @param numToCreate
+ * @param cacheName
+ * @return ICacheElement[]
+ */
+ public static ICacheElement<Integer, DiskTestObject>[] createCacheElementsWithTestObjectsOfVariableSizes( int numToCreate, String cacheName )
+ {
+ @SuppressWarnings("unchecked")
+ ICacheElement<Integer, DiskTestObject>[] elements = new ICacheElement[numToCreate];
+ Random random = new Random( 89 );
+ for ( int i = 0; i < numToCreate; i++ )
+ {
+ int bytes = random.nextInt( 20 );
+ // 4-24 KB
+ int size = ( bytes + 4 ) * 1024;
+ DiskTestObject tile = new DiskTestObject( Integer.valueOf( i ), new byte[size] );
+
+ ICacheElement<Integer, DiskTestObject> element = new CacheElement<>( cacheName, tile.id, tile );
+ elements[i] = element;
+ }
+ return elements;
+ }
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/HugeQuantityIndDiskCacheLoadTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/HugeQuantityIndDiskCacheLoadTest.java
new file mode 100644
index 0000000..4ea19a6
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/HugeQuantityIndDiskCacheLoadTest.java
@@ -0,0 +1,125 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Put a few hundred thousand entries in the disk cache.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class HugeQuantityIndDiskCacheLoadTest
+ extends TestCase
+{
+ /** Test setup. */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestDiskCacheHuge.ccf" );
+ }
+
+ /**
+ * Adds items to cache, gets them, and removes them. The item count is more than the size of the
+ * memory cache, so items should spool to disk.
+ * <p>
+ * @throws Exception If an error occurs
+ */
+ public void testLargeNumberOfItems()
+ throws Exception
+ {
+ int items = 300000;
+ String region = "testCache1";
+
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+
+ try
+ {
+ System.out.println( "Start: " + measureMemoryUse() );
+
+ // Add items to cache
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+
+ System.out.println( jcs.getStats() );
+ System.out.println( "--------------------------" );
+ System.out.println( "After put: " + measureMemoryUse() );
+
+ Thread.sleep( 5000 );
+
+ System.out.println( jcs.getStats() );
+ System.out.println( "--------------------------" );
+ System.out.println( "After wait: " + measureMemoryUse() );
+
+ // Test that all items are in cache
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ String value = jcs.get( i + ":key" );
+
+ assertEquals( region + " data " + i, value );
+ }
+
+ System.out.println( "After get: " + measureMemoryUse() );
+
+ // // Remove all the items
+ // for ( int i = 0; i <= items; i++ )
+ // {
+ // jcs.remove( i + ":key" );
+ // }
+ //
+ // // Verify removal
+ // for ( int i = 0; i <= items; i++ )
+ // {
+ // assertNull( "Removed key should be null: " + i + ":key" + "\n
+ // stats " + jcs.getStats(), jcs.get( i + ":key" ) );
+ // }
+
+ }
+ finally
+ {
+ // dump the stats to the report
+ System.out.println( jcs.getStats() );
+ System.out.println( "--------------------------" );
+ System.out.println( "End: " + measureMemoryUse() );
+ }
+ }
+
+ /**
+ * Measure memory used by the VM.
+ * <p>
+ * @return memory used
+ * @throws InterruptedException
+ */
+ protected long measureMemoryUse()
+ throws InterruptedException
+ {
+ System.gc();
+ Thread.sleep( 3000 );
+ System.gc();
+ return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexDiskCacheCountUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexDiskCacheCountUnitTest.java
new file mode 100644
index 0000000..aec3d75
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexDiskCacheCountUnitTest.java
@@ -0,0 +1,111 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
+import org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache;
+import org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+public class IndexDiskCacheCountUnitTest extends IndexDiskCacheUnitTestAbstract {
+
+ @Override
+ public IndexedDiskCacheAttributes getCacheAttributes() {
+ IndexedDiskCacheAttributes ret = new IndexedDiskCacheAttributes();
+ ret.setDiskLimitType(DiskLimitType.COUNT);
+ return ret;
+ }
+ public void testRecycleBin()
+ throws IOException
+ {
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName( "testRemoveItems" );
+ cattr.setOptimizeAtRemoveCount( 7 );
+ cattr.setMaxKeySize( 5 );
+ cattr.setMaxPurgatorySize( 0 );
+ cattr.setDiskPath( "target/test-sandbox/BreakIndexTest" );
+ IndexedDiskCache<String, String> disk = new IndexedDiskCache<>( cattr );
+
+ String[] test = { "a", "bb", "ccc", "dddd", "eeeee", "ffffff", "ggggggg", "hhhhhhhhh", "iiiiiiiiii" };
+ String[] expect = { null, "bb", "ccc", null, null, "ffffff", null, "hhhhhhhhh", "iiiiiiiiii" };
+
+ //System.out.println( "------------------------- testRecycleBin " );
+
+ for ( int i = 0; i < 6; i++ )
+ {
+ ICacheElement<String, String> element = new CacheElement<>( "testRecycleBin", "key:" + test[i], test[i] );
+ //System.out.println( "About to add " + "key:" + test[i] + " i = " + i );
+ disk.processUpdate( element );
+ }
+
+ for ( int i = 3; i < 5; i++ )
+ {
+ //System.out.println( "About to remove " + "key:" + test[i] + " i = " + i );
+ disk.remove( "key:" + test[i] );
+ }
+
+ // there was a bug where 7 would try to be put in the empty slot left by 4's removal, but it
+ // will not fit.
+ for ( int i = 7; i < 9; i++ )
+ {
+ ICacheElement<String, String> element = new CacheElement<>( "testRecycleBin", "key:" + test[i], test[i] );
+ //System.out.println( "About to add " + "key:" + test[i] + " i = " + i );
+ disk.processUpdate( element );
+ }
+
+ try
+ {
+ for ( int i = 0; i < 9; i++ )
+ {
+ ICacheElement<String, String> element = disk.get( "key:" + test[i] );
+ if ( element != null )
+ {
+ //System.out.println( "element = " + element.getVal() );
+ }
+ else
+ {
+ //System.out.println( "null --" + "key:" + test[i] );
+ }
+
+ String expectedValue = expect[i];
+ if ( expectedValue == null )
+ {
+ assertNull( "Expected a null element", element );
+ }
+ else
+ {
+ assertNotNull( "The element for key [" + "key:" + test[i] + "] should not be null. i = " + i,
+ element );
+ assertEquals( "Elements contents do not match expected", element.getVal(), expectedValue );
+ }
+ }
+ }
+ catch ( Exception e )
+ {
+ e.printStackTrace();
+ fail( "Should not get an exception: " + e.toString() );
+ }
+
+ disk.removeAll();
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexDiskCacheSizeUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexDiskCacheSizeUnitTest.java
new file mode 100644
index 0000000..4fafde9
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexDiskCacheSizeUnitTest.java
@@ -0,0 +1,112 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.auxiliary.disk.DiskTestObject;
+import org.apache.commons.jcs3.auxiliary.disk.behavior.IDiskCacheAttributes.DiskLimitType;
+import org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache;
+import org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+public class IndexDiskCacheSizeUnitTest extends IndexDiskCacheUnitTestAbstract {
+
+ @Override
+ public IndexedDiskCacheAttributes getCacheAttributes() {
+ IndexedDiskCacheAttributes ret = new IndexedDiskCacheAttributes();
+ ret.setDiskLimitType(DiskLimitType.SIZE);
+ return ret;
+ }
+ public void testRecycleBin()
+ throws IOException
+ {
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName( "testRemoveItems" );
+ cattr.setOptimizeAtRemoveCount( 7 );
+ cattr.setMaxKeySize( 8); // 1kb DiskTestObject takes 1420 bytes, so 5*1420 = 7100, so to keep 5 ojbects, we need max key size of 8
+ cattr.setMaxPurgatorySize( 0 );
+ cattr.setDiskPath( "target/test-sandbox/BreakIndexTest" );
+ IndexedDiskCache<String, DiskTestObject> disk = new IndexedDiskCache<>( cattr );
+
+ String[] test = { "a", "bb", "ccc", "dddd", "eeeee", "ffffff", "ggggggg", "hhhhhhhhh", "iiiiiiiiii" };
+ String[] expect = { null, "bb", "ccc", null, null, "ffffff", null, "hhhhhhhhh", "iiiiiiiiii" };
+ DiskTestObject value = DiskTestObjectUtil.createCacheElementsWithTestObjects( 1, 1, cattr .getCacheName())[0].getVal();
+ //System.out.println( "------------------------- testRecycleBin " );
+
+ for ( int i = 0; i < 6; i++ )
+ {
+ ICacheElement<String, DiskTestObject> element = new CacheElement<>( "testRecycleBin", "key:" + test[i], value);
+ //System.out.println( "About to add " + "key:" + test[i] + " i = " + i );
+ disk.processUpdate( element );
+ }
+
+ for ( int i = 3; i < 5; i++ )
+ {
+ //System.out.println( "About to remove " + "key:" + test[i] + " i = " + i );
+ disk.remove( "key:" + test[i] );
+ }
+
+ // there was a bug where 7 would try to be put in the empty slot left by 4's removal, but it
+ // will not fit.
+ for ( int i = 7; i < 9; i++ )
+ {
+ ICacheElement<String, DiskTestObject> element = new CacheElement<>( "testRecycleBin", "key:" + test[i], value);
+ //System.out.println( "About to add " + "key:" + test[i] + " i = " + i );
+ disk.processUpdate( element );
+ }
+
+ try
+ {
+ for ( int i = 0; i < 9; i++ )
+ {
+ ICacheElement<String, DiskTestObject> element = disk.get( "key:" + test[i] );
+ if ( element != null )
+ {
+ //System.out.println( "element = " + element.getVal() );
+ }
+ else
+ {
+ //System.out.println( "null --" + "key:" + test[i] );
+ }
+
+ String expectedValue = expect[i];
+ if ( expectedValue == null )
+ {
+ assertNull( "Expected a null element", element );
+ }
+ else
+ {
+ assertNotNull( "The element for key [" + "key:" + test[i] + "] should not be null. i = " + i,
+ element );
+ assertEquals( "Elements contents do not match expected", element.getVal(), value );
+ }
+ }
+ }
+ catch ( Exception e )
+ {
+ e.printStackTrace();
+ fail( "Should not get an exception: " + e.toString() );
+ }
+
+ disk.removeAll();
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexDiskCacheUnitTestAbstract.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexDiskCacheUnitTestAbstract.java
new file mode 100644
index 0000000..52975b0
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexDiskCacheUnitTestAbstract.java
@@ -0,0 +1,993 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.auxiliary.MockCacheEventLogger;
+import org.apache.commons.jcs3.auxiliary.disk.DiskTestObject;
+import org.apache.commons.jcs3.utils.timing.SleepUtil;
+import org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDisk;
+import org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache;
+import org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskElementDescriptor;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.ElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.control.group.GroupAttrName;
+import org.apache.commons.jcs3.engine.control.group.GroupId;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for common functionality.
+ * <p>
+ *
+ * @author Aaron Smuts
+ */
+public abstract class IndexDiskCacheUnitTestAbstract extends TestCase
+{
+ public abstract IndexedDiskCacheAttributes getCacheAttributes();
+
+ /**
+ * Simply verify that we can put items in the disk cache and retrieve them.
+ *
+ * @throws IOException
+ */
+ public void testSimplePutAndGet() throws IOException
+ {
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName("testSimplePutAndGet");
+ cattr.setMaxKeySize(1000);
+ cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
+ IndexedDiskCache<String, String> disk = new IndexedDiskCache<>(cattr);
+
+ disk.processRemoveAll();
+
+ int cnt = 999;
+ for (int i = 0; i < cnt; i++)
+ {
+ IElementAttributes eAttr = new ElementAttributes();
+ eAttr.setIsSpool(true);
+ ICacheElement<String, String> element = new CacheElement<>("testSimplePutAndGet", "key:" + i, "data:" + i);
+ element.setElementAttributes(eAttr);
+ disk.processUpdate(element);
+ }
+
+ for (int i = 0; i < cnt; i++)
+ {
+ ICacheElement<String, String> element = disk.processGet("key:" + i);
+ assertNotNull("Should have received an element.", element);
+ assertEquals("Element is wrong.", "data:" + i, element.getVal());
+ }
+
+ // Test that getMultiple returns all the expected values
+ Set<String> keys = new HashSet<>();
+ for (int i = 0; i < cnt; i++)
+ {
+ keys.add("key:" + i);
+ }
+
+ Map<String, ICacheElement<String, String>> elements = disk.getMultiple(keys);
+ for (int i = 0; i < cnt; i++)
+ {
+ ICacheElement<String, String> element = elements.get("key:" + i);
+ assertNotNull("element " + i + ":key is missing", element);
+ assertEquals("value key:" + i, "data:" + i, element.getVal());
+ }
+ // System.out.println( disk.getStats() );
+ }
+
+ /**
+ * Add some items to the disk cache and then remove them one by one.
+ *
+ * @throws IOException
+ */
+ public void testRemoveItems() throws IOException
+ {
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName("testRemoveItems");
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
+ IndexedDiskCache<String, String> disk = new IndexedDiskCache<>(cattr);
+
+ disk.processRemoveAll();
+
+ int cnt = 25;
+ for (int i = 0; i < cnt; i++)
+ {
+ IElementAttributes eAttr = new ElementAttributes();
+ eAttr.setIsSpool(true);
+ ICacheElement<String, String> element = new CacheElement<>("testRemoveItems", "key:" + i, "data:" + i);
+ element.setElementAttributes(eAttr);
+ disk.processUpdate(element);
+ }
+
+ // remove each
+ for (int i = 0; i < cnt; i++)
+ {
+ disk.remove("key:" + i);
+ ICacheElement<String, String> element = disk.processGet("key:" + i);
+ assertNull("Should not have received an element.", element);
+ }
+ }
+
+ /**
+ * Verify that we don't override the largest item.
+ * <p>
+ *
+ * @throws IOException
+ */
+
+ /**
+ * Verify that the overlap check returns true when there are no overlaps.
+ */
+ public void testCheckForDedOverlaps_noOverlap()
+ {
+ // SETUP
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName("testCheckForDedOverlaps_noOverlap");
+ cattr.setDiskPath("target/test-sandbox/UnitTest");
+ IndexedDiskCache<String, String> disk = new IndexedDiskCache<>(cattr);
+
+ int numDescriptors = 5;
+ int pos = 0;
+ IndexedDiskElementDescriptor[] sortedDescriptors = new IndexedDiskElementDescriptor[numDescriptors];
+ for (int i = 0; i < numDescriptors; i++)
+ {
+ IndexedDiskElementDescriptor descriptor = new IndexedDiskElementDescriptor(pos, i * 2);
+ pos = pos + (i * 2) + IndexedDisk.HEADER_SIZE_BYTES;
+ sortedDescriptors[i] = descriptor;
+ }
+
+ // DO WORK
+ boolean result = disk.checkForDedOverlaps(sortedDescriptors);
+
+ // VERIFY
+ assertTrue("There should be no overlap. it should be ok", result);
+ }
+
+ /**
+ * Verify that the overlap check returns false when there are overlaps.
+ */
+ public void testCheckForDedOverlaps_overlaps()
+ {
+ // SETUP
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName("testCheckForDedOverlaps_overlaps");
+ cattr.setDiskPath("target/test-sandbox/UnitTest");
+ IndexedDiskCache<String, String> disk = new IndexedDiskCache<>(cattr);
+
+ int numDescriptors = 5;
+ int pos = 0;
+ IndexedDiskElementDescriptor[] sortedDescriptors = new IndexedDiskElementDescriptor[numDescriptors];
+ for (int i = 0; i < numDescriptors; i++)
+ {
+ IndexedDiskElementDescriptor descriptor = new IndexedDiskElementDescriptor(pos, i * 2);
+ // don't add the header + IndexedDisk.RECORD_HEADER;
+ pos = pos + (i * 2);
+ sortedDescriptors[i] = descriptor;
+ }
+
+ // DO WORK
+ boolean result = disk.checkForDedOverlaps(sortedDescriptors);
+
+ // VERIFY
+ assertFalse("There should be overlaps. it should be not ok", result);
+ }
+
+ /**
+ * Verify that the file size is as expected.
+ * <p>
+ *
+ * @throws IOException
+ * @throws InterruptedException
+ */
+ public void testFileSize() throws IOException, InterruptedException
+ {
+ // SETUP
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName("testFileSize");
+ cattr.setDiskPath("target/test-sandbox/UnitTest");
+ IndexedDiskCache<Integer, DiskTestObject> disk = new IndexedDiskCache<>(cattr);
+
+ int numberToInsert = 20;
+ int bytes = 24;
+ ICacheElement<Integer, DiskTestObject>[] elements = DiskTestObjectUtil.createCacheElementsWithTestObjects(numberToInsert,
+ bytes, cattr.getCacheName());
+
+ for (int i = 0; i < elements.length; i++)
+ {
+ disk.processUpdate(elements[i]);
+ }
+
+ Thread.yield();
+ Thread.sleep(100);
+ Thread.yield();
+
+ long expectedSize = DiskTestObjectUtil.totalSize(elements, numberToInsert);
+ long resultSize = disk.getDataFileSize();
+
+ // System.out.println( "testFileSize stats " + disk.getStats() );
+
+ assertEquals("Wrong file size", expectedSize, resultSize);
+ }
+
+ /**
+ * Verify that items are added to the recycle bin on removal.
+ * <p>
+ *
+ * @throws IOException
+ * @throws InterruptedException
+ */
+ public void testRecyleBinSize() throws IOException, InterruptedException
+ {
+ // SETUP
+ int numberToInsert = 20;
+
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName("testRecyleBinSize");
+ cattr.setDiskPath("target/test-sandbox/UnitTest");
+ cattr.setOptimizeAtRemoveCount(numberToInsert);
+ cattr.setMaxKeySize(numberToInsert * 2);
+ cattr.setMaxPurgatorySize(numberToInsert);
+ IndexedDiskCache<Integer, DiskTestObject> disk = new IndexedDiskCache<>(cattr);
+
+ int bytes = 1;
+ ICacheElement<Integer, DiskTestObject>[] elements = DiskTestObjectUtil.createCacheElementsWithTestObjects(numberToInsert,
+ bytes, cattr.getCacheName());
+
+ for (int i = 0; i < elements.length; i++)
+ {
+ disk.processUpdate(elements[i]);
+ }
+
+ Thread.yield();
+ Thread.sleep(100);
+ Thread.yield();
+
+ // remove half
+ int numberToRemove = elements.length / 2;
+ for (int i = 0; i < numberToRemove; i++)
+ {
+ disk.processRemove(elements[i].getKey());
+ }
+
+ // verify that the recycle bin has the correct amount.
+ assertEquals("The recycle bin should have the number removed.", numberToRemove, disk.getRecyleBinSize());
+ }
+
+ /**
+ * Verify that items of the same size use recycle bin spots. Setup the recycle bin by removing
+ * some items. Add some of the same size. Verify that the recycle count is the number added.
+ * <p>
+ *
+ * @throws IOException
+ * @throws InterruptedException
+ */
+ public void testRecyleBinUsage() throws IOException, InterruptedException
+ {
+ // SETUP
+ int numberToInsert = 20;
+
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName("testRecyleBinUsage");
+ cattr.setDiskPath("target/test-sandbox/UnitTest");
+ cattr.setOptimizeAtRemoveCount(numberToInsert);
+ cattr.setMaxKeySize(numberToInsert * 2);
+ cattr.setMaxPurgatorySize(numberToInsert);
+ IndexedDiskCache<Integer, DiskTestObject> disk = new IndexedDiskCache<>(cattr);
+
+ // we will reuse these
+ int bytes = 1;
+ ICacheElement<Integer, DiskTestObject>[] elements = DiskTestObjectUtil.createCacheElementsWithTestObjects(numberToInsert,
+ bytes, cattr.getCacheName());
+
+ // Add some to the disk
+ for (int i = 0; i < elements.length; i++)
+ {
+ disk.processUpdate(elements[i]);
+ }
+
+ Thread.yield();
+ Thread.sleep(100);
+ Thread.yield();
+
+ // remove half of those added
+ int numberToRemove = elements.length / 2;
+ for (int i = 0; i < numberToRemove; i++)
+ {
+ disk.processRemove(elements[i].getKey());
+ }
+
+ // verify that the recycle bin has the correct amount.
+ assertEquals("The recycle bin should have the number removed.", numberToRemove, disk.getRecyleBinSize());
+
+ // add half as many as we removed. These should all use spots in the recycle bin.
+ int numberToAdd = numberToRemove / 2;
+ for (int i = 0; i < numberToAdd; i++)
+ {
+ disk.processUpdate(elements[i]);
+ }
+
+ // verify that we used the correct number of spots
+ assertEquals("The recycle bin should have the number removed." + disk.getStats(), numberToAdd, disk.getRecyleCount());
+ }
+
+ /**
+ * Verify that the data size is as expected after a remove and after a put that should use the
+ * spots.
+ * <p>
+ *
+ * @throws IOException
+ * @throws InterruptedException
+ */
+ public void testBytesFreeSize() throws IOException, InterruptedException
+ {
+ // SETUP
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName("testBytesFreeSize");
+ cattr.setDiskPath("target/test-sandbox/UnitTest");
+ IndexedDiskCache<Integer, DiskTestObject> disk = new IndexedDiskCache<>(cattr);
+
+ int numberToInsert = 20;
+ int bytes = 24;
+ ICacheElement<Integer, DiskTestObject>[] elements = DiskTestObjectUtil.createCacheElementsWithTestObjects(numberToInsert,
+ bytes, cattr.getCacheName());
+
+ for (int i = 0; i < elements.length; i++)
+ {
+ disk.processUpdate(elements[i]);
+ }
+
+ Thread.yield();
+ Thread.sleep(100);
+ Thread.yield();
+
+ // remove half of those added
+ int numberToRemove = elements.length / 2;
+ for (int i = 0; i < numberToRemove; i++)
+ {
+ disk.processRemove(elements[i].getKey());
+ }
+
+ long expectedSize = DiskTestObjectUtil.totalSize(elements, numberToRemove);
+ long resultSize = disk.getBytesFree();
+
+ // System.out.println( "testBytesFreeSize stats " + disk.getStats() );
+
+ assertEquals("Wrong bytes free size" + disk.getStats(), expectedSize, resultSize);
+
+ // add half as many as we removed. These should all use spots in the recycle bin.
+ int numberToAdd = numberToRemove / 2;
+ for (int i = 0; i < numberToAdd; i++)
+ {
+ disk.processUpdate(elements[i]);
+ }
+
+ long expectedSize2 = DiskTestObjectUtil.totalSize(elements, numberToAdd);
+ long resultSize2 = disk.getBytesFree();
+ assertEquals("Wrong bytes free size" + disk.getStats(), expectedSize2, resultSize2);
+ }
+
+ /**
+ * Add some items to the disk cache and then remove them one by one.
+ * <p>
+ *
+ * @throws IOException
+ */
+ public void testRemove_PartialKey() throws IOException
+ {
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName("testRemove_PartialKey");
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
+ IndexedDiskCache<String, String> disk = new IndexedDiskCache<>(cattr);
+
+ disk.processRemoveAll();
+
+ int cnt = 25;
+ for (int i = 0; i < cnt; i++)
+ {
+ IElementAttributes eAttr = new ElementAttributes();
+ eAttr.setIsSpool(true);
+ ICacheElement<String, String> element = new CacheElement<>("testRemove_PartialKey", i + ":key", "data:"
+ + i);
+ element.setElementAttributes(eAttr);
+ disk.processUpdate(element);
+ }
+
+ // verif each
+ for (int i = 0; i < cnt; i++)
+ {
+ ICacheElement<String, String> element = disk.processGet(i + ":key");
+ assertNotNull("Shoulds have received an element.", element);
+ }
+
+ // remove each
+ for (int i = 0; i < cnt; i++)
+ {
+ disk.remove(i + ":");
+ ICacheElement<String, String> element = disk.processGet(i + ":key");
+ assertNull("Should not have received an element.", element);
+ }
+ // https://issues.apache.org/jira/browse/JCS-67
+ assertEquals("Recylenbin should not have more elements than we removed. Check for JCS-67", cnt, disk.getRecyleBinSize());
+ }
+
+ /**
+ * Verify that group members are removed if we call remove with a group.
+ *
+ * @throws IOException
+ */
+ public void testRemove_Group() throws IOException
+ {
+ // SETUP
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName("testRemove_Group");
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
+ IndexedDiskCache<GroupAttrName<String>, String> disk = new IndexedDiskCache<>(cattr);
+
+ disk.processRemoveAll();
+
+ String cacheName = "testRemove_Group_Region";
+ String groupName = "testRemove_Group";
+
+ int cnt = 25;
+ for (int i = 0; i < cnt; i++)
+ {
+ GroupAttrName<String> groupAttrName = getGroupAttrName(cacheName, groupName, i + ":key");
+ CacheElement<GroupAttrName<String>, String> element = new CacheElement<>(cacheName,
+ groupAttrName, "data:" + i);
+
+ IElementAttributes eAttr = new ElementAttributes();
+ eAttr.setIsSpool(true);
+ element.setElementAttributes(eAttr);
+
+ disk.processUpdate(element);
+ }
+
+ // verify each
+ for (int i = 0; i < cnt; i++)
+ {
+ GroupAttrName<String> groupAttrName = getGroupAttrName(cacheName, groupName, i + ":key");
+ ICacheElement<GroupAttrName<String>, String> element = disk.processGet(groupAttrName);
+ assertNotNull("Should have received an element.", element);
+ }
+
+ // DO WORK
+ // remove the group
+ disk.remove(getGroupAttrName(cacheName, groupName, null));
+
+ for (int i = 0; i < cnt; i++)
+ {
+ GroupAttrName<String> groupAttrName = getGroupAttrName(cacheName, groupName, i + ":key");
+ ICacheElement<GroupAttrName<String>, String> element = disk.processGet(groupAttrName);
+
+ // VERIFY
+ assertNull("Should not have received an element.", element);
+ }
+
+ }
+
+ /**
+ * Internal method used for group functionality.
+ * <p>
+ *
+ * @param cacheName
+ * @param group
+ * @param name
+ * @return GroupAttrName
+ */
+ private GroupAttrName<String> getGroupAttrName(String cacheName, String group, String name)
+ {
+ GroupId gid = new GroupId(cacheName, group);
+ return new GroupAttrName<>(gid, name);
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ *
+ * @throws Exception
+ */
+ public void testUpdate_EventLogging_simple() throws Exception
+ {
+ // SETUP
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName("testUpdate_EventLogging_simple");
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTestCEL");
+ IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
+ diskCache.processRemoveAll();
+
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ diskCache.setCacheEventLogger(cacheEventLogger);
+
+ ICacheElement<String, String> item = new CacheElement<>("region", "key", "value");
+
+ // DO WORK
+ diskCache.update(item);
+
+ SleepUtil.sleepAtLeast(200);
+
+ // VERIFY
+ assertEquals("Start should have been called.", 1, cacheEventLogger.startICacheEventCalls);
+ assertEquals("End should have been called.", 1, cacheEventLogger.endICacheEventCalls);
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ *
+ * @throws Exception
+ */
+ public void testGet_EventLogging_simple() throws Exception
+ {
+ // SETUP
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName("testGet_EventLogging_simple");
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTestCEL");
+ IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
+ diskCache.processRemoveAll();
+
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ diskCache.setCacheEventLogger(cacheEventLogger);
+
+ // DO WORK
+ diskCache.get("key");
+
+ // VERIFY
+ assertEquals("Start should have been called.", 1, cacheEventLogger.startICacheEventCalls);
+ assertEquals("End should have been called.", 1, cacheEventLogger.endICacheEventCalls);
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ *
+ * @throws Exception
+ */
+ public void testGetMultiple_EventLogging_simple() throws Exception
+ {
+ // SETUP
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName("testGetMultiple_EventLogging_simple");
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTestCEL");
+ IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
+ diskCache.processRemoveAll();
+
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ diskCache.setCacheEventLogger(cacheEventLogger);
+
+ Set<String> keys = new HashSet<>();
+ keys.add("junk");
+
+ // DO WORK
+ diskCache.getMultiple(keys);
+
+ // VERIFY
+ // 1 for get multiple and 1 for get.
+ assertEquals("Start should have been called.", 2, cacheEventLogger.startICacheEventCalls);
+ assertEquals("End should have been called.", 2, cacheEventLogger.endICacheEventCalls);
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ *
+ * @throws Exception
+ */
+ public void testRemove_EventLogging_simple() throws Exception
+ {
+ // SETUP
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName("testRemoveAll_EventLogging_simple");
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTestCEL");
+ IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
+ diskCache.processRemoveAll();
+
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ diskCache.setCacheEventLogger(cacheEventLogger);
+
+ // DO WORK
+ diskCache.remove("key");
+
+ // VERIFY
+ assertEquals("Start should have been called.", 1, cacheEventLogger.startICacheEventCalls);
+ assertEquals("End should have been called.", 1, cacheEventLogger.endICacheEventCalls);
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ *
+ * @throws Exception
+ */
+ public void testRemoveAll_EventLogging_simple() throws Exception
+ {
+ // SETUP
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName("testRemoveAll_EventLogging_simple");
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTestCEL");
+ IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
+ diskCache.processRemoveAll();
+
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ diskCache.setCacheEventLogger(cacheEventLogger);
+
+ // DO WORK
+ diskCache.remove("key");
+
+ // VERIFY
+ assertEquals("Start should have been called.", 1, cacheEventLogger.startICacheEventCalls);
+ assertEquals("End should have been called.", 1, cacheEventLogger.endICacheEventCalls);
+ }
+
+ /**
+ * Test the basic get matching.
+ * <p>
+ *
+ * @throws Exception
+ */
+ public void testPutGetMatching_SmallWait() throws Exception
+ {
+ // SETUP
+ int items = 200;
+
+ String cacheName = "testPutGetMatching_SmallWait";
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
+ IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
+
+ // DO WORK
+ for (int i = 0; i <= items; i++)
+ {
+ diskCache.update(new CacheElement<>(cacheName, i + ":key", cacheName + " data " + i));
+ }
+ Thread.sleep(500);
+
+ Map<String, ICacheElement<String, String>> matchingResults = diskCache.getMatching("1.8.+");
+
+ // VERIFY
+ assertEquals("Wrong number returned", 10, matchingResults.size());
+ // System.out.println( "matchingResults.keySet() " + matchingResults.keySet() );
+ // System.out.println( "\nAFTER TEST \n" + diskCache.getStats() );
+ }
+
+ /**
+ * Test the basic get matching. With no wait this will all come from purgatory.
+ * <p>
+ *
+ * @throws Exception
+ */
+ public void testPutGetMatching_NoWait() throws Exception
+ {
+ // SETUP
+ int items = 200;
+
+ String cacheName = "testPutGetMatching_NoWait";
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
+ IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
+
+ // DO WORK
+ for (int i = 0; i <= items; i++)
+ {
+ diskCache.update(new CacheElement<>(cacheName, i + ":key", cacheName + " data " + i));
+ }
+
+ Map<String, ICacheElement<String, String>> matchingResults = diskCache.getMatching("1.8.+");
+
+ // VERIFY
+ assertEquals("Wrong number returned", 10, matchingResults.size());
+ // System.out.println( "matchingResults.keySet() " + matchingResults.keySet() );
+ // System.out.println( "\nAFTER TEST \n" + diskCache.getStats() );
+ }
+
+ /**
+ * Verify that the block disk cache can handle utf encoded strings.
+ * <p>
+ *
+ * @throws Exception
+ */
+ public void testUTF8String() throws Exception
+ {
+ String string = "IÒtÎrn‚tiÙn‡lizÊti¯n";
+ StringBuilder sb = new StringBuilder();
+ sb.append(string);
+ for (int i = 0; i < 4; i++)
+ {
+ sb.append(sb.toString()); // big string
+ }
+ string = sb.toString();
+
+ // System.out.println( "The string contains " + string.length() + " characters" );
+
+ String cacheName = "testUTF8String";
+
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
+ IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
+
+ // DO WORK
+ diskCache.update(new CacheElement<>(cacheName, "x", string));
+
+ // VERIFY
+ assertNotNull(diskCache.get("x"));
+ Thread.sleep(1000);
+ ICacheElement<String, String> afterElement = diskCache.get("x");
+ assertNotNull(afterElement);
+ // System.out.println( "afterElement = " + afterElement );
+ String after = afterElement.getVal();
+
+ assertNotNull(after);
+ assertEquals("wrong string after retrieval", string, after);
+ }
+
+ /**
+ * Verify that the block disk cache can handle utf encoded strings.
+ * <p>
+ *
+ * @throws Exception
+ */
+ public void testUTF8ByteArray() throws Exception
+ {
+ String string = "IÒtÎrn‚tiÙn‡lizÊti¯n";
+ StringBuilder sb = new StringBuilder();
+ sb.append(string);
+ for (int i = 0; i < 4; i++)
+ {
+ sb.append(sb.toString()); // big string
+ }
+ string = sb.toString();
+ // System.out.println( "The string contains " + string.length() + " characters" );
+ byte[] bytes = string.getBytes(StandardCharsets.UTF_8);
+
+ String cacheName = "testUTF8ByteArray";
+
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
+ IndexedDiskCache<String, byte[]> diskCache = new IndexedDiskCache<>(cattr);
+
+ // DO WORK
+ diskCache.update(new CacheElement<>(cacheName, "x", bytes));
+
+ // VERIFY
+ assertNotNull(diskCache.get("x"));
+ Thread.sleep(1000);
+ ICacheElement<String, byte[]> afterElement = diskCache.get("x");
+ assertNotNull(afterElement);
+ // System.out.println( "afterElement = " + afterElement );
+ byte[] after = afterElement.getVal();
+
+ assertNotNull(after);
+ assertEquals("wrong bytes after retrieval", string, new String(after, StandardCharsets.UTF_8));
+ }
+
+ /**
+ * Verify the item makes it to disk.
+ * <p>
+ *
+ * @throws IOException
+ */
+ public void testProcessUpdate_Simple() throws IOException
+ {
+ // SETUP
+ String cacheName = "testProcessUpdate_Simple";
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
+ IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
+
+ String key = "myKey";
+ String value = "myValue";
+ ICacheElement<String, String> ce = new CacheElement<>(cacheName, key, value);
+
+ // DO WORK
+ diskCache.processUpdate(ce);
+ ICacheElement<String, String> result = diskCache.processGet(key);
+
+ // VERIFY
+ assertNotNull("Should have a result", result);
+ long fileSize = diskCache.getDataFileSize();
+ assertTrue("File should be greater than 0", fileSize > 0);
+ }
+
+ /**
+ * Verify the item makes it to disk.
+ * <p>
+ *
+ * @throws IOException
+ */
+ public void testProcessUpdate_SameKeySameSize() throws IOException
+ {
+ // SETUP
+ String cacheName = "testProcessUpdate_SameKeySameSize";
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
+ IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
+
+ String key = "myKey";
+ String value = "myValue";
+ ICacheElement<String, String> ce1 = new CacheElement<>(cacheName, key, value);
+
+ // DO WORK
+ diskCache.processUpdate(ce1);
+ long fileSize1 = diskCache.getDataFileSize();
+
+ // DO WORK
+ ICacheElement<String, String> ce2 = new CacheElement<>(cacheName, key, value);
+ diskCache.processUpdate(ce2);
+ ICacheElement<String, String> result = diskCache.processGet(key);
+
+ // VERIFY
+ assertNotNull("Should have a result", result);
+ long fileSize2 = diskCache.getDataFileSize();
+ assertEquals("File should be the same", fileSize1, fileSize2);
+ int binSize = diskCache.getRecyleBinSize();
+ assertEquals("Should be nothing in the bin.", 0, binSize);
+ }
+
+ /**
+ * Verify the item makes it to disk.
+ * <p>
+ *
+ * @throws IOException
+ */
+ public void testProcessUpdate_SameKeySmallerSize() throws IOException
+ {
+ // SETUP
+ String cacheName = "testProcessUpdate_SameKeySmallerSize";
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
+ IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
+
+ String key = "myKey";
+ String value = "myValue";
+ String value2 = "myValu";
+ ICacheElement<String, String> ce1 = new CacheElement<>(cacheName, key, value);
+
+ // DO WORK
+ diskCache.processUpdate(ce1);
+ long fileSize1 = diskCache.getDataFileSize();
+
+ // DO WORK
+ ICacheElement<String, String> ce2 = new CacheElement<>(cacheName, key, value2);
+ diskCache.processUpdate(ce2);
+ ICacheElement<String, String> result = diskCache.processGet(key);
+
+ // VERIFY
+ assertNotNull("Should have a result", result);
+ long fileSize2 = diskCache.getDataFileSize();
+ assertEquals("File should be the same", fileSize1, fileSize2);
+ int binSize = diskCache.getRecyleBinSize();
+ assertEquals("Should be nothing in the bin.", 0, binSize);
+ }
+
+ /**
+ * Verify that the old slot gets in the recycle bin.
+ * <p>
+ *
+ * @throws IOException
+ */
+ public void testProcessUpdate_SameKeyBiggerSize() throws IOException
+ {
+ // SETUP
+ String cacheName = "testProcessUpdate_SameKeyBiggerSize";
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/IndexDiskCacheUnitTest");
+ IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
+
+ String key = "myKey";
+ String value = "myValue";
+ String value2 = "myValue2";
+ ICacheElement<String, String> ce1 = new CacheElement<>(cacheName, key, value);
+
+ // DO WORK
+ diskCache.processUpdate(ce1);
+ long fileSize1 = diskCache.getDataFileSize();
+
+ // DO WORK
+ ICacheElement<String, String> ce2 = new CacheElement<>(cacheName, key, value2);
+ diskCache.processUpdate(ce2);
+ ICacheElement<String, String> result = diskCache.processGet(key);
+
+ // VERIFY
+ assertNotNull("Should have a result", result);
+ long fileSize2 = diskCache.getDataFileSize();
+ assertTrue("File should be greater.", fileSize1 < fileSize2);
+ int binSize = diskCache.getRecyleBinSize();
+ assertEquals("Should be one in the bin.", 1, binSize);
+ }
+
+ public void testLoadFromDisk() throws Exception
+ {
+ for (int i = 0; i < 15; i++)
+ { // usually after 2 time it fails
+ oneLoadFromDisk();
+ }
+ }
+
+ public void oneLoadFromDisk() throws Exception
+ {
+ // initialize object to be stored
+ String string = "IÒtÎrn‚tiÙn‡lizÊti¯n";
+ StringBuilder sb = new StringBuilder();
+ sb.append(string);
+ for (int i = 0; i < 4; i++)
+ {
+ sb.append(sb.toString()); // big string
+ }
+ string = sb.toString();
+
+ // initialize cache
+ String cacheName = "testLoadFromDisk";
+ IndexedDiskCacheAttributes cattr = getCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMaxKeySize(100);
+ cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
+ IndexedDiskCache<String, String> diskCache = new IndexedDiskCache<>(cattr);
+
+ // DO WORK
+ for (int i = 0; i < 50; i++)
+ {
+ diskCache.update(new CacheElement<>(cacheName, "x" + i, string));
+ }
+ // Thread.sleep(1000);
+ // VERIFY
+ diskCache.dispose();
+ // Thread.sleep(1000);
+
+ diskCache = new IndexedDiskCache<>(cattr);
+
+ for (int i = 0; i < 50; i++)
+ {
+ ICacheElement<String, String> afterElement = diskCache.get("x" + i);
+ assertNotNull("Missing element from cache. Cache size: " + diskCache.getSize() + " element: x" + i, afterElement);
+ assertEquals("wrong string after retrieval", string, afterElement.getVal());
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheConcurrentNoDeadLockUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheConcurrentNoDeadLockUnitTest.java
new file mode 100644
index 0000000..8fce991
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheConcurrentNoDeadLockUnitTest.java
@@ -0,0 +1,149 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+
+/*
+ * 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.
+ */
+
+import junit.extensions.ActiveTestSuite;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.textui.TestRunner;
+
+/**
+ * Test which exercises the indexed disk cache. Runs three threads against the
+ * same region.
+ *
+ * @version $Id: TestDiskCacheConcurrentForDeadLock.java,v 1.2 2005/02/01
+ * 00:01:59 asmuts Exp $
+ */
+public class IndexedDiskCacheConcurrentNoDeadLockUnitTest
+ extends TestCase
+{
+ /**
+ * Constructor for the TestDiskCache object.
+ *
+ * @param testName
+ */
+ public IndexedDiskCacheConcurrentNoDeadLockUnitTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * Main method passes this test to the text test runner.
+ *
+ * @param args
+ */
+ public static void main( String args[] )
+ {
+ String[] testCaseName = { IndexedDiskCacheConcurrentNoDeadLockUnitTest.class.getName() };
+ TestRunner.main( testCaseName );
+ }
+
+ /**
+ * A unit test suite for JUnit
+ *
+ * @return The test suite
+ */
+ public static Test suite()
+ {
+ ActiveTestSuite suite = new ActiveTestSuite();
+
+ suite.addTest( new IndexedDiskCacheRandomConcurrentTestUtil( "testIndexedDiskCache1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion4", 1, 200, 1 );
+ }
+ } );
+
+ suite.addTest( new IndexedDiskCacheRandomConcurrentTestUtil( "testIndexedDiskCache2" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion4", 10000, 50000, 2 );
+ }
+ } );
+
+ suite.addTest( new IndexedDiskCacheRandomConcurrentTestUtil( "testIndexedDiskCache3" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion4", 10000, 50000, 3 );
+ }
+ } );
+
+ suite.addTest( new IndexedDiskCacheRandomConcurrentTestUtil( "testIndexedDiskCache4" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion4", 10000, 50000, 4 );
+ }
+ } );
+
+ suite.addTest( new IndexedDiskCacheRandomConcurrentTestUtil( "testIndexedDiskCache5" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion4", 10000, 50000, 5 );
+ }
+ } );
+
+ return suite;
+ }
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestDiskCacheCon.ccf" );
+ }
+
+ /**
+ * Test tearDown. Dispose of the cache.
+ */
+ @Override
+ public void tearDown()
+ {
+ try
+ {
+ CompositeCacheManager cacheMgr = CompositeCacheManager.getInstance();
+ cacheMgr.shutDown();
+ }
+ catch ( Exception e )
+ {
+ // log.error(e);
+ }
+ }
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheConcurrentUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheConcurrentUnitTest.java
new file mode 100644
index 0000000..c0efe32
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheConcurrentUnitTest.java
@@ -0,0 +1,252 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+/*
+ * 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.
+ */
+
+import junit.extensions.ActiveTestSuite;
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/**
+ * Test which exercises the indexed disk cache. This one uses three different
+ * regions for thre threads.
+ *
+ * @version $Id$
+ */
+public class IndexedDiskCacheConcurrentUnitTest
+ extends TestCase
+{
+ /**
+ * Number of items to cache, twice the configured maxObjects for the memory
+ * cache regions.
+ */
+ private static int items = 200;
+
+ /**
+ * Constructor for the TestDiskCache object.
+ *
+ * @param testName
+ */
+ public IndexedDiskCacheConcurrentUnitTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * Main method passes this test to the text test runner.
+ *
+ * @param args
+ */
+ public static void main( String args[] )
+ {
+ String[] testCaseName = { IndexedDiskCacheConcurrentUnitTest.class.getName() };
+ junit.textui.TestRunner.main( testCaseName );
+ }
+
+ /**
+ * A unit test suite for JUnit
+ *
+ * @return The test suite
+ */
+ public static Test suite()
+ {
+ ActiveTestSuite suite = new ActiveTestSuite();
+
+ suite.addTest( new IndexedDiskCacheConcurrentUnitTest( "testIndexedDiskCache1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion1" );
+ }
+ } );
+
+ suite.addTest( new IndexedDiskCacheConcurrentUnitTest( "testIndexedDiskCache2" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion2" );
+ }
+ } );
+
+ suite.addTest( new IndexedDiskCacheConcurrentUnitTest( "testIndexedDiskCache3" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion3" );
+ }
+ } );
+
+ suite.addTest( new IndexedDiskCacheConcurrentUnitTest( "testIndexedDiskCache4" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegionInRange( "indexedRegion3", 300, 600 );
+ }
+ } );
+
+ return suite;
+ }
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestDiskCache.ccf" );
+ }
+
+ /**
+ * Adds items to cache, gets them, and removes them. The item count is more
+ * than the size of the memory cache, so items should spool to disk.
+ *
+ * @param region
+ * Name of the region to access
+ *
+ * @throws Exception
+ * If an error occurs
+ */
+ public void runTestForRegion( String region )
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+
+ // Add items to cache
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+
+ // Test that all items are in cache
+ for ( int i = 0; i <= items; i++ )
+ {
+ String value = jcs.get( i + ":key" );
+
+ assertEquals( region + " data " + i, value );
+ }
+
+ // Test that getElements returns all the expected values
+ Set<String> keys = new HashSet<>();
+ for ( int i = 0; i <= items; i++ )
+ {
+ keys.add( i + ":key" );
+ }
+
+ Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
+ for ( int i = 0; i <= items; i++ )
+ {
+ ICacheElement<String, String> element = elements.get( i + ":key" );
+ assertNotNull( "element " + i + ":key is missing", element );
+ assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
+ }
+
+ // Remove all the items
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.remove( i + ":key" );
+ }
+
+ // Verify removal
+ // another thread may have inserted since
+ for ( int i = 0; i <= items; i++ )
+ {
+ assertNull( "Removed key should be null: " + i + ":key" + "\n stats " + jcs.getStats(), jcs
+ .get( i + ":key" ) );
+ }
+ }
+
+ /**
+ * Adds items to cache, gets them, and removes them. The item count is more
+ * than the size of the memory cache, so items should spool to disk.
+ *
+ * @param region
+ * Name of the region to access
+ * @param start
+ * @param end
+ *
+ * @throws Exception
+ * If an error occurs
+ */
+ public void runTestForRegionInRange( String region, int start, int end )
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+
+ // Add items to cache
+ for ( int i = start; i <= end; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+
+ // Test that all items are in cache
+ for ( int i = start; i <= end; i++ )
+ {
+ String value = jcs.get( i + ":key" );
+
+ assertEquals( region + " data " + i, value );
+ }
+
+ // Test that getElements returns all the expected values
+ Set<String> keys = new HashSet<>();
+ for ( int i = start; i <= end; i++ )
+ {
+ keys.add( i + ":key" );
+ }
+
+ Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
+ for ( int i = start; i <= end; i++ )
+ {
+ ICacheElement<String, String> element = elements.get( i + ":key" );
+ assertNotNull( "element " + i + ":key is missing", element );
+ assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
+ }
+
+ // Remove all the items
+ for ( int i = start; i <= end; i++ )
+ {
+ jcs.remove( i + ":key" );
+ }
+
+// System.out.println( jcs.getStats() );
+
+ // Verify removal
+ // another thread may have inserted since
+ for ( int i = start; i <= end; i++ )
+ {
+ assertNull( "Removed key should be null: " + i + ":key " + "\n stats " + jcs.getStats(), jcs.get( i
+ + ":key" ) );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheDefragPerformanceTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheDefragPerformanceTest.java
new file mode 100644
index 0000000..d64f88f
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheDefragPerformanceTest.java
@@ -0,0 +1,181 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import java.io.Serializable;
+import java.text.DecimalFormat;
+import java.util.Random;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+
+/**
+ * This is for manually testing the defrag process.
+ */
+public class IndexedDiskCacheDefragPerformanceTest
+ extends TestCase
+{
+ /** For readability */
+ private static final String LOG_DIVIDER = "---------------------------";
+
+ /** total to test with */
+ private static final int TOTAL_ELEMENTS = 30000;
+
+ /** time to wait */
+ private static final long SLEEP_TIME_DISK = 8000;
+
+ /** how often to log */
+ private static final int LOG_INCREMENT = 5000;
+
+ /** for getting memory usage */
+ private static Runtime rt = Runtime.getRuntime();
+
+ /** for displaying memory usage */
+ private static DecimalFormat format = new DecimalFormat( "#,###" );
+
+ /**
+ * @throws Exception
+ */
+ public void testRealTimeOptimization()
+ throws Exception
+ {
+ System.out.println( LOG_DIVIDER );
+ System.out.println( "JCS DEFRAG PERFORMANCE TESTS" );
+ System.out.println( LOG_DIVIDER );
+ logMemoryUsage();
+ IndexedDiskCacheDefragPerformanceTest.runRealTimeOptimizationTest();
+ logMemoryUsage();
+
+ System.out.println( LOG_DIVIDER );
+ }
+
+ /**
+ * @throws Exception
+ */
+ private static void runRealTimeOptimizationTest()
+ throws Exception
+ {
+ JCS.setConfigFilename( "/TestDiskCacheDefragPerformance.ccf" );
+ CacheAccess<Integer, Tile> jcs = JCS.getInstance( "defrag" );
+
+ Tile tile;
+ System.out.println( "Cache Defrag Test" );
+
+ Random random = new Random( 89 );
+ for ( int i = 0; i < TOTAL_ELEMENTS; i++ )
+ {
+ int bytes = random.nextInt( 20 );
+ // 4-24 KB
+ tile = new Tile( Integer.valueOf( i ), new byte[( bytes + 4 ) * 1024] );
+ // images
+
+ jcs.put( tile.id, tile );
+
+ if ( ( i != 0 ) && ( 0 == ( i % 100 ) ) )
+ {
+ jcs.get( Integer.valueOf( random.nextInt( i ) ) );
+ }
+
+ if ( 0 == ( i % LOG_INCREMENT ) )
+ {
+ System.out.print( i + ", " );
+ Thread.sleep( SLEEP_TIME_DISK );
+ }
+ }
+
+ System.out.println( LOG_DIVIDER );
+ System.out.println( "Total elements = " + TOTAL_ELEMENTS );
+ System.out.println( "Stats prior to sleeping " + jcs.getStats() );
+
+ // Allow system to settle down
+ System.out.println( "Sleeping for a a minute." );
+ Thread.sleep( 60000 );
+
+ System.out.println( LOG_DIVIDER );
+ System.out.println( "Stats prior to dispose " + jcs.getStats() );
+
+ jcs.dispose();
+ System.out.println( LOG_DIVIDER );
+ System.out.println( "Stats after dispose " + jcs.getStats() );
+ System.out.println( "Done testing." );
+ }
+
+ /**
+ * Logs the memory usage.
+ */
+ private static void logMemoryUsage()
+ {
+ long byte2MB = 1024 * 1024;
+ long total = rt.totalMemory() / byte2MB;
+ long free = rt.freeMemory() / byte2MB;
+ long used = total - free;
+ System.out.println( LOG_DIVIDER );
+ System.out.println( "Memory:" + " Used:" + format.format( used ) + "MB" + " Free:" + format.format( free )
+ + "MB" + " Total:" + format.format( total ) + "MB" );
+ }
+
+ /**
+ * Resembles a cached image.
+ */
+ private static class Tile
+ implements Serializable
+ {
+ /** Don't change */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Key
+ */
+ public Integer id;
+
+ /**Byte size
+ *
+ */
+ public byte[] imageBytes;
+
+ /**
+ * @param id
+ * @param imageBytes
+ */
+ public Tile( Integer id, byte[] imageBytes )
+ {
+ this.id = id;
+ this.imageBytes = imageBytes;
+ }
+ }
+
+ /**
+ * @param args
+ */
+ public static void main( String args[] )
+ {
+ try
+ {
+ IndexedDiskCacheDefragPerformanceTest tester = new IndexedDiskCacheDefragPerformanceTest();
+ tester.testRealTimeOptimization();
+ }
+ catch ( Exception e )
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheKeyStoreUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheKeyStoreUnitTest.java
new file mode 100644
index 0000000..04677ba
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheKeyStoreUnitTest.java
@@ -0,0 +1,152 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+import org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache;
+import org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.ElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Test store and load keys.
+ *
+ * @author Aaron Smuts
+ *
+ */
+public class IndexedDiskCacheKeyStoreUnitTest
+ extends TestCase
+{
+
+ /**
+ * Add some keys, store them, load them from disk, then check to see that we
+ * can get the items.
+ *
+ * @throws Exception
+ *
+ */
+ public void testStoreKeys()
+ throws Exception
+ {
+ IndexedDiskCacheAttributes cattr = new IndexedDiskCacheAttributes();
+ cattr.setCacheName( "testStoreKeys" );
+ cattr.setMaxKeySize( 100 );
+ cattr.setDiskPath( "target/test-sandbox/KeyStoreUnitTest" );
+ IndexedDiskCache<String, String> disk = new IndexedDiskCache<>( cattr );
+
+ disk.processRemoveAll();
+
+ int cnt = 25;
+ for ( int i = 0; i < cnt; i++ )
+ {
+ IElementAttributes eAttr = new ElementAttributes();
+ eAttr.setIsSpool( true );
+ ICacheElement<String, String> element = new CacheElement<>( cattr.getCacheName(), "key:" + i, "data:" + i );
+ element.setElementAttributes( eAttr );
+ disk.processUpdate( element );
+ }
+
+ for ( int i = 0; i < cnt; i++ )
+ {
+ ICacheElement<String, String> element = disk.processGet( "key:" + i );
+ assertNotNull( "presave, Should have received an element.", element );
+ assertEquals( "presave, element is wrong.", "data:" + i, element.getVal() );
+ }
+
+ disk.saveKeys();
+
+ disk.loadKeys();
+
+ assertEquals( "The disk is the wrong size.", cnt, disk.getSize() );
+
+ for ( int i = 0; i < cnt; i++ )
+ {
+ ICacheElement<String, String> element = disk.processGet( "key:" + i );
+ assertNotNull( "postsave, Should have received an element.", element );
+ assertEquals( "postsave, element is wrong.", "data:" + i, element.getVal() );
+ }
+
+ disk.dump();
+
+ }
+
+
+ /**
+ * Add some elements, remove 1, call optimize, verify that the removed isn't present.
+ *
+ * We should also compare the data file sizes. . . .
+ *
+ * @throws Exception
+ *
+ */
+ public void testOptiimize()
+ throws Exception
+ {
+ IndexedDiskCacheAttributes cattr = new IndexedDiskCacheAttributes();
+ cattr.setCacheName( "testOptimize" );
+ cattr.setMaxKeySize( 100 );
+ cattr.setDiskPath( "target/test-sandbox/KeyStoreUnitTest" );
+ IndexedDiskCache<String, String> disk = new IndexedDiskCache<>( cattr );
+
+ disk.processRemoveAll();
+
+ int cnt = 25;
+ for ( int i = 0; i < cnt; i++ )
+ {
+ IElementAttributes eAttr = new ElementAttributes();
+ eAttr.setIsSpool( true );
+ ICacheElement<String, String> element = new CacheElement<>( cattr.getCacheName(), "key:" + i, "data:" + i );
+ element.setElementAttributes( eAttr );
+ disk.processUpdate( element );
+ }
+
+ long preAddRemoveSize = disk.getDataFileSize();
+
+ IElementAttributes eAttr = new ElementAttributes();
+ eAttr.setIsSpool( true );
+ ICacheElement<String, String> elementSetup = new CacheElement<>( cattr.getCacheName(), "key:" + "A", "data:" + "A" );
+ elementSetup.setElementAttributes( eAttr );
+ disk.processUpdate( elementSetup );
+
+ ICacheElement<String, String> elementRet = disk.processGet( "key:" + "A" );
+ assertNotNull( "postsave, Should have received an element.", elementRet );
+ assertEquals( "postsave, element is wrong.", "data:" + "A", elementRet.getVal() );
+
+ disk.remove( "key:" + "A" );
+
+ long preSize = disk.getDataFileSize();
+ // synchronous versoin
+ disk.optimizeFile(); //deoptimizeRealTime();
+ long postSize = disk.getDataFileSize();
+
+ assertTrue( "Should be smaller. postsize="+postSize+" preSize="+preSize, postSize < preSize );
+ assertEquals( "Should be the same size after optimization as before add and remove.", preAddRemoveSize, postSize );
+
+ for ( int i = 0; i < cnt; i++ )
+ {
+ ICacheElement<String, String> element = disk.processGet( "key:" + i );
+ assertNotNull( "postsave, Should have received an element.", element );
+ assertEquals( "postsave, element is wrong.", "data:" + i, element.getVal() );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheNoMemoryUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheNoMemoryUnitTest.java
new file mode 100644
index 0000000..ed63a59
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheNoMemoryUnitTest.java
@@ -0,0 +1,179 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+/*
+ * 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.
+ */
+
+import junit.extensions.ActiveTestSuite;
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/**
+ * Test which exercises the indexed disk cache. This one uses three different
+ * regions for thre threads. It uses a config file that specifies 0 items in
+ * memory.
+ */
+public class IndexedDiskCacheNoMemoryUnitTest
+ extends TestCase
+{
+ /**
+ * Number of items to cache; the configured maxObjects for the memory cache
+ * regions is 0.
+ */
+ private static int items = 2000;
+
+ /**
+ * @param testName
+ */
+ public IndexedDiskCacheNoMemoryUnitTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * Main method passes this test to the text test runner.
+ * <p>
+ * @param args
+ */
+ public static void main( String args[] )
+ {
+ String[] testCaseName = { IndexedDiskCacheNoMemoryUnitTest.class.getName() };
+ junit.textui.TestRunner.main( testCaseName );
+ }
+
+ /**
+ * A unit test suite for JUnit
+ * <p>
+ * @return The test suite
+ */
+ public static Test suite()
+ {
+ ActiveTestSuite suite = new ActiveTestSuite();
+
+ suite.addTest( new IndexedDiskCacheNoMemoryUnitTest( "testIndexedDiskCache1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion1" );
+ }
+ } );
+
+ suite.addTest( new IndexedDiskCacheNoMemoryUnitTest( "testIndexedDiskCache2" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion2" );
+ }
+ } );
+
+ suite.addTest( new IndexedDiskCacheNoMemoryUnitTest( "testIndexedDiskCache3" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion3" );
+ }
+ } );
+
+ return suite;
+ }
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestDiskCacheNoMemory.ccf" );
+ }
+
+ /**
+ * Adds items to cache, gets them, and removes them. The item count is more
+ * than the size of the memory cache, so items should spool to disk.
+ *
+ * @param region
+ * Name of the region to access
+ *
+ * @throws Exception
+ * If an error occurs
+ */
+ public void runTestForRegion( String region )
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+
+ // Add items to cache
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+
+ // Test that all items are in cache
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ String value = jcs.get( i + ":key" );
+
+ assertEquals( region + " data " + i, value );
+ }
+
+ // Test that getElements returns all the expected values
+ Set<String> keys = new HashSet<>();
+ for ( int i = 0; i <= items; i++ )
+ {
+ keys.add( i + ":key" );
+ }
+
+ Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
+ for ( int i = 0; i <= items; i++ )
+ {
+ ICacheElement<String, String> element = elements.get( i + ":key" );
+ assertNotNull( "element " + i + ":key is missing", element );
+ assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
+ }
+
+ // Remove all the items
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.remove( i + ":key" );
+ }
+
+ // Verify removal
+ for ( int i = 0; i <= items; i++ )
+ {
+ assertNull( "Removed key should be null: " + i + ":key" + "\n stats " + jcs.getStats(), jcs.get( i + ":key" ) );
+ }
+
+ // dump the stats to the report
+// System.out.println( jcs.getStats() );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheOptimizationUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheOptimizationUnitTest.java
new file mode 100644
index 0000000..5971ef8
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheOptimizationUnitTest.java
@@ -0,0 +1,97 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+import org.apache.commons.jcs3.auxiliary.disk.DiskTestObject;
+import org.apache.commons.jcs3.utils.timing.SleepUtil;
+import org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache;
+import org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for the optimization routine.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class IndexedDiskCacheOptimizationUnitTest
+ extends TestCase
+{
+ /**
+ * Set the optimize at remove count to 10. Add 20. Check the file size. Remove 10. Check the
+ * times optimized. Check the file size.
+ * @throws Exception
+ */
+ public void testBasicOptimization()
+ throws Exception
+ {
+ // SETUP
+ int removeCount = 50;
+
+ IndexedDiskCacheAttributes cattr = new IndexedDiskCacheAttributes();
+ cattr.setCacheName( "testOptimization" );
+ cattr.setMaxKeySize( removeCount * 2 );
+ cattr.setOptimizeAtRemoveCount( removeCount );
+ cattr.setDiskPath( "target/test-sandbox/testOptimization" );
+ IndexedDiskCache<Integer, DiskTestObject> disk = new IndexedDiskCache<>( cattr );
+
+ disk.removeAll();
+
+ int numberToInsert = removeCount * 3;
+ ICacheElement<Integer, DiskTestObject>[] elements = DiskTestObjectUtil
+ .createCacheElementsWithTestObjectsOfVariableSizes( numberToInsert, cattr.getCacheName() );
+
+ for ( int i = 0; i < elements.length; i++ )
+ {
+ disk.processUpdate( elements[i] );
+ }
+
+
+ Thread.sleep( 1000 );
+ long sizeBeforeRemove = disk.getDataFileSize();
+ // System.out.println( "file sizeBeforeRemove " + sizeBeforeRemove );
+ // System.out.println( "totalSize inserted " + DiskTestObjectUtil.totalSize( elements, numberToInsert ) );
+
+ // DO WORK
+ for ( int i = 0; i < removeCount; i++ )
+ {
+ disk.processRemove( Integer.valueOf( i ) );
+ }
+
+ SleepUtil.sleepAtLeast( 1000 );
+
+ disk.optimizeFile();
+ // VERIFY
+ long sizeAfterRemove = disk.getDataFileSize();
+ long expectedSizeAfterRemove = DiskTestObjectUtil.totalSize( elements, removeCount, elements.length );
+
+ // test is prone to failure for timing reasons.
+ if ( expectedSizeAfterRemove != sizeAfterRemove )
+ {
+ SleepUtil.sleepAtLeast( 2000 );
+ }
+
+ assertTrue( "The post optimization size should be smaller."
+ +"sizeAfterRemove=" + sizeAfterRemove + " sizeBeforeRemove= " +sizeBeforeRemove
+ , sizeAfterRemove < sizeBeforeRemove );
+ assertEquals( "The file size is not as expected size.", expectedSizeAfterRemove, sizeAfterRemove );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheRandomConcurrentTestUtil.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheRandomConcurrentTestUtil.java
new file mode 100644
index 0000000..a557892
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheRandomConcurrentTestUtil.java
@@ -0,0 +1,87 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import org.apache.commons.jcs3.access.TestCacheAccess;
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+
+/**
+ * This is used by other tests to generate a random load on the disk cache.
+ */
+public class IndexedDiskCacheRandomConcurrentTestUtil
+ extends TestCase
+{
+
+ /**
+ * Constructor for the TestDiskCache object.
+ *
+ * @param testName
+ */
+ public IndexedDiskCacheRandomConcurrentTestUtil( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * Randomly adds items to cache, gets them, and removes them. The range
+ * count is more than the size of the memory cache, so items should spool to
+ * disk.
+ *
+ * @param region
+ * Name of the region to access
+ * @param range
+ * @param numOps
+ * @param testNum
+ *
+ * @throws Exception
+ * If an error occurs
+ */
+ public void runTestForRegion( String region, int range, int numOps, int testNum )
+ throws Exception
+ {
+ // run a rondom operation test to detect deadlocks
+ TestCacheAccess tca = new TestCacheAccess( "/TestDiskCacheCon.ccf" );
+ tca.setRegion( region );
+ tca.random( range, numOps );
+
+ // make sure a simple put then get works
+ // this may fail if the other tests are flooding the disk cache
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+ String key = "testKey" + testNum;
+ String data = "testData" + testNum;
+ jcs.put( key, data );
+ String value = jcs.get( key );
+ assertEquals( data, value );
+
+ }
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestDiskCacheCon.ccf" );
+ }
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheSameRegionConcurrentUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheSameRegionConcurrentUnitTest.java
new file mode 100644
index 0000000..21fd45a
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheSameRegionConcurrentUnitTest.java
@@ -0,0 +1,209 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+/*
+ * 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.
+ */
+
+import junit.extensions.ActiveTestSuite;
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/**
+ * Test which exercises the indexed disk cache. Runs three threads against the
+ * same region.
+ */
+public class IndexedDiskCacheSameRegionConcurrentUnitTest
+ extends TestCase
+{
+ /**
+ * Constructor for the TestDiskCache object.
+ *
+ * @param testName
+ */
+ public IndexedDiskCacheSameRegionConcurrentUnitTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * Main method passes this test to the text test runner.
+ *
+ * @param args
+ */
+ public static void main( String args[] )
+ {
+ String[] testCaseName = { IndexedDiskCacheSameRegionConcurrentUnitTest.class.getName() };
+ junit.textui.TestRunner.main( testCaseName );
+ }
+
+ /**
+ * A unit test suite for JUnit
+ *
+ * @return The test suite
+ */
+ public static Test suite()
+ {
+ ActiveTestSuite suite = new ActiveTestSuite();
+
+ suite.addTest( new IndexedDiskCacheSameRegionConcurrentUnitTest( "testIndexedDiskCache1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion4", 0, 200 );
+ }
+ } );
+
+ suite.addTest( new IndexedDiskCacheSameRegionConcurrentUnitTest( "testIndexedDiskCache2" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion4", 1000, 1200 );
+ }
+ } );
+
+ suite.addTest( new IndexedDiskCacheSameRegionConcurrentUnitTest( "testIndexedDiskCache3" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion4", 2000, 2200 );
+ }
+ } );
+
+ suite.addTest( new IndexedDiskCacheSameRegionConcurrentUnitTest( "testIndexedDiskCache4" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion4", 2200, 5200 );
+ }
+ } );
+
+ suite.addTest( new IndexedDiskCacheSameRegionConcurrentUnitTest( "testIndexedDiskCache5" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion4", 0, 5100 );
+ }
+ } );
+
+ return suite;
+ }
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestDiskCacheCon.ccf" );
+ }
+
+ // /**
+ // * Tests the region which uses the indexed disk cache
+ // */
+ // public void testIndexedDiskCache()
+ // throws Exception
+ // {
+ // runTestForRegion( "indexedRegion" );
+ // }
+ //
+ // /**
+ // * Tests the region which uses the indexed disk cache
+ // */
+ // public void testIndexedDiskCache2()
+ // throws Exception
+ // {
+ // runTestForRegion( "indexedRegion2" );
+ // }
+
+ /**
+ * Adds items to cache, gets them, and removes them. The item count is more
+ * than the size of the memory cache, so items should spool to disk.
+ *
+ * @param region
+ * Name of the region to access
+ * @param start
+ * @param end
+ *
+ * @throws Exception
+ * If an error occurs
+ */
+ public void runTestForRegion( String region, int start, int end )
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+
+ // Add items to cache
+
+ for ( int i = start; i <= end; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+
+ // Test that all items are in cache
+
+ for ( int i = start; i <= end; i++ )
+ {
+ String key = i + ":key";
+ String value = jcs.get( key );
+
+ assertEquals( "Wrong value for key [" + key + "]", region + " data " + i, value );
+ }
+
+ // Test that getElements returns all the expected values
+ Set<String> keys = new HashSet<>();
+ for ( int i = start; i <= end; i++ )
+ {
+ keys.add( i + ":key" );
+ }
+
+ Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
+ for ( int i = start; i <= end; i++ )
+ {
+ ICacheElement<String, String> element = elements.get( i + ":key" );
+ assertNotNull( "element " + i + ":key is missing", element );
+ assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
+ }
+
+ // you can't remove in one thread and expect them to be in another //
+ // Remove all the items
+ //
+ // for ( int i = start; i <= end; i++ ) { jcs.remove( i + ":key" ); } //
+ // Verify removal
+ //
+ // for ( int i = start; i <= end; i++ ) { assertNull( "Removed key
+ // should be null: " + i + ":key", jcs.get( i + ":key" ) ); }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheSteadyLoadTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheSteadyLoadTest.java
new file mode 100644
index 0000000..ad700ac
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/IndexedDiskCacheSteadyLoadTest.java
@@ -0,0 +1,154 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import org.apache.commons.jcs3.auxiliary.disk.DiskTestObject;
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.utils.timing.ElapsedTimer;
+
+import java.text.DecimalFormat;
+import java.util.Random;
+
+/**
+ * This allows you to put thousands of large objects into the disk cache and to force removes to
+ * trigger optimizations along the way.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class IndexedDiskCacheSteadyLoadTest
+ extends TestCase
+{
+ /** For display */
+ private static final String LOG_DIVIDER = "---------------------------";
+
+ /** For getting memory info */
+ private static Runtime rt = Runtime.getRuntime();
+
+ /** For display */
+ private static DecimalFormat format = new DecimalFormat( "#,###" );
+
+ /**
+ * Insert 2000 wait 1 second, repeat. Average 1000 / sec.
+ * <p>
+ * @throws Exception
+ */
+ public void testRunSteadyLoadTest()
+ throws Exception
+ {
+ JCS.setConfigFilename( "/TestDiskCacheSteadyLoad.ccf" );
+
+ System.out.println( "runSteadyLoadTest" );
+
+ logMemoryUsage();
+
+ int numPerRun = 200;
+ long pauseBetweenRuns = 1000;
+ int runCount = 0;
+ int runs = 1000;
+ int upperKB = 50;
+
+ CacheAccess<String, DiskTestObject> jcs = JCS.getInstance( ( numPerRun / 2 ) + "aSecond" );
+
+ ElapsedTimer timer = new ElapsedTimer();
+ int numToGet = numPerRun * ( runs / 10 );
+ for ( int i = 0; i < numToGet; i++ )
+ {
+ jcs.get( String.valueOf( i ) );
+ }
+ System.out.println( LOG_DIVIDER );
+ System.out.println( "After getting " + numToGet );
+ System.out.println( "Elapsed " + timer.getElapsedTimeString() );
+ logMemoryUsage();
+
+ jcs.clear();
+ Thread.sleep( 3000 );
+ System.out.println( LOG_DIVIDER );
+ System.out.println( "Start putting" );
+
+ long totalSize = 0;
+ int totalPut = 0;
+
+ Random random = new Random( 89 );
+ while ( runCount < runs )
+ {
+ runCount++;
+ for ( int i = 0; i < numPerRun; i++ )
+ {
+ // 1/2 upper to upperKB-4 KB
+ int kiloBytes = Math.max( upperKB / 2, random.nextInt( upperKB ) );
+ int bytes = ( kiloBytes ) * 1024;
+ totalSize += bytes;
+ totalPut++;
+ DiskTestObject object = new DiskTestObject( Integer.valueOf( i ), new byte[bytes] );
+ jcs.put( String.valueOf( totalPut ), object );
+ }
+
+ // remove half of those inserted the previous run
+ if ( runCount > 1 )
+ {
+ for ( int j = ( ( totalPut - numPerRun ) - ( numPerRun / 2 ) ); j < ( totalPut - numPerRun ); j++ )
+ {
+ jcs.remove( String.valueOf( j ) );
+ }
+ }
+
+ Thread.sleep( pauseBetweenRuns );
+ if ( runCount % 100 == 0 )
+ {
+ System.out.println( LOG_DIVIDER );
+ System.out.println( "Elapsed " + timer.getElapsedTimeString() );
+ System.out.println( "Run count: " + runCount + " Average size: " + ( totalSize / totalPut ) + "\n"
+ + jcs.getStats() );
+ logMemoryUsage();
+ }
+ }
+
+ Thread.sleep( 3000 );
+ System.out.println( jcs.getStats() );
+ logMemoryUsage();
+
+ Thread.sleep( 10000 );
+ System.out.println( jcs.getStats() );
+ logMemoryUsage();
+
+ System.gc();
+ Thread.sleep( 3000 );
+ System.gc();
+ System.out.println( jcs.getStats() );
+ logMemoryUsage();
+ }
+
+ /**
+ * Logs the memory usage.
+ */
+ private static void logMemoryUsage()
+ {
+ long byte2MB = 1024 * 1024;
+ long total = rt.totalMemory() / byte2MB;
+ long free = rt.freeMemory() / byte2MB;
+ long used = total - free;
+ System.out.println( LOG_DIVIDER );
+ System.out.println( "Memory:" + " Used:" + format.format( used ) + "MB" + " Free:" + format.format( free )
+ + "MB" + " Total:" + format.format( total ) + "MB" );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/LRUMapSizeVsCount.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/LRUMapSizeVsCount.java
new file mode 100644
index 0000000..3bbf6d3
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/indexed/LRUMapSizeVsCount.java
@@ -0,0 +1,240 @@
+package org.apache.commons.jcs3.auxiliary.disk.indexed;
+
+/*
+ * 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.
+ */
+
+import java.util.Map;
+
+import org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache;
+import org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskElementDescriptor;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * This ensures that the jcs version of the LRU map is as fast as the commons
+ * version. It has been testing at .6 to .7 times the commons LRU.
+ * <p>
+ * @author aaronsm
+ *
+ */
+public class LRUMapSizeVsCount
+ extends TestCase
+{
+ /** The put put ration after the test */
+ double ratioPut = 0;
+
+ /** The ratio after the test */
+ double ratioGet = 0;
+
+ /** put size / count ratio */
+ float targetPut = 1.2f;
+
+ /** get size / count ratio */
+ float targetGet = 1.2f;
+
+ /** Time to loop */
+ int loops = 20;
+
+ /** items to put and get per loop */
+ int tries = 100000;
+
+ /**
+ * @param testName
+ */
+ public LRUMapSizeVsCount( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * A unit test suite for JUnit
+ * <p>
+ * @return The test suite
+ */
+ public static Test suite()
+ {
+ return new TestSuite( LRUMapSizeVsCount.class );
+ }
+
+ /**
+ * A unit test for JUnit
+ *
+ * @throws Exception
+ * Description of the Exception
+ */
+ public void testSimpleLoad()
+ throws Exception
+ {
+ doWork();
+ assertTrue( this.ratioPut < targetPut );
+ assertTrue( this.ratioGet < targetGet );
+ }
+
+ /**
+ *
+ */
+ public void doWork()
+ {
+ long start = 0;
+ long end = 0;
+ long time = 0;
+ float tPer = 0;
+
+ long putTotalCount = 0;
+ long getTotalCount = 0;
+ long putTotalSize = 0;
+ long getTotalSize = 0;
+
+ long minTimeSizePut = Long.MAX_VALUE;
+ long minTimeSizeGet = Long.MAX_VALUE;
+ long minTimeCountPut = Long.MAX_VALUE;
+ long minTimeCountGet = Long.MAX_VALUE;
+
+ String cacheName = "LRUMap";
+ String cache2Name = "";
+
+ try
+ {
+ IndexedDiskCacheAttributes cattr = new IndexedDiskCacheAttributes();
+ cattr.setName("junit");
+ cattr.setCacheName("junit");
+ cattr.setDiskPath(".");
+ IndexedDiskCache<String, String> idc = new IndexedDiskCache<>(cattr);
+
+ Map<String, IndexedDiskElementDescriptor> cacheCount = idc.new LRUMapCountLimited( tries );
+ Map<String, IndexedDiskElementDescriptor> cacheSize = idc.new LRUMapSizeLimited( tries/1024/2 );
+
+ for ( int j = 0; j < loops; j++ )
+ {
+ cacheName = "LRU Count ";
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ cacheCount.put( "key:" + i, new IndexedDiskElementDescriptor(i, i) );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ putTotalCount += time;
+ minTimeCountPut = Math.min(time, minTimeCountPut);
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( cacheName + " put time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ cacheCount.get( "key:" + i );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ getTotalCount += time;
+ minTimeCountGet = Math.min(minTimeCountGet, time);
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( cacheName + " get time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ ///////////////////////////////////////////////////////////////
+ cache2Name = "LRU Size ";
+ //or LRUMapJCS
+ //cache2Name = "Hashtable";
+ //Hashtable cache2 = new Hashtable();
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ cacheSize.put( "key:" + i, new IndexedDiskElementDescriptor(i, i) );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ putTotalSize += time;
+ minTimeSizePut = Math.min(minTimeSizePut, time);
+
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( cache2Name + " put time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ cacheSize.get( "key:" + i );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ getTotalSize += time;
+ minTimeSizeGet = Math.min(minTimeSizeGet, time);
+
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( cache2Name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ System.out.println( "\n" );
+ }
+ }
+ catch ( Exception e )
+ {
+ e.printStackTrace( System.out );
+ System.out.println( e );
+ }
+
+ long putAvCount = putTotalCount / loops;
+ long getAvCount = getTotalCount / loops;
+ long putAvSize = putTotalSize / loops;
+ long getAvSize = getTotalSize / loops;
+
+ System.out.println( "Finished " + loops + " loops of " + tries + " gets and puts" );
+
+ System.out.println( "\n" );
+ System.out.println( "Put average for " + cacheName + " = " + putAvCount );
+ System.out.println( "Put average for " + cache2Name + " = " + putAvSize );
+ ratioPut = (putAvSize *1.0) / putAvCount;
+ System.out.println( cache2Name.trim() + " puts took " + ratioPut + " times the " + cacheName.trim() + ", the goal is <" + targetPut
+ + "x" );
+
+ System.out.println( "\n" );
+ System.out.println( "Put minimum for " + cacheName + " = " + minTimeCountPut );
+ System.out.println( "Put minimum for " + cache2Name + " = " + minTimeSizePut );
+ ratioPut = (minTimeSizePut * 1.0) / minTimeCountPut;
+ System.out.println( cache2Name.trim() + " puts took " + ratioPut + " times the " + cacheName.trim() + ", the goal is <" + targetPut
+ + "x" );
+
+ System.out.println( "\n" );
+ System.out.println( "Get average for " + cacheName + " = " + getAvCount );
+ System.out.println( "Get average for " + cache2Name + " = " + getAvSize );
+ ratioGet = Float.intBitsToFloat( (int) getAvCount ) / Float.intBitsToFloat( (int) getAvSize );
+ ratioGet = (getAvSize * 1.0) / getAvCount;
+ System.out.println( cache2Name.trim() + " gets took " + ratioGet + " times the " + cacheName.trim() + ", the goal is <" + targetGet
+ + "x" );
+
+ System.out.println( "\n" );
+ System.out.println( "Get minimum for " + cacheName + " = " + minTimeCountGet );
+ System.out.println( "Get minimum for " + cache2Name + " = " + minTimeSizeGet );
+ ratioPut = (minTimeSizeGet * 1.0) / minTimeCountGet;
+ System.out.println( cache2Name.trim() + " puts took " + ratioPut + " times the " + cacheName.trim() + ", the goal is <" + targetGet
+ + "x" );
+
+ }
+
+ /**
+ * @param args
+ */
+ public static void main( String args[] )
+ {
+ LRUMapSizeVsCount test = new LRUMapSizeVsCount( "command" );
+ test.doWork();
+ }
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/HsqlSetupTableUtil.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/HsqlSetupTableUtil.java
new file mode 100644
index 0000000..7246109
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/HsqlSetupTableUtil.java
@@ -0,0 +1,43 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc;
+
+/*
+ * 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.
+ */
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.hsql.HSQLDiskCacheFactory;
+
+/** Can use this to setup a table. */
+public class HsqlSetupTableUtil extends HSQLDiskCacheFactory
+{
+ /**
+ * SETUP a TABLE FOR CACHE testing
+ * <p>
+ * @param cConn
+ * @param tableName
+ *
+ * @throws SQLException if database problems occur
+ */
+ public static void setupTABLE( Connection cConn, String tableName ) throws SQLException
+ {
+ HsqlSetupTableUtil util = new HsqlSetupTableUtil();
+ util.setupTable(cConn, tableName);
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDataSourceFactoryUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDataSourceFactoryUnitTest.java
new file mode 100644
index 0000000..bbec16b
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDataSourceFactoryUnitTest.java
@@ -0,0 +1,207 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc;
+
+/*
+ * 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.
+ */
+
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+
+import org.apache.commons.dbcp2.BasicDataSource;
+import org.apache.commons.dbcp2.datasources.SharedPoolDataSource;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheFactory;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.DataSourceFactory;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.JndiDataSourceFactory;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.SharedPoolDataSourceFactory;
+
+import junit.framework.TestCase;
+
+/** Unit tests for the data source factories */
+public class JDBCDataSourceFactoryUnitTest
+ extends TestCase
+{
+ /** Verify that we can configure the object based on the props.
+ * @throws SQLException
+ */
+ public void testConfigureDataSourceFactory_Simple() throws SQLException
+ {
+ // SETUP
+ String poolName = "testConfigurePoolAccessAttributes_Simple";
+
+ String url = "adfads";
+ String userName = "zvzvz";
+ String password = "qewrrewq";
+ int maxActive = 10;
+ String driverClassName = "org.hsqldb.jdbcDriver";
+
+ Properties props = new Properties();
+ String prefix = JDBCDiskCacheFactory.POOL_CONFIGURATION_PREFIX
+ + poolName
+ + JDBCDiskCacheFactory.ATTRIBUTE_PREFIX;
+ props.put( prefix + ".url", url );
+ props.put( prefix + ".userName", userName );
+ props.put( prefix + ".password", password );
+ props.put( prefix + ".maxActive", String.valueOf( maxActive ) );
+ props.put( prefix + ".driverClassName", driverClassName );
+
+ JDBCDiskCacheFactory factory = new JDBCDiskCacheFactory();
+ factory.initialize();
+
+ JDBCDiskCacheAttributes cattr = new JDBCDiskCacheAttributes();
+ cattr.setConnectionPoolName( poolName );
+
+ // DO WORK
+ DataSourceFactory result = factory.getDataSourceFactory( cattr, props );
+ assertTrue("Should be a shared pool data source factory", result instanceof SharedPoolDataSourceFactory);
+
+ SharedPoolDataSource spds = (SharedPoolDataSource) result.getDataSource();
+ assertNotNull( "Should have a data source class", spds );
+
+ // VERIFY
+ assertEquals( "Wrong pool name", poolName, spds.getDescription() );
+ assertEquals( "Wrong maxActive value", maxActive, spds.getMaxTotal() );
+ }
+
+ /** Verify that we can configure the object based on the attributes.
+ * @throws SQLException
+ */
+ public void testConfigureDataSourceFactory_Attributes() throws SQLException
+ {
+ // SETUP
+ String url = "adfads";
+ String userName = "zvzvz";
+ String password = "qewrrewq";
+ int maxActive = 10;
+ String driverClassName = "org.hsqldb.jdbcDriver";
+
+ JDBCDiskCacheFactory factory = new JDBCDiskCacheFactory();
+ factory.initialize();
+
+ JDBCDiskCacheAttributes cattr = new JDBCDiskCacheAttributes();
+ cattr.setUrl(url);
+ cattr.setUserName(userName);
+ cattr.setPassword(password);
+ cattr.setMaxTotal(maxActive);
+ cattr.setDriverClassName(driverClassName);
+
+ // DO WORK
+ DataSourceFactory result = factory.getDataSourceFactory( cattr, null );
+ assertTrue("Should be a shared pool data source factory", result instanceof SharedPoolDataSourceFactory);
+
+ SharedPoolDataSource spds = (SharedPoolDataSource) result.getDataSource();
+ assertNotNull( "Should have a data source class", spds );
+
+ // VERIFY
+ assertEquals( "Wrong maxActive value", maxActive, spds.getMaxTotal() );
+ }
+
+ /** Verify that we can configure the object based on JNDI.
+ * @throws SQLException
+ */
+ public void testConfigureDataSourceFactory_JNDI() throws SQLException
+ {
+ // SETUP
+ String jndiPath = "java:comp/env/jdbc/MyDB";
+ long ttl = 300000L;
+
+ System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
+ MockInitialContextFactory.class.getName());
+
+ MockInitialContextFactory.bind(jndiPath, new BasicDataSource());
+
+ JDBCDiskCacheFactory factory = new JDBCDiskCacheFactory();
+ factory.initialize();
+
+ JDBCDiskCacheAttributes cattr = new JDBCDiskCacheAttributes();
+ cattr.setJndiPath(jndiPath);
+ cattr.setJndiTTL(ttl);
+
+ // DO WORK
+ DataSourceFactory result = factory.getDataSourceFactory( cattr, null );
+ assertTrue("Should be a JNDI data source factory", result instanceof JndiDataSourceFactory);
+ }
+
+ /* For JNDI mocking */
+ public static class MockInitialContextFactory implements InitialContextFactory
+ {
+ private static Context context;
+
+ static
+ {
+ try
+ {
+ context = new InitialContext(true)
+ {
+ Map<String, Object> bindings = new HashMap<>();
+
+ @Override
+ public void bind(String name, Object obj) throws NamingException
+ {
+ bindings.put(name, obj);
+ }
+
+ @Override
+ public Object lookup(String name) throws NamingException
+ {
+ return bindings.get(name);
+ }
+
+ @Override
+ public Hashtable<?, ?> getEnvironment() throws NamingException
+ {
+ return new Hashtable<>();
+ }
+ };
+ }
+ catch (NamingException e)
+ {
+ // can't happen.
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException
+ {
+ return context;
+ }
+
+ public static void bind(String name, Object obj)
+ {
+ try
+ {
+ context.bind(name, obj);
+ }
+ catch (NamingException e)
+ {
+ // can't happen.
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
+
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCacheRemovalUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCacheRemovalUnitTest.java
new file mode 100644
index 0000000..c103a81
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCacheRemovalUnitTest.java
@@ -0,0 +1,109 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc;
+
+/*
+ * 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.
+ */
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+
+import junit.framework.TestCase;
+
+/** Tests for the removal functionality. */
+public class JDBCDiskCacheRemovalUnitTest
+ extends TestCase
+{
+ /** db name -- set in system props */
+ private final String databaseName = "JCS_STORE_REMOVAL";
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ System.setProperty( "DATABASE_NAME", databaseName );
+ JCS.setConfigFilename( "/TestJDBCDiskCacheRemoval.ccf" );
+ }
+
+ /**
+ * Verify the fix for BUG JCS-20
+ * <p>
+ * Setup an hsql db. Add an item. Remove using partial key.
+ * @throws Exception
+ */
+ public void testPartialKeyRemoval_Good()
+ throws Exception
+ {
+ // SETUP
+ setupDatabase();
+
+ String keyPart1 = "part1";
+ String keyPart2 = "part2";
+ String region = "testCache1";
+ String data = "adfadsfasfddsafasasd";
+
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+
+ // DO WORK
+ jcs.put( keyPart1 + ":" + keyPart2, data );
+ Thread.sleep( 1000 );
+
+ // VERIFY
+ String resultBeforeRemove = jcs.get( keyPart1 + ":" + keyPart2 );
+ assertEquals( "Wrong result", data, resultBeforeRemove );
+
+ jcs.remove( keyPart1 + ":" );
+ String resultAfterRemove = jcs.get( keyPart1 + ":" + keyPart2 );
+ assertNull( "Should not have a result after removal.", resultAfterRemove );
+
+// System.out.println( jcs.getStats() );
+ }
+
+ /**
+ * Create the database.
+ * @throws InstantiationException
+ * @throws IllegalAccessException
+ * @throws ClassNotFoundException
+ * @throws SQLException
+ */
+ private void setupDatabase()
+ throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException
+ {
+ System.setProperty( "hsqldb.cache_scale", "8" );
+
+ String rafroot = "target";
+ Properties p = new Properties();
+ String driver = p.getProperty( "driver", "org.hsqldb.jdbcDriver" );
+ String url = p.getProperty( "url", "jdbc:hsqldb:" );
+ String database = p.getProperty( "database", rafroot + "/JDBCDiskCacheRemovalUnitTest" );
+ String user = p.getProperty( "user", "sa" );
+ String password = p.getProperty( "password", "" );
+
+ new org.hsqldb.jdbcDriver();
+ Class.forName( driver ).newInstance();
+ Connection cConn = DriverManager.getConnection( url + database, user, password );
+
+ HsqlSetupTableUtil.setupTABLE( cConn, databaseName );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCacheSharedPoolUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCacheSharedPoolUnitTest.java
new file mode 100644
index 0000000..7a2d233
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCacheSharedPoolUnitTest.java
@@ -0,0 +1,142 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/**
+ * Runs basic tests for the JDBC disk cache using a shared connection pool.
+ *<p>
+ * @author Aaron Smuts
+ */
+public class JDBCDiskCacheSharedPoolUnitTest
+ extends TestCase
+{
+ /** Test setup */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestJDBCDiskCacheSharedPool.ccf" );
+ }
+
+ /**
+ * Test the basic JDBC disk cache functionality with a hsql backing.
+ * @throws Exception
+ */
+ public void testSimpleJDBCPutGetWithHSQL()
+ throws Exception
+ {
+ System.setProperty( "hsqldb.cache_scale", "8" );
+
+ String rafroot = "target";
+ Properties p = new Properties();
+ String driver = p.getProperty( "driver", "org.hsqldb.jdbcDriver" );
+ String url = p.getProperty( "url", "jdbc:hsqldb:" );
+ String database = p.getProperty( "database", rafroot + "/cache_hsql_db_sharedpool" );
+ String user = p.getProperty( "user", "sa" );
+ String password = p.getProperty( "password", "" );
+
+ new org.hsqldb.jdbcDriver();
+ Class.forName( driver ).newInstance();
+ Connection cConn = DriverManager.getConnection( url + database, user, password );
+
+ HsqlSetupTableUtil.setupTABLE( cConn, "JCS_STORE_0" );
+
+ HsqlSetupTableUtil.setupTABLE( cConn, "JCS_STORE_1" );
+
+ runTestForRegion( "testCache1", 200 );
+ }
+
+ /**
+ * Adds items to cache, gets them, and removes them. The item count is more than the size of the
+ * memory cache, so items should spool to disk.
+ * <p>
+ * @param region Name of the region to access
+ * @param items
+ * @throws Exception If an error occurs
+ */
+ public void runTestForRegion( String region, int items )
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+
+// System.out.println( "BEFORE PUT \n" + jcs.getStats() );
+
+ // Add items to cache
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+
+// System.out.println( jcs.getStats() );
+
+ Thread.sleep( 1000 );
+
+// System.out.println( jcs.getStats() );
+
+ // Test that all items are in cache
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ String value = jcs.get( i + ":key" );
+
+ assertEquals( "key = [" + i + ":key] value = [" + value + "]", region + " data " + i, value );
+ }
+
+ // Test that getElements returns all the expected values
+ Set<String> keys = new HashSet<>();
+ for ( int i = 0; i <= items; i++ )
+ {
+ keys.add( i + ":key" );
+ }
+
+ Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
+ for ( int i = 0; i <= items; i++ )
+ {
+ ICacheElement<String, String> element = elements.get( i + ":key" );
+ assertNotNull( "element " + i + ":key is missing", element );
+ assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
+ }
+
+ // Remove all the items
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.remove( i + ":key" );
+ }
+
+ // Verify removal
+ for ( int i = 0; i <= items; i++ )
+ {
+ assertNull( "Removed key should be null: " + i + ":key", jcs.get( i + ":key" ) );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCacheShrinkUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCacheShrinkUnitTest.java
new file mode 100644
index 0000000..264be54
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCacheShrinkUnitTest.java
@@ -0,0 +1,222 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc;
+
+/*
+ * 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.
+ */
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.util.Properties;
+
+import org.apache.commons.jcs3.utils.timing.SleepUtil;
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Runs basic tests for the JDBC disk cache.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class JDBCDiskCacheShrinkUnitTest
+{
+ /**
+ * Creates the DB
+ * <p>
+ * @throws Exception
+ */
+ @BeforeClass
+ public static void setupDatabase() throws Exception
+ {
+ System.setProperty( "hsqldb.cache_scale", "8" );
+
+ String rafroot = "target";
+ Properties p = new Properties();
+ String driver = p.getProperty( "driver", "org.hsqldb.jdbcDriver" );
+ String url = p.getProperty( "url", "jdbc:hsqldb:" );
+ String database = p.getProperty( "database", rafroot + "/JDBCDiskCacheShrinkUnitTest" );
+ String user = p.getProperty( "user", "sa" );
+ String password = p.getProperty( "password", "" );
+
+ new org.hsqldb.jdbcDriver();
+ Class.forName( driver ).newInstance();
+ Connection cConn = DriverManager.getConnection( url + database, user, password );
+
+ HsqlSetupTableUtil.setupTABLE( cConn, "JCS_STORE_SHRINK" );
+ }
+
+ /**
+ * Test setup
+ */
+ @Before
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestJDBCDiskCacheShrink.ccf" );
+ }
+
+ /**
+ * Test the basic JDBC disk cache functionality with a hsql backing. Verify that items
+ * configured to expire after 1 second actually expire.
+ * <p>
+ * @throws Exception
+ */
+ @Test
+ public void testExpireInBackground()
+ throws Exception
+ {
+ String regionExpire = "expire1Second";
+ int items = 200;
+
+ CacheAccess<String, String> jcsExpire = JCS.getInstance( regionExpire );
+
+// System.out.println( "BEFORE PUT \n" + jcsExpire.getStats() );
+
+ // Add items to cache
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcsExpire.put( i + ":key", regionExpire + " data " + i );
+ }
+
+// System.out.println( jcsExpire.getStats() );
+
+ // the shrinker is supposed to run every second
+ SleepUtil.sleepAtLeast( 3000 );
+
+// System.out.println( jcsExpire.getStats() );
+
+ // Test that all items have been removed from the cache
+ for ( int i = 0; i <= items; i++ )
+ {
+ assertNull( "Removed key should be null: " + i + ":key", jcsExpire.get( i + ":key" ) );
+ }
+ }
+
+ /**
+ * Verify that those not scheduled to expire do not expire.
+ * <p>
+ * @throws CacheException
+ * @throws InterruptedException
+ */
+ @Test
+ public void testDidNotExpire()
+ throws CacheException, InterruptedException
+ {
+ String region = "expire100Second";
+ int items = 200;
+
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+
+// System.out.println( "BEFORE PUT \n" + jcs.getStats() );
+
+ // Add items to cache
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+
+// System.out.println( jcs.getStats() );
+
+ SleepUtil.sleepAtLeast( 1000 );
+
+// System.out.println( jcs.getStats() );
+
+ // Test that all items are in cache
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ String value = jcs.get( i + ":key" );
+
+ assertEquals( "key = [" + i + ":key] value = [" + value + "]", region + " data " + i, value );
+ }
+
+ // Remove all the items
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.remove( i + ":key" );
+ }
+
+ // Verify removal
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ assertNull( "Removed key should be null: " + i + ":key", jcs.get( i + ":key" ) );
+ }
+ }
+
+ /**
+ * Verify that eternal trumps max life.
+ * @throws CacheException
+ * @throws InterruptedException
+ */
+ @Test
+ public void testDidNotExpireEternal()
+ throws CacheException, InterruptedException
+ {
+ String region = "eternal";
+ int items = 200;
+
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+
+// System.out.println( "BEFORE PUT \n" + jcs.getStats() );
+
+ // Add items to cache
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+
+// System.out.println( jcs.getStats() );
+
+ SleepUtil.sleepAtLeast( 1000 );
+
+// System.out.println( jcs.getStats() );
+
+ // Test that all items are in cache
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ String value = jcs.get( i + ":key" );
+
+ assertEquals( "key = [" + i + ":key] value = [" + value + "]", region + " data " + i, value );
+ }
+
+ // Remove all the items
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.remove( i + ":key" );
+ }
+
+ // Verify removal
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ assertNull( "Removed key should be null: " + i + ":key", jcs.get( i + ":key" ) );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCacheUnitTest.java
new file mode 100644
index 0000000..a58423b
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/JDBCDiskCacheUnitTest.java
@@ -0,0 +1,209 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc;
+
+/*
+ * 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.
+ */
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.Executors;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.jcs3.engine.control.MockCompositeCacheManager;
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCache;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheFactory;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.DataSourceFactory;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+import org.apache.commons.jcs3.utils.threadpool.DaemonThreadFactory;
+
+/**
+ * Runs basic tests for the JDBC disk cache.
+ *<p>
+ * @author Aaron Smuts
+ */
+public class JDBCDiskCacheUnitTest
+ extends TestCase
+{
+ /** Test setup */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestJDBCDiskCache.ccf" );
+ }
+
+ /**
+ * Test the basic JDBC disk cache functionality with a hsql backing.
+ * @throws Exception
+ */
+ public void testSimpleJDBCPutGetWithHSQL()
+ throws Exception
+ {
+ System.setProperty( "hsqldb.cache_scale", "8" );
+
+ String rafroot = "target";
+ Properties p = new Properties();
+ String driver = p.getProperty( "driver", "org.hsqldb.jdbcDriver" );
+ String url = p.getProperty( "url", "jdbc:hsqldb:" );
+ String database = p.getProperty( "database", rafroot + "/cache_hsql_db" );
+ String user = p.getProperty( "user", "sa" );
+ String password = p.getProperty( "password", "" );
+
+ new org.hsqldb.jdbcDriver();
+ Class.forName( driver ).newInstance();
+ Connection cConn = DriverManager.getConnection( url + database, user, password );
+
+ HsqlSetupTableUtil.setupTABLE( cConn, "JCS_STORE2" );
+
+ runTestForRegion( "testCache1", 200 );
+ }
+
+ /**
+ * Adds items to cache, gets them, and removes them. The item count is more than the size of the
+ * memory cache, so items should spool to disk.
+ * <p>
+ * @param region Name of the region to access
+ * @param items
+ * @throws Exception If an error occurs
+ */
+ public void runTestForRegion( String region, int items )
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+
+// System.out.println( "BEFORE PUT \n" + jcs.getStats() );
+
+ // Add items to cache
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+
+// System.out.println( jcs.getStats() );
+
+ Thread.sleep( 1000 );
+
+// System.out.println( jcs.getStats() );
+
+ // Test that all items are in cache
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ String value = jcs.get( i + ":key" );
+
+ assertEquals( "key = [" + i + ":key] value = [" + value + "]", region + " data " + i, value );
+ }
+
+ // Test that getElements returns all the expected values
+ Set<String> keys = new HashSet<>();
+ for ( int i = 0; i <= items; i++ )
+ {
+ keys.add( i + ":key" );
+ }
+
+ Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
+ for ( int i = 0; i <= items; i++ )
+ {
+ ICacheElement<String, String> element = elements.get( i + ":key" );
+ assertNotNull( "element " + i + ":key is missing", element );
+ assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
+ }
+
+ // Remove all the items
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.remove( i + ":key" );
+ }
+
+ // Verify removal
+ for ( int i = 0; i <= items; i++ )
+ {
+ assertNull( "Removed key should be null: " + i + ":key", jcs.get( i + ":key" ) );
+ }
+ }
+
+ /**
+ * Verfiy that it uses the pool access manager config.
+ * <p>
+ * @throws Exception
+ */
+ public void testInitializePoolAccess_withPoolName()
+ throws Exception
+ {
+ // SETUP
+ String poolName = "testInitializePoolAccess_withPoolName";
+
+ String url = "jdbc:hsqldb:";
+ String userName = "sa";
+ String password = "";
+ int maxActive = 10;
+ String driverClassName = "org.hsqldb.jdbcDriver";
+
+ Properties props = new Properties();
+ String prefix = JDBCDiskCacheFactory.POOL_CONFIGURATION_PREFIX
+ + poolName
+ + JDBCDiskCacheFactory.ATTRIBUTE_PREFIX;
+ props.put( prefix + ".url", url );
+ props.put( prefix + ".userName", userName );
+ props.put( prefix + ".password", password );
+ props.put( prefix + ".maxActive", String.valueOf( maxActive ) );
+ props.put( prefix + ".driverClassName", driverClassName );
+
+ JDBCDiskCacheAttributes cattr = new JDBCDiskCacheAttributes();
+ cattr.setConnectionPoolName( poolName );
+ cattr.setTableName("JCSTESTTABLE_InitializePoolAccess");
+
+ MockCompositeCacheManager compositeCacheManager = new MockCompositeCacheManager();
+ compositeCacheManager.setConfigurationProperties( props );
+ JDBCDiskCacheFactory dcFactory = new JDBCDiskCacheFactory();
+ dcFactory.initialize();
+ dcFactory.setScheduledExecutorService(Executors.newScheduledThreadPool(2,
+ new DaemonThreadFactory("JCS-JDBCDiskCacheManager-", Thread.MIN_PRIORITY)));
+
+ JDBCDiskCache<String, String> diskCache = dcFactory.createCache( cattr, compositeCacheManager, null, new StandardSerializer() );
+ assertNotNull( "Should have a cache instance", diskCache );
+
+ // DO WORK
+ DataSourceFactory result = dcFactory.getDataSourceFactory(cattr, props);
+
+ // VERIFY
+ assertNotNull( "Should have a data source factory class", result );
+ assertEquals( "wrong name", poolName, result.getName() );
+
+ System.setProperty( "hsqldb.cache_scale", "8" );
+
+ String rafroot = "target";
+ String database = rafroot + "/cache_hsql_db";
+
+ new org.hsqldb.jdbcDriver();
+ Class.forName( driverClassName ).newInstance();
+ Connection cConn = DriverManager.getConnection( url + database, userName, password );
+
+ HsqlSetupTableUtil.setupTABLE( cConn, "JCSTESTTABLE_InitializePoolAccess" );
+
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/hsql/HSQLDiskCacheConcurrentUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/hsql/HSQLDiskCacheConcurrentUnitTest.java
new file mode 100644
index 0000000..c85a6e6
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/hsql/HSQLDiskCacheConcurrentUnitTest.java
@@ -0,0 +1,161 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc.hsql;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/*
+ * 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.
+ */
+
+import junit.extensions.ActiveTestSuite;
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+/**
+ * Test which exercises the indexed disk cache. This one uses three different regions for thre
+ * threads.
+ */
+public class HSQLDiskCacheConcurrentUnitTest
+ extends TestCase
+{
+ /**
+ * Number of items to cache, twice the configured maxObjects for the memory cache regions.
+ */
+ private static int items = 100;
+
+ /**
+ * Constructor for the TestDiskCache object.
+ * @param testName
+ */
+ public HSQLDiskCacheConcurrentUnitTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * A unit test suite for JUnit. Uses ActiveTestSuite to run multiple tests concurrently.
+ * <p>
+ * @return The test suite
+ */
+ public static Test suite()
+ {
+ ActiveTestSuite suite = new ActiveTestSuite();
+
+ suite.addTest( new HSQLDiskCacheConcurrentUnitTest( "testHSQLDiskCache1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion1" );
+ }
+ } );
+
+ suite.addTest( new HSQLDiskCacheConcurrentUnitTest( "testHSQLDiskCache2" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion2" );
+ }
+ } );
+
+ suite.addTest( new HSQLDiskCacheConcurrentUnitTest( "testHSQLDiskCache3" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion3" );
+ }
+ } );
+
+ return suite;
+ }
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestHSQLDiskCacheConcurrent.ccf" );
+ }
+
+ /**
+ * Adds items to cache, gets them, and removes them. The item count is more than the size of the
+ * memory cache, so items should spool to disk.
+ * <p>
+ * @param region Name of the region to access
+ * @throws Exception If an error occurs
+ */
+ public void runTestForRegion( String region )
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+
+ // Add items to cache
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+
+// System.out.println( jcs.getStats() );
+
+ // Test that all items are in cache
+ for ( int i = 0; i <= items; i++ )
+ {
+ String value = jcs.get( i + ":key" );
+
+ assertEquals( "key = [" + i + ":key] value = [" + value + "]", region + " data " + i, value );
+ }
+
+ // Test that getElements returns all the expected values
+ Set<String> keys = new HashSet<>();
+ for ( int i = 0; i <= items; i++ )
+ {
+ keys.add( i + ":key" );
+ }
+
+ Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
+ for ( int i = 0; i <= items; i++ )
+ {
+ ICacheElement<String, String> element = elements.get( i + ":key" );
+ assertNotNull( "element " + i + ":key is missing", element );
+ assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
+ }
+
+ // Remove all the items
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.remove( i + ":key" );
+ }
+
+ // Verify removal
+ for ( int i = 0; i <= items; i++ )
+ {
+ assertNull( "Removed key should be null: " + i + ":key", jcs.get( i + ":key" ) );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/hsql/HSQLDiskCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/hsql/HSQLDiskCacheUnitTest.java
new file mode 100644
index 0000000..cf5132d
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/hsql/HSQLDiskCacheUnitTest.java
@@ -0,0 +1,173 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc.hsql;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Test which exercises the HSQL cache.
+ */
+public class HSQLDiskCacheUnitTest
+ extends TestCase
+{
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestHSQLDiskCache.ccf" );
+ }
+
+ /**
+ * Adds items to cache, gets them, and removes them. The item count is more than the size of the
+ * memory cache, so items should spool to disk.
+ * <p>
+ * @throws Exception If an error occurs
+ */
+ public void testBasicPutRemove()
+ throws Exception
+ {
+ int items = 20;
+
+ String region = "testBasicPutRemove";
+
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+
+ // Add items to cache
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+
+ // Test that all items are in cache
+ for ( int i = 0; i <= items; i++ )
+ {
+ String value = jcs.get( i + ":key" );
+ assertEquals( "key = [" + i + ":key] value = [" + value + "]", region + " data " + i, value );
+ }
+
+ // Test that getElements returns all the expected values
+ Set<String> keys = new HashSet<>();
+ for ( int i = 0; i <= items; i++ )
+ {
+ keys.add( i + ":key" );
+ }
+
+ Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
+ for ( int i = 0; i <= items; i++ )
+ {
+ ICacheElement<String, String> element = elements.get( i + ":key" );
+ assertNotNull( "element " + i + ":key is missing", element );
+ assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
+ }
+
+ // Remove all the items
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.remove( i + ":key" );
+ }
+
+ // Verify removal
+ for ( int i = 0; i <= items; i++ )
+ {
+ assertNull( "Removed key should be null: " + i + ":key", jcs.get( i + ":key" ) );
+ }
+ }
+
+ /**
+ * Verify that remove all work son a region where it is not prohibited.
+ * <p>
+ * @throws CacheException
+ * @throws InterruptedException
+ */
+ public void testRemoveAll()
+ throws CacheException, InterruptedException
+ {
+ String region = "removeAllAllowed";
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+
+ int items = 20;
+
+ // Add items to cache
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+
+ // a db thread could be updating when we call remove all?
+ // there was a race on remove all, an element may be put to disk after it is called even
+ // though the put
+ // was called before clear.
+ // I discovered it and removed it.
+ // Thread.sleep( 500 );
+
+// System.out.println( jcs.getStats() );
+
+ jcs.clear();
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ String value = jcs.get( i + ":key" );
+ assertNull( "value should be null key = [" + i + ":key] value = [" + value + "]", value );
+ }
+ }
+
+ /**
+ * Verify that remove all does not work on a region where it is prohibited.
+ * <p>
+ * @throws CacheException
+ * @throws InterruptedException
+ */
+ public void testRemoveAllProhibition()
+ throws CacheException, InterruptedException
+ {
+ String region = "noRemoveAll";
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+
+ int items = 20;
+
+ // Add items to cache
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+
+ // a db thread could be updating the disk when
+ // Thread.sleep( 500 );
+
+ jcs.clear();
+
+ for ( int i = 0; i <= items; i++ )
+ {
+ String value = jcs.get( i + ":key" );
+ assertEquals( "key = [" + i + ":key] value = [" + value + "]", region + " data " + i, value );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/MySQLDiskCacheHsqlBackedUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/MySQLDiskCacheHsqlBackedUnitTest.java
new file mode 100644
index 0000000..d876b5d
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/MySQLDiskCacheHsqlBackedUnitTest.java
@@ -0,0 +1,178 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc.mysql;
+
+/*
+ * 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.
+ */
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.HsqlSetupTableUtil;
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Runs basic tests for the JDBC disk cache.
+ * @author Aaron Smuts
+ */
+public class MySQLDiskCacheHsqlBackedUnitTest
+{
+ /**
+ * Creates the DB
+ * <p>
+ * @throws Exception
+ */
+ @BeforeClass
+ public static void setupDatabase() throws Exception
+ {
+ System.setProperty( "hsqldb.cache_scale", "8" );
+
+ String rafroot = "target";
+ String url = "jdbc:hsqldb:";
+ String database = rafroot + "/MySQLDiskCacheHsqlBackedUnitTest";
+ String user = "sa";
+ String password = "";
+
+ new org.hsqldb.jdbcDriver();
+ Connection cConn = DriverManager.getConnection( url + database, user, password );
+
+ HsqlSetupTableUtil.setupTABLE( cConn, "JCS_STORE_MYSQL" );
+ }
+
+ /**
+ * Test setup
+ */
+ @Before
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestMySQLDiskCache.ccf" );
+ }
+
+ /**
+ * Test the basic JDBC disk cache functionality with a hsql backing.
+ * @throws Exception
+ */
+ @Test
+ public void testSimpleJDBCPutGetWithHSQL()
+ throws Exception
+ {
+ runTestForRegion( "testCache1", 200 );
+ }
+
+ /**
+ * Adds items to cache, gets them, and removes them. The item count is more than the size of the
+ * memory cache, so items should spool to disk.
+ * <p>
+ * @param region Name of the region to access
+ * @param items
+ * @throws Exception If an error occurs
+ */
+ public void runTestForRegion( String region, int items )
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+ //System.out.println( "BEFORE PUT \n" + jcs.getStats() );
+
+ // Add items to cache
+ for ( int i = 0; i < items; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+
+ //System.out.println( jcs.getStats() );
+ Thread.sleep( 1000 );
+ //System.out.println( jcs.getStats() );
+
+ // Test that all items are in cache
+ for ( int i = 0; i < items; i++ )
+ {
+ String value = jcs.get( i + ":key" );
+
+ assertEquals( "key = [" + i + ":key] value = [" + value + "]", region + " data " + i, value );
+ }
+
+ // Test that getElements returns all the expected values
+ Set<String> keys = new HashSet<>();
+ for ( int i = 0; i < items; i++ )
+ {
+ keys.add( i + ":key" );
+ }
+
+ Map<String, ICacheElement<String, String>> elements = jcs.getCacheElements( keys );
+ for ( int i = 0; i < items; i++ )
+ {
+ ICacheElement<String, String> element = elements.get( i + ":key" );
+ assertNotNull( "element " + i + ":key is missing", element );
+ assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
+ }
+
+ // Remove all the items
+ for ( int i = 0; i < items; i++ )
+ {
+ jcs.remove( i + ":key" );
+ }
+
+ // Verify removal
+
+ for ( int i = 0; i < items; i++ )
+ {
+ assertNull( "Removed key should be null: " + i + ":key", jcs.get( i + ":key" ) );
+ }
+ }
+
+ /**
+ * Test the basic JDBC disk cache functionality with a hsql backing.
+ * <p>
+ * @throws Exception
+ */
+ @Test
+ public void testPutGetMatchingWithHSQL()
+ throws Exception
+ {
+ // SETUP
+ int items = 200;
+ String region = "testCache2";
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+// System.out.println( "BEFORE PUT \n" + jcs.getStats() );
+
+ // DO WORK
+ for ( int i = 0; i < items; i++ )
+ {
+ jcs.put( i + ":key", region + " data " + i );
+ }
+ Thread.sleep( 1000 );
+
+ Map<String, ICacheElement<String, String>> matchingResults = jcs.getMatchingCacheElements( "1.8.+" );
+
+ // VERIFY
+ assertEquals( "Wrong number returned", 10, matchingResults.size() );
+// System.out.println( "matchingResults.keySet() " + matchingResults.keySet() );
+// System.out.println( "\nAFTER TEST \n" + jcs.getStats() );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/MySQLDiskCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/MySQLDiskCacheUnitTest.java
new file mode 100644
index 0000000..ee2cc64
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/MySQLDiskCacheUnitTest.java
@@ -0,0 +1,74 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc.mysql;
+
+/*
+ * 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.
+ */
+
+import java.sql.SQLException;
+
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.TableState;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.SharedPoolDataSourceFactory;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.mysql.MySQLDiskCache;
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.mysql.MySQLDiskCacheAttributes;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+
+import junit.framework.TestCase;
+
+/**
+ * Simple tests for the MySQLDisk Cache.
+ * <p>
+ * We will probably need to setup an hsql behind this, to test some of the pass through methods.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class MySQLDiskCacheUnitTest
+ extends TestCase
+{
+ /**
+ * Verify that we simply return null on get if an optimization is in
+ * progress and the cache is configured to balk on optimization.
+ * <p>
+ * This is a bit tricky since we don't want to have to have a mysql instance
+ * running. Right now this doesn't really test much
+ * @throws SQLException
+ */
+ public void testBalkOnGet() throws SQLException
+ {
+ // SETUP
+ MySQLDiskCacheAttributes attributes = new MySQLDiskCacheAttributes();
+ String tableName = "JCS_TEST";
+ // Just use something that exists
+ attributes.setDriverClassName( "org.hsqldb.jdbcDriver" );
+ attributes.setTableName( tableName );
+ attributes.setBalkDuringOptimization( true );
+ SharedPoolDataSourceFactory dsFactory = new SharedPoolDataSourceFactory();
+ dsFactory.initialize(attributes);
+
+ TableState tableState = new TableState( tableName );
+ tableState.setState( TableState.OPTIMIZATION_RUNNING );
+
+ MySQLDiskCache<String, String> cache = new MySQLDiskCache<>( attributes, dsFactory, tableState,
+ CompositeCacheManager.getUnconfiguredInstance() );
+
+ // DO WORK
+ Object result = cache.processGet( "myKey" );
+
+ // VERIFY
+ assertNull( "The result should be null", result );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/util/ScheduleParserUtilUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/util/ScheduleParserUtilUnitTest.java
new file mode 100644
index 0000000..dad2f2d
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/disk/jdbc/mysql/util/ScheduleParserUtilUnitTest.java
@@ -0,0 +1,131 @@
+package org.apache.commons.jcs3.auxiliary.disk.jdbc.mysql.util;
+
+/*
+ * 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.
+ */
+
+import java.text.ParseException;
+import java.util.Date;
+
+import org.apache.commons.jcs3.auxiliary.disk.jdbc.mysql.util.ScheduleParser;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for the schedule parser.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class ScheduleParserUtilUnitTest
+ extends TestCase
+{
+
+ /**
+ * Verify that we get an exception and not a null pointer for null input.
+ */
+ public void testGetDatesWithNullInput()
+ {
+ try
+ {
+ ScheduleParser.createDatesForSchedule( null );
+
+ fail( "Should have thrown an exception" );
+ }
+ catch ( ParseException e )
+ {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that we get an exception and not a null pointer for null input.
+ */
+ public void testGetDateWithNullInput()
+ {
+ try
+ {
+ ScheduleParser.getDateForSchedule( null );
+
+ fail( "Should have thrown an exception" );
+ }
+ catch ( ParseException e )
+ {
+ // expected
+ }
+ }
+
+ /**
+ * Verify that we get one date for one date.
+ * @throws ParseException
+ */
+ public void testGetsDatesSingle()
+ throws ParseException
+ {
+ String schedule = "12:34:56";
+ Date[] dates = ScheduleParser.createDatesForSchedule( schedule );
+
+ assertEquals( "Wrong number of dates returned.", 1, dates.length );
+ }
+ /**
+ * Verify that we get one date for one date.
+ * @throws ParseException
+ */
+ public void testGetsDatesMultiple()
+ throws ParseException
+ {
+ String schedule = "12:34:56,03:51:00,12:34:12";
+ Date[] dates = ScheduleParser.createDatesForSchedule( schedule );
+ //System.out.println( dates );
+ assertEquals( "Wrong number of dates returned.", 3, dates.length );
+ }
+
+ /**
+ * Verify that we get an exception for a single bad date in a list.
+ */
+ public void testGetDatesMalformedNoColon()
+ {
+ try
+ {
+ String schedule = "12:34:56,03:51:00,123234";
+ ScheduleParser.createDatesForSchedule( schedule );
+
+ fail( "Should have thrown an exception for a malformed date" );
+ }
+ catch ( ParseException e )
+ {
+ // expected
+ }
+ }
+ /**
+ * Verify that we get an exception for a schedule that has a non numeric item.
+ */
+ public void testGetDatesMalformedNan()
+ {
+ try
+ {
+ String schedule = "12:34:56,03:51:00,aa:12:12";
+ ScheduleParser.createDatesForSchedule( schedule );
+
+ fail( "Should have thrown an exception for a malformed date" );
+ }
+ catch ( ParseException e )
+ {
+ // expected
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheNoWaitFacadeUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheNoWaitFacadeUnitTest.java
new file mode 100644
index 0000000..df8eb47
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/LateralCacheNoWaitFacadeUnitTest.java
@@ -0,0 +1,148 @@
+package org.apache.commons.jcs3.auxiliary.lateral;
+
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCache;
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCacheNoWait;
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCacheNoWaitFacade;
+import org.apache.commons.jcs3.auxiliary.lateral.behavior.ILateralCacheAttributes;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for LateralCacheNoWaitFacade.
+ */
+public class LateralCacheNoWaitFacadeUnitTest
+ extends TestCase
+{
+ /**
+ * Verify that we can remove an item.
+ */
+ public void testAddThenRemoveNoWait_InList()
+ {
+ // SETUP
+ @SuppressWarnings("unchecked")
+ LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
+ ILateralCacheAttributes cattr = new LateralCacheAttributes();
+ cattr.setCacheName( "testCache1" );
+
+ LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
+
+ LateralCache<String, String> cache = new LateralCache<>( cattr );
+ LateralCacheNoWait<String, String> noWait = new LateralCacheNoWait<>( cache );
+
+ // DO WORK
+ facade.addNoWait( noWait );
+
+ // VERIFY
+ assertTrue( "Should be in the list.", facade.containsNoWait( noWait ) );
+
+ // DO WORK
+ facade.removeNoWait( noWait );
+
+ // VERIFY
+ assertEquals( "Should have 0", 0, facade.noWaits.length );
+ assertFalse( "Should not be in the list. ", facade.containsNoWait( noWait ) );
+ }
+
+ /**
+ * Verify that we can remove an item.
+ */
+ public void testAddThenRemoveNoWait_InListSize2()
+ {
+ // SETUP
+ @SuppressWarnings("unchecked")
+ LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
+ ILateralCacheAttributes cattr = new LateralCacheAttributes();
+ cattr.setCacheName( "testCache1" );
+
+ LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
+
+ LateralCache<String, String> cache = new LateralCache<>( cattr );
+ LateralCacheNoWait<String, String> noWait = new LateralCacheNoWait<>( cache );
+ LateralCacheNoWait<String, String> noWait2 = new LateralCacheNoWait<>( cache );
+
+ // DO WORK
+ facade.addNoWait( noWait );
+ facade.addNoWait( noWait2 );
+
+ // VERIFY
+ assertEquals( "Should have 2", 2, facade.noWaits.length );
+ assertTrue( "Should be in the list.", facade.containsNoWait( noWait ) );
+ assertTrue( "Should be in the list.", facade.containsNoWait( noWait2 ) );
+
+ // DO WORK
+ facade.removeNoWait( noWait );
+
+ // VERIFY
+ assertEquals( "Should only have 1", 1, facade.noWaits.length );
+ assertFalse( "Should not be in the list. ", facade.containsNoWait( noWait ) );
+ assertTrue( "Should be in the list.", facade.containsNoWait( noWait2 ) );
+ }
+
+ /**
+ * Verify that we can remove an item.
+ */
+ public void testAdd_InList()
+ {
+ // SETUP
+ @SuppressWarnings("unchecked")
+ LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
+ ILateralCacheAttributes cattr = new LateralCacheAttributes();
+ cattr.setCacheName( "testCache1" );
+
+ LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
+
+ LateralCache<String, String> cache = new LateralCache<>( cattr );
+ LateralCacheNoWait<String, String> noWait = new LateralCacheNoWait<>( cache );
+
+ // DO WORK
+ facade.addNoWait( noWait );
+ facade.addNoWait( noWait );
+
+ // VERIFY
+ assertTrue( "Should be in the list.", facade.containsNoWait( noWait ) );
+ assertEquals( "Should only have 1", 1, facade.noWaits.length );
+ }
+
+ /**
+ * Verify that we can remove an item.
+ */
+ public void testAddThenRemoveNoWait_NotInList()
+ {
+ // SETUP
+ @SuppressWarnings("unchecked")
+ LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
+ ILateralCacheAttributes cattr = new LateralCacheAttributes();
+ cattr.setCacheName( "testCache1" );
+
+ LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
+
+ LateralCache<String, String> cache = new LateralCache<>( cattr );
+ LateralCacheNoWait<String, String> noWait = new LateralCacheNoWait<>( cache );
+
+ // DO WORK
+ facade.removeNoWait( noWait );
+
+ // VERIFY
+ assertFalse( "Should not be in the list.", facade.containsNoWait( noWait ) );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/http/broadcast/LateralCacheTester.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/http/broadcast/LateralCacheTester.java
new file mode 100644
index 0000000..1482ffa
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/http/broadcast/LateralCacheTester.java
@@ -0,0 +1,61 @@
+package org.apache.commons.jcs3.auxiliary.lateral.http.broadcast;
+
+/*
+ * 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.
+ */
+
+/**
+ * @author Aaron Smuts
+ * @version 1.0
+ */
+public class LateralCacheTester
+{
+
+ // /** Description of the Method */
+ // public static void main( String args[] )
+ // {
+ //
+ // String[] servers = {"10.1.17.109", "10.1.17.108"};
+ //
+ // try
+ // {
+ //
+ // //for ( int i=0; i <100; i++ ) {
+ // String val = "test object value";
+ // LateralCacheThread dct = new LateralCacheThread( "testTable", "testkey",
+ // val, servers );
+ // dct.setPriority( Thread.NORM_PRIORITY - 1 );
+ // dct.start();
+ //
+ // String val2 = "test object value2";
+ // LateralCacheThread dct2 = new LateralCacheThread( "testTable", "testkey",
+ // val, servers );
+ // dct2.setPriority( Thread.NORM_PRIORITY - 1 );
+ // dct2.start();
+ // //}
+ //
+ // }
+ // catch ( Exception e )
+ // {
+ // System.out.println( e.toString() );
+ // }
+ //
+ // }
+
+}
+// end class
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPConcurrentRandomTestUtil.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPConcurrentRandomTestUtil.java
new file mode 100644
index 0000000..386d548
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPConcurrentRandomTestUtil.java
@@ -0,0 +1,198 @@
+package org.apache.commons.jcs3.auxiliary.lateral.socket.tcp;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import java.util.Random;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPService;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/**
+ * @author Aaron Smuts
+ */
+public class LateralTCPConcurrentRandomTestUtil
+ extends TestCase
+{
+ /** Should we write out. */
+ private static boolean isSysOut = false;
+ //private static boolean isSysOut = true;
+
+ /**
+ * Constructor for the TestDiskCache object.
+ *
+ * @param testName
+ */
+ public LateralTCPConcurrentRandomTestUtil( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestTCPLateralCacheConcurrent.ccf" );
+ }
+
+ /**
+ * Randomly adds items to cache, gets them, and removes them. The range
+ * count is more than the size of the memory cache, so items should spool to
+ * disk.
+ * <p>
+ * @param region
+ * Name of the region to access
+ * @param range
+ * @param numOps
+ * @param testNum
+ *
+ * @throws Exception
+ * If an error occurs
+ */
+ public void runTestForRegion( String region, int range, int numOps, int testNum )
+ throws Exception
+ {
+ boolean show = true;//false;
+
+ CacheAccess<String, String> cache = JCS.getInstance( region );
+
+ TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
+ lattr2.setTcpListenerPort( 1103 );
+ lattr2.setTransmissionTypeName( "TCP" );
+ lattr2.setTcpServer( "localhost:1102" );
+
+ // this service will put and remove using the lateral to
+ // the cache instance above
+ // the cache thinks it is different since the listenerid is different
+ LateralTCPService<String, String> service = new LateralTCPService<>( lattr2 );
+ service.setListenerId( 123456 );
+
+ try
+ {
+ for ( int i = 1; i < numOps; i++ )
+ {
+ Random ran = new Random( i );
+ int n = ran.nextInt( 4 );
+ int kn = ran.nextInt( range );
+ String key = "key" + kn;
+ if ( n == 1 )
+ {
+ ICacheElement<String, String> element = new CacheElement<>( region, key, region + ":data" + i
+ + " junk asdfffffffadfasdfasf " + kn + ":" + n );
+ service.update( element );
+ if ( show )
+ {
+ p( "put " + key );
+ }
+ }
+ /**/
+ else if ( n == 2 )
+ {
+ service.remove( region, key );
+ if ( show )
+ {
+ p( "removed " + key );
+ }
+ }
+ /**/
+ else
+ {
+ // slightly greater chance of get
+ try
+ {
+ Object obj = service.get( region, key );
+ if ( show && obj != null )
+ {
+ p( obj.toString() );
+ }
+ }
+ catch ( Exception e )
+ {
+ // consider failing, some timeouts are expected
+ e.printStackTrace();
+ }
+ }
+
+ if ( i % 100 == 0 )
+ {
+ p( cache.getStats() );
+ }
+
+ }
+ p( "Finished random cycle of " + numOps );
+ }
+ catch ( Exception e )
+ {
+ p( e.toString() );
+ e.printStackTrace( System.out );
+ throw e;
+ }
+
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+ String key = "testKey" + testNum;
+ String data = "testData" + testNum;
+ jcs.put( key, data );
+ String value = jcs.get( key );
+ assertEquals( "Couldn't put normally.", data, value );
+
+ // make sure the items we can find are in the correct region.
+ for ( int i = 1; i < numOps; i++ )
+ {
+ String keyL = "key" + i;
+ String dataL = jcs.get( keyL );
+ if ( dataL != null )
+ {
+ assertTrue( "Incorrect region detected.", dataL.startsWith( region ) );
+ }
+
+ }
+
+ //Thread.sleep( 1000 );
+
+ //ICacheElement<String, String> element = new CacheElement( region, "abc", "testdata");
+ //service.update( element );
+
+ //Thread.sleep( 2500 );
+ // could be too mcuh going on right now to get ti through, sot he test
+ // might fail.
+ //String value2 = (String) jcs.get( "abc" );
+ //assertEquals( "Couldn't put laterally, could be too much traffic in
+ // queue.", "testdata", value2 );
+
+ }
+
+ /**
+ * @param s string to print
+ */
+ public static void p( String s )
+ {
+ if ( isSysOut )
+ {
+ System.out.println( s );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPDiscoveryListenerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPDiscoveryListenerUnitTest.java
new file mode 100644
index 0000000..f855686
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPDiscoveryListenerUnitTest.java
@@ -0,0 +1,295 @@
+package org.apache.commons.jcs3.auxiliary.lateral.socket.tcp;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import org.apache.commons.jcs3.engine.logging.MockCacheEventLogger;
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCache;
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCacheNoWait;
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCacheNoWaitFacade;
+import org.apache.commons.jcs3.auxiliary.lateral.behavior.ILateralCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPDiscoveryListener;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+import org.apache.commons.jcs3.utils.discovery.DiscoveredService;
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+
+import java.util.ArrayList;
+
+/** Test for the listener that observers UDP discovery events. */
+public class LateralTCPDiscoveryListenerUnitTest
+ extends TestCase
+{
+ /** the listener */
+ private LateralTCPDiscoveryListener listener;
+
+ /** the cache factory */
+ private LateralTCPCacheFactory factory;
+
+ /** The cache manager. */
+ private CompositeCacheManager cacheMgr;
+
+ /** The event logger. */
+ protected MockCacheEventLogger cacheEventLogger;
+
+ /** The serializer. */
+ protected IElementSerializer elementSerializer;
+
+ /** Create the listener for testing */
+ @Override
+ protected void setUp() throws Exception
+ {
+ factory = new LateralTCPCacheFactory();
+ factory.initialize();
+
+ cacheMgr = CompositeCacheManager.getInstance();
+ cacheEventLogger = new MockCacheEventLogger();
+ elementSerializer = new StandardSerializer();
+
+ listener = new LateralTCPDiscoveryListener( factory.getName(), cacheMgr );
+ }
+
+ /**
+ * Add a no wait facade.
+ */
+ public void testAddNoWaitFacade_NotInList()
+ {
+ // SETUP
+ String cacheName = "testAddNoWaitFacade_NotInList";
+
+ @SuppressWarnings("unchecked")
+ LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
+ ILateralCacheAttributes cattr = new LateralCacheAttributes();
+ cattr.setCacheName( cacheName );
+
+ LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
+
+ // DO WORK
+ listener.addNoWaitFacade( cacheName, facade );
+
+ // VERIFY
+ assertTrue( "Should have the facade.", listener.containsNoWaitFacade( cacheName ) );
+ }
+
+ /**
+ * Add a no wait to a known facade.
+ */
+ public void testAddNoWait_FacadeInList()
+ {
+ // SETUP
+ String cacheName = "testAddNoWaitFacade_FacadeInList";
+
+ @SuppressWarnings("unchecked")
+ LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
+ ILateralCacheAttributes cattr = new LateralCacheAttributes();
+ cattr.setCacheName( cacheName );
+
+ LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
+ listener.addNoWaitFacade( cacheName, facade );
+
+ LateralCache<String, String> cache = new LateralCache<>( cattr );
+ LateralCacheNoWait<String, String> noWait = new LateralCacheNoWait<>( cache );
+
+ // DO WORK
+ boolean result = listener.addNoWait( noWait );
+
+ // VERIFY
+ assertTrue( "Should have added the no wait.", result );
+ }
+
+ /**
+ * Add a no wait from an unknown facade.
+ */
+ public void testAddNoWait_FacadeNotInList()
+ {
+ // SETUP
+ String cacheName = "testAddNoWaitFacade_FacadeInList";
+ ILateralCacheAttributes cattr = new LateralCacheAttributes();
+ cattr.setCacheName( cacheName );
+
+ LateralCache<String, String> cache = new LateralCache<>( cattr );
+ LateralCacheNoWait<String, String> noWait = new LateralCacheNoWait<>( cache );
+
+ // DO WORK
+ boolean result = listener.addNoWait( noWait );
+
+ // VERIFY
+ assertFalse( "Should not have added the no wait.", result );
+ }
+
+ /**
+ * Remove a no wait from an unknown facade.
+ */
+ public void testRemoveNoWait_FacadeNotInList()
+ {
+ // SETUP
+ String cacheName = "testRemoveNoWaitFacade_FacadeNotInList";
+ ILateralCacheAttributes cattr = new LateralCacheAttributes();
+ cattr.setCacheName( cacheName );
+
+ LateralCache<String, String> cache = new LateralCache<>( cattr );
+ LateralCacheNoWait<String, String> noWait = new LateralCacheNoWait<>( cache );
+
+ // DO WORK
+ boolean result = listener.removeNoWait( noWait );
+
+ // VERIFY
+ assertFalse( "Should not have removed the no wait.", result );
+ }
+
+ /**
+ * Remove a no wait from a known facade.
+ */
+ public void testRemoveNoWait_FacadeInList_NoWaitNot()
+ {
+ // SETUP
+ String cacheName = "testAddNoWaitFacade_FacadeInList";
+
+ @SuppressWarnings("unchecked")
+ LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
+ ILateralCacheAttributes cattr = new LateralCacheAttributes();
+ cattr.setCacheName( cacheName );
+
+ LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
+ listener.addNoWaitFacade( cacheName, facade );
+
+ LateralCache<String, String> cache = new LateralCache<>( cattr );
+ LateralCacheNoWait<String, String> noWait = new LateralCacheNoWait<>( cache );
+
+ // DO WORK
+ boolean result = listener.removeNoWait( noWait );
+
+ // VERIFY
+ assertFalse( "Should not have removed the no wait.", result );
+ }
+
+ /**
+ * Remove a no wait from a known facade.
+ */
+ public void testRemoveNoWait_FacadeInList_NoWaitIs()
+ {
+ // SETUP
+ String cacheName = "testRemoveNoWaitFacade_FacadeInListNoWaitIs";
+
+ @SuppressWarnings("unchecked")
+ LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
+ ILateralCacheAttributes cattr = new LateralCacheAttributes();
+ cattr.setCacheName( cacheName );
+
+ LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
+ listener.addNoWaitFacade( cacheName, facade );
+
+ LateralCache<String, String> cache = new LateralCache<>( cattr );
+ LateralCacheNoWait<String, String> noWait = new LateralCacheNoWait<>( cache );
+ listener.addNoWait( noWait );
+
+ // DO WORK
+ boolean result = listener.removeNoWait( noWait );
+
+ // VERIFY
+ assertTrue( "Should have removed the no wait.", result );
+ }
+
+ /**
+ * Add a no wait to a known facade.
+ */
+ public void testAddDiscoveredService_FacadeInList_NoWaitNot()
+ {
+ // SETUP
+ String cacheName = "testAddDiscoveredService_FacadeInList_NoWaitNot";
+
+ ArrayList<String> cacheNames = new ArrayList<>();
+ cacheNames.add( cacheName );
+
+ DiscoveredService service = new DiscoveredService();
+ service.setCacheNames( cacheNames );
+ service.setServiceAddress( "localhost" );
+ service.setServicePort( 9999 );
+
+ // since the no waits are compared by object equality, I have to do this
+ // TODO add an equals method to the noWait. the problem if is figuring out what to compare.
+ ITCPLateralCacheAttributes lca = new TCPLateralCacheAttributes();
+ lca.setTransmissionType( LateralCacheAttributes.Type.TCP );
+ lca.setTcpServer( service.getServiceAddress() + ":" + service.getServicePort() );
+ lca.setCacheName(cacheName);
+ LateralCacheNoWait<String, String> noWait = factory.createCacheNoWait(lca, cacheEventLogger, elementSerializer);
+ // this is the normal process, the discovery service expects it there
+ cacheMgr.addAuxiliaryCache(factory.getName(), cacheName, noWait);
+
+ @SuppressWarnings("unchecked")
+ LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
+ ILateralCacheAttributes cattr = new LateralCacheAttributes();
+ cattr.setCacheName( cacheName );
+ LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
+ listener.addNoWaitFacade( cacheName, facade );
+
+ // DO WORK
+ listener.addDiscoveredService( service );
+
+ // VERIFY
+ assertTrue( "Should have no wait.", listener.containsNoWait( cacheName, noWait ) );
+ }
+
+ /**
+ * Remove a no wait from a known facade.
+ */
+ public void testRemoveDiscoveredService_FacadeInList_NoWaitIs()
+ {
+ // SETUP
+ String cacheName = "testRemoveDiscoveredService_FacadeInList_NoWaitIs";
+
+ ArrayList<String> cacheNames = new ArrayList<>();
+ cacheNames.add( cacheName );
+
+ DiscoveredService service = new DiscoveredService();
+ service.setCacheNames( cacheNames );
+ service.setServiceAddress( "localhost" );
+ service.setServicePort( 9999 );
+
+ // since the no waits are compared by object equality, I have to do this
+ // TODO add an equals method to the noWait. the problem if is figuring out what to compare.
+ ITCPLateralCacheAttributes lca = new TCPLateralCacheAttributes();
+ lca.setTransmissionType( LateralCacheAttributes.Type.TCP );
+ lca.setTcpServer( service.getServiceAddress() + ":" + service.getServicePort() );
+ lca.setCacheName(cacheName);
+ LateralCacheNoWait<String, String> noWait = factory.createCacheNoWait(lca, cacheEventLogger, elementSerializer);
+ // this is the normal process, the discovery service expects it there
+ cacheMgr.addAuxiliaryCache(factory.getName(), cacheName, noWait);
+
+ @SuppressWarnings("unchecked")
+ LateralCacheNoWait<String, String>[] noWaits = new LateralCacheNoWait[0];
+ ILateralCacheAttributes cattr = new LateralCacheAttributes();
+ cattr.setCacheName( cacheName );
+ LateralCacheNoWaitFacade<String, String> facade = new LateralCacheNoWaitFacade<>( null, noWaits, cattr );
+ listener.addNoWaitFacade( cacheName, facade );
+ listener.addDiscoveredService( service );
+
+ // DO WORK
+ listener.removeDiscoveredService( service );
+
+ // VERIFY
+ assertFalse( "Should not have no wait.", listener.containsNoWait( cacheName, noWait ) );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPFilterRemoveHashCodeUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPFilterRemoveHashCodeUnitTest.java
new file mode 100644
index 0000000..7e028ca
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPFilterRemoveHashCodeUnitTest.java
@@ -0,0 +1,195 @@
+package org.apache.commons.jcs3.auxiliary.lateral.socket.tcp;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import java.io.Serializable;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPService;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/**
+ * @author Aaron Smuts
+ */
+public class LateralTCPFilterRemoveHashCodeUnitTest
+ extends TestCase
+{
+ /** Does the test print to system out. */
+ private static boolean isSysOut = false;
+
+ /** The port the server will listen to. */
+ private final int serverPort = 2001;
+
+ /**
+ * Constructor for the TestDiskCache object.
+ *
+ * @param testName
+ */
+ public LateralTCPFilterRemoveHashCodeUnitTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ System.setProperty( "jcs.auxiliary.LTCP.attributes.TcpServers", "localhost:" + serverPort );
+ JCS.setConfigFilename( "/TestTCPLateralRemoveFilter.ccf" );
+ }
+
+ /**
+ *
+ * @throws Exception
+ */
+ public void test()
+ throws Exception
+ {
+ this.runTestForRegion( "region1", 200, 1 );
+ }
+
+ /**
+ * This tests issues tons of puts. It also check to see that a key that was
+ * put in was removed by the clients remove command.
+ *
+ * @param region
+ * Name of the region to access
+ * @param numOps
+ * @param testNum
+ *
+ * @throws Exception
+ * If an error occurs
+ */
+ public void runTestForRegion( String region, int numOps, int testNum )
+ throws Exception
+ {
+ CacheAccess<String, Serializable> cache = JCS.getInstance( region );
+
+ Thread.sleep( 100 );
+
+ TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
+ lattr2.setTcpListenerPort( 1102 );
+ lattr2.setTransmissionTypeName( "TCP" );
+ lattr2.setTcpServer( "localhost:" + serverPort );
+ lattr2.setIssueRemoveOnPut( true );
+ // should still try to remove
+ lattr2.setAllowPut( false );
+
+ // this service will put and remove using the lateral to
+ // the cache instance above
+ // the cache thinks it is different since the listenerid is different
+ LateralTCPService<String, Serializable> service = new LateralTCPService<>( lattr2 );
+ service.setListenerId( 123456 );
+
+ String keyToBeRemovedOnPut = "test1";
+
+ String keyToNotBeRemovedOnPut = "test2";
+
+ Serializable dataToPassHashCodeCompare = new Serializable()
+ {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public int hashCode()
+ {
+ return 1;
+ }
+ };
+ //String dataToPassHashCodeCompare = "this should be the same and not
+ // get removed.";
+ //p( "dataToPassHashCodeCompare hashcode = " + +
+ // dataToPassHashCodeCompare.hashCode() );
+
+ cache.put( keyToBeRemovedOnPut, "this should get removed." );
+ ICacheElement<String, Serializable> element1 = new CacheElement<>( region, keyToBeRemovedOnPut, region
+ + ":data-this shouldn't get there" );
+ service.update( element1 );
+
+ cache.put( keyToNotBeRemovedOnPut, dataToPassHashCodeCompare );
+ ICacheElement<String, Serializable> element2 = new CacheElement<>( region, keyToNotBeRemovedOnPut, dataToPassHashCodeCompare );
+ service.update( element2 );
+
+ /*
+ * try { for ( int i = 1; i < numOps; i++ ) { Random ran = new Random( i );
+ * int n = ran.nextInt( 4 ); int kn = ran.nextInt( range ); String key =
+ * "key" + kn;
+ *
+ * ICacheElement<String, String> element = new CacheElement( region, key, region +
+ * ":data" + i + " junk asdfffffffadfasdfasf " + kn + ":" + n );
+ * service.update( element ); if ( show ) { p( "put " + key ); }
+ *
+ * if ( i % 100 == 0 ) { System.out.println( cache.getStats() ); }
+ * } p( "Finished cycle of " + numOps ); } catch ( Exception e ) { p(
+ * e.toString() ); e.printStackTrace( System.out ); throw e; }
+ */
+
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+ String key = "testKey" + testNum;
+ String data = "testData" + testNum;
+ jcs.put( key, data );
+ String value = jcs.get( key );
+ assertEquals( "Couldn't put normally.", data, value );
+
+ // make sure the items we can find are in the correct region.
+ for ( int i = 1; i < numOps; i++ )
+ {
+ String keyL = "key" + i;
+ String dataL = jcs.get( keyL );
+ if ( dataL != null )
+ {
+ assertTrue( "Incorrect region detected.", dataL.startsWith( region ) );
+ }
+
+ }
+
+ Thread.sleep( 200 );
+
+ Object testObj1 = cache.get( keyToBeRemovedOnPut );
+ p( "test object1 = " + testObj1 );
+ assertNull( "The test object should have been remvoed by a put.", testObj1 );
+
+ Object testObj2 = cache.get( keyToNotBeRemovedOnPut );
+ p( "test object2 = " + testObj2 + " hashCode = " );
+ if ( testObj2 != null )
+ {
+ p( "test2 hashcode = " + +testObj2.hashCode() );
+ }
+ assertNotNull( "This should not have been removed, since the hascode were the same.", testObj2 );
+
+ }
+
+ /**
+ * @param s String to print
+ */
+ public static void p( String s )
+ {
+ if ( isSysOut )
+ {
+ System.out.println( s );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPIssueRemoveOnPutUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPIssueRemoveOnPutUnitTest.java
new file mode 100644
index 0000000..e4e9323
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPIssueRemoveOnPutUnitTest.java
@@ -0,0 +1,228 @@
+package org.apache.commons.jcs3.auxiliary.lateral.socket.tcp;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import java.util.Random;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPService;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/**
+ * Tests the issue remove on put fuctionality.
+ * @author asmuts
+ */
+public class LateralTCPIssueRemoveOnPutUnitTest
+ extends TestCase
+{
+ /** Should log data go to system out. */
+ private static boolean isSysOut = false;
+
+ /** The port the server will listen to. */
+ private final int serverPort = 1118;
+
+ /**
+ * Constructor for the TestDiskCache object.
+ * <p>
+ * @param testName
+ */
+ public LateralTCPIssueRemoveOnPutUnitTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ System.setProperty( "jcs.auxiliary.LTCP.attributes.TcpServers", "localhost:" + serverPort );
+
+ JCS.setConfigFilename( "/TestTCPLateralIssueRemoveCache.ccf" );
+ }
+
+ /**
+ * @throws Exception
+ */
+ public void testPutLocalPutRemoteGetBusyVerifyRemoved()
+ throws Exception
+ {
+ this.runTestForRegion( "region1", 1, 200, 1 );
+ }
+
+ /**
+ * Verify that a standard put works. Get the cache configured from a file. Create a tcp service
+ * to talk to that cache. Put via the service. Verify that the cache got the data.
+ * <p>
+ * @throws Exception
+ */
+ public void testStandardPut()
+ throws Exception
+ {
+ String region = "region1";
+
+ CacheAccess<String, String> cache = JCS.getInstance( region );
+
+ Thread.sleep( 100 );
+
+ TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
+ lattr2.setTcpListenerPort( 1102 );
+ lattr2.setTransmissionTypeName( "TCP" );
+ lattr2.setTcpServer( "localhost:" + serverPort );
+ lattr2.setIssueRemoveOnPut( false );
+ // should still try to remove
+ // lattr2.setAllowPut( false );
+
+ // Using the lateral, this service will put to and remove from
+ // the cache instance above.
+ // The cache thinks it is different since the listenerid is different
+ LateralTCPService<String, String> service = new LateralTCPService<>( lattr2 );
+ service.setListenerId( 123456 );
+
+ String keyToBeRemovedOnPut = "test1_notremoved";
+
+ ICacheElement<String, String> element1 = new CacheElement<>( region, keyToBeRemovedOnPut, region
+ + ":data-this shouldn't get removed, it should get to the cache." );
+ service.update( element1 );
+
+ Thread.sleep( 1000 );
+
+ Object testObj = cache.get( keyToBeRemovedOnPut );
+ p( "testStandardPut, test object = " + testObj );
+ assertNotNull( "The test object should not have been removed by a put.", testObj );
+ }
+
+ /**
+ * This tests issues tons of puts. It also check to see that a key that was put in was removed
+ * by the clients remove command.
+ * <p>
+ * @param region Name of the region to access
+ * @param range
+ * @param numOps
+ * @param testNum
+ * @throws Exception If an error occurs
+ */
+ public void runTestForRegion( String region, int range, int numOps, int testNum )
+ throws Exception
+ {
+
+ boolean show = false;
+
+ CacheAccess<String, String> cache = JCS.getInstance( region );
+
+ Thread.sleep( 100 );
+
+ TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
+ lattr2.setTcpListenerPort( 1102 );
+ lattr2.setTransmissionTypeName( "TCP" );
+ lattr2.setTcpServer( "localhost:" + serverPort );
+ lattr2.setIssueRemoveOnPut( true );
+ // should still try to remove
+ lattr2.setAllowPut( false );
+
+ // Using the lateral, this service will put to and remove from
+ // the cache instance above.
+ // The cache thinks it is different since the listenerid is different
+ LateralTCPService<String, String> service = new LateralTCPService<>( lattr2 );
+ service.setListenerId( 123456 );
+
+ String keyToBeRemovedOnPut = "test1";
+ cache.put( keyToBeRemovedOnPut, "this should get removed." );
+
+ ICacheElement<String, String> element1 = new CacheElement<>( region, keyToBeRemovedOnPut, region
+ + ":data-this shouldn't get there" );
+ service.update( element1 );
+
+ try
+ {
+ for ( int i = 1; i < numOps; i++ )
+ {
+ Random ran = new Random( i );
+ int n = ran.nextInt( 4 );
+ int kn = ran.nextInt( range );
+ String key = "key" + kn;
+
+ ICacheElement<String, String> element = new CacheElement<>( region, key, region + ":data" + i
+ + " junk asdfffffffadfasdfasf " + kn + ":" + n );
+ service.update( element );
+ if ( show )
+ {
+ p( "put " + key );
+ }
+
+ if (show && i % 100 == 0 )
+ {
+ System.out.println( cache.getStats() );
+ }
+
+ }
+ p( "Finished cycle of " + numOps );
+ }
+ catch ( Exception e )
+ {
+ p( e.toString() );
+ e.printStackTrace( System.out );
+ throw e;
+ }
+
+ CacheAccess<String, String> jcs = JCS.getInstance( region );
+ String key = "testKey" + testNum;
+ String data = "testData" + testNum;
+ jcs.put( key, data );
+ String value = jcs.get( key );
+ assertEquals( "Couldn't put normally.", data, value );
+
+ // make sure the items we can find are in the correct region.
+ for ( int i = 1; i < numOps; i++ )
+ {
+ String keyL = "key" + i;
+ String dataL = jcs.get( keyL );
+ if ( dataL != null )
+ {
+ assertTrue( "Incorrect region detected.", dataL.startsWith( region ) );
+ }
+
+ }
+
+ Thread.sleep( 200 );
+
+ Object testObj = cache.get( keyToBeRemovedOnPut );
+ p( "runTestForRegion, test object = " + testObj );
+ assertNull( "The test object should have been removed by a put.", testObj );
+
+ }
+
+ /**
+ * @param s String to be printed
+ */
+ public static void p( String s )
+ {
+ if ( isSysOut )
+ {
+ System.out.println( s );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPNoDeadLockConcurrentTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPNoDeadLockConcurrentTest.java
new file mode 100644
index 0000000..d19d85e
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/LateralTCPNoDeadLockConcurrentTest.java
@@ -0,0 +1,147 @@
+package org.apache.commons.jcs3.auxiliary.lateral.socket.tcp;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+
+/*
+ * 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.
+ */
+
+import junit.extensions.ActiveTestSuite;
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+/**
+ * Test which exercises the tcp lateral cache. Runs two threads against the
+ * same region and two against other regions.
+ */
+public class LateralTCPNoDeadLockConcurrentTest
+ extends TestCase
+{
+ /**
+ * Constructor for the TestDiskCache object.
+ *
+ * @param testName
+ */
+ public LateralTCPNoDeadLockConcurrentTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * Main method passes this test to the text test runner.
+ *
+ * @param args
+ */
+ public static void main( String args[] )
+ {
+ String[] testCaseName = { LateralTCPNoDeadLockConcurrentTest.class.getName() };
+ junit.textui.TestRunner.main( testCaseName );
+ }
+
+ /**
+ * A unit test suite for JUnit
+ *
+ * @return The test suite
+ */
+ public static Test suite()
+ {
+
+ System.setProperty( "jcs.auxiliary.LTCP.attributes.PutOnlyMode", "false" );
+
+ ActiveTestSuite suite = new ActiveTestSuite();
+
+ suite.addTest( new LateralTCPConcurrentRandomTestUtil( "testLateralTCPCache1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "region1", 1, 200, 1 );
+ }
+ } );
+
+ suite.addTest( new LateralTCPConcurrentRandomTestUtil( "testLateralTCPCache2" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "region2", 10000, 12000, 2 );
+ }
+ } );
+
+ suite.addTest( new LateralTCPConcurrentRandomTestUtil( "testLateralTCPCache3" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "region3", 10000, 12000, 3 );
+ }
+ } );
+
+ suite.addTest( new LateralTCPConcurrentRandomTestUtil( "testLateralTCPCache4" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "region3", 10000, 13000, 4 );
+ }
+ } );
+
+ suite.addTest( new LateralTCPConcurrentRandomTestUtil( "testLateralTCPCache5" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "region4", 10000, 11000, 5 );
+ }
+ } );
+
+ return suite;
+ }
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestTCPLateralCacheConcurrent.ccf" );
+ }
+
+ /**
+ * Test tearDown. Dispose of the cache.
+ */
+ @Override
+ public void tearDown()
+ {
+ try
+ {
+ CompositeCacheManager cacheMgr = CompositeCacheManager.getInstance();
+ cacheMgr.shutDown();
+ }
+ catch ( Exception e )
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/TestTCPLateralUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/TestTCPLateralUnitTest.java
new file mode 100644
index 0000000..2f5d1e0
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/lateral/socket/tcp/TestTCPLateralUnitTest.java
@@ -0,0 +1,372 @@
+package org.apache.commons.jcs3.auxiliary.lateral.socket.tcp;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.engine.control.MockCompositeCacheManager;
+import org.apache.commons.jcs3.utils.timing.SleepUtil;
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.lateral.LateralCommand;
+import org.apache.commons.jcs3.auxiliary.lateral.LateralElementDescriptor;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPListener;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPSender;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPService;
+import org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+import org.apache.commons.jcs3.engine.control.group.GroupAttrName;
+import org.apache.commons.jcs3.engine.control.group.GroupId;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Basic unit tests for the sending and receiving portions of the lateral cache.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class TestTCPLateralUnitTest
+ extends TestCase
+{
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestTCPLateralCache.ccf" );
+ }
+
+ /**
+ * Make sure we can send a bunch to the listener. This would be better if we could plugin a Mock
+ * CacheManger. The listener will instantiate it on its own. We have to configure one before
+ * that.
+ * <p>
+ * @throws Exception
+ */
+ public void testSimpleSend()
+ throws Exception
+ {
+ // SETUP
+ // force initialization
+ JCS.getInstance( "test" );
+
+ TCPLateralCacheAttributes lac = new TCPLateralCacheAttributes();
+ lac.setTransmissionType( LateralCacheAttributes.Type.TCP );
+ lac.setTcpServer( "localhost" + ":" + 8111 );
+ lac.setTcpListenerPort( 8111 );
+
+ ICompositeCacheManager cacheMgr = CompositeCacheManager.getInstance();
+
+ // start the listener
+ LateralTCPListener<String, String> listener = LateralTCPListener.getInstance( lac, cacheMgr );
+
+ // send to the listener
+ LateralTCPSender lur = new LateralTCPSender( lac );
+
+ // DO WORK
+ int numMes = 10;
+ for ( int i = 0; i < numMes; i++ )
+ {
+ String message = "adsfasasfasfasdasf";
+ CacheElement<String, String> ce = new CacheElement<>( "test", "test", message );
+ LateralElementDescriptor<String, String> led = new LateralElementDescriptor<>( ce );
+ led.command = LateralCommand.UPDATE;
+ led.requesterId = 1;
+ lur.send( led );
+ }
+
+ SleepUtil.sleepAtLeast( numMes * 3 );
+
+ // VERIFY
+ assertEquals( "Should have received " + numMes + " by now.", numMes, listener.getPutCnt() );
+ }
+
+ /**
+ * @throws Exception
+ */
+ public void testReceive()
+ throws Exception
+ {
+ // VERIFY
+ TCPLateralCacheAttributes lattr = new TCPLateralCacheAttributes();
+ lattr.setTcpListenerPort( 1101 );
+ lattr.setTransmissionTypeName( "TCP" );
+ MockCompositeCacheManager cacheMgr = new MockCompositeCacheManager();
+// System.out.println( "mock cache = " + cacheMgr.getCache( "test" ) );
+
+ LateralTCPListener.getInstance( lattr, cacheMgr );
+
+ TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
+ lattr2.setTcpListenerPort( 1102 );
+ lattr2.setTransmissionTypeName( "TCP" );
+ lattr2.setTcpServer( "localhost:1101" );
+
+ LateralTCPService<String, String> service = new LateralTCPService<>( lattr2 );
+ service.setListenerId( 123456 );
+
+ // DO WORK
+ int cnt = 100;
+ for ( int i = 0; i < cnt; i++ )
+ {
+ ICacheElement<String, String> element = new CacheElement<>( "test", "key" + i, "value1" );
+ service.update( element );
+ }
+
+ SleepUtil.sleepAtLeast( 1000 );
+
+ // VERIFY
+ assertEquals( "Didn't get the correct number", cnt, cacheMgr.getCache().getUpdateCount() );
+ }
+
+ /**
+ * Send objects with the same key but different values.
+ * <p>
+ * @throws Exception
+ */
+ public void testSameKeyDifferentObject()
+ throws Exception
+ {
+ // SETUP
+ // setup a listener
+ TCPLateralCacheAttributes lattr = new TCPLateralCacheAttributes();
+ lattr.setTcpListenerPort( 1103 );
+ MockCompositeCacheManager cacheMgr = new MockCompositeCacheManager();
+ CompositeCache<String, String> cache = cacheMgr.getCache( "test" );
+// System.out.println( "mock cache = " + cache );
+
+ // get the listener started
+ // give it our mock cache manager
+ //LateralTCPListener listener = (LateralTCPListener)
+ LateralTCPListener.getInstance( lattr, cacheMgr );
+
+ // setup a service to talk to the listener started above.
+ TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
+ lattr2.setTcpListenerPort( 1104 );
+ lattr2.setTcpServer( "localhost:1103" );
+
+ LateralTCPService<String, String> service = new LateralTCPService<>( lattr2 );
+ service.setListenerId( 123456 );
+
+ // DO WORK
+ ICacheElement<String, String> element = new CacheElement<>( "test", "key", "value1" );
+ service.update( element );
+
+ SleepUtil.sleepAtLeast( 300 );
+
+ ICacheElement<String, String> element2 = new CacheElement<>( "test", "key", "value2" );
+ service.update( element2 );
+
+ SleepUtil.sleepAtLeast( 1000 );
+
+ // VERIFY
+ ICacheElement<String, String> cacheElement = cache.get( "key" );
+ assertEquals( "Didn't get the correct object "+ cacheElement, element2.getVal(), cacheElement.getVal() );
+ }
+
+ /**
+ * Send objects with the same key but different values.
+ * <p>
+ * @throws Exception
+ */
+ public void testSameKeyObjectDifferentValueObject()
+ throws Exception
+ {
+ TCPLateralCacheAttributes lattr = new TCPLateralCacheAttributes();
+ lattr.setTcpListenerPort( 1105 );
+ lattr.setTransmissionTypeName( "TCP" );
+ MockCompositeCacheManager cacheMgr = new MockCompositeCacheManager();
+ CompositeCache<String, String> cache = cacheMgr.getCache( "test" );
+// System.out.println( "mock cache = " + cache );
+
+ // get the listener started
+ // give it our mock cache manager
+ //LateralTCPListener listener = (LateralTCPListener)
+ LateralTCPListener.getInstance( lattr, cacheMgr );
+
+ TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
+ lattr2.setTcpListenerPort( 1106 );
+ lattr2.setTransmissionTypeName( "TCP" );
+ lattr2.setTcpServer( "localhost:1105" );
+
+ LateralTCPService<String, String> service = new LateralTCPService<>( lattr2 );
+ service.setListenerId( 123456 );
+
+ // DO WORK
+ String key = "key";
+ ICacheElement<String, String> element = new CacheElement<>( "test", key, "value1" );
+ service.update( element );
+
+ SleepUtil.sleepAtLeast( 300 );
+
+ ICacheElement<String, String> element2 = new CacheElement<>( "test", key, "value2" );
+ service.update( element2 );
+
+ SleepUtil.sleepAtLeast( 1000 );
+
+ // VERIFY
+ ICacheElement<String, String> cacheElement = cache.get( "key" );
+ assertEquals( "Didn't get the correct object: " + cacheElement , element2.getVal(), cacheElement.getVal() );
+ }
+
+ /**
+ * Create a listener. Add an element to the listeners cache. Setup a service. Try to get from
+ * the service.
+ * <p>
+ * @throws Exception
+ */
+ public void testGet_SendAndReceived()
+ throws Exception
+ {
+ // SETUP
+ // setup a listener
+ TCPLateralCacheAttributes lattr = new TCPLateralCacheAttributes();
+ lattr.setTcpListenerPort( 1107 );
+ MockCompositeCacheManager cacheMgr = new MockCompositeCacheManager();
+ CompositeCache<String, String> cache = cacheMgr.getCache( "test" );
+// System.out.println( "mock cache = " + cache );
+
+ // get the listener started
+ // give it our mock cache manager
+ LateralTCPListener.getInstance( lattr, cacheMgr );
+
+ // add the item to the listeners cache
+ ICacheElement<String, String> element = new CacheElement<>( "test", "key", "value1" );
+ cache.update( element );
+
+ // setup a service to talk to the listener started above.
+ TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
+ lattr2.setTcpListenerPort( 1108 );
+ lattr2.setTcpServer( "localhost:1107" );
+
+ LateralTCPService<String, String> service = new LateralTCPService<>( lattr2 );
+ service.setListenerId( 123456 );
+
+ SleepUtil.sleepAtLeast( 300 );
+
+ // DO WORK
+ ICacheElement<String, String> result = service.get( "test", "key" );
+
+ // VERIFY
+ assertNotNull( "Result should not be null.", result );
+ assertEquals( "Didn't get the correct object", element.getVal(), result.getVal() );
+ }
+
+ /**
+ * Create a listener. Add an element to the listeners cache. Setup a service. Try to get keys from
+ * the service.
+ * <p>
+ * @throws Exception
+ */
+ public void testGetGroupKeys_SendAndReceived() throws Exception
+ {
+ // SETUP
+ // setup a listener
+ TCPLateralCacheAttributes lattr = new TCPLateralCacheAttributes();
+ lattr.setTcpListenerPort( 1150 );
+ MockCompositeCacheManager cacheMgr = new MockCompositeCacheManager();
+ CompositeCache<GroupAttrName<String>, String> cache = cacheMgr.getCache( "test" );
+// System.out.println( "mock cache = " + cache );
+
+ // get the listener started
+ // give it our mock cache manager
+ LateralTCPListener.getInstance( lattr, cacheMgr );
+
+ // add the item to the listeners cache
+ GroupAttrName<String> groupKey = new GroupAttrName<>(new GroupId("test", "group"), "key");
+ ICacheElement<GroupAttrName<String>, String> element =
+ new CacheElement<>( "test", groupKey, "value1" );
+ cache.update( element );
+
+ // setup a service to talk to the listener started above.
+ TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
+ lattr2.setTcpListenerPort( 1151 );
+ lattr2.setTcpServer( "localhost:1150" );
+
+ LateralTCPService<GroupAttrName<String>, String> service =
+ new LateralTCPService<>( lattr2 );
+ service.setListenerId( 123459 );
+
+ SleepUtil.sleepAtLeast( 500 );
+
+ // DO WORK
+ Set<GroupAttrName<String>> result = service.getKeySet("test");
+
+ // SleepUtil.sleepAtLeast( 5000000 );
+
+ // VERIFY
+ assertNotNull( "Result should not be null.", result );
+ assertEquals( "Didn't get the correct object", "key", result.iterator().next().attrName );
+ }
+
+ /**
+ * Create a listener. Add an element to the listeners cache. Setup a service. Try to get from
+ * the service.
+ * <p>
+ * @throws Exception
+ */
+ public void testGetMatching_WithData()
+ throws Exception
+ {
+ // SETUP
+ // setup a listener
+ TCPLateralCacheAttributes lattr = new TCPLateralCacheAttributes();
+ lattr.setTcpListenerPort( 1108 );
+ MockCompositeCacheManager cacheMgr = new MockCompositeCacheManager();
+ CompositeCache<String, Integer> cache = cacheMgr.getCache( "test" );
+// System.out.println( "mock cache = " + cache );
+
+ // get the listener started
+ // give it our mock cache manager
+ LateralTCPListener.getInstance( lattr, cacheMgr );
+
+ String keyprefix1 = "MyPrefix1";
+ int numToInsertPrefix1 = 10;
+ // insert with prefix1
+ for ( int i = 0; i < numToInsertPrefix1; i++ )
+ {
+ // add the item to the listeners cache
+ ICacheElement<String, Integer> element = new CacheElement<>( "test", keyprefix1 + String.valueOf( i ), Integer.valueOf( i ) );
+ cache.update( element );
+ }
+
+ // setup a service to talk to the listener started above.
+ TCPLateralCacheAttributes lattr2 = new TCPLateralCacheAttributes();
+ lattr2.setTcpListenerPort( 1108 );
+ lattr2.setTcpServer( "localhost:1108" );
+
+ LateralTCPService<String, Integer> service = new LateralTCPService<>( lattr2 );
+ service.setListenerId( 123456 );
+
+ SleepUtil.sleepAtLeast( 300 );
+
+ // DO WORK
+ Map<String, ICacheElement<String, Integer>> result = service.getMatching( "test", keyprefix1 + ".+" );
+
+ // VERIFY
+ assertNotNull( "Result should not be null.", result );
+ assertEquals( "Wrong number returned 1:", numToInsertPrefix1, result.size() );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/MockRemoteCacheClient.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/MockRemoteCacheClient.java
new file mode 100644
index 0000000..fba96ba
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/MockRemoteCacheClient.java
@@ -0,0 +1,262 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheClient;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheListener;
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * Used for testing the no wait.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class MockRemoteCacheClient<K, V>
+ extends AbstractAuxiliaryCache<K, V>
+ implements IRemoteCacheClient<K, V>
+{
+ /** log instance */
+ private static final Log log = LogManager.getLog( MockRemoteCacheClient.class );
+
+ /** List of ICacheElement<K, V> objects passed into update. */
+ public List<ICacheElement<K, V>> updateList = new LinkedList<>();
+
+ /** List of key objects passed into remove. */
+ public List<K> removeList = new LinkedList<>();
+
+ /** status to return. */
+ public CacheStatus status = CacheStatus.ALIVE;
+
+ /** Can setup values to return from get. values must be ICacheElement<K, V> */
+ public Map<K, ICacheElement<K, V>> getSetupMap = new HashMap<>();
+
+ /** Can setup values to return from get. values must be Map<K, ICacheElement<K, V>> */
+ public Map<Set<K>, Map<K, ICacheElement<K, V>>> getMultipleSetupMap =
+ new HashMap<>();
+
+ /** The last service passed to fixCache */
+ public ICacheServiceNonLocal<K, V> fixed;
+
+ /** Attributes. */
+ public RemoteCacheAttributes attributes = new RemoteCacheAttributes();
+
+ /**
+ * Stores the last argument as fixed.
+ */
+ @Override
+ @SuppressWarnings("unchecked") // Don't know how to do this properly
+ public void fixCache( ICacheServiceNonLocal<?, ?> remote )
+ {
+ fixed = (ICacheServiceNonLocal<K, V>)remote;
+ }
+
+ /**
+ * @return long
+ */
+ @Override
+ public long getListenerId()
+ {
+ return 0;
+ }
+
+ /**
+ * @return null
+ */
+ @Override
+ public IRemoteCacheListener<K, V> getListener()
+ {
+ return null;
+ }
+
+ /**
+ * Adds the argument to the updatedList.
+ */
+ @Override
+ public void update( ICacheElement<K, V> ce )
+ {
+ updateList.add( ce );
+ }
+
+ /**
+ * Looks in the getSetupMap for a value.
+ */
+ @Override
+ public ICacheElement<K, V> get( K key )
+ {
+ log.info( "get [" + key + "]" );
+ return getSetupMap.get( key );
+ }
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
+ * data in cache for any of these keys
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
+ {
+ log.info( "get [" + keys + "]" );
+ return getMultipleSetupMap.get( keys );
+ }
+
+ /**
+ * Adds the key to the remove list.
+ */
+ @Override
+ public boolean remove( K key )
+ {
+ removeList.add( key );
+ return false;
+ }
+
+ /**
+ * Removes all cached items from the cache.
+ */
+ @Override
+ public void removeAll()
+ {
+ // do nothing
+ }
+
+ /**
+ * Prepares for shutdown.
+ */
+ @Override
+ public void dispose()
+ {
+ // do nothing
+ }
+
+ /**
+ * Returns the current cache size in number of elements.
+ * <p>
+ * @return number of elements
+ */
+ @Override
+ public int getSize()
+ {
+ return 0;
+ }
+
+ /**
+ * Returns the status setup variable.
+ */
+ @Override
+ public CacheStatus getStatus()
+ {
+ return status;
+ }
+
+ /**
+ * Returns the cache name.
+ * <p>
+ * @return usually the region name.
+ */
+ @Override
+ public String getCacheName()
+ {
+ return null;
+ }
+
+ /**
+ * @return null
+ */
+ @Override
+ public Set<K> getKeySet( )
+ {
+ return null;
+ }
+
+ /**
+ * @return null
+ */
+ @Override
+ public IStats getStatistics()
+ {
+ return null;
+ }
+
+ /**
+ * Returns the setup attributes. By default they are not null.
+ */
+ @Override
+ public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
+ {
+ return attributes;
+ }
+
+ /**
+ * Returns the cache stats.
+ * <p>
+ * @return String of important historical information.
+ */
+ @Override
+ public String getStats()
+ {
+ return null;
+ }
+
+ /** @return 0 */
+ @Override
+ public CacheType getCacheType()
+ {
+ return CacheType.REMOTE_CACHE;
+ }
+
+ /**
+ * @param pattern
+ * @return Map
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching(String pattern)
+ throws IOException
+ {
+ return new HashMap<>();
+ }
+
+ /**
+ * Nothing important
+ * <p>
+ * @return null
+ */
+ @Override
+ public String getEventLoggingExtraInfo()
+ {
+ return null;
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/MockRemoteCacheListener.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/MockRemoteCacheListener.java
new file mode 100644
index 0000000..bb88c6a
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/MockRemoteCacheListener.java
@@ -0,0 +1,168 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheListener;
+import org.apache.commons.jcs3.auxiliary.remote.server.behavior.RemoteType;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/**
+ * For testing.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class MockRemoteCacheListener<K, V>
+ implements IRemoteCacheListener<K, V>
+{
+ /** Setup the listener id that this will return. */
+ private long listenerId;
+
+ /** Setup the listener ip that this will return. */
+ public String localAddress;
+
+ /** Number of times handlePut was called. */
+ public int putCount;
+
+ /** List of ICacheElements passed to handlePut. */
+ public List<ICacheElement<K, V>> putItems = new LinkedList<>();
+
+ /** List of Serializable objects passed to handleRemove. */
+ public List<K> removedKeys = new LinkedList<>();
+
+ /** Number of times handleRemote was called. */
+ public int removeCount;
+
+ /** The type of remote listener */
+ public RemoteType remoteType = RemoteType.LOCAL;
+
+ /**
+ * @throws IOException
+ */
+ @Override
+ public void dispose()
+ throws IOException
+ {
+ // TODO Auto-generated method stub
+ }
+
+ /**
+ * returns the listener id, which can be setup.
+ * @return listenerId
+ * @throws IOException
+ */
+ @Override
+ public long getListenerId()
+ throws IOException
+ {
+ return listenerId;
+ }
+
+ /**
+ * @return localAddress
+ * @throws IOException
+ */
+ @Override
+ public String getLocalHostAddress()
+ throws IOException
+ {
+ return localAddress;
+ }
+
+ /**
+ * Return the setup remoteType.
+ * @return remoteType
+ * @throws IOException
+ */
+ @Override
+ public RemoteType getRemoteType()
+ throws IOException
+ {
+ return remoteType;
+ }
+
+ /**
+ * Allows you to setup the listener id.
+ * <p>
+ * @param id
+ * @throws IOException
+ */
+ @Override
+ public void setListenerId( long id )
+ throws IOException
+ {
+ listenerId = id;
+ }
+
+ /**
+ * @param cacheName
+ * @throws IOException
+ */
+ @Override
+ public void handleDispose( String cacheName )
+ throws IOException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * This increments the put count and adds the item to the putItem list.
+ * <p>
+ * @param item
+ * @throws IOException
+ */
+ @Override
+ public void handlePut( ICacheElement<K, V> item )
+ throws IOException
+ {
+ putCount++;
+ this.putItems.add( item );
+ }
+
+ /**
+ * Increments the remove count and adds the key to the removedKeys list.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @throws IOException
+ */
+ @Override
+ public void handleRemove( String cacheName, K key )
+ throws IOException
+ {
+ removeCount++;
+ removedKeys.add( key );
+ }
+
+ /**
+ * @param cacheName
+ * @throws IOException
+ */
+ @Override
+ public void handleRemoveAll( String cacheName )
+ throws IOException
+ {
+ // TODO Auto-generated method stub
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/MockRemoteCacheService.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/MockRemoteCacheService.java
new file mode 100644
index 0000000..19ba06f
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/MockRemoteCacheService.java
@@ -0,0 +1,241 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+
+/**
+ * This is a mock impl of the remote cache service.
+ */
+public class MockRemoteCacheService<K, V>
+ implements ICacheServiceNonLocal<K, V>
+{
+ /** The key last passed to get */
+ public K lastGetKey;
+
+ /** The pattern last passed to get */
+ public String lastGetMatchingPattern;
+
+ /** The keya last passed to getMatching */
+ public Set<K> lastGetMultipleKeys;
+
+ /** The object that was last passed to update. */
+ public ICacheElement<K, V> lastUpdate;
+
+ /** List of updates. */
+ public List<ICacheElement<K, V>> updateRequestList = new ArrayList<>();
+
+ /** List of request ids. */
+ public List<Long> updateRequestIdList = new ArrayList<>();
+
+ /** The key that was last passed to remove. */
+ public K lastRemoveKey;
+
+ /** The cache name that was last passed to removeAll. */
+ public String lastRemoveAllCacheName;
+
+ /**
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ * @return null
+ */
+ @Override
+ public ICacheElement<K, V> get( String cacheName, K key, long requesterId )
+ {
+ lastGetKey = key;
+ return null;
+ }
+
+ /**
+ * @param cacheName
+ * @return empty set
+ */
+ @Override
+ public Set<K> getKeySet( String cacheName )
+ {
+ return new HashSet<>();
+ }
+
+ /**
+ * Set the last remove key.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId
+ */
+ @Override
+ public void remove( String cacheName, K key, long requesterId )
+ {
+ lastRemoveKey = key;
+ }
+
+ /**
+ * Set the lastRemoveAllCacheName to the cacheName.
+ */
+ @Override
+ public void removeAll( String cacheName, long requesterId )
+ throws IOException
+ {
+ lastRemoveAllCacheName = cacheName;
+ }
+
+ /**
+ * Set the last update item.
+ * <p>
+ * @param item
+ * @param requesterId
+ */
+ @Override
+ public void update( ICacheElement<K, V> item, long requesterId )
+ {
+ lastUpdate = item;
+ updateRequestList.add( item );
+ updateRequestIdList.add( Long.valueOf( requesterId ) );
+ }
+
+ /**
+ * Do nothing.
+ * <p>
+ * @param cacheName
+ */
+ @Override
+ public void dispose( String cacheName )
+ {
+ return;
+ }
+
+ /**
+ * @param cacheName
+ * @param key
+ * @return null
+ */
+ @Override
+ public ICacheElement<K, V> get( String cacheName, K key )
+ {
+ return get( cacheName, key, 0 );
+ }
+
+ /**
+ * Do nothing.
+ */
+ @Override
+ public void release()
+ {
+ return;
+ }
+
+ /**
+ * Set the last remove key.
+ * <p>
+ * @param cacheName
+ * @param key
+ */
+ @Override
+ public void remove( String cacheName, K key )
+ {
+ lastRemoveKey = key;
+ }
+
+ /**
+ * Set the last remove all cache name.
+ * <p>
+ * @param cacheName
+ */
+ @Override
+ public void removeAll( String cacheName )
+ {
+ lastRemoveAllCacheName = cacheName;
+ }
+
+ /**
+ * Set the last update item.
+ * <p>
+ * @param item
+ */
+ @Override
+ public void update( ICacheElement<K, V> item )
+ {
+ lastUpdate = item;
+ }
+
+ /**
+ * @param cacheName
+ * @param keys
+ * @param requesterId
+ * @return empty map
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys, long requesterId )
+ {
+ lastGetMultipleKeys = keys;
+ return new HashMap<>();
+ }
+
+ /**
+ * @param cacheName
+ * @param keys
+ * @return empty map
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys )
+ {
+ return getMultiple( cacheName, keys, 0 );
+ }
+
+ /**
+ * Returns an empty map. Zombies have no internal data.
+ * <p>
+ * @param cacheName
+ * @param pattern
+ * @return an empty map
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern )
+ throws IOException
+ {
+ return getMatching( cacheName, pattern, 0 );
+ }
+
+ /**
+ * @param cacheName
+ * @param pattern
+ * @param requesterId
+ * @return Map
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern, long requesterId )
+ throws IOException
+ {
+ lastGetMatchingPattern = pattern;
+ return new HashMap<>();
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheClientTester.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheClientTester.java
new file mode 100644
index 0000000..cdcef1f
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheClientTester.java
@@ -0,0 +1,343 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.rmi.Naming;
+import java.rmi.NotBoundException;
+import java.rmi.Remote;
+import java.rmi.registry.Registry;
+import java.rmi.server.ExportException;
+import java.rmi.server.UnicastRemoteObject;
+
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.access.exception.ObjectExistsException;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteUtils;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheConstants;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheListener;
+import org.apache.commons.jcs3.auxiliary.remote.server.behavior.RemoteType;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheObserver;
+import org.apache.commons.jcs3.engine.behavior.ICacheService;
+
+/**
+ * Manual tester.
+ */
+public class RemoteCacheClientTester
+ implements IRemoteCacheListener<String, String>, IRemoteCacheConstants, Remote
+{
+ /** the observer */
+ protected ICacheObserver watch;
+
+ /** the service */
+ protected ICacheService<String, String> cache;
+
+ /** The registry host name. */
+ final String host;
+
+ /** The registry port number. */
+ final int port;
+
+ /** call count */
+ final int count;
+
+ /** Description of the Field */
+ protected static long listenerId = 0;
+
+ /**
+ * Gets the remoteType attribute of the RemoteCacheClientTest object
+ * @return The remoteType value
+ * @throws IOException
+ */
+ @Override
+ public RemoteType getRemoteType()
+ throws IOException
+ {
+ return RemoteType.LOCAL;
+ }
+
+ /**
+ * Constructor for the RemoteCacheClientTest object
+ * @param count
+ * @throws MalformedURLException
+ * @throws NotBoundException
+ * @throws IOException
+ */
+ public RemoteCacheClientTester( int count )
+ throws MalformedURLException, NotBoundException, IOException
+ {
+ this( count, true, true, false );
+ }
+
+ /**
+ * Constructor for the RemoteCacheClientTest object
+ * @param count
+ * @param write
+ * @param read
+ * @param delete
+ * @throws MalformedURLException
+ * @throws NotBoundException
+ * @throws IOException
+ */
+ public RemoteCacheClientTester( int count, boolean write, boolean read, boolean delete )
+ throws MalformedURLException, NotBoundException, IOException
+ {
+ this( "", Registry.REGISTRY_PORT, count, write, read, delete );
+ }
+
+ /**
+ * Constructor for the RemoteCacheClientTest object
+ * @param host
+ * @param port
+ * @param count
+ * @param write
+ * @param read
+ * @param delete
+ * @throws MalformedURLException
+ * @throws NotBoundException
+ * @throws IOException
+ */
+ @SuppressWarnings("unchecked")
+ public RemoteCacheClientTester( String host, int port, int count, boolean write, boolean read, boolean delete )
+ throws MalformedURLException, NotBoundException, IOException
+ {
+ this.count = count;
+ this.host = host;
+ this.port = port;
+ // record export exception
+ Exception ee = null;
+
+ try
+ {
+ // Export this remote object to make it available to receive
+ // incoming calls,
+ // using an anonymous port.
+ UnicastRemoteObject.exportObject( this );
+ }
+ catch ( ExportException e )
+ {
+ // use already exported object; remember exception
+ ee = e;
+ ee.printStackTrace();
+ }
+ String service = System.getProperty( REMOTE_CACHE_SERVICE_NAME );
+
+ if ( service == null )
+ {
+ service = REMOTE_CACHE_SERVICE_VAL;
+ }
+ String registry = RemoteUtils.getNamingURL(host, port, service);
+
+ p( "looking up server " + registry );
+
+ Object obj = Naming.lookup( registry );
+
+ p( "server found" );
+
+ cache = (ICacheService<String, String>) obj;
+ watch = (ICacheObserver) obj;
+
+ p( "subscribing to the server" );
+
+ watch.addCacheListener( "testCache", this );
+ ICacheElement<String, String> cb = new CacheElement<>( "testCache", "testKey", "testVal" );
+
+ for ( int i = 0; i < count; i++ )
+ {
+ cb = new CacheElement<>( "testCache", "" + i, "" + i );
+
+ if ( delete )
+ {
+ p( "deleting a cache item from the server " + i );
+
+ cache.remove( cb.getCacheName(), cb.getKey() );
+ }
+ if ( write )
+ {
+ p( "putting a cache bean to the server " + i );
+
+ try
+ {
+ cache.update( cb );
+ }
+ catch ( ObjectExistsException oee )
+ {
+ p( oee.toString() );
+ }
+ }
+ if ( read )
+ {
+ try
+ {
+ Object val = cache.get( cb.getCacheName(), cb.getKey() );
+ p( "get " + cb.getKey() + " returns " + val );
+ }
+ catch ( CacheException onfe )
+ {
+ // nothing
+ }
+ }
+ }
+ }
+
+ /**
+ * @param cb
+ * @throws IOException
+ */
+ @Override
+ public void handlePut( ICacheElement<String, String> cb )
+ throws IOException
+ {
+ p( "handlePut> cb=" + cb );
+ }
+
+ /**
+ * @param cacheName
+ * @param key
+ * @throws IOException
+ */
+ @Override
+ public void handleRemove( String cacheName, String key )
+ throws IOException
+ {
+ p( "handleRemove> cacheName=" + cacheName + ", key=" + key );
+ }
+
+ /**
+ * @param cacheName
+ * @throws IOException
+ */
+ @Override
+ public void handleRemoveAll( String cacheName )
+ throws IOException
+ {
+ p( "handleRemove> cacheName=" + cacheName );
+ }
+
+ /**
+ * @param cacheName
+ * @throws IOException
+ */
+ @Override
+ public void handleDispose( String cacheName )
+ throws IOException
+ {
+ p( "handleDispose> cacheName=" + cacheName );
+ }
+
+ /*
+ * public void handleRelease() throws IOException { p("handleRelease>"); }
+ */
+ /**
+ * The main program for the RemoteCacheClientTest class
+ * @param args The command line arguments
+ * @throws Exception
+ */
+ public static void main( String[] args )
+ throws Exception
+ {
+ int count = 0;
+ boolean read = false;
+ boolean write = false;
+ boolean delete = false;
+
+ for ( int i = 0; i < args.length; i++ )
+ {
+ if ( args[i].startsWith( "-" ) )
+ {
+ if ( !read )
+ {
+ read = args[i].indexOf( "r" ) != -1;
+ }
+ if ( !write )
+ {
+ write = args[i].indexOf( "w" ) != -1;
+ }
+ if ( !delete )
+ {
+ delete = args[i].indexOf( "d" ) != -1;
+ }
+ }
+ else
+ {
+ count = Integer.parseInt( args[i] );
+ }
+ }
+ new RemoteCacheClientTester( count, write, read, delete );
+ }
+
+ /**
+ * Sets the listenerId attribute of the RemoteCacheClientTest object
+ * @param id The new listenerId value
+ * @throws IOException
+ */
+ @Override
+ public void setListenerId( long id )
+ throws IOException
+ {
+ listenerId = id;
+ p( "listenerId = " + id );
+ }
+
+ /**
+ * Gets the listenerId attribute of the RemoteCacheClientTest object
+ * @return The listenerId value
+ * @throws IOException
+ */
+ @Override
+ public long getListenerId()
+ throws IOException
+ {
+ return listenerId;
+ }
+
+ /**
+ * Helper for output, this is an user run test class
+ * @param s
+ */
+ private static void p( String s )
+ {
+ System.out.println( s );
+ }
+
+ /**
+ * @return null
+ * @throws IOException
+ */
+ @Override
+ public String getLocalHostAddress()
+ throws IOException
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /**
+ * @throws IOException
+ */
+ @Override
+ public void dispose()
+ throws IOException
+ {
+ // TODO Auto-generated method stub
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheListenerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheListenerUnitTest.java
new file mode 100644
index 0000000..49d5dcd
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheListenerUnitTest.java
@@ -0,0 +1,126 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import org.apache.commons.jcs3.engine.control.MockCompositeCacheManager;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCacheListener;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheElementSerialized;
+import org.apache.commons.jcs3.engine.ElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICache;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElementSerialized;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+
+/**
+ * Tests for the remote cache listener.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class RemoteCacheListenerUnitTest
+ extends TestCase
+{
+ /**
+ * Create a RemoteCacheListener with a mock cache manager. Set remove on put to false.
+ * Create a serialized element. Call put on the listener.
+ * Verify that the deserialized element is in the cache.
+ * <p>
+ * @throws Exception
+ */
+ public void testUpdate_PutOnPut()
+ throws Exception
+ {
+ // SETUP
+ IRemoteCacheAttributes irca = new RemoteCacheAttributes();
+ irca.setRemoveUponRemotePut( false );
+ ICompositeCacheManager cacheMgr = new MockCompositeCacheManager();
+ RemoteCacheListener<String, String> listener = new RemoteCacheListener<>( irca, cacheMgr, new StandardSerializer() );
+
+ String cacheName = "testName";
+ String key = "key";
+ String value = "value fdsadf dsafdsa fdsaf dsafdsaf dsafdsaf dsaf dsaf dsaf dsafa dsaf dsaf dsafdsaf";
+ IElementAttributes attr = new ElementAttributes();
+ attr.setMaxLife(34);
+
+ IElementSerializer elementSerializer = new StandardSerializer();
+
+ ICacheElementSerialized<String, String> element =
+ new CacheElementSerialized<>( cacheName, key, elementSerializer
+ .serialize( value ), attr );
+
+ // DO WORK
+ listener.handlePut( element );
+
+ // VERIFY
+ ICache<String, String> cache = cacheMgr.getCache( cacheName );
+ ICacheElement<String, String> after = cache.get( key );
+
+ assertNotNull( "Should have a deserialized object.", after );
+ assertEquals( "Values should be the same.", value, after.getVal() );
+ assertEquals( "Attributes should be the same.", attr.getMaxLife(), after
+ .getElementAttributes().getMaxLife() );
+ assertEquals( "Keys should be the same.", key, after.getKey() );
+ assertEquals( "Cache name should be the same.", cacheName, after.getCacheName() );
+ }
+
+ /**
+ * Create a RemoteCacheListener with a mock cache manager. Set remove on put to true.
+ * Create a serialized element. Call put on the listener.
+ * Verify that the deserialized element is not in the cache.
+ * <p>
+ * @throws Exception
+ */
+ public void testUpdate_RemoveOnPut()
+ throws Exception
+ {
+ // SETUP
+ IRemoteCacheAttributes irca = new RemoteCacheAttributes();
+ irca.setRemoveUponRemotePut( true );
+ ICompositeCacheManager cacheMgr = new MockCompositeCacheManager();
+ RemoteCacheListener<String, String> listener = new RemoteCacheListener<>( irca, cacheMgr, new StandardSerializer() );
+
+ String cacheName = "testName";
+ String key = "key";
+ String value = "value fdsadf dsafdsa fdsaf dsafdsaf dsafdsaf dsaf dsaf dsaf dsafa dsaf dsaf dsafdsaf";
+ IElementAttributes attr = new ElementAttributes();
+ attr.setMaxLife(34);
+
+ IElementSerializer elementSerializer = new StandardSerializer();
+
+ ICacheElementSerialized<String, String> element =
+ new CacheElementSerialized<>( cacheName, key, elementSerializer
+ .serialize( value ), attr );
+
+ // DO WORK
+ listener.handlePut( element );
+
+ // VERIFY
+ ICache<String, String> cache = cacheMgr.getCache( cacheName );
+ ICacheElement<String, String> after = cache.get( key );
+
+ assertNull( "Should not have a deserialized object since remove on put is true.", after );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheNoWaitFacadeUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheNoWaitFacadeUnitTest.java
new file mode 100644
index 0000000..5968936
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheNoWaitFacadeUnitTest.java
@@ -0,0 +1,60 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCache;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCacheNoWait;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCacheNoWaitFacade;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheAttributes;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for RemoteCacheNoWaitFacade.
+ */
+public class RemoteCacheNoWaitFacadeUnitTest
+ extends TestCase
+{
+ /**
+ * Verify that we can add an item.
+ */
+ public void testAddNoWait_InList()
+ {
+ // SETUP
+ List<RemoteCacheNoWait<String, String>> noWaits = new ArrayList<>();
+ IRemoteCacheAttributes cattr = new RemoteCacheAttributes();
+ cattr.setCacheName( "testCache1" );
+
+ RemoteCache<String, String> client = new RemoteCache<>(cattr, null, null, null);
+ RemoteCacheNoWait<String, String> noWait = new RemoteCacheNoWait<>( client );
+ noWaits.add( noWait );
+
+ RemoteCacheNoWaitFacade<String, String> facade = new RemoteCacheNoWaitFacade<>(noWaits, cattr, null, null, null );
+
+ // VERIFY
+ assertEquals( "Should have one entry.", 1, facade.noWaits.size() );
+ assertTrue( "Should be in the list.", facade.noWaits.contains( noWait ) );
+ assertSame( "Should have same facade.", facade, ((RemoteCache<String, String>)facade.noWaits.get(0).getRemoteCache()).getFacade() );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheNoWaitUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheNoWaitUnitTest.java
new file mode 100644
index 0000000..44a121c
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheNoWaitUnitTest.java
@@ -0,0 +1,212 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.utils.timing.SleepUtil;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCacheNoWait;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for the remote cache no wait. The no wait manages a queue on top of the client.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class RemoteCacheNoWaitUnitTest
+ extends TestCase
+{
+ /**
+ * Simply verify that the client gets updated via the no wait.
+ * <p>
+ * @throws Exception
+ */
+ public void testUpdate()
+ throws Exception
+ {
+ // SETUP
+ MockRemoteCacheClient<String, String> client = new MockRemoteCacheClient<>();
+ RemoteCacheNoWait<String, String> noWait = new RemoteCacheNoWait<>( client );
+
+ ICacheElement<String, String> element = new CacheElement<>( "testUpdate", "key", "value" );
+
+ // DO WORK
+ noWait.update( element );
+
+ // VERIFY
+ SleepUtil.sleepAtLeast( 10 );
+
+ assertEquals( "Wrong number updated.", 1, client.updateList.size() );
+ assertEquals( "Wrong element", element, client.updateList.get( 0 ) );
+ }
+
+ /**
+ * Simply verify that the client get is called from the no wait.
+ * <p>
+ * @throws Exception
+ */
+ public void testGet()
+ throws Exception
+ {
+ // SETUP
+ MockRemoteCacheClient<String, String> client = new MockRemoteCacheClient<>();
+ RemoteCacheNoWait<String, String> noWait = new RemoteCacheNoWait<>( client );
+
+ ICacheElement<String, String> input = new CacheElement<>( "testUpdate", "key", "value" );
+ client.getSetupMap.put( "key", input );
+
+ // DO WORK
+ ICacheElement<String, String> result = noWait.get( "key" );
+
+ // VERIFY
+ assertEquals( "Wrong element", input, result );
+ }
+
+ /**
+ * Simply verify that the client getMultiple is called from the no wait.
+ * <p>
+ * @throws Exception
+ */
+ public void testGetMultiple()
+ throws Exception
+ {
+ // SETUP
+ MockRemoteCacheClient<String, String> client = new MockRemoteCacheClient<>();
+ RemoteCacheNoWait<String, String> noWait = new RemoteCacheNoWait<>( client );
+
+ ICacheElement<String, String> inputElement = new CacheElement<>( "testUpdate", "key", "value" );
+ Map<String, ICacheElement<String, String>> inputMap = new HashMap<>();
+ inputMap.put( "key", inputElement );
+
+ Set<String> keys = new HashSet<>();
+ keys.add( "key" );
+
+ client.getMultipleSetupMap.put( keys, inputMap );
+
+ // DO WORK
+ Map<String, ICacheElement<String, String>> result = noWait.getMultiple( keys );
+
+ // VERIFY
+ assertEquals( "elements map", inputMap, result );
+ }
+
+ /**
+ * Simply verify that the client gets updated via the no wait.
+ * <p>
+ * @throws Exception
+ */
+ public void testRemove()
+ throws Exception
+ {
+ // SETUP
+ MockRemoteCacheClient<String, String> client = new MockRemoteCacheClient<>();
+ RemoteCacheNoWait<String, String> noWait = new RemoteCacheNoWait<>( client );
+
+ String input = "MyKey";
+
+ // DO WORK
+ noWait.remove( input );
+
+ SleepUtil.sleepAtLeast( 10 );
+
+ // VERIFY
+ assertEquals( "Wrong number updated.", 1, client.removeList.size() );
+ assertEquals( "Wrong key", input, client.removeList.get( 0 ) );
+ }
+
+ /**
+ * Simply verify that the client status is returned in the stats.
+ * <p>
+ * @throws Exception
+ */
+ public void testGetStats()
+ throws Exception
+ {
+ // SETUP
+ MockRemoteCacheClient<String, String> client = new MockRemoteCacheClient<>();
+ client.status = CacheStatus.ALIVE;
+ RemoteCacheNoWait<String, String> noWait = new RemoteCacheNoWait<>( client );
+
+ // DO WORK
+ String result = noWait.getStats();
+
+ // VERIFY
+ assertTrue( "Status should contain 'ALIVE'", result.indexOf( "ALIVE" ) != -1 );
+ }
+
+ /**
+ * Simply verify that we get a status of error if the cache is in error..
+ * <p>
+ * @throws Exception
+ */
+ public void testGetStatus_error()
+ throws Exception
+ {
+ // SETUP
+ MockRemoteCacheClient<String, String> client = new MockRemoteCacheClient<>();
+ client.status = CacheStatus.ERROR;
+ RemoteCacheNoWait<String, String> noWait = new RemoteCacheNoWait<>( client );
+
+ // DO WORK
+ CacheStatus result = noWait.getStatus();
+
+ // VERIFY
+ assertEquals( "Wrong status", CacheStatus.ERROR, result );
+ }
+
+ /**
+ * Simply verify that the serviced supplied to fix is passed onto the client. Verify that the
+ * original event queue is destroyed. A new event queue willbe plugged in on fix.
+ * <p>
+ * @throws Exception
+ */
+ public void testFixCache()
+ throws Exception
+ {
+ // SETUP
+ MockRemoteCacheClient<String, String> client = new MockRemoteCacheClient<>();
+ client.status = CacheStatus.ALIVE;
+ RemoteCacheNoWait<String, String> noWait = new RemoteCacheNoWait<>( client );
+
+ MockRemoteCacheService<String, String> service = new MockRemoteCacheService<>();
+
+ ICacheElement<String, String> element = new CacheElement<>( "testUpdate", "key", "value" );
+
+ // DO WORK
+ noWait.update( element );
+ SleepUtil.sleepAtLeast( 10 );
+ // ICacheEventQueue<String, String> originalQueue = noWait.getCacheEventQueue();
+
+ noWait.fixCache( service );
+
+ noWait.update( element );
+ SleepUtil.sleepAtLeast( 10 );
+
+ // VERIFY
+ assertEquals( "Wrong status", service, client.fixed );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheUnitTest.java
new file mode 100644
index 0000000..3ab8ce8
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/RemoteCacheUnitTest.java
@@ -0,0 +1,298 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.util.HashSet;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.jcs3.auxiliary.MockCacheEventLogger;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCache;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCacheMonitor;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.ZombieCacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElementSerialized;
+import org.apache.commons.jcs3.utils.serialization.SerializationConversionUtil;
+
+/**
+ * Unit Tests for the Remote Cache.
+ */
+public class RemoteCacheUnitTest
+ extends TestCase
+{
+ private IRemoteCacheAttributes cattr;
+ private MockRemoteCacheService<String, String> service;
+ private MockRemoteCacheListener<String, String> listener;
+ private RemoteCacheMonitor monitor;
+
+ /**
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ cattr = new RemoteCacheAttributes();
+ service = new MockRemoteCacheService<>();
+ listener = new MockRemoteCacheListener<>();
+ monitor = new RemoteCacheMonitor();
+ }
+
+ /**
+ * Verify that the remote service update method is called. The remote cache serializes the object
+ * first.
+ * <p>
+ * @throws Exception
+ */
+ public void testUpdate()
+ throws Exception
+ {
+ // SETUP
+ long listenerId = 123;
+ listener.setListenerId( listenerId );
+
+ RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, service, listener, monitor );
+
+ String cacheName = "testUpdate";
+
+ // DO WORK
+ ICacheElement<String, String> element = new CacheElement<>( cacheName, "key", "value" );
+ remoteCache.update( element );
+
+ // VERIFY
+ assertTrue( "The element should be in the serialized wrapper.",
+ service.lastUpdate instanceof ICacheElementSerialized );
+ ICacheElement<String, String> result = SerializationConversionUtil
+ .getDeSerializedCacheElement( (ICacheElementSerialized<String, String>) service.lastUpdate, remoteCache
+ .getElementSerializer() );
+ assertEquals( "Wrong element updated.", element.getVal(), result.getVal() );
+ assertEquals( "Wrong listener id.", Long.valueOf( listenerId ), service.updateRequestIdList.get( 0 ) );
+ }
+
+ /**
+ * Verify that when we call fix events queued in the zombie are propagated to the new service.
+ * <p>
+ * @throws Exception
+ */
+ public void testUpdateZombieThenFix()
+ throws Exception
+ {
+ // SETUP
+ ZombieCacheServiceNonLocal<String, String> zombie = new ZombieCacheServiceNonLocal<>( 10 );
+
+ // set the zombie
+ RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, zombie, listener, monitor );
+
+ String cacheName = "testUpdate";
+
+ // DO WORK
+ ICacheElement<String, String> element = new CacheElement<>( cacheName, "key", "value" );
+ remoteCache.update( element );
+ // set the new service, this should call propagate
+ remoteCache.fixCache( service );
+
+ // VERIFY
+ assertTrue( "The element should be in the serialized warapper.",
+ service.lastUpdate instanceof ICacheElementSerialized );
+ ICacheElement<String, String> result = SerializationConversionUtil
+ .getDeSerializedCacheElement( (ICacheElementSerialized<String, String>) service.lastUpdate, remoteCache
+ .getElementSerializer() );
+ assertEquals( "Wrong element updated.", element.getVal(), result.getVal() );
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testUpdate_simple()
+ throws Exception
+ {
+ RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, service, listener, monitor );
+
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ remoteCache.setCacheEventLogger( cacheEventLogger );
+
+ ICacheElement<String, String> item = new CacheElement<>( "region", "key", "value" );
+
+ // DO WORK
+ remoteCache.update( item );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testGet_simple()
+ throws Exception
+ {
+ RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, service, listener, monitor );
+
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ remoteCache.setCacheEventLogger( cacheEventLogger );
+
+ // DO WORK
+ remoteCache.get( "key" );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testGetMultiple_simple()
+ throws Exception
+ {
+ RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, service, listener, monitor );
+
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ remoteCache.setCacheEventLogger( cacheEventLogger );
+
+ // DO WORK
+ remoteCache.getMultiple( new HashSet<>() );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testRemove_simple()
+ throws Exception
+ {
+ RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, service, listener, monitor );
+
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ remoteCache.setCacheEventLogger( cacheEventLogger );
+
+ // DO WORK
+ remoteCache.remove( "key" );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testRemoveAll_simple()
+ throws Exception
+ {
+ RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, service, listener, monitor );
+
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ remoteCache.setCacheEventLogger( cacheEventLogger );
+
+ // DO WORK
+ remoteCache.remove( "key" );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testGetMatching_simple()
+ throws Exception
+ {
+ // SETUP
+ String pattern = "adsfasdfasd.?";
+
+ RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, service, listener, monitor );
+
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ remoteCache.setCacheEventLogger( cacheEventLogger );
+
+ // DO WORK
+ Map<String, ICacheElement<String, String>> result = remoteCache.getMatching( pattern );
+
+ // VERIFY
+ assertNotNull( "Should have a map", result );
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testDispose_simple()
+ throws Exception
+ {
+ RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, service, listener, monitor );
+
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ remoteCache.setCacheEventLogger( cacheEventLogger );
+
+ // DO WORK
+ remoteCache.dispose( );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+
+ /**
+ * Verify that there is no problem if there is no listener.
+ * <p>
+ * @throws Exception
+ */
+ public void testDispose_nullListener()
+ throws Exception
+ {
+ // SETUP
+ RemoteCache<String, String> remoteCache = new RemoteCache<>( cattr, service, null, monitor );
+
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ remoteCache.setCacheEventLogger( cacheEventLogger );
+
+ // DO WORK
+ remoteCache.dispose( );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/RemoteUtilsUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/RemoteUtilsUnitTest.java
new file mode 100644
index 0000000..dfec2f7
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/RemoteUtilsUnitTest.java
@@ -0,0 +1,68 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+/*
+ * 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.
+ */
+
+import java.rmi.registry.Registry;
+
+import org.apache.commons.jcs3.auxiliary.remote.RemoteLocation;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteUtils;
+
+import junit.framework.TestCase;
+
+/**
+ * Simple tests for remote utils. It is difficult to verify most of the things is does.
+ *<p>
+ * @author Aaron Smuts
+ */
+public class RemoteUtilsUnitTest
+ extends TestCase
+{
+ /**
+ * Call create registry.
+ * <p>
+ * The exception is in the security manager setting.
+ */
+ public void testCreateRegistry()
+ {
+ Registry registry = RemoteUtils.createRegistry( 1102 );
+ assertNotNull("Registry should not be null", registry);
+ }
+
+ public void testGetNamingURL()
+ {
+ assertEquals("//host:1/servicename", RemoteUtils.getNamingURL("host",1,"servicename"));
+ assertEquals("//127.0.0.1:2/servicename", RemoteUtils.getNamingURL("127.0.0.1",2,"servicename"));
+ assertEquals("//[0:0:0:0:0:0:0:1%251]:3/servicename", RemoteUtils.getNamingURL("0:0:0:0:0:0:0:1%1",3,"servicename"));
+ }
+
+ public void testParseServerAndPort()
+ {
+ RemoteLocation loc = RemoteLocation.parseServerAndPort("server1:1234");
+ assertEquals("server1", loc.getHost());
+ assertEquals(1234, loc.getPort());
+
+ loc = RemoteLocation.parseServerAndPort(" server2 : 4567 ");
+ assertEquals("server2", loc.getHost());
+ assertEquals(4567, loc.getPort());
+
+ loc = RemoteLocation.parseServerAndPort("server2 : port");
+ assertNull(loc);
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/TestRemoteCache.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/TestRemoteCache.java
new file mode 100644
index 0000000..79ba83e
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/TestRemoteCache.java
@@ -0,0 +1,145 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+import java.util.Properties;
+
+import org.apache.commons.jcs3.auxiliary.MockCacheEventLogger;
+import org.apache.commons.jcs3.engine.control.MockCompositeCacheManager;
+import org.apache.commons.jcs3.engine.control.MockElementSerializer;
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCacheManager;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteUtils;
+import org.apache.commons.jcs3.auxiliary.remote.server.RemoteCacheServerFactory;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * @author Aaron SMuts
+ */
+public class TestRemoteCache
+ extends TestCase
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( TestRemoteCache.class );
+
+ /**
+ * Start the cache.
+ */
+ public TestRemoteCache()
+ {
+ super();
+ try
+ {
+ System.out.println( "main> creating registry on the localhost" );
+ RemoteUtils.createRegistry( 1101 );
+ Properties config = RemoteUtils.loadProps("/TestRemoteServer.ccf");
+
+ RemoteCacheServerFactory.startup( "localhost", 1101, config);
+ }
+ catch ( Exception e )
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestRemoteClient.ccf" );
+ }
+
+ /**
+ * @throws Exception
+ *
+ *
+ */
+ public void skiptestSimpleSend()
+ throws Exception
+ {
+ log.info( "testSimpleSend" );
+
+ CacheAccess<String, String> cache = JCS.getInstance( "testCache" );
+
+ log.info( "cache = " + cache );
+
+ for ( int i = 0; i < 1000; i++ )
+ {
+// System.out.println( "puttting " + i );
+ cache.put( "key" + i, "data" + i );
+// System.out.println( "put " + i );
+ log.info( "put " + i );
+ }
+ }
+
+ /**
+ * @throws Exception
+ */
+ public void testService()
+ throws Exception
+ {
+
+ Thread.sleep( 100 );
+
+ ICompositeCacheManager cacheMgr = new MockCompositeCacheManager();
+
+ RemoteCacheAttributes rca = new RemoteCacheAttributes();
+ rca.setRemoteLocation( "localhost", 1101 );
+ rca.setCacheName( "testCache" );
+
+ RemoteCacheFactory factory = new RemoteCacheFactory();
+ factory.initialize();
+ RemoteCacheManager mgr = factory.getManager( rca, cacheMgr, new MockCacheEventLogger(), new MockElementSerializer() );
+ AuxiliaryCache<String, String> cache = mgr.getCache( rca );
+
+ int numMes = 100;
+ for ( int i = 0; i < numMes; i++ )
+ {
+ String message = "adsfasasfasfasdasf";
+ CacheElement<String, String> ce = new CacheElement<>( "key" + 1, "data" + i, message );
+ cache.update( ce );
+// System.out.println( "put " + ce );
+ }
+
+ // Thread.sleep( 2000 );
+
+ /*
+ * // the receiver instance. JCS cacheReceiver = JCS.getInstance(
+ * "testCache" );
+ *
+ * log.info( "cache = " + cache );
+ *
+ * for ( int i = 0; i < numMes; i++ ) { System.out.println( "getting " +
+ * i ); Object data = cacheReceiver.get( "key" + i );
+ * System.out.println( i + " = " + data ); }
+ */
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/ZombieRemoteCacheServiceUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/ZombieRemoteCacheServiceUnitTest.java
new file mode 100644
index 0000000..ead3b81
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/ZombieRemoteCacheServiceUnitTest.java
@@ -0,0 +1,128 @@
+package org.apache.commons.jcs3.auxiliary.remote;
+
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.ZombieCacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for the zombie remote cache service.
+ */
+public class ZombieRemoteCacheServiceUnitTest
+ extends TestCase
+{
+ /**
+ * Verify that an update event gets added and then is sent to the service passed to propagate.
+ * <p>
+ * @throws Exception
+ */
+ public void testUpdateThenWalk()
+ throws Exception
+ {
+ // SETUP
+ MockRemoteCacheService<String, String> service = new MockRemoteCacheService<>();
+
+ ZombieCacheServiceNonLocal<String, String> zombie = new ZombieCacheServiceNonLocal<>( 10 );
+
+ String cacheName = "testUpdate";
+
+ // DO WORK
+ ICacheElement<String, String> element = new CacheElement<>( cacheName, "key", "value" );
+ zombie.update( element, 123l );
+ zombie.propagateEvents( service );
+
+ // VERIFY
+ assertEquals( "Updated element is not as expected.", element, service.lastUpdate );
+ }
+
+ /**
+ * Verify that nothing is added if the max is set to 0.
+ * <p>
+ * @throws Exception
+ */
+ public void testUpdateThenWalk_zeroSize()
+ throws Exception
+ {
+ // SETUP
+ MockRemoteCacheService<String, String> service = new MockRemoteCacheService<>();
+
+ ZombieCacheServiceNonLocal<String, String> zombie = new ZombieCacheServiceNonLocal<>( 0 );
+
+ String cacheName = "testUpdate";
+
+ // DO WORK
+ ICacheElement<String, String> element = new CacheElement<>( cacheName, "key", "value" );
+ zombie.update( element, 123l );
+ zombie.propagateEvents( service );
+
+ // VERIFY
+ assertNull( "Nothing should have been put to the service.", service.lastUpdate );
+ }
+
+ /**
+ * Verify that a remove event gets added and then is sent to the service passed to propagate.
+ * <p>
+ * @throws Exception
+ */
+ public void testRemoveThenWalk()
+ throws Exception
+ {
+ // SETUP
+ MockRemoteCacheService<String, String> service = new MockRemoteCacheService<>();
+
+ ZombieCacheServiceNonLocal<String, String> zombie = new ZombieCacheServiceNonLocal<>( 10 );
+
+ String cacheName = "testRemoveThenWalk";
+ String key = "myKey";
+
+ // DO WORK
+ zombie.remove( cacheName, key, 123l );
+ zombie.propagateEvents( service );
+
+ // VERIFY
+ assertEquals( "Updated element is not as expected.", key, service.lastRemoveKey );
+ }
+
+ /**
+ * Verify that a removeAll event gets added and then is sent to the service passed to propagate.
+ * <p>
+ * @throws Exception
+ */
+ public void testRemoveAllThenWalk()
+ throws Exception
+ {
+ // SETUP
+ MockRemoteCacheService<String, String> service = new MockRemoteCacheService<>();
+
+ ZombieCacheServiceNonLocal<String, String> zombie = new ZombieCacheServiceNonLocal<>( 10 );
+
+ String cacheName = "testRemoveThenWalk";
+
+ // DO WORK
+ zombie.removeAll( cacheName, 123l );
+ zombie.propagateEvents( service );
+
+ // VERIFY
+ assertEquals( "Updated element is not as expected.", cacheName, service.lastRemoveAllCacheName);
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/http/client/MockRemoteCacheDispatcher.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/http/client/MockRemoteCacheDispatcher.java
new file mode 100644
index 0000000..575bd33
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/http/client/MockRemoteCacheDispatcher.java
@@ -0,0 +1,53 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.client;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheDispatcher;
+import org.apache.commons.jcs3.auxiliary.remote.value.RemoteCacheRequest;
+import org.apache.commons.jcs3.auxiliary.remote.value.RemoteCacheResponse;
+
+/** For testing the service. */
+public class MockRemoteCacheDispatcher
+ implements IRemoteCacheDispatcher
+{
+ /** The last request passes to dispatch */
+ public RemoteCacheRequest<?, ?> lastRemoteCacheRequest;
+
+ /** The response setup */
+ public RemoteCacheResponse<?> setupRemoteCacheResponse;
+
+ /** Records the last and returns setupRemoteCacheResponse.
+ * <p>
+ * @param remoteCacheRequest
+ * @return RemoteCacheResponse
+ * @throws IOException
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public <K, V, T>
+ RemoteCacheResponse<T> dispatchRequest( RemoteCacheRequest<K, V> remoteCacheRequest )
+ throws IOException
+ {
+ this.lastRemoteCacheRequest = remoteCacheRequest;
+ return (RemoteCacheResponse<T>)setupRemoteCacheResponse;
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheClientUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheClientUnitTest.java
new file mode 100644
index 0000000..b9c0ce8
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheClientUnitTest.java
@@ -0,0 +1,278 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.client;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.auxiliary.remote.http.client.RemoteHttpCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.http.client.RemoteHttpCacheClient;
+import org.apache.commons.jcs3.auxiliary.remote.value.RemoteCacheResponse;
+import org.apache.commons.jcs3.auxiliary.remote.value.RemoteRequestType;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/** Unit tests for the client. */
+public class RemoteHttpCacheClientUnitTest
+ extends TestCase
+{
+ /**
+ * Verify get functionality
+ * <p>
+ * @throws IOException
+ */
+ public void testGet_nullFromDispatcher()
+ throws IOException
+ {
+ // SETUP
+ RemoteHttpCacheAttributes attributes = new RemoteHttpCacheAttributes();
+ RemoteHttpCacheClient<String, String> client = new RemoteHttpCacheClient<>( attributes );
+
+ MockRemoteCacheDispatcher mockDispatcher = new MockRemoteCacheDispatcher();
+ client.setRemoteDispatcher( mockDispatcher );
+
+ String cacheName = "test";
+ String key = "key";
+
+ mockDispatcher.setupRemoteCacheResponse = null;
+
+ // DO WORK
+ ICacheElement<String, String> result = client.get( cacheName, key );
+
+ // VERIFY
+ assertNull( "Wrong result.", result );
+ assertEquals( "Wrong type.", RemoteRequestType.GET, mockDispatcher.lastRemoteCacheRequest
+ .getRequestType() );
+ }
+
+ /**
+ * Verify get functionality
+ * <p>
+ * @throws IOException
+ */
+ public void testGet_normal()
+ throws IOException
+ {
+ // SETUP
+ RemoteHttpCacheAttributes attributes = new RemoteHttpCacheAttributes();
+ RemoteHttpCacheClient<String, String> client = new RemoteHttpCacheClient<>( attributes );
+
+ MockRemoteCacheDispatcher mockDispatcher = new MockRemoteCacheDispatcher();
+ client.setRemoteDispatcher( mockDispatcher );
+
+ String cacheName = "test";
+ String key = "key";
+
+ ICacheElement<String, String> expected = new CacheElement<>( cacheName, key, "value" );
+ RemoteCacheResponse<ICacheElement<String, String>> remoteHttpCacheResponse =
+ new RemoteCacheResponse<>();
+ remoteHttpCacheResponse.setPayload( expected );
+
+ mockDispatcher.setupRemoteCacheResponse = remoteHttpCacheResponse;
+
+ // DO WORK
+ ICacheElement<String, String> result = client.get( cacheName, key );
+
+ // VERIFY
+ assertEquals( "Wrong result.", expected, result );
+ assertEquals( "Wrong type.", RemoteRequestType.GET, mockDispatcher.lastRemoteCacheRequest
+ .getRequestType() );
+ }
+
+ /**
+ * Verify get functionality
+ * <p>
+ * @throws IOException
+ */
+ public void testGetMatching_normal()
+ throws IOException
+ {
+ // SETUP
+ RemoteHttpCacheAttributes attributes = new RemoteHttpCacheAttributes();
+ RemoteHttpCacheClient<String, String> client = new RemoteHttpCacheClient<>( attributes );
+
+ MockRemoteCacheDispatcher mockDispatcher = new MockRemoteCacheDispatcher();
+ client.setRemoteDispatcher( mockDispatcher );
+
+ String cacheName = "test";
+ String pattern = "key";
+
+ ICacheElement<String, String> expected = new CacheElement<>( cacheName, "key", "value" );
+ Map<String, ICacheElement<String, String>> expectedMap = new HashMap<>();
+ expectedMap.put( "key", expected );
+ RemoteCacheResponse<Map<String, ICacheElement<String, String>>> remoteHttpCacheResponse =
+ new RemoteCacheResponse<>();
+ remoteHttpCacheResponse.setPayload( expectedMap );
+
+ mockDispatcher.setupRemoteCacheResponse = remoteHttpCacheResponse;
+
+ // DO WORK
+ Map<String, ICacheElement<String, String>> result = client.getMatching( cacheName, pattern );
+
+ // VERIFY
+ assertEquals( "Wrong result.", expected, result.get( "key" ) );
+ assertEquals( "Wrong type.", RemoteRequestType.GET_MATCHING,
+ mockDispatcher.lastRemoteCacheRequest.getRequestType() );
+ }
+
+ /**
+ * Verify get functionality
+ * <p>
+ * @throws IOException
+ */
+ public void testGetMultiple_normal()
+ throws IOException
+ {
+ // SETUP
+ RemoteHttpCacheAttributes attributes = new RemoteHttpCacheAttributes();
+ RemoteHttpCacheClient<String, String> client = new RemoteHttpCacheClient<>( attributes );
+
+ MockRemoteCacheDispatcher mockDispatcher = new MockRemoteCacheDispatcher();
+ client.setRemoteDispatcher( mockDispatcher );
+
+ String cacheName = "test";
+ Set<String> keys = Collections.emptySet();
+
+ ICacheElement<String, String> expected = new CacheElement<>( cacheName, "key", "value" );
+ Map<String, ICacheElement<String, String>> expectedMap = new HashMap<>();
+ expectedMap.put( "key", expected );
+ RemoteCacheResponse<Map<String, ICacheElement<String, String>>> remoteHttpCacheResponse =
+ new RemoteCacheResponse<>();
+ remoteHttpCacheResponse.setPayload( expectedMap );
+
+ mockDispatcher.setupRemoteCacheResponse = remoteHttpCacheResponse;
+
+ // DO WORK
+ Map<String, ICacheElement<String, String>> result = client.getMultiple( cacheName, keys );
+
+ // VERIFY
+ assertEquals( "Wrong result.", expected, result.get( "key" ) );
+ assertEquals( "Wrong type.", RemoteRequestType.GET_MULTIPLE,
+ mockDispatcher.lastRemoteCacheRequest.getRequestType() );
+ }
+
+ /**
+ * Verify remove functionality
+ * <p>
+ * @throws IOException
+ */
+ public void testRemove_normal()
+ throws IOException
+ {
+ // SETUP
+ RemoteHttpCacheAttributes attributes = new RemoteHttpCacheAttributes();
+ RemoteHttpCacheClient<String, String> client = new RemoteHttpCacheClient<>( attributes );
+
+ MockRemoteCacheDispatcher mockDispatcher = new MockRemoteCacheDispatcher();
+ client.setRemoteDispatcher( mockDispatcher );
+
+ String cacheName = "test";
+ String key = "key";
+
+ // DO WORK
+ client.remove( cacheName, key );
+
+ // VERIFY
+ assertEquals( "Wrong type.", RemoteRequestType.REMOVE, mockDispatcher.lastRemoteCacheRequest
+ .getRequestType() );
+ }
+
+ /**
+ * Verify removeall functionality
+ * <p>
+ * @throws IOException
+ */
+ public void testRemoveAll_normal()
+ throws IOException
+ {
+ // SETUP
+ RemoteHttpCacheAttributes attributes = new RemoteHttpCacheAttributes();
+ RemoteHttpCacheClient<String, String> client = new RemoteHttpCacheClient<>( attributes );
+
+ MockRemoteCacheDispatcher mockDispatcher = new MockRemoteCacheDispatcher();
+ client.setRemoteDispatcher( mockDispatcher );
+
+ String cacheName = "test";
+
+ // DO WORK
+ client.removeAll( cacheName );
+
+ // VERIFY
+ assertEquals( "Wrong type.", RemoteRequestType.REMOVE_ALL, mockDispatcher.lastRemoteCacheRequest
+ .getRequestType() );
+ }
+
+ /**
+ * Verify update functionality
+ * <p>
+ * @throws IOException
+ */
+ public void testUpdate_normal()
+ throws IOException
+ {
+ // SETUP
+ RemoteHttpCacheAttributes attributes = new RemoteHttpCacheAttributes();
+ RemoteHttpCacheClient<String, String> client = new RemoteHttpCacheClient<>( attributes );
+
+ MockRemoteCacheDispatcher mockDispatcher = new MockRemoteCacheDispatcher();
+ client.setRemoteDispatcher( mockDispatcher );
+
+ String cacheName = "test";
+
+ ICacheElement<String, String> element = new CacheElement<>( cacheName, "key", "value" );
+
+ // DO WORK
+ client.update( element );
+
+ // VERIFY
+ assertEquals( "Wrong type.", RemoteRequestType.UPDATE, mockDispatcher.lastRemoteCacheRequest
+ .getRequestType() );
+ }
+
+ /**
+ * Verify dispose functionality
+ * <p>
+ * @throws IOException
+ */
+ public void testDispose_normal()
+ throws IOException
+ {
+ // SETUP
+ RemoteHttpCacheAttributes attributes = new RemoteHttpCacheAttributes();
+ RemoteHttpCacheClient<String, String> client = new RemoteHttpCacheClient<>( attributes );
+
+ MockRemoteCacheDispatcher mockDispatcher = new MockRemoteCacheDispatcher();
+ client.setRemoteDispatcher( mockDispatcher );
+
+ String cacheName = "test";
+
+ // DO WORK
+ client.dispose( cacheName );
+
+ // VERIFY
+ assertEquals( "Wrong type.", RemoteRequestType.DISPOSE, mockDispatcher.lastRemoteCacheRequest
+ .getRequestType() );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheFactoryUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheFactoryUnitTest.java
new file mode 100644
index 0000000..d2c5388
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheFactoryUnitTest.java
@@ -0,0 +1,93 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.client;
+
+import org.apache.commons.jcs3.engine.control.MockCompositeCacheManager;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.remote.http.client.RemoteHttpCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.http.client.RemoteHttpCacheClient;
+import org.apache.commons.jcs3.auxiliary.remote.http.client.RemoteHttpCacheFactory;
+import org.apache.commons.jcs3.auxiliary.remote.http.client.behavior.IRemoteHttpCacheClient;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/** Unit tests for the manager. */
+public class RemoteHttpCacheFactoryUnitTest
+ extends TestCase
+{
+ /** Verify that we get the default. */
+ public void testCreateRemoteHttpCacheClient_Bad()
+ {
+ // SETUP
+ String remoteHttpClientClassName = "junk";
+ RemoteHttpCacheAttributes cattr = new RemoteHttpCacheAttributes();
+ cattr.setRemoteHttpClientClassName( remoteHttpClientClassName );
+
+ RemoteHttpCacheFactory factory = new RemoteHttpCacheFactory();
+
+ // DO WORK
+ IRemoteHttpCacheClient<String, String> result = factory.createRemoteHttpCacheClientForAttributes( cattr );
+
+ // VEIFY
+ assertNotNull( "Should have a cache.", result );
+ assertTrue( "Wrong default.", result instanceof RemoteHttpCacheClient );
+ assertTrue( "Should be initialized", ((RemoteHttpCacheClient<String, String>)result).isInitialized() );
+ }
+
+ /** Verify that we get the default. */
+ public void testCreateRemoteHttpCacheClient_default()
+ {
+ // SETUP
+ RemoteHttpCacheAttributes cattr = new RemoteHttpCacheAttributes();
+ RemoteHttpCacheFactory factory = new RemoteHttpCacheFactory();
+
+ // DO WORK
+ IRemoteHttpCacheClient<String, String> result = factory.createRemoteHttpCacheClientForAttributes( cattr );
+
+ // VEIFY
+ assertNotNull( "Should have a cache.", result );
+ assertTrue( "Wrong default.", result instanceof RemoteHttpCacheClient );
+ }
+
+ /** Verify that we get a cache no wait. */
+ public void testGetCache_normal()
+ {
+ // SETUP
+ ICompositeCacheManager cacheMgr = new MockCompositeCacheManager();
+ assertNotNull( "Should have a manager.", cacheMgr );
+ ICacheEventLogger cacheEventLogger = null;
+ IElementSerializer elementSerializer = null;
+
+ RemoteHttpCacheAttributes cattr = new RemoteHttpCacheAttributes();
+ assertNotNull( "Should have attributes.", cattr );
+ RemoteHttpCacheFactory factory = new RemoteHttpCacheFactory();
+ assertNotNull( "Should have a factory.", factory );
+
+
+ // DO WORK
+ AuxiliaryCache<String, String> result = factory.createCache(cattr, cacheMgr, cacheEventLogger, elementSerializer);
+
+ // VERIFY
+ assertNotNull( "Should have a cache.", result );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheManualTester.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheManualTester.java
new file mode 100644
index 0000000..0c3cac2
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/http/client/RemoteHttpCacheManualTester.java
@@ -0,0 +1,76 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.client;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/** Manual tester for a JCS instance configured to use the http client. */
+public class RemoteHttpCacheManualTester
+ extends TestCase
+{
+ /** number to use for the test */
+ private static int items = 100;
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestRemoteHttpCache.ccf" );
+ }
+
+ /**
+ * A unit test for JUnit
+ * @throws Exception Description of the Exception
+ */
+ public void testSimpleLoad()
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( "testCache1" );
+
+ jcs.put( "TestKey", "TestValue" );
+
+// System.out.println( jcs.getStats() );
+
+ for ( int i = 1; i <= items; i++ )
+ {
+ jcs.put( i + ":key", "data" + i );
+ }
+
+ for ( int i = items; i > 0; i-- )
+ {
+ String res = jcs.get( i + ":key" );
+ if ( res == null )
+ {
+ //assertNotNull( "[" + i + ":key] should not be null", res );
+ }
+ }
+
+ // test removal
+ jcs.remove( "300:key" );
+ assertNull( jcs.get( "TestKey" ) );
+
+// System.out.println( jcs.getStats() );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/http/server/RemoteHttpCacheServiceUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/http/server/RemoteHttpCacheServiceUnitTest.java
new file mode 100644
index 0000000..6922f56
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/http/server/RemoteHttpCacheServiceUnitTest.java
@@ -0,0 +1,183 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.server;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+import org.apache.commons.jcs3.auxiliary.MockCacheEventLogger;
+import org.apache.commons.jcs3.engine.control.MockCompositeCacheManager;
+import org.apache.commons.jcs3.auxiliary.remote.http.server.RemoteHttpCacheServerAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.http.server.RemoteHttpCacheService;
+import org.apache.commons.jcs3.engine.CacheElement;
+
+import java.util.HashSet;
+
+/** Unit tests for the service. */
+public class RemoteHttpCacheServiceUnitTest
+ extends TestCase
+{
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testUpdate_simple()
+ throws Exception
+ {
+ // SETUP
+ MockCompositeCacheManager manager = new MockCompositeCacheManager();
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+
+ RemoteHttpCacheServerAttributes rcsa = new RemoteHttpCacheServerAttributes();
+ RemoteHttpCacheService<String, String> server =
+ new RemoteHttpCacheService<>( manager, rcsa, cacheEventLogger );
+
+ String cacheName = "test";
+ String key = "key";
+ long requesterId = 2;
+ CacheElement<String, String> element = new CacheElement<>( cacheName, key, null );
+
+ // DO WORK
+ server.update( element, requesterId );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testGet_simple()
+ throws Exception
+ {
+ // SETUP
+ MockCompositeCacheManager manager = new MockCompositeCacheManager();
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+
+ RemoteHttpCacheServerAttributes rcsa = new RemoteHttpCacheServerAttributes();
+ RemoteHttpCacheService<String, String> server =
+ new RemoteHttpCacheService<>( manager, rcsa, cacheEventLogger );
+
+ // DO WORK
+ server.get( "region", "key" );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testGetMatching_simple()
+ throws Exception
+ {
+ // SETUP
+ MockCompositeCacheManager manager = new MockCompositeCacheManager();
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+
+ RemoteHttpCacheServerAttributes rcsa = new RemoteHttpCacheServerAttributes();
+ RemoteHttpCacheService<String, String> server =
+ new RemoteHttpCacheService<>( manager, rcsa, cacheEventLogger );
+
+ // DO WORK
+ server.getMatching( "region", "pattern", 0 );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testGetMultiple_simple()
+ throws Exception
+ {
+ // SETUP
+ MockCompositeCacheManager manager = new MockCompositeCacheManager();
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+
+ RemoteHttpCacheServerAttributes rcsa = new RemoteHttpCacheServerAttributes();
+ RemoteHttpCacheService<String, String> server =
+ new RemoteHttpCacheService<>( manager, rcsa, cacheEventLogger );
+
+ // DO WORK
+ server.getMultiple( "region", new HashSet<>() );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testRemove_simple()
+ throws Exception
+ {
+ // SETUP
+ MockCompositeCacheManager manager = new MockCompositeCacheManager();
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+
+ RemoteHttpCacheServerAttributes rcsa = new RemoteHttpCacheServerAttributes();
+ RemoteHttpCacheService<String, String> server =
+ new RemoteHttpCacheService<>( manager, rcsa, cacheEventLogger );
+
+ // DO WORK
+ server.remove( "region", "key" );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testRemoveAll_simple()
+ throws Exception
+ {
+ // SETUP
+ MockCompositeCacheManager manager = new MockCompositeCacheManager();
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+
+ RemoteHttpCacheServerAttributes rcsa = new RemoteHttpCacheServerAttributes();
+ RemoteHttpCacheService<String, String> server =
+ new RemoteHttpCacheService<>( manager, rcsa, cacheEventLogger );
+
+ // DO WORK
+ server.removeAll( "region" );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/http/server/RemoteHttpCacheServletUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/http/server/RemoteHttpCacheServletUnitTest.java
new file mode 100644
index 0000000..b865d69
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/http/server/RemoteHttpCacheServletUnitTest.java
@@ -0,0 +1,178 @@
+package org.apache.commons.jcs3.auxiliary.remote.http.server;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.jcs3.auxiliary.remote.MockRemoteCacheService;
+import org.apache.commons.jcs3.auxiliary.remote.http.server.RemoteHttpCacheServlet;
+import org.apache.commons.jcs3.auxiliary.remote.util.RemoteCacheRequestFactory;
+import org.apache.commons.jcs3.auxiliary.remote.value.RemoteCacheRequest;
+import org.apache.commons.jcs3.auxiliary.remote.value.RemoteCacheResponse;
+import org.apache.commons.jcs3.engine.CacheElement;
+
+/** Unit tests for the servlet. */
+public class RemoteHttpCacheServletUnitTest
+ extends TestCase
+{
+ private RemoteHttpCacheServlet servlet;
+ private MockRemoteCacheService<Serializable, Serializable> remoteHttpCacheService;
+
+ /**
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ servlet = new RemoteHttpCacheServlet();
+ servlet.init(null);
+
+ remoteHttpCacheService = new MockRemoteCacheService<>();
+ servlet.setRemoteCacheService( remoteHttpCacheService );
+ }
+
+ /**
+ * @see junit.framework.TestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception
+ {
+ servlet.destroy();
+ super.tearDown();
+ }
+
+ /** Verify that we balk and return an error. */
+ public void testProcessRequest_null()
+ {
+ RemoteCacheRequest<Serializable, Serializable> request = null;
+
+ // DO WORK
+ RemoteCacheResponse<Object> result = servlet.processRequest( request );
+
+ // VERIFY
+ assertNotNull( "Should have a result.", result );
+ assertTrue( "Should have 'The request is null' in the errorMessage", result.getErrorMessage().indexOf( "The request is null" ) != -1 );
+ assertTrue( "Should have 'The request is null' in the toString", result.toString().indexOf( "The request is null" ) != -1 );
+ }
+
+ /** Verify that the service is called. */
+ public void testProcessRequest_Get()
+ {
+ String cacheName = "test";
+ Serializable key = "key";
+ long requesterId = 2;
+ RemoteCacheRequest<Serializable, Serializable> request = RemoteCacheRequestFactory.createGetRequest( cacheName, key, requesterId );
+
+ // DO WORK
+ RemoteCacheResponse<Object> result = servlet.processRequest( request );
+
+ // VERIFY
+ assertNotNull( "Should have a result.", result );
+ assertEquals( "Wrong key.", key, remoteHttpCacheService.lastGetKey );
+ }
+
+ /** Verify that the service is called. */
+ public void testProcessRequest_GetMatching()
+ {
+ String cacheName = "test";
+ String pattern = "pattern";
+ long requesterId = 2;
+ RemoteCacheRequest<Serializable, Serializable> request = RemoteCacheRequestFactory.createGetMatchingRequest( cacheName, pattern,
+ requesterId );
+
+ // DO WORK
+ RemoteCacheResponse<Object> result = servlet.processRequest( request );
+
+ // VERIFY
+ assertNotNull( "Should have a result.", result );
+ assertEquals( "Wrong pattern.", pattern, remoteHttpCacheService.lastGetMatchingPattern );
+ }
+
+ /** Verify that the service is called. */
+ public void testProcessRequest_GetMultiple()
+ {
+ String cacheName = "test";
+ Set<Serializable> keys = Collections.emptySet();
+ long requesterId = 2;
+ RemoteCacheRequest<Serializable, Serializable> request = RemoteCacheRequestFactory.createGetMultipleRequest( cacheName, keys,
+ requesterId );
+
+ // DO WORK
+ RemoteCacheResponse<Object> result = servlet.processRequest( request );
+
+ // VERIFY
+ assertNotNull( "Should have a result.", result );
+ assertEquals( "Wrong keys.", keys, remoteHttpCacheService.lastGetMultipleKeys );
+
+ }
+
+ /** Verify that the service is called. */
+ public void testProcessRequest_Update()
+ {
+ String cacheName = "test";
+ String key = "key";
+ long requesterId = 2;
+ CacheElement<Serializable, Serializable> element = new CacheElement<>( cacheName, key, null );
+ RemoteCacheRequest<Serializable, Serializable> request = RemoteCacheRequestFactory.createUpdateRequest( element, requesterId );
+
+ // DO WORK
+ RemoteCacheResponse<Object> result = servlet.processRequest( request );
+
+ // VERIFY
+ assertNotNull( "Should have a result.", result );
+ assertEquals( "Wrong object.", element, remoteHttpCacheService.lastUpdate );
+ }
+
+ /** Verify that the service is called. */
+ public void testProcessRequest_Remove()
+ {
+ String cacheName = "test";
+ Serializable key = "key";
+ long requesterId = 2;
+ RemoteCacheRequest<Serializable, Serializable> request = RemoteCacheRequestFactory.createRemoveRequest( cacheName, key, requesterId );
+
+ // DO WORK
+ RemoteCacheResponse<Object> result = servlet.processRequest( request );
+
+ // VERIFY
+ assertNotNull( "Should have a result.", result );
+ assertEquals( "Wrong key.", key, remoteHttpCacheService.lastRemoveKey );
+ }
+
+ /** Verify that the service is called. */
+ public void testProcessRequest_RemoveAll()
+ {
+ String cacheName = "testRemoveALl";
+ long requesterId = 2;
+ RemoteCacheRequest<Serializable, Serializable> request = RemoteCacheRequestFactory.createRemoveAllRequest( cacheName, requesterId );
+
+ // DO WORK
+ RemoteCacheResponse<Object> result = servlet.processRequest( request );
+
+ // VERIFY
+ assertNotNull( "Should have a result.", result );
+ assertEquals( "Wrong cacheName.", cacheName, remoteHttpCacheService.lastRemoveAllCacheName );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/BasicRemoteCacheClientServerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/BasicRemoteCacheClientServerUnitTest.java
new file mode 100644
index 0000000..cb04b7c
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/BasicRemoteCacheClientServerUnitTest.java
@@ -0,0 +1,342 @@
+package org.apache.commons.jcs3.auxiliary.remote.server;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.util.Enumeration;
+
+import org.apache.commons.jcs3.auxiliary.MockCacheEventLogger;
+import org.apache.commons.jcs3.auxiliary.remote.MockRemoteCacheListener;
+import org.apache.commons.jcs3.engine.control.MockCompositeCacheManager;
+import org.apache.commons.jcs3.engine.control.MockElementSerializer;
+import org.apache.commons.jcs3.utils.timing.SleepUtil;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteCacheManager;
+import org.apache.commons.jcs3.auxiliary.remote.server.RemoteCacheServer;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.utils.net.HostNameUtil;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * These tests startup the remote server and make requests to it.
+ * <p>
+ *
+ * @author Aaron Smuts
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class BasicRemoteCacheClientServerUnitTest extends Assert
+{
+ private static final int LOCAL_PORT = 12020;
+
+ /**
+ * Server instance to use in the tests.
+ */
+ private static RemoteCacheServer<String, String> server = null;
+
+ /**
+ * Factory instance to use in the tests.
+ */
+ private static RemoteCacheFactory factory = null;
+
+ /**
+ * the remote server port
+ */
+ private static int remotePort;
+
+ /**
+ * Starts the server. This is not in a setup, since the server is slow to kill right now.
+ */
+ @BeforeClass
+ public static void setup()
+ {
+ // Add some debug to try and find out why test fails on Jenkins/Continuum
+ try {
+ InetAddress lh = InetAddress.getByName("localhost");
+ System.out.println("localhost="+lh);
+ InetAddress ina=InetAddress.getLocalHost();
+ System.out.println("InetAddress.getLocalHost()="+ina);
+ // Iterate all NICs (network interface cards)...
+ for ( Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); )
+ {
+ NetworkInterface iface = ifaces.nextElement();
+ // Iterate all IP addresses assigned to each card...
+ for ( Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); )
+ {
+ InetAddress inetAddr = inetAddrs.nextElement();
+ boolean loopbackAddress = inetAddr.isLoopbackAddress();
+ boolean siteLocalAddress = inetAddr.isSiteLocalAddress();
+ System.out.println("Found: "+ inetAddr +
+ " isLoopback: " + loopbackAddress +
+ " isSiteLocal: " + siteLocalAddress +
+ ((!loopbackAddress && siteLocalAddress) ? " *" : ""));
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ // end of debug
+ String configFile = "TestRemoteCacheClientServer.ccf";
+ server = RemoteCacheServerStartupUtil.startServerUsingProperties(configFile);
+ factory = new RemoteCacheFactory();
+ factory.initialize();
+ remotePort = server.remoteCacheServerAttributes.getRemoteLocation().getPort();
+ }
+
+ @AfterClass
+ public static void stop() throws IOException
+ {
+ if (server != null) { // in case setup failed, no point throwing NPE as well
+ server.shutdown("localhost", remotePort);
+ }
+ // Debug: unfortunately Surefire restarts JVM so log files get overwritten
+ // There's probably a better way to fix this ...
+ java.io.File jcsLog = new java.io.File("target/jcs.log");
+ java.io.File logSave = new java.io.File("target/BasicRemoteCacheClientServerUnitTest_jcs.log");
+ System.out.println("Renamed log file? "+jcsLog.renameTo(logSave));
+ }
+
+ /**
+ * Verify that we can start the remote cache server. Send an item to the remote. Verify that the
+ * remote put count goes up. If we go through JCS, the manager will be shared and we will get
+ * into an endless loop. We will use a mock cache manager instead.
+ * <p>
+ * The remote server uses the real JCS. We can verify that items are added to JCS behind the
+ * server by calling get. We cannot access it directly via JCS since it is serialized.
+ * <p>
+ * This test uses a mock injected client to test a normal server.
+ * <p>
+ *
+ * @throws Exception
+ */
+ @Test
+ public void test1SinglePut()
+ throws Exception
+ {
+ // SETUP
+ MockCompositeCacheManager compositeCacheManager = new MockCompositeCacheManager();
+
+ RemoteCacheAttributes attributes = new RemoteCacheAttributes();
+ attributes.setRemoteLocation("localhost", remotePort);
+ attributes.setLocalPort(LOCAL_PORT);
+ attributes.setCacheName("testSinglePut");
+
+ RemoteCacheManager remoteCacheManager = factory.getManager(attributes, compositeCacheManager, new MockCacheEventLogger(), new MockElementSerializer());
+ AuxiliaryCache<String, String> cache = remoteCacheManager.getCache(attributes);
+
+ // DO WORK
+ int numPutsPrior = server.getPutCount();
+ ICacheElement<String, String> element = new CacheElement<>(cache.getCacheName(), "key", "value");
+ cache.update(element);
+ SleepUtil.sleepAtLeast(200);
+
+ // VERIFY
+ try
+ {
+ assertEquals("Cache is alive", CacheStatus.ALIVE, cache.getStatus());
+ assertEquals("Wrong number of puts", 1, server.getPutCount() - numPutsPrior);
+ }
+ catch (junit.framework.AssertionFailedError e)
+ {
+ System.out.println(cache.getStats());
+ System.out.println(server.getStats());
+ throw e;
+ }
+
+ // DO WORK
+ ICacheElement<String, String> result = cache.get("key");
+
+ // VERIFY
+ assertEquals("Wrong element.", element.getVal(), result.getVal());
+ }
+
+ /**
+ * Verify that we can remove an item via the remote server.
+ * <p>
+ *
+ * @throws Exception
+ */
+ @Test
+ public void test2PutRemove()
+ throws Exception
+ {
+ // SETUP
+ MockCompositeCacheManager compositeCacheManager = new MockCompositeCacheManager();
+
+ RemoteCacheAttributes attributes = new RemoteCacheAttributes();
+ attributes.setRemoteLocation("localhost", remotePort);
+ attributes.setLocalPort(LOCAL_PORT);
+ attributes.setCacheName("testPutRemove");
+
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+
+ RemoteCacheManager remoteCacheManager = factory.getManager(attributes, compositeCacheManager, cacheEventLogger, null);
+ AuxiliaryCache<String, String> cache = remoteCacheManager.getCache(attributes);
+
+ // DO WORK
+ int numPutsPrior = server.getPutCount();
+ ICacheElement<String, String> element = new CacheElement<>(cache.getCacheName(), "key", "value");
+ cache.update(element);
+ SleepUtil.sleepAtLeast(50);
+
+ // VERIFY
+ try
+ {
+ assertEquals("Cache is alive", CacheStatus.ALIVE, cache.getStatus());
+ assertEquals("Wrong number of puts", 1, server.getPutCount() - numPutsPrior);
+ }
+ catch (junit.framework.AssertionFailedError e)
+ {
+ System.out.println(cache.getStats());
+ System.out.println(server.getStats());
+ throw e;
+ }
+
+ // DO WORK
+ ICacheElement<String, String> result = cache.get("key");
+
+ // VERIFY
+ assertEquals("Wrong element.", element.getVal(), result.getVal());
+
+ // DO WORK
+ cache.remove("key");
+ SleepUtil.sleepAtLeast(200);
+ ICacheElement<String, String> resultAfterRemote = cache.get("key");
+
+ // VERIFY
+ assertNull("Element resultAfterRemote should be null.", resultAfterRemote);
+ }
+
+ /**
+ * Register a listener with the server. Send an update. Verify that the listener received it.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void test3PutAndListen()
+ throws Exception
+ {
+ // SETUP
+ MockCompositeCacheManager compositeCacheManager = new MockCompositeCacheManager();
+
+ RemoteCacheAttributes attributes = new RemoteCacheAttributes();
+ attributes.setRemoteLocation("localhost", remotePort);
+ attributes.setLocalPort(LOCAL_PORT);
+ attributes.setCacheName("testPutAndListen");
+
+ RemoteCacheManager remoteCacheManager = factory.getManager(attributes, compositeCacheManager, new MockCacheEventLogger(), new MockElementSerializer());
+ AuxiliaryCache<String, String> cache = remoteCacheManager.getCache(attributes);
+
+ MockRemoteCacheListener<String, String> listener = new MockRemoteCacheListener<>();
+ server.addCacheListener(cache.getCacheName(), listener);
+
+ // DO WORK
+ int numPutsPrior = server.getPutCount();
+ ICacheElement<String, String> element = new CacheElement<>(cache.getCacheName(), "key", "value");
+ cache.update(element);
+ SleepUtil.sleepAtLeast(50);
+
+ // VERIFY
+ try
+ {
+ assertEquals("Cache is alive", CacheStatus.ALIVE, cache.getStatus());
+ assertEquals("Wrong number of puts", 1, server.getPutCount() - numPutsPrior);
+ assertEquals("Wrong number of puts to listener.", 1, listener.putCount);
+ }
+ catch (junit.framework.AssertionFailedError e)
+ {
+ System.out.println(cache.getStats());
+ System.out.println(server.getStats());
+ throw e;
+ }
+ finally
+ {
+ // remove from all regions.
+ server.removeCacheListener(listener);
+ }
+ }
+
+ /**
+ * Register a listener with the server. Send an update. Verify that the listener received it.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void test4PutaMultipleAndListen()
+ throws Exception
+ {
+ // SETUP
+ MockCompositeCacheManager compositeCacheManager = new MockCompositeCacheManager();
+
+ RemoteCacheAttributes attributes = new RemoteCacheAttributes();
+ attributes.setRemoteLocation("localhost", remotePort);
+ attributes.setLocalPort(LOCAL_PORT);
+ attributes.setCacheName("testPutaMultipleAndListen");
+
+ RemoteCacheManager remoteCacheManager = factory.getManager(attributes, compositeCacheManager, new MockCacheEventLogger(), new MockElementSerializer());
+ AuxiliaryCache<String, String> cache = remoteCacheManager.getCache(attributes);
+
+ MockRemoteCacheListener<String, String> listener = new MockRemoteCacheListener<>();
+ server.addCacheListener(cache.getCacheName(), listener);
+
+ // DO WORK
+ int numPutsPrior = server.getPutCount();
+ int numToPut = 100;
+ for (int i = 0; i < numToPut; i++)
+ {
+ ICacheElement<String, String> element = new CacheElement<>(cache.getCacheName(), "key" + 1, "value" + i);
+ cache.update(element);
+ }
+ SleepUtil.sleepAtLeast(500);
+
+ // VERIFY
+ try
+ {
+ assertEquals("Cache is alive", CacheStatus.ALIVE, cache.getStatus());
+ assertEquals("Wrong number of puts", numToPut, server.getPutCount() - numPutsPrior);
+ assertEquals("Wrong number of puts to listener.", numToPut, listener.putCount);
+ }
+ catch (junit.framework.AssertionFailedError e)
+ {
+ System.out.println(cache.getStats());
+ System.out.println(server.getStats());
+ throw e;
+ }
+ }
+
+ @Test
+ public void testLocalHost() throws Exception
+ {
+ final InetAddress byName = InetAddress.getByName("localhost");
+ assertTrue("Expected localhost (" + byName.getHostAddress() + ") to be a loopback address", byName.isLoopbackAddress());
+ final InetAddress localHost = HostNameUtil.getLocalHostLANAddress();
+ assertTrue("Expected getLocalHostLANAddress() (" + localHost + ") to return a site local address", localHost.isSiteLocalAddress());
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/MockRMISocketFactory.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/MockRMISocketFactory.java
new file mode 100644
index 0000000..e345cd4
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/MockRMISocketFactory.java
@@ -0,0 +1,88 @@
+package org.apache.commons.jcs3.auxiliary.remote.server;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.rmi.server.RMISocketFactory;
+
+/** For testing the custom socket factory configuration */
+public class MockRMISocketFactory
+ extends RMISocketFactory
+ implements Serializable
+{
+ /** Don't change */
+ private static final long serialVersionUID = 1056199478581218676L;
+
+ /** for testing automatic property configuration. */
+ private String testStringProperty;
+
+ /**
+ * @param host
+ * @param port
+ * @return Socket
+ * @throws IOException
+ */
+ @Override
+ public Socket createSocket( String host, int port )
+ throws IOException
+ {
+// System.out.println( "Creating socket" );
+
+ Socket socket = new Socket();
+ socket.setSoTimeout( 1000 );
+ socket.setSoLinger( false, 0 );
+ socket.connect( new InetSocketAddress( host, port ), 1000 );
+ return socket;
+ }
+
+ /**
+ * @param port
+ * @return ServerSocket
+ * @throws IOException
+ */
+ @Override
+ public ServerSocket createServerSocket( int port )
+ throws IOException
+ {
+// System.out.println( "Creating server socket" );
+
+ return new ServerSocket( port );
+ }
+
+ /**
+ * @param testStringProperty the testStringProperty to set
+ */
+ public void setTestStringProperty( String testStringProperty )
+ {
+ this.testStringProperty = testStringProperty;
+ }
+
+ /**
+ * @return the testStringProperty
+ */
+ public String getTestStringProperty()
+ {
+ return testStringProperty;
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/RegistryKeepAliveRunnerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/RegistryKeepAliveRunnerUnitTest.java
new file mode 100644
index 0000000..4b6aec1
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/RegistryKeepAliveRunnerUnitTest.java
@@ -0,0 +1,50 @@
+package org.apache.commons.jcs3.auxiliary.remote.server;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+import org.apache.commons.jcs3.auxiliary.MockCacheEventLogger;
+import org.apache.commons.jcs3.auxiliary.remote.server.RegistryKeepAliveRunner;
+
+/** Unit tests for the registry keep alive runner. */
+public class RegistryKeepAliveRunnerUnitTest
+ extends TestCase
+{
+ /** Verify that we get the appropriate event log */
+ public void testCheckAndRestoreIfNeeded_failure()
+ {
+ // SETUP
+ String host = "localhost";
+ int port = 1234;
+ String service = "doesn'texist";
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+
+ RegistryKeepAliveRunner runner = new RegistryKeepAliveRunner( host, port, service );
+ runner.setCacheEventLogger( cacheEventLogger );
+
+ // DO WORK
+ runner.checkAndRestoreIfNeeded();
+
+ // VERIFY
+ // 1 for the lookup, one for the rebind since the server isn't created yet
+ assertEquals( "error tally", 2, cacheEventLogger.errorEventCalls );
+ //System.out.println( cacheEventLogger.errorMessages );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServerAttributesUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServerAttributesUnitTest.java
new file mode 100644
index 0000000..1e2569b
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServerAttributesUnitTest.java
@@ -0,0 +1,66 @@
+package org.apache.commons.jcs3.auxiliary.remote.server;
+
+import org.apache.commons.jcs3.auxiliary.remote.server.RemoteCacheServerAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.server.behavior.RemoteType;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for the remote cache server attributes.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class RemoteCacheServerAttributesUnitTest
+ extends TestCase
+{
+
+ /**
+ * Verify that we get a string, even if not attributes are set.
+ */
+ public void testToString()
+ {
+ RemoteCacheServerAttributes attributes = new RemoteCacheServerAttributes();
+ assertNotNull( "Should have a string.", attributes.toString() );
+ }
+
+ /**
+ * Verify that the type is set correctly and that the correct name is returned for the type.
+ */
+ public void testSetRemoteTypeName_local()
+ {
+ RemoteCacheServerAttributes attributes = new RemoteCacheServerAttributes();
+ attributes.setRemoteTypeName( "LOCAL" );
+ assertEquals( "Wrong type.", RemoteType.LOCAL, attributes.getRemoteType() );
+ assertEquals( "Wrong name", "LOCAL", attributes.getRemoteTypeName() );
+ }
+
+ /**
+ * Verify that the type is set correctly and that the correct name is returned for the type.
+ */
+ public void testSetRemoteTypeName_cluster()
+ {
+ RemoteCacheServerAttributes attributes = new RemoteCacheServerAttributes();
+ attributes.setRemoteTypeName( "CLUSTER" );
+ assertEquals( "Wrong type.", RemoteType.CLUSTER, attributes.getRemoteType() );
+ assertEquals( "Wrong name", "CLUSTER", attributes.getRemoteTypeName() );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServerFactoryUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServerFactoryUnitTest.java
new file mode 100644
index 0000000..a5a4a0e
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServerFactoryUnitTest.java
@@ -0,0 +1,206 @@
+package org.apache.commons.jcs3.auxiliary.remote.server;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import java.rmi.server.RMISocketFactory;
+import java.util.Properties;
+
+import org.apache.commons.jcs3.auxiliary.remote.behavior.ICommonRemoteCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheConstants;
+import org.apache.commons.jcs3.auxiliary.remote.server.RemoteCacheServerAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.server.RemoteCacheServerFactory;
+import org.apache.commons.jcs3.auxiliary.remote.server.TimeoutConfigurableRMISocketFactory;
+
+/** Unit tests for the factory */
+public class RemoteCacheServerFactoryUnitTest
+ extends TestCase
+{
+ /** verify that we get the timeout value */
+ public void testConfigureRemoteCacheServerAttributes_eventQueuePoolName()
+ {
+ // SETUP
+ String eventQueuePoolName = "specialName";
+ Properties props = new Properties();
+ props.put( IRemoteCacheConstants.CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + ".EventQueuePoolName", eventQueuePoolName );
+
+ // DO WORK
+ RemoteCacheServerAttributes result = RemoteCacheServerFactory.configureRemoteCacheServerAttributes( props );
+
+ // VERIFY
+ assertEquals( "Wrong eventQueuePoolName", eventQueuePoolName, result.getEventQueuePoolName() );
+ }
+
+ /** verify that we get the timeout value */
+ public void testConfigureRemoteCacheServerAttributes_timeoutPresent()
+ {
+ // SETUP
+ int timeout = 123245;
+ Properties props = new Properties();
+ props.put( IRemoteCacheConstants.SOCKET_TIMEOUT_MILLIS, String.valueOf( timeout ) );
+
+ // DO WORK
+ RemoteCacheServerAttributes result = RemoteCacheServerFactory.configureRemoteCacheServerAttributes( props );
+
+ // VERIFY
+ assertEquals( "Wrong timeout", timeout, result.getRmiSocketFactoryTimeoutMillis() );
+ }
+
+ /** verify that we get the timeout value */
+ public void testConfigureRemoteCacheServerAttributes_timeoutNotPresent()
+ {
+ // SETUP
+ Properties props = new Properties();
+
+ // DO WORK
+ RemoteCacheServerAttributes result = RemoteCacheServerFactory.configureRemoteCacheServerAttributes( props );
+
+ // VERIFY
+ assertEquals( "Wrong timeout", ICommonRemoteCacheAttributes.DEFAULT_RMI_SOCKET_FACTORY_TIMEOUT_MILLIS, result.getRmiSocketFactoryTimeoutMillis() );
+ }
+
+ /** verify that we get the registryKeepAliveDelayMillis value */
+ public void testConfigureRemoteCacheServerAttributes_registryKeepAliveDelayMillisPresent()
+ {
+ // SETUP
+ int registryKeepAliveDelayMillis = 123245;
+ Properties props = new Properties();
+ props.put( IRemoteCacheConstants.CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + ".registryKeepAliveDelayMillis", String.valueOf( registryKeepAliveDelayMillis ) );
+
+ // DO WORK
+ RemoteCacheServerAttributes result = RemoteCacheServerFactory.configureRemoteCacheServerAttributes( props );
+
+ // VERIFY
+ assertEquals( "Wrong registryKeepAliveDelayMillis", registryKeepAliveDelayMillis, result.getRegistryKeepAliveDelayMillis() );
+ }
+
+ /** verify that we get the useRegistryKeepAlive value */
+ public void testConfigureRemoteCacheServerAttributes_useRegistryKeepAlivePresent()
+ {
+ // SETUP
+ boolean useRegistryKeepAlive = false;
+ Properties props = new Properties();
+ props.put( IRemoteCacheConstants.CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + ".useRegistryKeepAlive", String.valueOf( useRegistryKeepAlive ) );
+
+ // DO WORK
+ RemoteCacheServerAttributes result = RemoteCacheServerFactory.configureRemoteCacheServerAttributes( props );
+
+ // VERIFY
+ assertEquals( "Wrong useRegistryKeepAlive", useRegistryKeepAlive, result.isUseRegistryKeepAlive() );
+ }
+
+ /** verify that we get the startRegistry value */
+ public void testConfigureRemoteCacheServerAttributes_startRegistryPresent()
+ {
+ // SETUP
+ boolean startRegistry = false;
+ Properties props = new Properties();
+ props.put( IRemoteCacheConstants.CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + ".startRegistry", String.valueOf( startRegistry ) );
+
+ // DO WORK
+ RemoteCacheServerAttributes result = RemoteCacheServerFactory.configureRemoteCacheServerAttributes( props );
+
+ // VERIFY
+ assertEquals( "Wrong startRegistry", startRegistry, result.isStartRegistry() );
+ }
+
+ /** verify that we get the registryKeepAliveDelayMillis value */
+ public void testConfigureRemoteCacheServerAttributes_rmiSocketFactoryTimeoutMillisPresent()
+ {
+ // SETUP
+ int rmiSocketFactoryTimeoutMillis = 123245;
+ Properties props = new Properties();
+ props.put( IRemoteCacheConstants.CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + ".rmiSocketFactoryTimeoutMillis", String.valueOf( rmiSocketFactoryTimeoutMillis ) );
+
+ // DO WORK
+ RemoteCacheServerAttributes result = RemoteCacheServerFactory.configureRemoteCacheServerAttributes( props );
+
+ // VERIFY
+ assertEquals( "Wrong rmiSocketFactoryTimeoutMillis", rmiSocketFactoryTimeoutMillis, result.getRmiSocketFactoryTimeoutMillis() );
+ }
+
+ /** verify that we get the startRegistry value */
+ public void testConfigureRemoteCacheServerAttributes_allowClusterGetPresent()
+ {
+ // SETUP
+ boolean allowClusterGet = false;
+ Properties props = new Properties();
+ props.put( IRemoteCacheConstants.CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + ".allowClusterGet", String.valueOf( allowClusterGet ) );
+
+ // DO WORK
+ RemoteCacheServerAttributes result = RemoteCacheServerFactory.configureRemoteCacheServerAttributes( props );
+
+ // VERIFY
+ assertEquals( "Wrong allowClusterGet", allowClusterGet, result.isAllowClusterGet() );
+ }
+
+ /** verify that we get the startRegistry value */
+ public void testConfigureRemoteCacheServerAttributes_localClusterConsistencyPresent()
+ {
+ // SETUP
+ boolean localClusterConsistency = false;
+ Properties props = new Properties();
+ props.put( IRemoteCacheConstants.CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + ".localClusterConsistency", String.valueOf( localClusterConsistency ) );
+
+ // DO WORK
+ RemoteCacheServerAttributes result = RemoteCacheServerFactory.configureRemoteCacheServerAttributes( props );
+
+ // VERIFY
+ assertEquals( "Wrong localClusterConsistency", localClusterConsistency, result.isLocalClusterConsistency() );
+ }
+
+ /** verify that we get the timeout value */
+ public void testConfigureObjectSpecificCustomFactory_withProperty()
+ {
+ // SETUP
+ String testValue = "123245";
+ Properties props = new Properties();
+ props.put( IRemoteCacheConstants.CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX, MockRMISocketFactory.class.getName() );
+ props.put( IRemoteCacheConstants.CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX + ".testStringProperty", testValue );
+
+ // DO WORK
+ RMISocketFactory result = RemoteCacheServerFactory.configureObjectSpecificCustomFactory( props );
+
+ // VERIFY
+ assertNotNull( "Should have a custom socket factory.", result );
+ assertEquals( "Wrong testValue", testValue, ((MockRMISocketFactory)result).getTestStringProperty() );
+ }
+
+ /** verify that we get the timeout value */
+ public void testConfigureObjectSpecificCustomFactory_withProperty_TimeoutConfigurableRMIScoketFactory()
+ {
+ // SETUP
+ int readTimeout = 1234;
+ int openTimeout = 1234;
+ Properties props = new Properties();
+ props.put( IRemoteCacheConstants.CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX, TimeoutConfigurableRMISocketFactory.class.getName() );
+ props.put( IRemoteCacheConstants.CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX + ".readTimeout", String.valueOf( readTimeout ) );
+ props.put( IRemoteCacheConstants.CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX + ".openTimeout", String.valueOf( openTimeout ) );
+
+ // DO WORK
+ RMISocketFactory result = RemoteCacheServerFactory.configureObjectSpecificCustomFactory( props );
+
+ // VERIFY
+ assertNotNull( "Should have a custom socket factory.", result );
+ assertEquals( "Wrong readTimeout", readTimeout, ((TimeoutConfigurableRMISocketFactory)result).getReadTimeout() );
+ assertEquals( "Wrong readTimeout", openTimeout, ((TimeoutConfigurableRMISocketFactory)result).getOpenTimeout() );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServerStartupUtil.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServerStartupUtil.java
new file mode 100644
index 0000000..ba42cb1
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServerStartupUtil.java
@@ -0,0 +1,114 @@
+package org.apache.commons.jcs3.auxiliary.remote.server;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.util.Properties;
+
+import org.apache.commons.jcs3.auxiliary.remote.RemoteUtils;
+import org.apache.commons.jcs3.auxiliary.remote.server.RemoteCacheServer;
+import org.apache.commons.jcs3.auxiliary.remote.server.RemoteCacheServerFactory;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.net.HostNameUtil;
+
+/**
+ *Starts the registry and runs the server via the factory.
+ *<p>
+ * @author Aaron Smuts
+ */
+public class RemoteCacheServerStartupUtil
+{
+ /** The logger */
+ private static final Log log = LogManager.getLog( RemoteCacheServerStartupUtil.class );
+
+ /** Registry to use in the test. */
+ private static final int DEFAULT_REGISTRY_PORT = 1101;
+
+ /**
+ * Starts the registry on port "registry.port"
+ * <p>
+ * @param propsFileName
+ * @return RemoteCacheServer
+ */
+ public static <K, V> RemoteCacheServer<K, V> startServerUsingProperties( String propsFileName )
+ {
+ // TODO load from props file or get as init param or get from jndi, or
+ // all three
+ int registryPort = DEFAULT_REGISTRY_PORT;
+
+ Properties props = null;
+ try
+ {
+ props = RemoteUtils.loadProps(propsFileName);
+ }
+ catch (IOException e)
+ {
+ log.error( "Problem loading configuration from " + propsFileName, e);
+ }
+
+ if ( props != null )
+ {
+ String portS = props.getProperty( "registry.port", String.valueOf( DEFAULT_REGISTRY_PORT ) );
+
+ try
+ {
+ registryPort = Integer.parseInt( portS );
+ }
+ catch ( NumberFormatException e )
+ {
+ log.error( "Problem converting port to an int.", e );
+ }
+ }
+
+ // we will always use the local machine for the registry
+ try
+ {
+ String registryHost = HostNameUtil.getLocalHostAddress();
+
+ if ( log.isDebugEnabled() )
+ {
+ log.debug( "registryHost = [" + registryHost + "]" );
+ }
+
+ if ( "localhost".equals( registryHost ) || "127.0.0.1".equals( registryHost ) )
+ {
+ log.warn( "The local address [" + registryHost
+ + "] is INVALID. Other machines must be able to use the address to reach this server." );
+ }
+
+ try
+ {
+ RemoteCacheServerFactory.startup( registryHost, registryPort, props );
+ }
+ catch ( IOException e )
+ {
+ log.error( "Problem starting remote cache server.", e );
+ }
+ }
+ catch ( UnknownHostException e )
+ {
+ log.error( "Could not get local address to use for the registry!", e );
+ }
+
+ return RemoteCacheServerFactory.getRemoteCacheServer();
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServerUnitTest.java
new file mode 100644
index 0000000..ca8ed9f
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/RemoteCacheServerUnitTest.java
@@ -0,0 +1,467 @@
+package org.apache.commons.jcs3.auxiliary.remote.server;
+
+/*
+ * 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.
+ */
+
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.commons.jcs3.auxiliary.MockCacheEventLogger;
+import org.apache.commons.jcs3.auxiliary.remote.MockRemoteCacheListener;
+import org.apache.commons.jcs3.utils.timing.SleepUtil;
+import org.apache.commons.jcs3.auxiliary.remote.RemoteUtils;
+import org.apache.commons.jcs3.auxiliary.remote.server.RemoteCacheServer;
+import org.apache.commons.jcs3.auxiliary.remote.server.RemoteCacheServerAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.server.behavior.IRemoteCacheServerAttributes;
+import org.apache.commons.jcs3.auxiliary.remote.server.behavior.RemoteType;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+import junit.framework.TestCase;
+
+/**
+ * Since the server does not know that it is a server, it is easy to unit test. The factory does all
+ * the rmi work.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class RemoteCacheServerUnitTest
+ extends TestCase
+{
+ private static final String expectedIp1 = "adfasdf";
+ private static final String expectedIp2 = "adsfadsafaf";
+
+ private RemoteCacheServer<String, String> server;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ IRemoteCacheServerAttributes rcsa = new RemoteCacheServerAttributes();
+ rcsa.setConfigFileName( "/TestRemoteCacheServer.ccf" );
+ Properties config = RemoteUtils.loadProps(rcsa.getConfigFileName());
+ this.server = new RemoteCacheServer<>( rcsa, config );
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ this.server.shutdown();
+
+ super.tearDown();
+ }
+
+ /**
+ * Add a listener. Pass the id of 0, verify that the server sets a new listener id. Do another
+ * and verify that the second gets an id of 2.
+ * <p>
+ * @throws Exception
+ */
+ public void testAddListenerToCache_LOCALtype()
+ throws Exception
+ {
+ MockRemoteCacheListener<String, String> mockListener1 = new MockRemoteCacheListener<>();
+ mockListener1.remoteType = RemoteType.LOCAL;
+ mockListener1.localAddress = expectedIp1;
+ MockRemoteCacheListener<String, String> mockListener2 = new MockRemoteCacheListener<>();
+ mockListener1.remoteType = RemoteType.LOCAL;
+ mockListener2.localAddress = expectedIp2;
+
+ String cacheName = "testAddListener";
+
+ // DO WORK
+ server.addCacheListener( cacheName, mockListener1 );
+ server.addCacheListener( cacheName, mockListener2 );
+
+ // VERIFY
+ assertEquals( "Wrong listener id.", 1, mockListener1.getListenerId() );
+ assertEquals( "Wrong listener id.", 2, mockListener2.getListenerId() );
+ assertEquals( "Wrong ip.", expectedIp1, server.getExtraInfoForRequesterId( 1 ) );
+ assertEquals( "Wrong ip.", expectedIp2, server.getExtraInfoForRequesterId( 2 ) );
+ }
+
+ /**
+ * Add a listener. Pass the id of 0, verify that the server sets a new listener id. Do another
+ * and verify that the second gets an id of 2.
+ * <p>
+ * @throws Exception
+ */
+ public void testAddListenerToCache_CLUSTERtype()
+ throws Exception
+ {
+ MockRemoteCacheListener<String, String> mockListener1 = new MockRemoteCacheListener<>();
+ mockListener1.remoteType = RemoteType.CLUSTER;
+ mockListener1.localAddress = expectedIp1;
+ MockRemoteCacheListener<String, String> mockListener2 = new MockRemoteCacheListener<>();
+ mockListener1.remoteType = RemoteType.CLUSTER;
+ mockListener2.localAddress = expectedIp2;
+
+ String cacheName = "testAddListener";
+
+ // DO WORK
+ server.addCacheListener( cacheName, mockListener1 );
+ server.addCacheListener( cacheName, mockListener2 );
+
+ // VERIFY
+ assertEquals( "Wrong listener id.", 1, mockListener1.getListenerId() );
+ assertEquals( "Wrong listener id.", 2, mockListener2.getListenerId() );
+ assertEquals( "Wrong ip.", expectedIp1, server.getExtraInfoForRequesterId( 1 ) );
+ assertEquals( "Wrong ip.", expectedIp2, server.getExtraInfoForRequesterId( 2 ) );
+ }
+
+ // TODO: This test only works if preconfigured remote caches exist. Need to fix.
+// /**
+// * Add a listener. Pass the id of 0, verify that the server sets a new listener id. Do another
+// * and verify that the second gets an id of 2.
+// * <p>
+// * @throws Exception
+// */
+// public void testAddListener_ToAll()
+// throws Exception
+// {
+// MockRemoteCacheListener<String, String> mockListener1 = new MockRemoteCacheListener<>();
+// mockListener1.localAddress = expectedIp1;
+// MockRemoteCacheListener<String, String> mockListener2 = new MockRemoteCacheListener<>();
+// mockListener2.localAddress = expectedIp2;
+//
+// // DO WORK
+// // don't specify the cache name
+// server.addCacheListener( mockListener1 );
+// server.addCacheListener( mockListener2 );
+//
+// // VERIFY
+// assertEquals( "Wrong listener id.", 1, mockListener1.getListenerId() );
+// assertEquals( "Wrong listener id.", 2, mockListener2.getListenerId() );
+// assertEquals( "Wrong ip.", expectedIp1, server.getExtraInfoForRequesterId( 1 ) );
+// assertEquals( "Wrong ip.", expectedIp2, server.getExtraInfoForRequesterId( 2 ) );
+// }
+
+ /**
+ * Add a listener. Pass the id of 0, verify that the server sets a new listener id. Do another
+ * and verify that the second gets an id of 2. Call remove Listener and verify that it is
+ * removed.
+ * <p>
+ * @throws Exception
+ */
+ public void testAddListener_ToAllThenRemove()
+ throws Exception
+ {
+ MockRemoteCacheListener<String, String> mockListener1 = new MockRemoteCacheListener<>();
+ MockRemoteCacheListener<String, String> mockListener2 = new MockRemoteCacheListener<>();
+
+ String cacheName = "testAddListenerToAllThenRemove";
+
+ // DO WORK
+ server.addCacheListener( cacheName, mockListener1 );
+ server.addCacheListener( cacheName, mockListener2 );
+
+ // VERIFY
+ assertEquals( "Wrong number of listeners.", 2, server.getCacheListeners( cacheName ).eventQMap.size() );
+ assertEquals( "Wrong listener id.", 1, mockListener1.getListenerId() );
+ assertEquals( "Wrong listener id.", 2, mockListener2.getListenerId() );
+
+ // DO WORK
+ server.removeCacheListener( cacheName, mockListener1.getListenerId() );
+ assertEquals( "Wrong number of listeners.", 1, server.getCacheListeners( cacheName ).eventQMap.size() );
+ }
+
+ /**
+ * Add a listener. Pass the id of 0, verify that the server sets a new listener id. Do another
+ * and verify that the second gets an id of 2. Call remove Listener and verify that it is
+ * removed.
+ * <p>
+ * @throws Exception
+ */
+ public void testAddListener_ToAllThenRemove_clusterType()
+ throws Exception
+ {
+ MockRemoteCacheListener<String, String> mockListener1 = new MockRemoteCacheListener<>();
+ mockListener1.remoteType = RemoteType.CLUSTER;
+ MockRemoteCacheListener<String, String> mockListener2 = new MockRemoteCacheListener<>();
+ mockListener2.remoteType = RemoteType.CLUSTER;
+
+ String cacheName = "testAddListenerToAllThenRemove";
+
+ // DO WORK
+ server.addCacheListener( cacheName, mockListener1 );
+ server.addCacheListener( cacheName, mockListener2 );
+
+ // VERIFY
+ assertEquals( "Wrong number of listeners.", 0, server.getCacheListeners( cacheName ).eventQMap.size() );
+ assertEquals( "Wrong number of listeners.", 2, server.getClusterListeners( cacheName ).eventQMap.size() );
+ assertEquals( "Wrong listener id.", 1, mockListener1.getListenerId() );
+ assertEquals( "Wrong listener id.", 2, mockListener2.getListenerId() );
+
+ // DO WORK
+ server.removeCacheListener( cacheName, mockListener1.getListenerId() );
+ assertEquals( "Wrong number of listeners.", 1, server.getClusterListeners( cacheName ).eventQMap.size() );
+ assertNull( "Should be no entry in the ip map.", server.getExtraInfoForRequesterId( 1 ) );
+ }
+
+ /**
+ * Register a listener and then verify that it is called when we put using a different listener
+ * id.
+ * @throws Exception
+ */
+ public void testSimpleRegisterListenerAndPut()
+ throws Exception
+ {
+ IRemoteCacheServerAttributes rcsa = new RemoteCacheServerAttributes();
+ rcsa.setConfigFileName( "/TestRemoteCacheServer.ccf" );
+
+ Properties config = RemoteUtils.loadProps(rcsa.getConfigFileName());
+ MockRemoteCacheListener<String, Long> mockListener = new MockRemoteCacheListener<>();
+ RemoteCacheServer<String, Long> server = new RemoteCacheServer<>( rcsa, config );
+
+ String cacheName = "testSimpleRegisterListenerAndPut";
+ server.addCacheListener( cacheName, mockListener );
+
+ // DO WORK
+ List<ICacheElement<String, Long>> inputItems = new LinkedList<>();
+ int numToPut = 10;
+
+ for ( int i = 0; i < numToPut; i++ )
+ {
+ ICacheElement<String, Long> element = new CacheElement<>( cacheName, String.valueOf( i ), Long.valueOf( i ) );
+ inputItems.add( element );
+ server.update( element, 9999 );
+ }
+
+ Thread.sleep( 100 );
+ Thread.yield();
+ Thread.sleep( 100 );
+
+ // VERIFY
+ assertEquals( "Wrong number of items put to listener.", numToPut, mockListener.putItems.size() );
+ for ( int i = 0; i < numToPut; i++ )
+ {
+ assertEquals( "Wrong item.", inputItems.get( i ), mockListener.putItems.get( i ) );
+ }
+
+ server.shutdown();
+ }
+
+ /**
+ * Register a listener and then verify that it is called when we put using a different listener
+ * id. The updates should come from a cluster listener and local cluster consistency should be
+ * true.
+ * <p>
+ * @throws Exception
+ */
+ public void testSimpleRegisterListenerAndPut_FromClusterWithLCC()
+ throws Exception
+ {
+ // SETUP
+ IRemoteCacheServerAttributes rcsa = new RemoteCacheServerAttributes();
+ rcsa.setLocalClusterConsistency( true );
+ rcsa.setConfigFileName( "/TestRemoteCacheServer.ccf" );
+ Properties config = RemoteUtils.loadProps(rcsa.getConfigFileName());
+ RemoteCacheServer<String, Long> server = new RemoteCacheServer<>( rcsa, config );
+
+ // this is to get the listener id for inserts.
+ MockRemoteCacheListener<String, Long> clusterListener = new MockRemoteCacheListener<>();
+ clusterListener.remoteType = RemoteType.CLUSTER;
+
+ // this should get the updates
+ MockRemoteCacheListener<String, Long> localListener = new MockRemoteCacheListener<>();
+ localListener.remoteType = RemoteType.LOCAL;
+
+ String cacheName = "testSimpleRegisterListenerAndPut_FromClusterWithLCC";
+ server.addCacheListener( cacheName, clusterListener );
+ server.addCacheListener( cacheName, localListener );
+
+ // DO WORK
+ List<ICacheElement<String, Long>> inputItems = new LinkedList<>();
+ int numToPut = 10;
+
+ for ( int i = 0; i < numToPut; i++ )
+ {
+ ICacheElement<String, Long> element = new CacheElement<>( cacheName, String.valueOf( i ), Long.valueOf( i ) );
+ inputItems.add( element );
+ // update using the cluster listener id
+ server.update( element, clusterListener.getListenerId() );
+ }
+
+ SleepUtil.sleepAtLeast( 200 );
+ Thread.yield();
+ SleepUtil.sleepAtLeast( 200 );
+
+ // VERIFY
+ assertEquals( "Wrong number of items put to listener.", numToPut, localListener.putItems.size() );
+ for ( int i = 0; i < numToPut; i++ )
+ {
+ assertEquals( "Wrong item.", inputItems.get( i ), localListener.putItems.get( i ) );
+ }
+
+ server.shutdown();
+ }
+
+ /**
+ * Register a listener and then verify that it is called when we put using a different listener
+ * id.
+ * @throws Exception
+ */
+ public void testSimpleRegisterListenerAndRemove()
+ throws Exception
+ {
+ MockRemoteCacheListener<String, String> mockListener = new MockRemoteCacheListener<>();
+
+ String cacheName = "testSimpleRegisterListenerAndPut";
+ server.addCacheListener( cacheName, mockListener );
+
+ // DO WORK
+ int numToPut = 10;
+
+ for ( int i = 0; i < numToPut; i++ )
+ {
+ // use a junk listener id
+ server.remove( cacheName, String.valueOf( i ), 9999 );
+ }
+
+ Thread.sleep( 100 );
+ Thread.yield();
+ Thread.sleep( 100 );
+
+ // VERIFY
+ assertEquals( "Wrong number of items removed from listener.", numToPut, mockListener.removedKeys.size() );
+ for ( int i = 0; i < numToPut; i++ )
+ {
+ assertEquals( "Wrong key.", String.valueOf( i ), mockListener.removedKeys.get( i ) );
+ }
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testUpdate_simple()
+ throws Exception
+ {
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ server.setCacheEventLogger( cacheEventLogger );
+
+ ICacheElement<String, String> item = new CacheElement<>( "region", "key", "value" );
+
+ // DO WORK
+ server.update( item );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testGet_simple()
+ throws Exception
+ {
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ server.setCacheEventLogger( cacheEventLogger );
+
+ // DO WORK
+ server.get( "region", "key" );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testGetMatching_simple()
+ throws Exception
+ {
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ server.setCacheEventLogger( cacheEventLogger );
+
+ // DO WORK
+ server.getMatching( "region", "pattern", 0 );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testGetMultiple_simple()
+ throws Exception
+ {
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ server.setCacheEventLogger( cacheEventLogger );
+
+ // DO WORK
+ server.getMultiple( "region", new HashSet<>() );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testRemove_simple()
+ throws Exception
+ {
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ server.setCacheEventLogger( cacheEventLogger );
+
+ // DO WORK
+ server.remove( "region", "key" );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+
+ /**
+ * Verify event log calls.
+ * <p>
+ * @throws Exception
+ */
+ public void testRemoveAll_simple()
+ throws Exception
+ {
+ MockCacheEventLogger cacheEventLogger = new MockCacheEventLogger();
+ server.setCacheEventLogger( cacheEventLogger );
+
+ // DO WORK
+ server.removeAll( "region" );
+
+ // VERIFY
+ assertEquals( "Start should have been called.", 1, cacheEventLogger.startICacheEventCalls );
+ assertEquals( "End should have been called.", 1, cacheEventLogger.endICacheEventCalls );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/TimeoutConfigurableRMISocketFactoryUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/TimeoutConfigurableRMISocketFactoryUnitTest.java
new file mode 100644
index 0000000..4e91feb
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/server/TimeoutConfigurableRMISocketFactoryUnitTest.java
@@ -0,0 +1,55 @@
+package org.apache.commons.jcs3.auxiliary.remote.server;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+import org.apache.commons.jcs3.auxiliary.remote.server.TimeoutConfigurableRMISocketFactory;
+
+/** Unit tests for the custom factory */
+public class TimeoutConfigurableRMISocketFactoryUnitTest
+ extends TestCase
+{
+ /**
+ * Simple test to see that we can create a server socket and connect.
+ * <p>
+ * @throws IOException
+ */
+ public void testCreateAndConnect() throws IOException
+ {
+ // SETUP
+ int port = 3455;
+ String host = "localhost";
+ TimeoutConfigurableRMISocketFactory factory = new TimeoutConfigurableRMISocketFactory();
+
+ // DO WORK
+ ServerSocket serverSocket = factory.createServerSocket( port );
+ Socket socket = factory.createSocket( host, port );
+ socket.close();
+ serverSocket.close();
+
+ // VERIFY
+ // passive, no errors
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/util/RemoteCacheRequestFactoryUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/util/RemoteCacheRequestFactoryUnitTest.java
new file mode 100644
index 0000000..3fac53d
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/auxiliary/remote/util/RemoteCacheRequestFactoryUnitTest.java
@@ -0,0 +1,146 @@
+package org.apache.commons.jcs3.auxiliary.remote.util;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Set;
+
+import org.apache.commons.jcs3.auxiliary.remote.util.RemoteCacheRequestFactory;
+import org.apache.commons.jcs3.auxiliary.remote.value.RemoteCacheRequest;
+import org.apache.commons.jcs3.auxiliary.remote.value.RemoteRequestType;
+import org.apache.commons.jcs3.engine.CacheElement;
+
+/** Unit tests for the request creator. */
+public class RemoteCacheRequestFactoryUnitTest
+ extends TestCase
+{
+ /** Simple test */
+ public void testCreateGetRequest_Normal()
+ {
+ // SETUP
+ String cacheName = "test";
+ Serializable key = "key";
+ long requesterId = 2;
+
+ // DO WORK
+ RemoteCacheRequest<Serializable, Serializable> result =
+ RemoteCacheRequestFactory.createGetRequest( cacheName, key, requesterId );
+
+ // VERIFY
+ assertNotNull( "Should have a result", result );
+ assertEquals( "Wrong cacheName", cacheName, result.getCacheName() );
+ assertEquals( "Wrong type", RemoteRequestType.GET, result.getRequestType() );
+ }
+
+ /** Simple test */
+ public void testCreateGetMatchingRequest_Normal()
+ {
+ // SETUP
+ String cacheName = "test";
+ String pattern = "pattern";
+ long requesterId = 2;
+
+ // DO WORK
+ RemoteCacheRequest<Serializable, Serializable> result =
+ RemoteCacheRequestFactory.createGetMatchingRequest( cacheName, pattern, requesterId );
+
+ // VERIFY
+ assertNotNull( "Should have a result", result );
+ assertEquals( "Wrong cacheName", cacheName, result.getCacheName() );
+ assertEquals( "Wrong type", RemoteRequestType.GET_MATCHING, result.getRequestType() );
+ }
+
+ /** Simple test */
+ public void testCreateGetMultipleRequest_Normal()
+ {
+ // SETUP
+ String cacheName = "test";
+ Set<Serializable> keys = Collections.emptySet();
+ long requesterId = 2;
+
+ // DO WORK
+ RemoteCacheRequest<Serializable, Serializable> result =
+ RemoteCacheRequestFactory.createGetMultipleRequest( cacheName, keys, requesterId );
+
+ // VERIFY
+ assertNotNull( "Should have a result", result );
+ assertEquals( "Wrong cacheName", cacheName, result.getCacheName() );
+ assertEquals( "Wrong type", RemoteRequestType.GET_MULTIPLE, result.getRequestType() );
+ }
+
+ /** Simple test */
+ public void testCreateRemoveRequest_Normal()
+ {
+ // SETUP
+ String cacheName = "test";
+ Serializable key = "key";
+ long requesterId = 2;
+
+ // DO WORK
+ RemoteCacheRequest<Serializable, Serializable> result = RemoteCacheRequestFactory
+ .createRemoveRequest( cacheName, key, requesterId );
+
+ // VERIFY
+ assertNotNull( "Should have a result", result );
+ assertEquals( "Wrong cacheName", cacheName, result.getCacheName() );
+ assertEquals( "Wrong type", RemoteRequestType.REMOVE, result.getRequestType() );
+ }
+
+ /** Simple test */
+ public void testCreateRemoveAllRequest_Normal()
+ {
+ // SETUP
+ String cacheName = "test";
+ long requesterId = 2;
+
+ // DO WORK
+ RemoteCacheRequest<Serializable, Serializable> result =
+ RemoteCacheRequestFactory.createRemoveAllRequest( cacheName, requesterId );
+
+ // VERIFY
+ assertNotNull( "Should have a result", result );
+ assertEquals( "Wrong cacheName", cacheName, result.getCacheName() );
+ assertEquals( "Wrong type", RemoteRequestType.REMOVE_ALL, result.getRequestType() );
+ }
+
+ /** Simple test */
+ public void testCreateUpdateRequest_Normal()
+ {
+ // SETUP
+ String cacheName = "test";
+ Serializable key = "key";
+ long requesterId = 2;
+
+ CacheElement<Serializable, Serializable> element =
+ new CacheElement<>( cacheName, key, null );
+
+ // DO WORK
+ RemoteCacheRequest<Serializable, Serializable> result =
+ RemoteCacheRequestFactory.createUpdateRequest( element, requesterId );
+
+ // VERIFY
+ assertNotNull( "Should have a result", result );
+ assertEquals( "Wrong cacheName", cacheName, result.getCacheName() );
+ assertEquals( "Wrong type", RemoteRequestType.UPDATE, result.getRequestType() );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/CacheEventQueueFactoryUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/CacheEventQueueFactoryUnitTest.java
new file mode 100644
index 0000000..23dec3e
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/CacheEventQueueFactoryUnitTest.java
@@ -0,0 +1,69 @@
+package org.apache.commons.jcs3.engine;
+
+import org.apache.commons.jcs3.auxiliary.remote.MockRemoteCacheListener;
+import org.apache.commons.jcs3.engine.CacheEventQueueFactory;
+import org.apache.commons.jcs3.engine.behavior.ICacheEventQueue;
+import org.apache.commons.jcs3.engine.behavior.ICacheListener;
+import org.apache.commons.jcs3.engine.behavior.ICacheEventQueue.QueueType;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/** Unit tests for the CacheEventQueueFactory */
+public class CacheEventQueueFactoryUnitTest
+ extends TestCase
+{
+ /** Test create */
+ public void testCreateCacheEventQueue_Single()
+ {
+ // SETUP
+ QueueType eventQueueType = QueueType.SINGLE;
+ ICacheListener<String, String> listener = new MockRemoteCacheListener<>();
+ long listenerId = 1;
+
+ CacheEventQueueFactory<String, String> factory = new CacheEventQueueFactory<>();
+
+ // DO WORK
+ ICacheEventQueue<String, String> result = factory.createCacheEventQueue( listener, listenerId, "cacheName", "threadPoolName", eventQueueType );
+
+ // VERIFY
+ assertNotNull( "Should have a result", result );
+ assertTrue( "Wrong type", result.getQueueType() == QueueType.SINGLE );
+ }
+
+ /** Test create */
+ public void testCreateCacheEventQueue_Pooled()
+ {
+ // SETUP
+ QueueType eventQueueType = QueueType.POOLED;
+ ICacheListener<String, String> listener = new MockRemoteCacheListener<>();
+ long listenerId = 1;
+
+ CacheEventQueueFactory<String, String> factory = new CacheEventQueueFactory<>();
+
+ // DO WORK
+ ICacheEventQueue<String, String> result = factory.createCacheEventQueue( listener, listenerId, "cacheName", "threadPoolName", eventQueueType );
+
+ // VERIFY
+ assertNotNull( "Should have a result", result );
+ assertTrue( "Wrong type", result.getQueueType() == QueueType.POOLED );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/ElementAttributesUtils.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/ElementAttributesUtils.java
new file mode 100644
index 0000000..82743ba
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/ElementAttributesUtils.java
@@ -0,0 +1,49 @@
+/*
+ * 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.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.engine.ElementAttributes;
+
+/**
+ * Allow test access to set last access time without exposing public method
+ */
+public class ElementAttributesUtils {
+ public static void setLastAccessTime(ElementAttributes ea, long time) {
+ ea.setLastAccessTime(time);
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/EventQueueConcurrentLoadTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/EventQueueConcurrentLoadTest.java
new file mode 100644
index 0000000..f219f89
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/EventQueueConcurrentLoadTest.java
@@ -0,0 +1,360 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.CacheEventQueue;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheListener;
+
+import junit.extensions.ActiveTestSuite;
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+/**
+ * This test case is designed to makes sure there are no deadlocks in the event queue. The time to
+ * live should be set to a very short interval to make a deadlock more likely.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class EventQueueConcurrentLoadTest
+ extends TestCase
+{
+ /** The queue implementation */
+ private static CacheEventQueue<String, String> queue = null;
+
+ /** The mock listener */
+ private static CacheListenerImpl<String, String> listen = null;
+
+ /** max failure setting */
+ private final int maxFailure = 3;
+
+ /** time to wait before retrying on failure. */
+ private final int waitBeforeRetry = 100;
+
+ /** very small idle time */
+ private final int idleTime = 2;
+
+ /**
+ * Constructor for the TestDiskCache object.
+ * @param testName
+ */
+ public EventQueueConcurrentLoadTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * Main method passes this test to the text test runner.
+ * @param args
+ */
+ public static void main( String args[] )
+ {
+ String[] testCaseName = { EventQueueConcurrentLoadTest.class.getName() };
+ junit.textui.TestRunner.main( testCaseName );
+ }
+
+ /**
+ * A unit test suite for JUnit
+ * @return The test suite
+ */
+ public static Test suite()
+ {
+ ActiveTestSuite suite = new ActiveTestSuite();
+
+ suite.addTest( new EventQueueConcurrentLoadTest( "testRunPutTest1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runPutTest( 200, 200 );
+ }
+ } );
+
+ suite.addTest( new EventQueueConcurrentLoadTest( "testRunPutTest2" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runPutTest( 1200, 1400 );
+ }
+ } );
+
+ suite.addTest( new EventQueueConcurrentLoadTest( "testRunRemoveTest1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runRemoveTest( 2200 );
+ }
+ } );
+
+ suite.addTest( new EventQueueConcurrentLoadTest( "testRunPutTest4" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runPutTest( 5200, 6600 );
+ }
+ } );
+
+ suite.addTest( new EventQueueConcurrentLoadTest( "testRunRemoveTest2" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runRemoveTest( 5200 );
+ }
+ } );
+
+ suite.addTest( new EventQueueConcurrentLoadTest( "testRunPutDelayTest" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runPutDelayTest( 100, 6700 );
+ }
+ } );
+
+ return suite;
+ }
+
+ /**
+ * Test setup. Create the static queue to be used by all tests
+ */
+ @Override
+ public void setUp()
+ {
+ listen = new CacheListenerImpl<>();
+ queue = new CacheEventQueue<>( listen, 1L, "testCache1", maxFailure, waitBeforeRetry );
+
+ queue.setWaitToDieMillis( idleTime );
+ }
+
+ /**
+ * Adds put events to the queue.
+ * @param end
+ * @param expectedPutCount
+ * @throws Exception
+ */
+ public void runPutTest( int end, int expectedPutCount )
+ throws Exception
+ {
+ for ( int i = 0; i <= end; i++ )
+ {
+ CacheElement<String, String> elem = new CacheElement<>( "testCache1", i + ":key", i + "data" );
+ queue.addPutEvent( elem );
+ }
+
+ while ( !queue.isEmpty() )
+ {
+ synchronized ( this )
+ {
+ System.out.println( "queue is still busy, waiting 250 millis" );
+ this.wait( 250 );
+ }
+ }
+ System.out.println( "queue is empty, comparing putCount" );
+
+ // this becomes less accurate with each test. It should never fail. If
+ // it does things are very off.
+ assertTrue( "The put count [" + listen.putCount + "] is below the expected minimum threshold ["
+ + expectedPutCount + "]", listen.putCount >= ( expectedPutCount - 1 ) );
+
+ }
+
+ /**
+ * Add remove events to the event queue.
+ * @param end
+ * @throws Exception
+ */
+ public void runRemoveTest( int end )
+ throws Exception
+ {
+ for ( int i = 0; i <= end; i++ )
+ {
+ queue.addRemoveEvent( i + ":key" );
+ }
+
+ }
+
+ /**
+ * Test putting and a delay. Waits until queue is empty to start.
+ * @param end
+ * @param expectedPutCount
+ * @throws Exception
+ */
+ public void runPutDelayTest( int end, int expectedPutCount )
+ throws Exception
+ {
+ while ( !queue.isEmpty() )
+ {
+ synchronized ( this )
+ {
+ System.out.println( "queue is busy, waiting 250 millis to begin" );
+ this.wait( 250 );
+ }
+ }
+ System.out.println( "queue is empty, begin" );
+
+ // get it going
+ CacheElement<String, String> elem = new CacheElement<>( "testCache1", "a:key", "adata" );
+ queue.addPutEvent( elem );
+
+ for ( int i = 0; i <= end; i++ )
+ {
+ synchronized ( this )
+ {
+ if ( i % 2 == 0 )
+ {
+ this.wait( idleTime );
+ }
+ else
+ {
+ this.wait( idleTime / 2 );
+ }
+ }
+ CacheElement<String, String> elem2 = new CacheElement<>( "testCache1", i + ":key", i + "data" );
+ queue.addPutEvent( elem2 );
+ }
+
+ while ( !queue.isEmpty() )
+ {
+ synchronized ( this )
+ {
+ System.out.println( "queue is still busy, waiting 250 millis" );
+ this.wait( 250 );
+ }
+ }
+ System.out.println( "queue is empty, comparing putCount" );
+
+ Thread.sleep( 1000 );
+
+ // this becomes less accurate with each test. It should never fail. If
+ // it does things are very off.
+ assertTrue( "The put count [" + listen.putCount + "] is below the expected minimum threshold ["
+ + expectedPutCount + "]", listen.putCount >= ( expectedPutCount - 1 ) );
+
+ }
+
+ /**
+ * This is a dummy cache listener to use when testing the event queue.
+ */
+ protected static class CacheListenerImpl<K, V>
+ implements ICacheListener<K, V>
+ {
+ /**
+ * <code>putCount</code>
+ */
+ protected int putCount = 0;
+
+ /**
+ * <code>removeCount</code>
+ */
+ protected int removeCount = 0;
+
+ /**
+ * @param item
+ * @throws IOException
+ */
+ @Override
+ public void handlePut( ICacheElement<K, V> item )
+ throws IOException
+ {
+ synchronized ( this )
+ {
+ putCount++;
+ }
+ }
+
+ /**
+ * @param cacheName
+ * @param key
+ * @throws IOException
+ */
+ @Override
+ public void handleRemove( String cacheName, K key )
+ throws IOException
+ {
+ synchronized ( this )
+ {
+ removeCount++;
+ }
+
+ }
+
+ /**
+ * @param cacheName
+ * @throws IOException
+ */
+ @Override
+ public void handleRemoveAll( String cacheName )
+ throws IOException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * @param cacheName
+ * @throws IOException
+ */
+ @Override
+ public void handleDispose( String cacheName )
+ throws IOException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * @param id
+ * @throws IOException
+ */
+ @Override
+ public void setListenerId( long id )
+ throws IOException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * @return 0
+ * @throws IOException
+ */
+ @Override
+ public long getListenerId()
+ throws IOException
+ {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/MockCacheServiceNonLocal.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/MockCacheServiceNonLocal.java
new file mode 100644
index 0000000..6496869
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/MockCacheServiceNonLocal.java
@@ -0,0 +1,245 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
+
+/**
+ * This is a mock impl of the non local cache service.
+ */
+public class MockCacheServiceNonLocal<K, V>
+ implements ICacheServiceNonLocal<K, V>
+{
+ /** The key last passed to get */
+ public K lastGetKey;
+
+ /** The pattern last passed to get */
+ public String lastGetMatchingPattern;
+
+ /** The keya last passed to getMatching */
+ public Set<K> lastGetMultipleKeys;
+
+ /** The object that was last passed to update. */
+ public ICacheElement<K, V> lastUpdate;
+
+ /** List of updates. */
+ public List<ICacheElement<K, V>> updateRequestList = new ArrayList<>();
+
+ /** List of request ids. */
+ public List<Long> updateRequestIdList = new ArrayList<>();
+
+ /** The key that was last passed to remove. */
+ public K lastRemoveKey;
+
+ /** The cache name that was last passed to removeAll. */
+ public String lastRemoveAllCacheName;
+
+ /**
+ * @param cacheName
+ * @param key
+ * @param requesterId - identity of requester
+ * @return null
+ */
+ @Override
+ public ICacheElement<K, V> get( String cacheName, K key, long requesterId )
+ {
+ lastGetKey = key;
+ return null;
+ }
+
+ /**
+ * @param cacheName
+ * @return empty set
+ */
+ @Override
+ public Set<K> getKeySet( String cacheName )
+ {
+ return new HashSet<>();
+ }
+
+ /**
+ * Set the last remove key.
+ * <p>
+ * @param cacheName
+ * @param key
+ * @param requesterId - identity of requester
+ */
+ @Override
+ public void remove( String cacheName, K key, long requesterId )
+ {
+ lastRemoveKey = key;
+ }
+
+ /**
+ * Set the lastRemoveAllCacheName to the cacheName.
+ * <p>
+ * @param cacheName - region name
+ * @param requesterId - identity of requester
+ * @throws IOException
+ */
+ @Override
+ public void removeAll( String cacheName, long requesterId )
+ throws IOException
+ {
+ lastRemoveAllCacheName = cacheName;
+ }
+
+ /**
+ * Set the last update item.
+ * <p>
+ * @param item
+ * @param requesterId - identity of requester
+ */
+ @Override
+ public void update( ICacheElement<K, V> item, long requesterId )
+ {
+ lastUpdate = item;
+ updateRequestList.add( item );
+ updateRequestIdList.add( Long.valueOf( requesterId ) );
+ }
+
+ /**
+ * Do nothing.
+ * <p>
+ * @param cacheName
+ */
+ @Override
+ public void dispose( String cacheName )
+ {
+ return;
+ }
+
+ /**
+ * @param cacheName
+ * @param key
+ * @return null
+ */
+ @Override
+ public ICacheElement<K, V> get( String cacheName, K key )
+ {
+ return get( cacheName, key, 0 );
+ }
+
+ /**
+ * Do nothing.
+ */
+ @Override
+ public void release()
+ {
+ return;
+ }
+
+ /**
+ * Set the last remove key.
+ * <p>
+ * @param cacheName
+ * @param key
+ */
+ @Override
+ public void remove( String cacheName, K key )
+ {
+ lastRemoveKey = key;
+ }
+
+ /**
+ * Set the last remove all cache name.
+ * <p>
+ * @param cacheName
+ */
+ @Override
+ public void removeAll( String cacheName )
+ {
+ lastRemoveAllCacheName = cacheName;
+ }
+
+ /**
+ * Set the last update item.
+ * <p>
+ * @param item
+ */
+ @Override
+ public void update( ICacheElement<K, V> item )
+ {
+ lastUpdate = item;
+ }
+
+ /**
+ * @param cacheName
+ * @param keys
+ * @param requesterId - identity of requester
+ * @return empty map
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys, long requesterId )
+ {
+ lastGetMultipleKeys = keys;
+ return new HashMap<>();
+ }
+
+ /**
+ * @param cacheName
+ * @param keys
+ * @return empty map
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys )
+ {
+ return getMultiple( cacheName, keys, 0 );
+ }
+
+ /**
+ * Returns an empty map. Zombies have no internal data.
+ * <p>
+ * @param cacheName
+ * @param pattern
+ * @return an empty map
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern )
+ throws IOException
+ {
+ return getMatching( cacheName, pattern, 0 );
+ }
+
+ /**
+ * @param cacheName
+ * @param pattern
+ * @param requesterId
+ * @return Map
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern, long requesterId )
+ throws IOException
+ {
+ lastGetMatchingPattern = pattern;
+ return new HashMap<>();
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/SystemPropertyUsageUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/SystemPropertyUsageUnitTest.java
new file mode 100644
index 0000000..146da95
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/SystemPropertyUsageUnitTest.java
@@ -0,0 +1,108 @@
+package org.apache.commons.jcs3.engine;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import org.apache.commons.jcs3.utils.props.PropertyLoader;
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+
+import java.util.Properties;
+
+/**
+ * Verify that system properties can override.
+ */
+public class SystemPropertyUsageUnitTest
+ extends TestCase
+{
+ private static final String JCS_DEFAULT_CACHEATTRIBUTES_MAX_OBJECTS = "jcs.default.cacheattributes.MaxObjects";
+ private static final int testValue = 6789;
+
+ private CompositeCacheManager manager = null;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ //First shut down any previously running manager.
+ manager = CompositeCacheManager.getInstance();
+ manager.shutDown();
+ }
+
+ /**
+ * @see junit.framework.TestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception
+ {
+ if (manager != null)
+ {
+ manager.shutDown();
+ }
+
+ System.clearProperty(JCS_DEFAULT_CACHEATTRIBUTES_MAX_OBJECTS);
+ super.tearDown();
+ }
+
+ /**
+ * Verify that the system properties are used.
+ * @throws Exception
+ *
+ */
+ public void testSystemPropertyUsage()
+ throws Exception
+ {
+ System.setProperty( JCS_DEFAULT_CACHEATTRIBUTES_MAX_OBJECTS, String.valueOf(testValue) );
+
+ JCS.setConfigFilename( "/TestSystemPropertyUsage.ccf" );
+
+ CacheAccess<String, String> jcs = JCS.getInstance( "someCacheNotInFile" );
+
+ manager = CompositeCacheManager.getInstance();
+
+ assertEquals( "System property value is not reflected.", testValue, jcs.getCacheAttributes().getMaxObjects());
+ }
+
+ /**
+ * Verify that the system properties are not used is specified.
+ *
+ * @throws Exception
+ *
+ */
+ public void testSystemPropertyUsage_inactive()
+ throws Exception
+ {
+ System.setProperty( JCS_DEFAULT_CACHEATTRIBUTES_MAX_OBJECTS, String.valueOf(testValue) );
+
+ manager = CompositeCacheManager.getUnconfiguredInstance();
+
+ Properties props = PropertyLoader.loadProperties( "TestSystemPropertyUsage.ccf" );
+
+ manager.configure( props, false );
+
+ CacheAccess<String, String> jcs = JCS.getInstance( "someCacheNotInFile" );
+
+ assertEquals( "System property value should not be reflected",
+ Integer.parseInt( props.getProperty( JCS_DEFAULT_CACHEATTRIBUTES_MAX_OBJECTS ) ),
+ jcs.getCacheAttributes().getMaxObjects());
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/ZombieCacheServiceNonLocalUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/ZombieCacheServiceNonLocalUnitTest.java
new file mode 100644
index 0000000..1d2b89b
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/ZombieCacheServiceNonLocalUnitTest.java
@@ -0,0 +1,128 @@
+package org.apache.commons.jcs3.engine;
+
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.ZombieCacheServiceNonLocal;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for the zombie remote cache service.
+ */
+public class ZombieCacheServiceNonLocalUnitTest
+ extends TestCase
+{
+ /**
+ * Verify that an update event gets added and then is sent to the service passed to propagate.
+ * <p>
+ * @throws Exception
+ */
+ public void testUpdateThenWalk()
+ throws Exception
+ {
+ // SETUP
+ MockCacheServiceNonLocal<String, String> service = new MockCacheServiceNonLocal<>();
+
+ ZombieCacheServiceNonLocal<String, String> zombie = new ZombieCacheServiceNonLocal<>( 10 );
+
+ String cacheName = "testUpdate";
+
+ // DO WORK
+ ICacheElement<String, String> element = new CacheElement<>( cacheName, "key", "value" );
+ zombie.update( element, 123l );
+ zombie.propagateEvents( service );
+
+ // VERIFY
+ assertEquals( "Updated element is not as expected.", element, service.lastUpdate );
+ }
+
+ /**
+ * Verify that nothing is added if the max is set to 0.
+ * <p>
+ * @throws Exception
+ */
+ public void testUpdateThenWalk_zeroSize()
+ throws Exception
+ {
+ // SETUP
+ MockCacheServiceNonLocal<String, String> service = new MockCacheServiceNonLocal<>();
+
+ ZombieCacheServiceNonLocal<String, String> zombie = new ZombieCacheServiceNonLocal<>( 0 );
+
+ String cacheName = "testUpdate";
+
+ // DO WORK
+ ICacheElement<String, String> element = new CacheElement<>( cacheName, "key", "value" );
+ zombie.update( element, 123l );
+ zombie.propagateEvents( service );
+
+ // VERIFY
+ assertNull( "Nothing should have been put to the service.", service.lastUpdate );
+ }
+
+ /**
+ * Verify that a remove event gets added and then is sent to the service passed to propagate.
+ * <p>
+ * @throws Exception
+ */
+ public void testRemoveThenWalk()
+ throws Exception
+ {
+ // SETUP
+ MockCacheServiceNonLocal<String, String> service = new MockCacheServiceNonLocal<>();
+
+ ZombieCacheServiceNonLocal<String, String> zombie = new ZombieCacheServiceNonLocal<>( 10 );
+
+ String cacheName = "testRemoveThenWalk";
+ String key = "myKey";
+
+ // DO WORK
+ zombie.remove( cacheName, key, 123l );
+ zombie.propagateEvents( service );
+
+ // VERIFY
+ assertEquals( "Updated element is not as expected.", key, service.lastRemoveKey );
+ }
+
+ /**
+ * Verify that a removeAll event gets added and then is sent to the service passed to propagate.
+ * <p>
+ * @throws Exception
+ */
+ public void testRemoveAllThenWalk()
+ throws Exception
+ {
+ // SETUP
+ MockCacheServiceNonLocal<String, String> service = new MockCacheServiceNonLocal<>();
+
+ ZombieCacheServiceNonLocal<String, String> zombie = new ZombieCacheServiceNonLocal<>( 10 );
+
+ String cacheName = "testRemoveThenWalk";
+
+ // DO WORK
+ zombie.removeAll( cacheName, 123l );
+ zombie.propagateEvents( service );
+
+ // VERIFY
+ assertEquals( "Updated element is not as expected.", cacheName, service.lastRemoveAllCacheName );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CacheManagerStatsUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CacheManagerStatsUnitTest.java
new file mode 100644
index 0000000..e9fc3d8
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CacheManagerStatsUnitTest.java
@@ -0,0 +1,73 @@
+package org.apache.commons.jcs3.engine.control;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+import org.apache.commons.jcs3.engine.stats.behavior.ICacheStats;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * @author Aaron Smuts
+ *
+ */
+public class CacheManagerStatsUnitTest
+ extends TestCase
+{
+
+ /**
+ * Just get the stats after putting a couple entries in the cache.
+ *
+ * @throws Exception
+ */
+ public void testSimpleGetStats() throws Exception
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testCache1" );
+
+ // 1 miss, 1 hit, 1 put
+ cache.get( "testKey" );
+ cache.put( "testKey", "testdata" );
+ // should have 4 hits
+ cache.get( "testKey" );
+ cache.get( "testKey" );
+ cache.get( "testKey" );
+ cache.get( "testKey" );
+
+ CompositeCacheManager mgr = CompositeCacheManager.getInstance();
+ String statsString = mgr.getStats();
+
+// System.out.println( statsString );
+
+ assertTrue( "Should have the cacheName in here.", statsString.indexOf("testCache1") != -1 );
+ assertTrue( "Should have the HitCountRam in here.", statsString.indexOf("HitCountRam") != -1 );
+ assertTrue( "Should have the 4 in here.", statsString.indexOf("4") != -1 );
+
+ ICacheStats[] stats = mgr.getStatistics();
+ int statsLen = stats.length;
+// System.out.println( "statsLen = " + statsLen );
+ for ( int i = 0; i < statsLen; i++ )
+ {
+ // TODO finish
+ }
+ }
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheConfiguratorUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheConfiguratorUnitTest.java
new file mode 100644
index 0000000..b0481e2
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheConfiguratorUnitTest.java
@@ -0,0 +1,95 @@
+package org.apache.commons.jcs3.engine.control;
+
+/*
+ * 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.
+ */
+
+import java.util.Properties;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.jcs3.auxiliary.MockAuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.MockAuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.auxiliary.MockAuxiliaryCacheFactory;
+import org.apache.commons.jcs3.engine.logging.MockCacheEventLogger;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheConfigurator;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.control.CompositeCacheConfigurator;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+
+/** Unit tests for the configurator. */
+public class CompositeCacheConfiguratorUnitTest
+ extends TestCase
+{
+ /**
+ * Verify that we can parse the event logger correctly
+ */
+ public void testParseAuxiliary_CacheEventLogger_Normal()
+ {
+ // SETUP
+ String regionName = "MyRegion";
+
+ String auxName = "MockAux";
+ String auxPrefix = CompositeCacheConfigurator.AUXILIARY_PREFIX + auxName;
+ String auxiliaryClassName = MockAuxiliaryCacheFactory.class.getName();
+ String eventLoggerClassName = MockCacheEventLogger.class.getName();
+ String auxiliaryAttributeClassName = MockAuxiliaryCacheAttributes.class.getName();
+
+ Properties props = new Properties();
+ props.put( auxPrefix, auxiliaryClassName );
+ props.put( auxPrefix + CompositeCacheConfigurator.ATTRIBUTE_PREFIX, auxiliaryAttributeClassName );
+ props.put( auxPrefix + AuxiliaryCacheConfigurator.CACHE_EVENT_LOGGER_PREFIX, eventLoggerClassName );
+
+// System.out.print( props );
+
+ CompositeCacheManager manager = CompositeCacheManager.getUnconfiguredInstance();
+ CompositeCacheConfigurator configurator = new CompositeCacheConfigurator();
+
+ // DO WORK
+ AuxiliaryCache<String, String> aux = configurator.parseAuxiliary( props, manager, auxName, regionName );
+ MockAuxiliaryCache<String, String> result = (MockAuxiliaryCache<String, String>)aux;
+
+ // VERIFY
+ assertNotNull( "Should have an auxcache.", result );
+ assertNotNull( "Should have an event logger.", result.getCacheEventLogger() );
+ }
+
+ /**
+ * Verify that we can parse the spool chunk size
+ */
+ public void testParseSpoolChunkSize_Normal()
+ {
+ // SETUP
+ String regionName = "MyRegion";
+ int chunkSize = 5;
+
+ Properties props = new Properties();
+ props.put( "jcs.default", "" );
+ props.put( "jcs.default.cacheattributes.SpoolChunkSize", String.valueOf( chunkSize ) );
+
+ CompositeCacheManager manager = CompositeCacheManager.getUnconfiguredInstance();
+
+ // DO WORK
+ manager.configure( props );
+
+ // VERIFY
+ CompositeCache<String, String> cache = manager.getCache( regionName );
+ assertEquals( "Wrong chunkSize", cache.getCacheAttributes().getSpoolChunkSize(), chunkSize );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheDiskUsageUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheDiskUsageUnitTest.java
new file mode 100644
index 0000000..75a0bcf
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheDiskUsageUnitTest.java
@@ -0,0 +1,511 @@
+package org.apache.commons.jcs3.engine.control;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCache;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.CompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.ElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.engine.behavior.ICacheType.CacheType;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests of the disk usage settings for the CompositeCache.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class CompositeCacheDiskUsageUnitTest
+ extends TestCase
+{
+ private static final String CACHE_NAME = "testSpoolAllowed";
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestDiskCacheUsagePattern.ccf" );
+ }
+
+ /**
+ * Verify that the swap region is set to the correct pattern.
+ * <p>
+ * @throws CacheException
+ */
+ public void testSwapConfig()
+ throws CacheException
+ {
+ CacheAccess<String, String> swap = JCS.getInstance( "Swap" );
+ assertEquals( ICompositeCacheAttributes.DiskUsagePattern.SWAP, swap.getCacheAttributes()
+ .getDiskUsagePattern() );
+ }
+
+ /**
+ * Verify that the swap region is set to the correct pattern.
+ * <p>
+ * @throws CacheException
+ */
+ public void testUpdateConfig()
+ throws CacheException
+ {
+ CacheAccess<String, String> swap = JCS.getInstance( "Update" );
+ assertEquals( ICompositeCacheAttributes.DiskUsagePattern.UPDATE, swap.getCacheAttributes()
+ .getDiskUsagePattern() );
+ }
+
+ /**
+ * Setup a disk cache. Configure the disk usage pattern to swap. Call spool. Verify that the
+ * item is put to disk.
+ */
+ public void testSpoolAllowed()
+ {
+ // SETUP
+ ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
+ cattr.setCacheName(CACHE_NAME);
+ cattr.setDiskUsagePattern( ICompositeCacheAttributes.DiskUsagePattern.SWAP );
+
+ IElementAttributes attr = new ElementAttributes();
+
+ CompositeCache<String, String> cache = new CompositeCache<>( cattr, attr );
+
+ MockAuxCache<String, String> mock = new MockAuxCache<>();
+ mock.cacheType = CacheType.DISK_CACHE;
+
+ @SuppressWarnings("unchecked")
+ AuxiliaryCache<String, String>[] auxArray = new AuxiliaryCache[] { mock };
+ cache.setAuxCaches( auxArray );
+
+ ICacheElement<String, String> inputElement = new CacheElement<>( CACHE_NAME, "key", "value" );
+
+ // DO WORK
+ cache.spoolToDisk( inputElement );
+
+ // VERIFY
+ assertEquals( "Wrong number of calls to the disk cache update.", 1, mock.updateCount );
+ assertEquals( "Wrong element updated.", inputElement, mock.lastUpdatedItem );
+ }
+
+ /**
+ * Setup a disk cache. Configure the disk usage pattern to not swap. Call spool. Verify that the
+ * item is not put to disk.
+ */
+ public void testSpoolNotAllowed()
+ {
+ // SETUP
+ ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
+ cattr.setCacheName(CACHE_NAME);
+ cattr.setDiskUsagePattern( ICompositeCacheAttributes.DiskUsagePattern.UPDATE );
+
+ IElementAttributes attr = new ElementAttributes();
+
+ CompositeCache<String, String> cache = new CompositeCache<>( cattr, attr );
+
+ MockAuxCache<String, String> mock = new MockAuxCache<>();
+ mock.cacheType = CacheType.DISK_CACHE;
+
+ @SuppressWarnings("unchecked")
+ AuxiliaryCache<String, String>[] auxArray = new AuxiliaryCache[] { mock };
+ cache.setAuxCaches( auxArray );
+
+ ICacheElement<String, String> inputElement = new CacheElement<>( CACHE_NAME, "key", "value" );
+
+ // DO WORK
+ cache.spoolToDisk( inputElement );
+
+ // VERIFY
+ assertEquals( "Wrong number of calls to the disk cache update.", 0, mock.updateCount );
+ }
+
+ /**
+ * Setup a disk cache. Configure the disk usage pattern to UPDATE. Call updateAuxiliaries.
+ * Verify that the item is put to disk.
+ * <p>
+ * This tests that the items are put to disk on a normal put when the usage pattern is set
+ * appropriately.
+ * @throws IOException
+ */
+ public void testUpdateAllowed()
+ throws IOException
+ {
+ // SETUP
+ ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
+ cattr.setCacheName(CACHE_NAME);
+ cattr.setDiskUsagePattern( ICompositeCacheAttributes.DiskUsagePattern.UPDATE );
+
+ IElementAttributes attr = new ElementAttributes();
+
+ CompositeCache<String, String> cache = new CompositeCache<>( cattr, attr );
+
+ MockAuxCache<String, String> mock = new MockAuxCache<>();
+ mock.cacheType = CacheType.DISK_CACHE;
+
+ @SuppressWarnings("unchecked")
+ AuxiliaryCache<String, String>[] auxArray = new AuxiliaryCache[] { mock };
+ cache.setAuxCaches( auxArray );
+
+ ICacheElement<String, String> inputElement = new CacheElement<>( CACHE_NAME, "key", "value" );
+
+ // DO WORK
+ cache.updateAuxiliaries( inputElement, true );
+
+ // VERIFY
+ assertEquals( "Wrong number of calls to the disk cache update.", 1, mock.updateCount );
+ assertEquals( "Wrong element updated.", inputElement, mock.lastUpdatedItem );
+ }
+
+ /**
+ * Setup a disk cache. Configure the disk usage pattern to UPDATE. Call updateAuxiliaries with
+ * local only set to false. Verify that the item is put to disk.
+ * <p>
+ * This tests that the items are put to disk on a normal put when the usage pattern is set
+ * appropriately. The local setting should have no impact on whether the item goes to disk.
+ * <p>
+ * @throws IOException
+ */
+ public void testUpdateAllowed_localFalse()
+ throws IOException
+ {
+ // SETUP
+ ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
+ cattr.setCacheName(CACHE_NAME);
+ cattr.setDiskUsagePattern( ICompositeCacheAttributes.DiskUsagePattern.UPDATE );
+
+ IElementAttributes attr = new ElementAttributes();
+
+ CompositeCache<String, String> cache = new CompositeCache<>( cattr, attr );
+
+ MockAuxCache<String, String> mock = new MockAuxCache<>();
+ mock.cacheType = CacheType.DISK_CACHE;
+
+ @SuppressWarnings("unchecked")
+ AuxiliaryCache<String, String>[] auxArray = new AuxiliaryCache[] { mock };
+ cache.setAuxCaches( auxArray );
+
+ ICacheElement<String, String> inputElement = new CacheElement<>( CACHE_NAME, "key", "value" );
+
+ // DO WORK
+ cache.updateAuxiliaries( inputElement, false );
+
+ // VERIFY
+ assertEquals( "Wrong number of calls to the disk cache update.", 1, mock.updateCount );
+ assertEquals( "Wrong element updated.", inputElement, mock.lastUpdatedItem );
+ }
+
+ /**
+ * Setup a disk cache. Configure the disk usage pattern to SWAP. Call updateAuxiliaries. Verify
+ * that the item is not put to disk.
+ * <p>
+ * This tests that the items are not put to disk on a normal put when the usage pattern is set
+ * to SWAP.
+ * <p>
+ * @throws IOException
+ */
+ public void testUpdateNotAllowed()
+ throws IOException
+ {
+ // SETUP
+ ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
+ cattr.setCacheName(CACHE_NAME);
+ cattr.setDiskUsagePattern( ICompositeCacheAttributes.DiskUsagePattern.SWAP );
+
+ IElementAttributes attr = new ElementAttributes();
+
+ CompositeCache<String, String> cache = new CompositeCache<>( cattr, attr );
+
+ MockAuxCache<String, String> mock = new MockAuxCache<>();
+ mock.cacheType = CacheType.DISK_CACHE;
+
+ @SuppressWarnings("unchecked")
+ AuxiliaryCache<String, String>[] auxArray = new AuxiliaryCache[] { mock };
+ cache.setAuxCaches( auxArray );
+
+ ICacheElement<String, String> inputElement = new CacheElement<>( CACHE_NAME, "key", "value" );
+
+ // DO WORK
+ cache.updateAuxiliaries( inputElement, true );
+
+ // VERIFY
+ assertEquals( "Wrong number of calls to the disk cache update.", 0, mock.updateCount );
+ }
+
+ /**
+ * Setup a disk cache. Configure the disk usage pattern to UPDATE. Call updateAuxiliaries.
+ * Verify that the item is put to disk.
+ * <p>
+ * This tests that the items are put to disk on a normal put when the usage pattern is set
+ * appropriately.
+ * @throws IOException
+ */
+ public void testUpdateAllowed_withOtherCaches()
+ throws IOException
+ {
+ // SETUP
+ ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
+ cattr.setCacheName(CACHE_NAME);
+ cattr.setDiskUsagePattern( ICompositeCacheAttributes.DiskUsagePattern.UPDATE );
+
+ IElementAttributes attr = new ElementAttributes();
+
+ CompositeCache<String, String> cache = new CompositeCache<>( cattr, attr );
+
+ MockAuxCache<String, String> mock = new MockAuxCache<>();
+ mock.cacheType = CacheType.DISK_CACHE;
+
+ MockAuxCache<String, String> mockLateral = new MockAuxCache<>();
+ mockLateral.cacheType = CacheType.LATERAL_CACHE;
+
+ @SuppressWarnings("unchecked")
+ AuxiliaryCache<String, String>[] auxArray = new AuxiliaryCache[] { mock, mockLateral };
+ cache.setAuxCaches( auxArray );
+
+ ICacheElement<String, String> inputElement = new CacheElement<>( CACHE_NAME, "key", "value" );
+
+ // DO WORK
+ cache.updateAuxiliaries( inputElement, false );
+
+ // VERIFY
+ assertEquals( "Wrong number of calls to the disk cache update.", 1, mock.updateCount );
+ assertEquals( "Wrong element updated.", inputElement, mock.lastUpdatedItem );
+
+ assertEquals( "Wrong number of calls to the lateral cache update.", 1, mockLateral.updateCount );
+ assertEquals( "Wrong element updated with lateral.", inputElement, mockLateral.lastUpdatedItem );
+ }
+
+ /**
+ * Used to test the disk cache functionality.
+ * <p>
+ * @author Aaron Smuts
+ */
+ public static class MockAuxCache<K, V>
+ extends AbstractAuxiliaryCache<K, V>
+ {
+ /** The last item passed to update. */
+ public ICacheElement<K, V> lastUpdatedItem;
+
+ /** The number of times update was called. */
+ public int updateCount = 0;
+
+ /** The type that should be returned from getCacheType. */
+ public CacheType cacheType = CacheType.DISK_CACHE;
+
+ /** Resets counters and catchers. */
+ public void reset()
+ {
+ updateCount = 0;
+ lastUpdatedItem = null;
+ }
+
+ /**
+ * @param ce
+ * @throws IOException
+ */
+ @Override
+ public void update( ICacheElement<K, V> ce )
+ throws IOException
+ {
+ lastUpdatedItem = ce;
+ updateCount++;
+ }
+
+ /**
+ * @param key
+ * @return ICacheElement
+ * @throws IOException
+ */
+ @Override
+ public ICacheElement<K, V> get( K key )
+ throws IOException
+ {
+ return null;
+ }
+
+ /**
+ * Gets multiple items from the cache based on the given set of keys.
+ * <p>
+ * @param keys
+ * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is
+ * no data in cache for any of these keys
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
+ {
+ return new HashMap<>();
+ }
+
+ /**
+ * @param key
+ * @return false
+ * @throws IOException
+ */
+ @Override
+ public boolean remove( K key )
+ throws IOException
+ {
+ return false;
+ }
+
+ /** @throws IOException */
+ @Override
+ public void removeAll()
+ throws IOException
+ {
+ // noop
+ }
+
+ /** @throws IOException */
+ @Override
+ public void dispose()
+ throws IOException
+ {
+ // noop
+ }
+
+ /** @return 0 */
+ @Override
+ public int getSize()
+ {
+ return 0;
+ }
+
+ /** @return 0 */
+ @Override
+ public CacheStatus getStatus()
+ {
+ return CacheStatus.ALIVE;
+ }
+
+ /** @return null */
+ @Override
+ public String getCacheName()
+ {
+ return null;
+ }
+
+ /**
+ * @return null
+ * @throws IOException
+ */
+ @Override
+ public Set<K> getKeySet( )
+ throws IOException
+ {
+ return null;
+ }
+
+ /** @return null */
+ @Override
+ public IStats getStatistics()
+ {
+ return null;
+ }
+
+ /** @return null */
+ @Override
+ public String getStats()
+ {
+ return null;
+ }
+
+ /**
+ * Returns the setup cache type. This allows you to use this mock as multiple cache types.
+ * <p>
+ * @see org.apache.commons.jcs3.engine.behavior.ICacheType#getCacheType()
+ * @return cacheType
+ */
+ @Override
+ public CacheType getCacheType()
+ {
+ return cacheType;
+ }
+
+ /**
+ * @return Returns the AuxiliaryCacheAttributes.
+ */
+ @Override
+ public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
+ {
+ return null;
+ }
+
+ /**
+ * @param cacheEventLogger
+ */
+ @Override
+ public void setCacheEventLogger( ICacheEventLogger cacheEventLogger )
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * @param elementSerializer
+ */
+ @Override
+ public void setElementSerializer( IElementSerializer elementSerializer )
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ /** @return null */
+ @Override
+ public String getEventLoggingExtraInfo()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /**
+ * @param pattern
+ * @return Collections.EMPTY_MAP;
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMatching(String pattern)
+ throws IOException
+ {
+ return Collections.emptyMap();
+ }
+
+
+ }
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheManagerTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheManagerTest.java
new file mode 100644
index 0000000..e9f144b
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheManagerTest.java
@@ -0,0 +1,56 @@
+package org.apache.commons.jcs3.engine.control;
+
+import org.apache.commons.jcs3.engine.CacheStatus;
+import org.apache.commons.jcs3.engine.CompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/** Unit tests for the composite cache manager */
+public class CompositeCacheManagerTest
+ extends TestCase
+{
+
+ /**
+ * Verify that calling release, when there are active clients, the caches are correctly disposed or not.
+ */
+ public void testRelease()
+ {
+ // See JCS-184
+ // create the manager
+ CompositeCacheManager manager = CompositeCacheManager.getInstance();
+ // add a simple cache
+ CompositeCacheAttributes cacheAttributes = new CompositeCacheAttributes();
+ CompositeCache<String, String> cache = new CompositeCache<>(cacheAttributes, /* attr */ null);
+ manager.addCache("simple_cache", cache);
+ // add a client to the cache
+ CompositeCacheManager.getUnconfiguredInstance();
+ // won't release as there are still clients. Only disposed when release() is called by
+ // the last client
+ manager.release();
+ assertEquals("The cache was disposed during release!", CacheStatus.ALIVE, cache.getStatus());
+ manager.release();
+ assertEquals("The cache was NOT disposed during release!", CacheStatus.DISPOSED, cache.getStatus());
+ }
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheUnitTest.java
new file mode 100644
index 0000000..d9e2f5b
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/CompositeCacheUnitTest.java
@@ -0,0 +1,247 @@
+package org.apache.commons.jcs3.engine.control;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import org.apache.commons.jcs3.auxiliary.MockAuxiliaryCache;
+import org.apache.commons.jcs3.engine.memory.MockMemoryCache;
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCache;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.CompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.ElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICacheType.CacheType;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * Tests that directly engage the composite cache.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class CompositeCacheUnitTest
+ extends TestCase
+{
+ /**
+ * Verify that the freeMemoryElements method on the memory cache is called on shutdown if there
+ * is a disk cache.
+ * <p>
+ * @throws IOException
+ */
+ public void testShutdownMemoryFlush()
+ throws IOException
+ {
+ // SETUP
+ String cacheName = "testCacheName";
+ String mockMemoryCacheClassName = "org.apache.commons.jcs3.engine.memory.MockMemoryCache";
+ ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
+ cattr.setMemoryCacheName( mockMemoryCacheClassName );
+
+ IElementAttributes attr = new ElementAttributes();
+
+ CompositeCache<String, Integer> cache = new CompositeCache<>( cattr, attr );
+
+ MockAuxiliaryCache<String, Integer> diskMock = new MockAuxiliaryCache<>();
+ diskMock.cacheType = CacheType.DISK_CACHE;
+ @SuppressWarnings("unchecked")
+ AuxiliaryCache<String, Integer>[] aux = new AuxiliaryCache[] { diskMock };
+ cache.setAuxCaches( aux );
+
+ // DO WORK
+ int numToInsert = 10;
+ for ( int i = 0; i < numToInsert; i++ )
+ {
+ ICacheElement<String, Integer> element = new CacheElement<>( cacheName, String.valueOf( i ), Integer.valueOf( i ) );
+ cache.update( element, false );
+ }
+
+ cache.dispose();
+
+ // VERIFY
+ MockMemoryCache<String, Integer> memoryCache = (MockMemoryCache<String, Integer>) cache.getMemoryCache();
+ assertEquals( "Wrong number freed.", numToInsert, memoryCache.lastNumberOfFreedElements );
+ }
+
+ /**
+ * Verify that the freeMemoryElements method on the memory cache is NOT called on shutdown if
+ * there is NOT a disk cache.
+ * <p>
+ * @throws IOException
+ */
+ public void testShutdownMemoryFlush_noDisk()
+ throws IOException
+ {
+ // SETUP
+ String cacheName = "testCacheName";
+ String mockMemoryCacheClassName = "org.apache.commons.jcs3.engine.memory.MockMemoryCache";
+ ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
+ cattr.setMemoryCacheName( mockMemoryCacheClassName );
+
+ IElementAttributes attr = new ElementAttributes();
+
+ CompositeCache<String, Integer> cache = new CompositeCache<>( cattr, attr );
+
+ MockAuxiliaryCache<String, Integer> diskMock = new MockAuxiliaryCache<>();
+ diskMock.cacheType = CacheType.REMOTE_CACHE;
+ @SuppressWarnings("unchecked")
+ AuxiliaryCache<String, Integer>[] aux = new AuxiliaryCache[] { diskMock };
+ cache.setAuxCaches( aux );
+
+ // DO WORK
+ int numToInsert = 10;
+ for ( int i = 0; i < numToInsert; i++ )
+ {
+ ICacheElement<String, Integer> element = new CacheElement<>( cacheName, String.valueOf( i ), Integer.valueOf( i ) );
+ cache.update( element, false );
+ }
+
+ cache.dispose();
+
+ // VERIFY
+ MockMemoryCache<String, Integer> memoryCache = (MockMemoryCache<String, Integer>) cache.getMemoryCache();
+ assertEquals( "Wrong number freed.", 0, memoryCache.lastNumberOfFreedElements );
+ }
+
+ /**
+ * Verify we can get some matching elements..
+ * <p>
+ * @throws IOException
+ */
+ public void testGetMatching_Normal()
+ throws IOException
+ {
+ // SETUP
+ int maxMemorySize = 1000;
+ String keyprefix1 = "MyPrefix1";
+ String keyprefix2 = "MyPrefix2";
+ String cacheName = "testGetMatching_Normal";
+ String memoryCacheClassName = "org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache";
+ ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
+ cattr.setMemoryCacheName( memoryCacheClassName );
+ cattr.setMaxObjects( maxMemorySize );
+
+ IElementAttributes attr = new ElementAttributes();
+
+ CompositeCache<String, Integer> cache = new CompositeCache<>( cattr, attr );
+
+ MockAuxiliaryCache<String, Integer> diskMock = new MockAuxiliaryCache<>();
+ diskMock.cacheType = CacheType.DISK_CACHE;
+ @SuppressWarnings("unchecked")
+ AuxiliaryCache<String, Integer>[] aux = new AuxiliaryCache[] { diskMock };
+ cache.setAuxCaches( aux );
+
+ // DO WORK
+ int numToInsertPrefix1 = 10;
+ // insert with prefix1
+ for ( int i = 0; i < numToInsertPrefix1; i++ )
+ {
+ ICacheElement<String, Integer> element = new CacheElement<>( cacheName, keyprefix1 + String.valueOf( i ), Integer.valueOf( i ) );
+ cache.update( element, false );
+ }
+
+ int numToInsertPrefix2 = 50;
+ // insert with prefix1
+ for ( int i = 0; i < numToInsertPrefix2; i++ )
+ {
+ ICacheElement<String, Integer> element = new CacheElement<>( cacheName, keyprefix2 + String.valueOf( i ), Integer.valueOf( i ) );
+ cache.update( element, false );
+ }
+
+ Map<?, ?> result1 = cache.getMatching( keyprefix1 + "\\S+" );
+ Map<?, ?> result2 = cache.getMatching( keyprefix2 + "\\S+" );
+
+ // VERIFY
+ assertEquals( "Wrong number returned 1:", numToInsertPrefix1, result1.size() );
+ assertEquals( "Wrong number returned 2:", numToInsertPrefix2, result2.size() );
+ }
+
+ /**
+ * Verify we try a disk aux on a getMatching call.
+ * <p>
+ * @throws IOException
+ */
+ public void testGetMatching_NotOnDisk()
+ throws IOException
+ {
+ // SETUP
+ int maxMemorySize = 0;
+ String cacheName = "testGetMatching_NotOnDisk";
+ String memoryCacheClassName = "org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache";
+ ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMemoryCacheName( memoryCacheClassName );
+ cattr.setMaxObjects( maxMemorySize );
+
+ IElementAttributes attr = new ElementAttributes();
+
+ CompositeCache<String, Integer> cache = new CompositeCache<>( cattr, attr );
+
+ MockAuxiliaryCache<String, Integer> diskMock = new MockAuxiliaryCache<>();
+ diskMock.cacheType = CacheType.DISK_CACHE;
+ @SuppressWarnings("unchecked")
+ AuxiliaryCache<String, Integer>[] aux = new AuxiliaryCache[] { diskMock };
+ cache.setAuxCaches( aux );
+
+ // DO WORK
+ cache.getMatching( "junk" );
+
+ // VERIFY
+ assertEquals( "Wrong number of calls", 1, diskMock.getMatchingCallCount );
+ }
+
+ /**
+ * Verify we try a remote aux on a getMatching call.
+ * <p>
+ * @throws IOException
+ */
+ public void testGetMatching_NotOnRemote()
+ throws IOException
+ {
+ // SETUP
+ int maxMemorySize = 0;
+ String cacheName = "testGetMatching_NotOnDisk";
+ String memoryCacheClassName = "org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache";
+ ICompositeCacheAttributes cattr = new CompositeCacheAttributes();
+ cattr.setCacheName(cacheName);
+ cattr.setMemoryCacheName( memoryCacheClassName );
+ cattr.setMaxObjects( maxMemorySize );
+
+ IElementAttributes attr = new ElementAttributes();
+
+ CompositeCache<String, Integer> cache = new CompositeCache<>( cattr, attr );
+
+ MockAuxiliaryCache<String, Integer> diskMock = new MockAuxiliaryCache<>();
+ diskMock.cacheType = CacheType.REMOTE_CACHE;
+ @SuppressWarnings("unchecked")
+ AuxiliaryCache<String, Integer>[] aux = new AuxiliaryCache[] { diskMock };
+ cache.setAuxCaches( aux );
+
+ // DO WORK
+ cache.getMatching( "junk" );
+
+ // VERIFY
+ assertEquals( "Wrong number of calls", 1, diskMock.getMatchingCallCount );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/MockCompositeCacheManager.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/MockCompositeCacheManager.java
new file mode 100644
index 0000000..18a025e
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/MockCompositeCacheManager.java
@@ -0,0 +1,127 @@
+package org.apache.commons.jcs3.engine.control;
+
+/*
+ * 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.
+ */
+
+import java.util.Properties;
+
+import org.apache.commons.jcs3.auxiliary.AuxiliaryCache;
+import org.apache.commons.jcs3.engine.CompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.ElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
+import org.apache.commons.jcs3.engine.behavior.IShutdownObserver;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+
+/** For testing. */
+public class MockCompositeCacheManager
+ implements ICompositeCacheManager
+{
+ /** The cache that was returned. */
+ private CompositeCache<?, ?> cache;
+
+ /** Properties with which this manager was configured. This is exposed for other managers. */
+ private Properties configurationProperties;
+
+ /**
+ * @param cacheName
+ * @return Returns a CompositeCache
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public <K, V> CompositeCache<K, V> getCache( String cacheName )
+ {
+ if ( cache == null )
+ {
+// System.out.println( "Creating mock cache" );
+ CompositeCache<K, V> newCache =
+ new CompositeCache<>( new CompositeCacheAttributes(), new ElementAttributes() );
+ this.setCache( newCache );
+ }
+
+ return (CompositeCache<K, V>)cache;
+ }
+
+ @Override
+ public <K, V> AuxiliaryCache<K, V> getAuxiliaryCache(String auxName, String cacheName)
+ {
+ return null;
+ }
+
+ /**
+ * @param cache The cache to set.
+ */
+ public void setCache( CompositeCache<?, ?> cache )
+ {
+ this.cache = cache;
+ }
+
+ /**
+ * @return Returns the cache.
+ */
+ public CompositeCache<?, ?> getCache()
+ {
+ return cache;
+ }
+
+ /**
+ * This is exposed so other manager can get access to the props.
+ * <p>
+ * @param props
+ */
+ public void setConfigurationProperties( Properties props )
+ {
+ this.configurationProperties = props;
+ }
+
+ /**
+ * This is exposed so other manager can get access to the props.
+ * <p>
+ * @return the configurationProperties
+ */
+ @Override
+ public Properties getConfigurationProperties()
+ {
+ return configurationProperties;
+ }
+
+ /** @return Mock */
+ @Override
+ public String getStats()
+ {
+ return "Mock";
+ }
+
+ /**
+ * @see org.apache.commons.jcs3.engine.behavior.IShutdownObservable#registerShutdownObserver(org.apache.commons.jcs3.engine.behavior.IShutdownObserver)
+ */
+ @Override
+ public void registerShutdownObserver(IShutdownObserver observer)
+ {
+ // Do nothing
+ }
+
+ /**
+ * @see org.apache.commons.jcs3.engine.behavior.IShutdownObservable#deregisterShutdownObserver(org.apache.commons.jcs3.engine.behavior.IShutdownObserver)
+ */
+ @Override
+ public void deregisterShutdownObserver(IShutdownObserver observer)
+ {
+ // Do nothing
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/MockElementSerializer.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/MockElementSerializer.java
new file mode 100644
index 0000000..7cc78b0
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/MockElementSerializer.java
@@ -0,0 +1,87 @@
+package org.apache.commons.jcs3.engine.control;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+
+/** For mocking. */
+public class MockElementSerializer
+ implements IElementSerializer
+{
+ /** test property */
+ private String testProperty;
+
+ /** What's used in the background */
+ private final StandardSerializer serializer = new StandardSerializer();
+
+ /** times out was called */
+ public int deSerializeCount = 0;
+
+ /** times in was called */
+ public int serializeCount = 0;
+
+ /**
+ * @param bytes
+ * @return Object
+ * @throws IOException
+ * @throws ClassNotFoundException
+ *
+ */
+ @Override
+ public <T> T deSerialize( byte[] bytes, ClassLoader loader )
+ throws IOException, ClassNotFoundException
+ {
+ deSerializeCount++;
+ return serializer.deSerialize( bytes, loader );
+ }
+
+ /**
+ * @param obj
+ * @return byte[]
+ * @throws IOException
+ *
+ */
+ @Override
+ public <T> byte[] serialize( T obj )
+ throws IOException
+ {
+ serializeCount++;
+ return serializer.serialize( obj );
+ }
+
+ /**
+ * @param testProperty
+ */
+ public void setTestProperty( String testProperty )
+ {
+ this.testProperty = testProperty;
+ }
+
+ /**
+ * @return testProperty
+ */
+ public String getTestProperty()
+ {
+ return testProperty;
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/event/ElementEventHandlerMockImpl.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/event/ElementEventHandlerMockImpl.java
new file mode 100644
index 0000000..07dc0fe
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/event/ElementEventHandlerMockImpl.java
@@ -0,0 +1,186 @@
+package org.apache.commons.jcs3.engine.control.event;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.engine.control.event.behavior.ElementEventType;
+import org.apache.commons.jcs3.engine.control.event.behavior.IElementEvent;
+import org.apache.commons.jcs3.engine.control.event.behavior.IElementEventHandler;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/**
+ * @author aaronsm
+ */
+public class ElementEventHandlerMockImpl
+ implements IElementEventHandler
+{
+ /** Times called. */
+ private int callCount = 0;
+
+ /** The logger */
+ private static final Log log = LogManager.getLog( ElementEventHandlerMockImpl.class );
+
+ /** ELEMENT_EVENT_SPOOLED_DISK_AVAILABLE */
+ private int spoolCount = 0;
+
+ /** ELEMENT_EVENT_SPOOLED_NOT_ALLOWED */
+ private int spoolNotAllowedCount = 0;
+
+ /** ELEMENT_EVENT_SPOOLED_DISK_NOT_AVAILABLE */
+ private int spoolNoDiskCount = 0;
+
+ /** ELEMENT_EVENT_EXCEEDED_MAXLIFE_BACKGROUND */
+ private int exceededMaxLifeBackgroundCount = 0;
+
+ /** ELEMENT_EVENT_EXCEEDED_IDLETIME_BACKGROUND */
+ private int exceededIdleTimeBackgroundCount = 0;
+
+ /**
+ * @param event
+ */
+ @Override
+ public synchronized <T> void handleElementEvent( IElementEvent<T> event )
+ {
+ setCallCount( getCallCount() + 1 );
+
+ if ( log.isDebugEnabled() )
+ {
+ log.debug( "HANDLER -- HANDLER -- HANDLER -- ---EVENT CODE = " + event.getElementEvent() );
+ log.debug( "/n/n EVENT CODE = " + event.getElementEvent() + " ***************************" );
+ }
+
+ if ( event.getElementEvent() == ElementEventType.SPOOLED_DISK_AVAILABLE )
+ {
+ setSpoolCount( getSpoolCount() + 1 );
+ }
+ else if ( event.getElementEvent() == ElementEventType.SPOOLED_NOT_ALLOWED )
+ {
+ setSpoolNotAllowedCount( getSpoolNotAllowedCount() + 1 );
+ }
+ else if ( event.getElementEvent() == ElementEventType.SPOOLED_DISK_NOT_AVAILABLE )
+ {
+ setSpoolNoDiskCount( getSpoolNoDiskCount() + 1 );
+ }
+ else if ( event.getElementEvent() == ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND )
+ {
+ setExceededMaxLifeBackgroundCount( getExceededMaxLifeBackgroundCount() + 1 );
+ }
+ else if ( event.getElementEvent() == ElementEventType.EXCEEDED_IDLETIME_BACKGROUND )
+ {
+ setExceededIdleTimeBackgroundCount( getExceededIdleTimeBackgroundCount() + 1 );
+ }
+ }
+
+ /**
+ * @param spoolCount The spoolCount to set.
+ */
+ public void setSpoolCount( int spoolCount )
+ {
+ this.spoolCount = spoolCount;
+ }
+
+ /**
+ * @return Returns the spoolCount.
+ */
+ public int getSpoolCount()
+ {
+ return spoolCount;
+ }
+
+ /**
+ * @param spoolNotAllowedCount The spoolNotAllowedCount to set.
+ */
+ public void setSpoolNotAllowedCount( int spoolNotAllowedCount )
+ {
+ this.spoolNotAllowedCount = spoolNotAllowedCount;
+ }
+
+ /**
+ * @return Returns the spoolNotAllowedCount.
+ */
+ public int getSpoolNotAllowedCount()
+ {
+ return spoolNotAllowedCount;
+ }
+
+ /**
+ * @param spoolNoDiskCount The spoolNoDiskCount to set.
+ */
+ public void setSpoolNoDiskCount( int spoolNoDiskCount )
+ {
+ this.spoolNoDiskCount = spoolNoDiskCount;
+ }
+
+ /**
+ * @return Returns the spoolNoDiskCount.
+ */
+ public int getSpoolNoDiskCount()
+ {
+ return spoolNoDiskCount;
+ }
+
+ /**
+ * @param exceededMaxLifeBackground The exceededMaxLifeBackground to set.
+ */
+ public void setExceededMaxLifeBackgroundCount( int exceededMaxLifeBackground )
+ {
+ this.exceededMaxLifeBackgroundCount = exceededMaxLifeBackground;
+ }
+
+ /**
+ * @return Returns the exceededMaxLifeBackground.
+ */
+ public int getExceededMaxLifeBackgroundCount()
+ {
+ return exceededMaxLifeBackgroundCount;
+ }
+
+ /**
+ * @param callCount The callCount to set.
+ */
+ public void setCallCount( int callCount )
+ {
+ this.callCount = callCount;
+ }
+
+ /**
+ * @return Returns the callCount.
+ */
+ public int getCallCount()
+ {
+ return callCount;
+ }
+
+ /**
+ * @param exceededIdleTimeBackground The exceededIdleTimeBackground to set.
+ */
+ public void setExceededIdleTimeBackgroundCount( int exceededIdleTimeBackground )
+ {
+ this.exceededIdleTimeBackgroundCount = exceededIdleTimeBackground;
+ }
+
+ /**
+ * @return Returns the exceededIdleTimeBackground.
+ */
+ public int getExceededIdleTimeBackgroundCount()
+ {
+ return exceededIdleTimeBackgroundCount;
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/event/SimpleEventHandlingUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/event/SimpleEventHandlingUnitTest.java
new file mode 100644
index 0000000..7ac78ae
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/control/event/SimpleEventHandlingUnitTest.java
@@ -0,0 +1,380 @@
+package org.apache.commons.jcs3.engine.control.event;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.engine.ElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.control.event.behavior.IElementEvent;
+import org.apache.commons.jcs3.engine.control.event.behavior.IElementEventHandler;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * This test suite verifies that the basic ElementEvent are called as they should be.
+ */
+public class SimpleEventHandlingUnitTest
+ extends TestCase
+{
+ /** Items to test with */
+ private static int items = 20000;
+
+ /**
+ * Test setup with expected configuration parameters.
+ */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestSimpleEventHandling.ccf" );
+ }
+
+ /**
+ * Verify that the spooled event is called as expected.
+ * <p>
+ * @throws Exception Description of the Exception
+ */
+ public void testSpoolEvent()
+ throws Exception
+ {
+ // SETUP
+ MyEventHandler meh = new MyEventHandler();
+
+ CacheAccess<String, String> jcs = JCS.getInstance( "WithDisk" );
+ // this should add the event handler to all items as they are created.
+ IElementAttributes attributes = jcs.getDefaultElementAttributes();
+ attributes.addElementEventHandler( meh );
+ jcs.setDefaultElementAttributes( attributes );
+
+ // DO WORK
+ // put them in
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", "data" + i );
+ }
+
+ // wait a bit for it to finish
+ Thread.sleep( items / 20 );
+
+ // VERIFY
+ // test to see if the count is right
+ assertTrue( "The number of ELEMENT_EVENT_SPOOLED_DISK_AVAILABLE events [" + meh.getSpoolCount()
+ + "] does not equal the number expected [" + items + "]", meh.getSpoolCount() >= items );
+ }
+
+ /**
+ * Test overflow with no disk configured for the region.
+ * <p>
+ * @throws Exception
+ */
+ public void testSpoolNoDiskEvent()
+ throws Exception
+ {
+ CacheAccess<String, String> jcs = JCS.getInstance( "NoDisk" );
+
+ MyEventHandler meh = new MyEventHandler();
+
+ // this should add the event handler to all items as they are created.
+ IElementAttributes attributes = jcs.getDefaultElementAttributes();
+ attributes.addElementEventHandler( meh );
+ jcs.setDefaultElementAttributes( attributes );
+
+ // put them in
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", "data" + i );
+ }
+
+ // wait a bit for it to finish
+ Thread.sleep( items / 20 );
+
+ // test to see if the count is right
+ assertTrue( "The number of ELEMENT_EVENT_SPOOLED_DISK_NOT_AVAILABLE events [" + meh.getSpoolNoDiskCount()
+ + "] does not equal the number expected.", meh.getSpoolNoDiskCount() >= items );
+
+ }
+
+ /**
+ * Test the ELEMENT_EVENT_SPOOLED_NOT_ALLOWED event.
+ * @throws Exception
+ */
+ public void testSpoolNotAllowedEvent()
+ throws Exception
+ {
+ MyEventHandler meh = new MyEventHandler();
+
+ CacheAccess<String, String> jcs = JCS.getInstance( "DiskButNotAllowed" );
+ // this should add the event handler to all items as they are created.
+ IElementAttributes attributes = jcs.getDefaultElementAttributes();
+ attributes.addElementEventHandler( meh );
+ jcs.setDefaultElementAttributes( attributes );
+
+ // put them in
+ for ( int i = 0; i <= items; i++ )
+ {
+ jcs.put( i + ":key", "data" + i );
+ }
+
+ // wait a bit for it to finish
+ Thread.sleep( items / 20 );
+
+ // test to see if the count is right
+ assertTrue( "The number of ELEMENT_EVENT_SPOOLED_NOT_ALLOWED events [" + meh.getSpoolNotAllowedCount()
+ + "] does not equal the number expected.", meh.getSpoolNotAllowedCount() >= items );
+
+ }
+
+ /**
+ * Test the ELEMENT_EVENT_SPOOLED_NOT_ALLOWED event.
+ * @throws Exception
+ */
+ public void testSpoolNotAllowedEventOnItem()
+ throws Exception
+ {
+ MyEventHandler meh = new MyEventHandler();
+
+ CacheAccess<String, String> jcs = JCS.getInstance( "DiskButNotAllowed" );
+ // this should add the event handler to all items as they are created.
+ //IElementAttributes attributes = jcs.getDefaultElementAttributes();
+ //attributes.addElementEventHandler( meh );
+ //jcs.setDefaultElementAttributes( attributes );
+
+ // put them in
+ for ( int i = 0; i <= items; i++ )
+ {
+ IElementAttributes attributes = jcs.getDefaultElementAttributes();
+ attributes.addElementEventHandler( meh );
+ jcs.put( i + ":key", "data" + i, attributes );
+ }
+
+ // wait a bit for it to finish
+ Thread.sleep( items / 20 );
+
+ // test to see if the count is right
+ assertTrue( "The number of ELEMENT_EVENT_SPOOLED_NOT_ALLOWED events [" + meh.getSpoolNotAllowedCount()
+ + "] does not equal the number expected.", meh.getSpoolNotAllowedCount() >= items );
+
+ }
+
+ /**
+ * Test the ELEMENT_EVENT_EXCEEDED_MAXLIFE_ONREQUEST event.
+ * @throws Exception
+ */
+ public void testExceededMaxlifeOnrequestEvent()
+ throws Exception
+ {
+ MyEventHandler meh = new MyEventHandler();
+
+ CacheAccess<String, String> jcs = JCS.getInstance( "Maxlife" );
+ // this should add the event handler to all items as they are created.
+ IElementAttributes attributes = jcs.getDefaultElementAttributes();
+ attributes.addElementEventHandler( meh );
+ jcs.setDefaultElementAttributes( attributes );
+
+ // put them in
+ for ( int i = 0; i < 200; i++ )
+ {
+ jcs.put( i + ":key", "data" + i);
+ }
+
+ // wait a bit for the items to expire
+ Thread.sleep( 3000 );
+
+ for ( int i = 0; i < 200; i++ )
+ {
+ String value = jcs.get( i + ":key");
+ assertNull("Item should be null for key " + i + ":key, but is " + value, value);
+ }
+
+ // wait a bit for it to finish
+ Thread.sleep( 100 );
+
+ // test to see if the count is right
+ assertTrue( "The number of ELEMENT_EVENT_EXCEEDED_MAXLIFE_ONREQUEST events [" + meh.getExceededMaxlifeCount()
+ + "] does not equal the number expected.", meh.getExceededMaxlifeCount() >= 200 );
+ }
+
+ /**
+ * Test the ELEMENT_EVENT_EXCEEDED_IDLETIME_ONREQUEST event.
+ * @throws Exception
+ */
+ public void testExceededIdletimeOnrequestEvent()
+ throws Exception
+ {
+ MyEventHandler meh = new MyEventHandler();
+
+ CacheAccess<String, String> jcs = JCS.getInstance( "Idletime" );
+ // this should add the event handler to all items as they are created.
+ IElementAttributes attributes = jcs.getDefaultElementAttributes();
+ attributes.addElementEventHandler( meh );
+ jcs.setDefaultElementAttributes( attributes );
+
+ // put them in
+ for ( int i = 0; i < 200; i++ )
+ {
+ jcs.put( i + ":key", "data" + i);
+ }
+
+ // update access time
+ for ( int i = 0; i < 200; i++ )
+ {
+ String value = jcs.get( i + ":key");
+ assertNotNull("Item should not be null for key " + i + ":key", value);
+ }
+
+ // wait a bit for the items to expire
+ Thread.sleep( 1500 );
+
+ for ( int i = 0; i < 200; i++ )
+ {
+ String value = jcs.get( i + ":key");
+ assertNull("Item should be null for key " + i + ":key, but is " + value, value);
+ }
+
+ // wait a bit for it to finish
+ Thread.sleep( 100 );
+
+ // test to see if the count is right
+ assertTrue( "The number of ELEMENT_EVENT_EXCEEDED_IDLETIME_ONREQUEST events [" + meh.getExceededIdletimeCount()
+ + "] does not equal the number expected.", meh.getExceededIdletimeCount() >= 200 );
+ }
+
+ /**
+ * Test that cloned ElementAttributes have different creation times.
+ * @throws Exception
+ */
+ public void testElementAttributesCreationTime()
+ throws Exception
+ {
+ ElementAttributes elem1 = new ElementAttributes();
+ long ctime1 = elem1.getCreateTime();
+
+ Thread.sleep(10);
+
+ IElementAttributes elem2 = elem1.clone();
+ long ctime2 = elem2.getCreateTime();
+
+ assertFalse("Creation times should be different", ctime1 == ctime2);
+ }
+
+ /**
+ * Simple event counter used to verify test results.
+ */
+ public static class MyEventHandler
+ implements IElementEventHandler
+ {
+ /** times spool called */
+ private int spoolCount = 0;
+
+ /** times spool not allowed */
+ private int spoolNotAllowedCount = 0;
+
+ /** times spool without disk */
+ private int spoolNoDiskCount = 0;
+
+ /** times exceeded maxlife */
+ private int exceededMaxlifeCount = 0;
+
+ /** times exceeded idle time */
+ private int exceededIdletimeCount = 0;
+
+ /**
+ * @param event
+ */
+ @Override
+ public synchronized <T> void handleElementEvent( IElementEvent<T> event )
+ {
+ //System.out.println( "Handling Event of Type " +
+ // event.getElementEvent() );
+
+ switch (event.getElementEvent())
+ {
+ case SPOOLED_DISK_AVAILABLE:
+ //System.out.println( "Handling Event of Type
+ // ELEMENT_EVENT_SPOOLED_DISK_AVAILABLE, " + getSpoolCount() );
+ spoolCount++;
+ break;
+
+ case SPOOLED_NOT_ALLOWED:
+ spoolNotAllowedCount++;
+ break;
+
+ case SPOOLED_DISK_NOT_AVAILABLE:
+ spoolNoDiskCount++;
+ break;
+
+ case EXCEEDED_MAXLIFE_ONREQUEST:
+ exceededMaxlifeCount++;
+ break;
+
+ case EXCEEDED_IDLETIME_ONREQUEST:
+ exceededIdletimeCount++;
+ break;
+
+ case EXCEEDED_IDLETIME_BACKGROUND:
+ break;
+
+ case EXCEEDED_MAXLIFE_BACKGROUND:
+ break;
+ }
+ }
+
+ /**
+ * @return Returns the spoolCount.
+ */
+ protected int getSpoolCount()
+ {
+ return spoolCount;
+ }
+
+ /**
+ * @return Returns the spoolNotAllowedCount.
+ */
+ protected int getSpoolNotAllowedCount()
+ {
+ return spoolNotAllowedCount;
+ }
+
+ /**
+ * @return Returns the spoolNoDiskCount.
+ */
+ protected int getSpoolNoDiskCount()
+ {
+ return spoolNoDiskCount;
+ }
+
+ /**
+ * @return the exceededMaxlifeCount
+ */
+ protected int getExceededMaxlifeCount()
+ {
+ return exceededMaxlifeCount;
+ }
+
+ /**
+ * @return the exceededIdletimeCount
+ */
+ protected int getExceededIdletimeCount()
+ {
+ return exceededIdletimeCount;
+ }
+ }
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/logging/CacheEventLoggerDebugLoggerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/logging/CacheEventLoggerDebugLoggerUnitTest.java
new file mode 100644
index 0000000..a4d80de
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/logging/CacheEventLoggerDebugLoggerUnitTest.java
@@ -0,0 +1,118 @@
+package org.apache.commons.jcs3.engine.logging;
+
+import java.io.StringWriter;
+
+import org.apache.commons.jcs3.TestLogConfigurationUtil;
+import org.apache.commons.jcs3.engine.logging.CacheEventLoggerDebugLogger;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEvent;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/** Unit tests for the debug implementation */
+public class CacheEventLoggerDebugLoggerUnitTest
+ extends TestCase
+{
+
+ /** verify that we can log */
+ public void testLogICacheEvent_normal()
+ {
+ // SETUP
+ String logCategoryName = "testLogEvent_normal";
+
+ String source = "mySource";
+ String region = "my region";
+ String eventName = "MyEventName";
+ String optionalDetails = "SomeExtraData";
+ String key = "my key";
+
+ StringWriter stringWriter = new StringWriter();
+ TestLogConfigurationUtil.configureLogger( stringWriter, logCategoryName );
+
+ CacheEventLoggerDebugLogger logger = new CacheEventLoggerDebugLogger();
+ logger.setLogCategoryName( logCategoryName );
+
+ ICacheEvent<String> event = logger.createICacheEvent( source, region, eventName, optionalDetails, key );
+
+ // DO WORK
+ logger.logICacheEvent( event );
+
+ // VERIFY
+ String result = stringWriter.toString();
+ assertTrue( "An event with the source should have been logged:" + result, result.indexOf( source ) != -1 );
+ assertTrue( "An event with the region should have been logged:" + result, result.indexOf( region ) != -1 );
+ assertTrue( "An event with the event name should have been logged:" + result, result.indexOf( eventName ) != -1 );
+ assertTrue( "An event with the optionalDetails should have been logged:" + result, result.indexOf( optionalDetails ) != -1 );
+ assertTrue( "An event with the key should have been logged:" + result, result.indexOf( key ) != -1 );
+ }
+
+ /** verify that we can log */
+ public void testLogApplicationEvent_normal()
+ {
+ // SETUP
+ String logCategoryName = "testLogApplicationEvent_normal";
+
+ String source = "mySource";
+ String eventName = "MyEventName";
+ String optionalDetails = "SomeExtraData";
+
+ StringWriter stringWriter = new StringWriter();
+ TestLogConfigurationUtil.configureLogger( stringWriter, logCategoryName );
+
+ CacheEventLoggerDebugLogger logger = new CacheEventLoggerDebugLogger();
+ logger.setLogCategoryName( logCategoryName );
+
+ // DO WORK
+ logger.logApplicationEvent( source, eventName, optionalDetails );
+
+ // VERIFY
+ String result = stringWriter.toString();
+ assertTrue( "An event with the source should have been logged:" + result, result.indexOf( source ) != -1 );
+ assertTrue( "An event with the event name should have been logged:" + result, result.indexOf( eventName ) != -1 );
+ assertTrue( "An event with the optionalDetails should have been logged:" + result, result.indexOf( optionalDetails ) != -1 );
+ }
+
+ /** verify that we can log */
+ public void testLogError_normal()
+ {
+ // SETUP
+ String logCategoryName = "testLogApplicationEvent_normal";
+
+ String source = "mySource";
+ String eventName = "MyEventName";
+ String errorMessage = "SomeExtraData";
+
+ StringWriter stringWriter = new StringWriter();
+ TestLogConfigurationUtil.configureLogger( stringWriter, logCategoryName );
+
+ CacheEventLoggerDebugLogger logger = new CacheEventLoggerDebugLogger();
+ logger.setLogCategoryName( logCategoryName );
+
+ // DO WORK
+ logger.logError( source, eventName, errorMessage );
+
+ // VERIFY
+ String result = stringWriter.toString();
+ assertTrue( "An event with the source should have been logged:" + result, result.indexOf( source ) != -1 );
+ assertTrue( "An event with the event name should have been logged:" + result, result.indexOf( eventName ) != -1 );
+ assertTrue( "An event with the errorMessage should have been logged:" + result, result.indexOf( errorMessage ) != -1 );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/logging/MockCacheEventLogger.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/logging/MockCacheEventLogger.java
new file mode 100644
index 0000000..036bcdb
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/logging/MockCacheEventLogger.java
@@ -0,0 +1,96 @@
+package org.apache.commons.jcs3.engine.logging;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.jcs3.engine.logging.CacheEvent;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEvent;
+import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
+
+/**
+ * For testing the configurator.
+ */
+public class MockCacheEventLogger
+ implements ICacheEventLogger
+{
+ /** test property */
+ private String testProperty;
+
+ /**
+ * @param source
+ * @param eventName
+ * @param optionalDetails
+ */
+ @Override
+ public void logApplicationEvent( String source, String eventName, String optionalDetails )
+ {
+ // TODO Auto-generated method stub
+ }
+
+ /**
+ * @param source
+ * @param eventName
+ * @param errorMessage
+ */
+ @Override
+ public void logError( String source, String eventName, String errorMessage )
+ {
+ // TODO Auto-generated method stub
+ }
+
+ /**
+ * @param source
+ * @param region
+ * @param eventName
+ * @param optionalDetails
+ * @param key
+ * @return ICacheEvent
+ */
+ @Override
+ public <T> ICacheEvent<T> createICacheEvent( String source, String region, String eventName, String optionalDetails,
+ T key )
+ {
+ return new CacheEvent<>();
+ }
+
+ /**
+ * @param event
+ */
+ @Override
+ public <T> void logICacheEvent( ICacheEvent<T> event )
+ {
+ // TODO Auto-generated method stub
+ }
+
+ /**
+ * @param testProperty
+ */
+ public void setTestProperty( String testProperty )
+ {
+ this.testProperty = testProperty;
+ }
+
+ /**
+ * @return testProperty
+ */
+ public String getTestProperty()
+ {
+ return testProperty;
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/match/KeyMatcherPatternImpllUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/match/KeyMatcherPatternImpllUnitTest.java
new file mode 100644
index 0000000..eea1518
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/match/KeyMatcherPatternImpllUnitTest.java
@@ -0,0 +1,120 @@
+package org.apache.commons.jcs3.engine.match;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.commons.jcs3.engine.match.KeyMatcherPatternImpl;
+
+/** Unit tests for the key matcher. */
+public class KeyMatcherPatternImpllUnitTest
+ extends TestCase
+{
+ /**
+ * Verify that the matching method works.
+ */
+ public void testGetMatchingKeysFromArray_AllMatch()
+ {
+ // SETUP
+ int numToInsertPrefix1 = 10;
+ Set<String> keyArray = new HashSet<>();
+
+ String keyprefix1 = "MyPrefixC";
+
+ // insert with prefix1
+ for ( int i = 0; i < numToInsertPrefix1; i++ )
+ {
+ keyArray.add(keyprefix1 + String.valueOf( i ));
+ }
+
+ KeyMatcherPatternImpl<String> keyMatcher = new KeyMatcherPatternImpl<>();
+
+ // DO WORK
+ Set<String> result1 = keyMatcher.getMatchingKeysFromArray( keyprefix1 + ".", keyArray );
+
+ // VERIFY
+ assertEquals( "Wrong number returned 1: " + result1, numToInsertPrefix1, result1.size() );
+ }
+
+ /**
+ * Verify that the matching method works.
+ */
+ public void testGetMatchingKeysFromArray_AllMatchFirstNull()
+ {
+ // SETUP
+ int numToInsertPrefix1 = 10;
+ Set<String> keyArray = new HashSet<>();
+
+ String keyprefix1 = "MyPrefixC";
+
+ // insert with prefix1
+ for ( int i = 1; i < numToInsertPrefix1 + 1; i++ )
+ {
+ keyArray.add(keyprefix1 + String.valueOf( i ));
+ }
+
+ KeyMatcherPatternImpl<String> keyMatcher = new KeyMatcherPatternImpl<>();
+
+ // DO WORK
+ Set<String> result1 = keyMatcher.getMatchingKeysFromArray( keyprefix1 + "\\S+", keyArray );
+
+ // VERIFY
+ assertEquals( "Wrong number returned 1: " + result1, numToInsertPrefix1, result1.size() );
+ }
+
+ /**
+ * Verify that the matching method works.
+ */
+ public void testGetMatchingKeysFromArray_TwoTypes()
+ {
+ // SETUP
+ int numToInsertPrefix1 = 10;
+ int numToInsertPrefix2 = 50;
+ Set<String> keyArray = new HashSet<>();
+
+ String keyprefix1 = "MyPrefixA";
+ String keyprefix2 = "MyPrefixB";
+
+ // insert with prefix1
+ for ( int i = 0; i < numToInsertPrefix1; i++ )
+ {
+ keyArray.add(keyprefix1 + String.valueOf( i ));
+ }
+
+ // insert with prefix2
+ for ( int i = numToInsertPrefix1; i < numToInsertPrefix2 + numToInsertPrefix1; i++ )
+ {
+ keyArray.add(keyprefix2 + String.valueOf( i ));
+ }
+
+ KeyMatcherPatternImpl<String> keyMatcher = new KeyMatcherPatternImpl<>();
+
+ // DO WORK
+ Set<String> result1 = keyMatcher.getMatchingKeysFromArray( keyprefix1 + ".+", keyArray );
+ Set<String> result2 = keyMatcher.getMatchingKeysFromArray( keyprefix2 + ".+", keyArray );
+
+ // VERIFY
+ assertEquals( "Wrong number returned 1: " + result1, numToInsertPrefix1, result1.size() );
+ assertEquals( "Wrong number returned 2: " + result2, numToInsertPrefix2, result2.size() );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/MockMemoryCache.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/MockMemoryCache.java
new file mode 100644
index 0000000..29e7f9d
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/MockMemoryCache.java
@@ -0,0 +1,255 @@
+package org.apache.commons.jcs3.engine.memory;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.memory.behavior.IMemoryCache;
+import org.apache.commons.jcs3.engine.stats.behavior.IStats;
+
+/**
+ * Mock implementation of a memory cache for testing things like the memory shrinker.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class MockMemoryCache<K, V>
+ implements IMemoryCache<K, V>
+{
+ /** Config */
+ private ICompositeCacheAttributes cacheAttr;
+
+ /** Internal map */
+ private final HashMap<K, ICacheElement<K, V>> map = new HashMap<>();
+
+ /** The number of times waterfall was called. */
+ public int waterfallCallCount = 0;
+
+ /** The number passed to the last call of free elements. */
+ public int lastNumberOfFreedElements = 0;
+
+ /**
+ * Does nothing
+ * @param cache
+ */
+ @Override
+ public void initialize( CompositeCache<K, V> cache )
+ {
+ // nothing
+ }
+
+ /**
+ * Destroy the memory cache
+ * <p>
+ * @throws IOException
+ */
+ @Override
+ public void dispose()
+ throws IOException
+ {
+ // nothing
+ }
+
+ /** @return size */
+ @Override
+ public int getSize()
+ {
+ return map.size();
+ }
+
+ /** @return stats */
+ @Override
+ public IStats getStatistics()
+ {
+ return null;
+ }
+
+ /**
+ * @return map.keySet().toArray( */
+ @Override
+ public Set<K> getKeySet()
+ {
+ return new LinkedHashSet<>(map.keySet());
+ }
+
+ /**
+ * @param key
+ * @return map.remove( key ) != null
+ * @throws IOException
+ */
+ @Override
+ public boolean remove( K key )
+ throws IOException
+ {
+ return map.remove( key ) != null;
+ }
+
+ /**
+ * @throws IOException
+ */
+ @Override
+ public void removeAll()
+ throws IOException
+ {
+ map.clear();
+ }
+
+ /**
+ * @param key
+ * @return (ICacheElement) map.get( key )
+ * @throws IOException
+ */
+ @Override
+ public ICacheElement<K, V> get( K key )
+ throws IOException
+ {
+ return map.get( key );
+ }
+
+ /**
+ * @param keys
+ * @return elements
+ * @throws IOException
+ */
+ @Override
+ public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
+ throws IOException
+ {
+ Map<K, ICacheElement<K, V>> elements = new HashMap<>();
+
+ if ( keys != null && !keys.isEmpty() )
+ {
+ Iterator<K> iterator = keys.iterator();
+
+ while ( iterator.hasNext() )
+ {
+ K key = iterator.next();
+
+ ICacheElement<K, V> element = get( key );
+
+ if ( element != null )
+ {
+ elements.put( key, element );
+ }
+ }
+ }
+
+ return elements;
+ }
+
+ /**
+ * @param key
+ * @return (ICacheElement) map.get( key )
+ * @throws IOException
+ */
+ @Override
+ public ICacheElement<K, V> getQuiet( K key )
+ throws IOException
+ {
+ return map.get( key );
+ }
+
+ /**
+ * @param ce
+ * @throws IOException
+ */
+ @Override
+ public void waterfal( ICacheElement<K, V> ce )
+ throws IOException
+ {
+ waterfallCallCount++;
+ }
+
+ /**
+ * @param ce
+ * @throws IOException
+ */
+ @Override
+ public void update( ICacheElement<K, V> ce )
+ throws IOException
+ {
+ if ( ce != null )
+ {
+ map.put( ce.getKey(), ce );
+ }
+ }
+
+ /**
+ * @return ICompositeCacheAttributes
+ */
+ @Override
+ public ICompositeCacheAttributes getCacheAttributes()
+ {
+ return cacheAttr;
+ }
+
+ /**
+ * @param cattr
+ */
+ @Override
+ public void setCacheAttributes( ICompositeCacheAttributes cattr )
+ {
+ this.cacheAttr = cattr;
+ }
+
+ /** @return null */
+ @Override
+ public CompositeCache<K, V> getCompositeCache()
+ {
+ return null;
+ }
+
+ /**
+ * @param group
+ * @return null
+ */
+ public Set<K> getGroupKeys( String group )
+ {
+ return null;
+ }
+
+ /**
+ * @return null
+ */
+ public Set<String> getGroupNames()
+ {
+ return null;
+ }
+
+ /**
+ * @param numberToFree
+ * @return 0
+ * @throws IOException
+ */
+ @Override
+ public int freeElements( int numberToFree )
+ throws IOException
+ {
+ lastNumberOfFreedElements = numberToFree;
+ return 0;
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/fifo/FIFOMemoryCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/fifo/FIFOMemoryCacheUnitTest.java
new file mode 100644
index 0000000..f6095a0
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/fifo/FIFOMemoryCacheUnitTest.java
@@ -0,0 +1,112 @@
+package org.apache.commons.jcs3.engine.memory.fifo;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.CompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.ElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.memory.fifo.FIFOMemoryCache;
+
+import junit.framework.TestCase;
+
+/** Unit tests for the fifo implementation. */
+public class FIFOMemoryCacheUnitTest
+ extends TestCase
+{
+ /**
+ * Verify that the oldest inserted item is removed
+ * <p>
+ * @throws IOException
+ */
+ public void testExpirationPolicy_oneExtra()
+ throws IOException
+ {
+ // SETUP
+ int maxObjects = 10;
+ String cacheName = "testExpirationPolicy_oneExtra";
+
+ ICompositeCacheAttributes attributes = new CompositeCacheAttributes();
+ attributes.setCacheName(cacheName);
+ attributes.setMaxObjects( maxObjects );
+ attributes.setSpoolChunkSize( 1 );
+
+ FIFOMemoryCache<String, String> cache = new FIFOMemoryCache<>();
+ cache.initialize( new CompositeCache<>( attributes, new ElementAttributes() ) );
+
+ for ( int i = 0; i <= maxObjects; i++ )
+ {
+ CacheElement<String, String> element = new CacheElement<>( cacheName, "key" + i, "value" + i );
+ cache.update( element );
+ }
+
+ CacheElement<String, String> oneMoreElement = new CacheElement<>( cacheName, "onemore", "onemore" );
+
+ // DO WORK
+ cache.update( oneMoreElement );
+
+ // VERIFY
+ assertEquals( "Should have max elements", maxObjects, cache.getSize() );
+ System.out.println(cache.getKeySet());
+ for ( int i = maxObjects; i > 1; i-- )
+ {
+ assertNotNull( "Should have element " + i, cache.get( "key" + i ) );
+ }
+ assertNotNull( "Should have oneMoreElement", cache.get( "onemore" ) );
+ }
+
+ /**
+ * Verify that the oldest inserted item is removed
+ * <p>
+ * @throws IOException
+ */
+ public void testExpirationPolicy_doubleOver()
+ throws IOException
+ {
+ // SETUP
+ int maxObjects = 10;
+ String cacheName = "testExpirationPolicy_oneExtra";
+
+ ICompositeCacheAttributes attributes = new CompositeCacheAttributes();
+ attributes.setCacheName(cacheName);
+ attributes.setMaxObjects( maxObjects );
+ attributes.setSpoolChunkSize( 1 );
+
+ FIFOMemoryCache<String, String> cache = new FIFOMemoryCache<>();
+ cache.initialize( new CompositeCache<>( attributes, new ElementAttributes() ) );
+
+ // DO WORK
+ for ( int i = 0; i <= (maxObjects * 2); i++ )
+ {
+ CacheElement<String, String> element = new CacheElement<>( cacheName, "key" + i, "value" + i );
+ cache.update( element );
+ }
+
+ // VERIFY
+ assertEquals( "Should have max elements", maxObjects, cache.getSize() );
+ for ( int i = (maxObjects * 2); i > maxObjects; i-- )
+ {
+ assertNotNull( "Shjould have elemnt " + i, cache.get( "key" + i ) );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/lru/LHMLRUMemoryCacheConcurrentUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/lru/LHMLRUMemoryCacheConcurrentUnitTest.java
new file mode 100644
index 0000000..b403244
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/lru/LHMLRUMemoryCacheConcurrentUnitTest.java
@@ -0,0 +1,177 @@
+package org.apache.commons.jcs3.engine.memory.lru;
+
+/*
+ * 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.
+ */
+
+import junit.extensions.ActiveTestSuite;
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+import org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache;
+
+/**
+ * Test which exercises the LRUMemory cache. This one uses three different
+ * regions for three threads.
+ */
+public class LHMLRUMemoryCacheConcurrentUnitTest
+ extends TestCase
+{
+ /**
+ * Number of items to cache, twice the configured maxObjects for the memory
+ * cache regions.
+ */
+ private static int items = 200;
+
+ /**
+ * Constructor for the TestDiskCache object.
+ *
+ * @param testName
+ */
+ public LHMLRUMemoryCacheConcurrentUnitTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * Main method passes this test to the text test runner.
+ *
+ * @param args
+ */
+ public static void main( String args[] )
+ {
+ String[] testCaseName = { LHMLRUMemoryCacheConcurrentUnitTest.class.getName() };
+ junit.textui.TestRunner.main( testCaseName );
+ }
+
+ /**
+ * A unit test suite for JUnit
+ * <p>
+ * @return The test suite
+ */
+ public static Test suite()
+ {
+ ActiveTestSuite suite = new ActiveTestSuite();
+
+ suite.addTest( new LHMLRUMemoryCacheConcurrentUnitTest( "testLHMLRUMemoryCache" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "indexedRegion1" );
+ }
+ } );
+
+ return suite;
+ }
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ //JCS.setConfigFilename( "/TestLHMLRUCache.ccf" );
+ }
+
+ /**
+ * Adds items to cache, gets them, and removes them. The item count is more
+ * than the size of the memory cache, so items should be dumped.
+ * <p>
+ * @param region
+ * Name of the region to access
+ *
+ * @throws Exception
+ * If an error occurs
+ */
+ public void runTestForRegion( String region )
+ throws Exception
+ {
+ CompositeCacheManager cacheMgr = CompositeCacheManager.getUnconfiguredInstance();
+ cacheMgr.configure( "/TestLHMLRUCache.ccf" );
+ CompositeCache<String, String> cache = cacheMgr.getCache( region );
+
+ LRUMemoryCache<String, String> lru = new LRUMemoryCache<>();
+ lru.initialize( cache );
+
+ // Add items to cache
+
+ for ( int i = 0; i < items; i++ )
+ {
+ ICacheElement<String, String> ice = new CacheElement<>( cache.getCacheName(), i + ":key", region + " data " + i );
+ ice.setElementAttributes( cache.getElementAttributes() );
+ lru.update( ice );
+ }
+
+ // Test that initial items have been purged
+ for ( int i = 0; i < 100; i++ )
+ {
+ assertNull( "Should not have " + i + ":key", lru.get( i + ":key" ) );
+ }
+
+ // Test that last items are in cache
+ for ( int i = 100; i < items; i++ )
+ {
+ String value = lru.get( i + ":key" ).getVal();
+ assertEquals( region + " data " + i, value );
+ }
+
+ // Test that getMultiple returns all the items remaining in cache and none of the missing ones
+ Set<String> keys = new HashSet<>();
+ for ( int i = 0; i < items; i++ )
+ {
+ keys.add( i + ":key" );
+ }
+
+ Map<String, ICacheElement<String, String>> elements = lru.getMultiple( keys );
+ for ( int i = 0; i < 100; i++ )
+ {
+ assertNull( "Should not have " + i + ":key", elements.get( i + ":key" ) );
+ }
+ for ( int i = 100; i < items; i++ )
+ {
+ ICacheElement<String, String> element = elements.get( i + ":key" );
+ assertNotNull( "element " + i + ":key is missing", element );
+ assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
+ }
+
+ // Remove all the items
+
+ for ( int i = 0; i < items; i++ )
+ {
+ lru.remove( i + ":key" );
+ }
+
+ // Verify removal
+
+ for ( int i = 0; i < items; i++ )
+ {
+ assertNull( "Removed key should be null: " + i + ":key", lru.get( i + ":key" ) );
+ }
+ }
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/lru/LHMLRUMemoryCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/lru/LHMLRUMemoryCacheUnitTest.java
new file mode 100644
index 0000000..c73d915
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/lru/LHMLRUMemoryCacheUnitTest.java
@@ -0,0 +1,314 @@
+package org.apache.commons.jcs3.engine.memory.lru;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+import org.apache.commons.jcs3.engine.memory.lru.LHMLRUMemoryCache;
+
+/**
+ * Tests for the test LHMLRU implementation.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class LHMLRUMemoryCacheUnitTest
+ extends TestCase
+{
+ /** Test setup */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestLHMLRUCache.ccf" );
+ }
+
+ /**
+ * Verify that the mru gets used by a non-defined region when it is set as the default in the
+ * default region.
+ * <p>
+ * @throws CacheException
+ */
+ public void testLoadFromCCF()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testLoadFromCCF" );
+ String memoryCacheName = cache.getCacheAttributes().getMemoryCacheName();
+ assertTrue( "Cache name should have LHMLRU in it.", memoryCacheName.indexOf( "LHMLRUMemoryCache" ) != -1 );
+ }
+
+ /**
+ * put twice as many as the max. verify that the second half is in the cache.
+ * <p>
+ * @throws CacheException
+ */
+ public void testPutGetThroughHub()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testPutGetThroughHub" );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max * 2;
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.put( i + ":key", "myregion" + " data " + i );
+ }
+
+ // Test that first items are not in the cache
+ for ( int i = max -1; i >= 0; i-- )
+ {
+ String value = cache.get( i + ":key" );
+ assertNull( "Should not have value for key [" + i + ":key" + "] in the cache." + cache.getStats(), value );
+ }
+
+ // Test that last items are in cache
+ // skip 2 for the buffer.
+ for ( int i = max + 2; i < items; i++ )
+ {
+ String value = cache.get( i + ":key" );
+ assertEquals( "myregion" + " data " + i, value );
+ }
+
+ // Test that getMultiple returns all the items remaining in cache and none of the missing ones
+ Set<String> keys = new HashSet<>();
+ for ( int i = 0; i < items; i++ )
+ {
+ keys.add( i + ":key" );
+ }
+
+ Map<String, ICacheElement<String, String>> elements = cache.getCacheElements( keys );
+ for ( int i = max-1; i >= 0; i-- )
+ {
+ assertNull( "Should not have value for key [" + i + ":key" + "] in the cache." + cache.getStats(), elements.get( i + ":key" ) );
+ }
+ for ( int i = max + 2; i < items; i++ )
+ {
+ ICacheElement<String, String> element = elements.get( i + ":key" );
+ assertNotNull( "element " + i + ":key is missing", element );
+ assertEquals( "value " + i + ":key", "myregion" + " data " + i, element.getVal() );
+ }
+ }
+
+ /**
+ * Put twice as many as the max, twice. verify that the second half is in the cache.
+ * <p>
+ * @throws CacheException
+ */
+ public void testPutGetThroughHubTwice()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testPutGetThroughHubTwice" );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max * 2;
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.put( i + ":key", "myregion" + " data " + i );
+ }
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.put( i + ":key", "myregion" + " data " + i );
+ }
+
+ // Test that first items are not in the cache
+ for ( int i = max -1; i >= 0; i-- )
+ {
+ String value = cache.get( i + ":key" );
+ assertNull( "Should not have value for key [" + i + ":key" + "] in the cache.", value );
+ }
+
+ // Test that last items are in cache
+ // skip 2 for the buffer.
+ for ( int i = max + 2; i < items; i++ )
+ {
+ String value = cache.get( i + ":key" );
+ assertEquals( "myregion" + " data " + i, value );
+ }
+
+ }
+
+ /**
+ * put the max and remove each. verify that they are all null.
+ * <p>
+ * @throws CacheException
+ */
+ public void testPutRemoveThroughHub()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testPutRemoveThroughHub" );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max * 2;
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.put( i + ":key", "myregion" + " data " + i );
+ }
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.remove( i + ":key" );
+ }
+
+ // Test that first items are not in the cache
+ for ( int i = max; i >= 0; i-- )
+ {
+ String value = cache.get( i + ":key" );
+ assertNull( "Should not have value for key [" + i + ":key" + "] in the cache.", value );
+ }
+ }
+
+ /**
+ * put the max and clear. verify that no elements remain.
+ * <p>
+ * @throws CacheException
+ */
+ public void testClearThroughHub()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testClearThroughHub" );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max * 2;
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.put( i + ":key", "myregion" + " data " + i );
+ }
+
+ cache.clear();
+
+ // Test that first items are not in the cache
+ for ( int i = max; i >= 0; i-- )
+ {
+ String value = cache.get( i + ":key" );
+ assertNull( "Should not have value for key [" + i + ":key" + "] in the cache.", value );
+ }
+ }
+
+ /**
+ * Get stats.
+ * <p>
+ * @throws CacheException
+ */
+ public void testGetStatsThroughHub()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testGetStatsThroughHub" );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max * 2;
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.put( i + ":key", "myregion" + " data " + i );
+ }
+
+ String stats = cache.getStats();
+
+ //System.out.println( stats );
+
+ // TODO improve stats check
+ assertTrue( "Should have 200 puts" + stats, stats.indexOf( "200" ) != -1 );
+ }
+
+ /**
+ * Put half the max and clear. get the key array and verify that it has the correct number of
+ * items.
+ * <p>
+ * @throws Exception
+ */
+ public void testGetKeyArray()
+ throws Exception
+ {
+ CompositeCacheManager cacheMgr = CompositeCacheManager.getUnconfiguredInstance();
+ cacheMgr.configure( "/TestLHMLRUCache.ccf" );
+ CompositeCache<String, String> cache = cacheMgr.getCache( "testGetKeyArray" );
+
+ LHMLRUMemoryCache<String, String> mru = new LHMLRUMemoryCache<>();
+ mru.initialize( cache );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max / 2;
+
+ for ( int i = 0; i < items; i++ )
+ {
+ ICacheElement<String, String> ice = new CacheElement<>( cache.getCacheName(), i + ":key", cache.getCacheName() + " data " + i );
+ ice.setElementAttributes( cache.getElementAttributes() );
+ mru.update( ice );
+ }
+
+ Set<String> keys = mru.getKeySet();
+
+ assertEquals( "Wrong number of keys.", items, keys.size() );
+ }
+
+ /**
+ * Add a few keys with the delimiter. Remove them.
+ * <p>
+ * @throws CacheException
+ */
+ public void testRemovePartialThroughHub()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testRemovePartialThroughHub" );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max / 2;
+
+ cache.put( "test", "data" );
+
+ String root = "myroot";
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.put( root + ":" + i + ":key", "myregion" + " data " + i );
+ }
+
+ // Test that last items are in cache
+ for ( int i = 0; i < items; i++ )
+ {
+ String value = cache.get( root + ":" + i + ":key" );
+ assertEquals( "myregion" + " data " + i, value );
+ }
+
+ // remove partial
+ cache.remove( root + ":" );
+
+ for ( int i = 0; i < items; i++ )
+ {
+ assertNull( "Should have been removed by partial loop.", cache.get( root + ":" + i + ":key" ) );
+ }
+
+ assertNotNull( "Other item should be in the cache.", cache.get( "test" ) );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/lru/LRUMemoryCacheConcurrentUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/lru/LRUMemoryCacheConcurrentUnitTest.java
new file mode 100644
index 0000000..4af77dc
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/lru/LRUMemoryCacheConcurrentUnitTest.java
@@ -0,0 +1,173 @@
+package org.apache.commons.jcs3.engine.memory.lru;
+
+/*
+ * 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.
+ */
+
+import junit.extensions.ActiveTestSuite;
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+import org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache;
+
+/**
+ * Test which exercises the LRUMemory cache. This one uses three different
+ * regions for three threads.
+ */
+public class LRUMemoryCacheConcurrentUnitTest
+ extends TestCase
+{
+ /**
+ * Number of items to cache, twice the configured maxObjects for the memory
+ * cache regions.
+ */
+ private static int items = 200;
+
+ /**
+ * Constructor for the TestDiskCache object.
+ * <p>
+ * @param testName
+ */
+ public LRUMemoryCacheConcurrentUnitTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * Main method passes this test to the text test runner.
+ * <p>
+ * @param args
+ */
+ public static void main( String args[] )
+ {
+ String[] testCaseName = { LRUMemoryCacheConcurrentUnitTest.class.getName() };
+ junit.textui.TestRunner.main( testCaseName );
+ }
+
+ /**
+ * A unit test suite for JUnit
+ * <p>
+ * @return The test suite
+ */
+ public static Test suite()
+ {
+ ActiveTestSuite suite = new ActiveTestSuite();
+
+ suite.addTest( new LRUMemoryCacheConcurrentUnitTest( "testLRUMemoryCache" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runTestForRegion( "testRegion1" );
+ }
+ } );
+
+ return suite;
+ }
+
+ /**
+ * Test setup
+ */
+ @Override
+ public void setUp()
+ {
+ //JCS.setConfigFilename( "/TestDiskCache.ccf" );
+ }
+
+ /**
+ * Adds items to cache, gets them, and removes them. The item count is more
+ * than the size of the memory cache, so items should be dumped.
+ * <p>
+ * @param region
+ * Name of the region to access
+ * @throws Exception
+ * If an error occurs
+ */
+ public void runTestForRegion( String region )
+ throws Exception
+ {
+ CompositeCacheManager cacheMgr = CompositeCacheManager.getUnconfiguredInstance();
+ cacheMgr.configure( "/TestDiskCache.ccf" );
+ CompositeCache<String, String> cache = cacheMgr.getCache( region );
+
+ LRUMemoryCache<String, String> lru = new LRUMemoryCache<>();
+ lru.initialize( cache );
+
+ // Add items to cache
+
+ for ( int i = 0; i < items; i++ )
+ {
+ ICacheElement<String, String> ice = new CacheElement<>( cache.getCacheName(), i + ":key", region + " data " + i );
+ ice.setElementAttributes( cache.getElementAttributes() );
+ lru.update( ice );
+ }
+
+ // Test that initial items have been purged
+ for ( int i = 0; i < 100; i++ )
+ {
+ assertNull( "Should not have " + i + ":key", lru.get( i + ":key" ) );
+ }
+
+ // Test that last items are in cache
+ for ( int i = 100; i < items; i++ )
+ {
+ String value = lru.get( i + ":key" ).getVal();
+ assertEquals( region + " data " + i, value );
+ }
+
+ // Test that getMultiple returns all the items remaining in cache and none of the missing ones
+ Set<String> keys = new HashSet<>();
+ for ( int i = 0; i < items; i++ )
+ {
+ keys.add( i + ":key" );
+ }
+
+ Map<String, ICacheElement<String, String>> elements = lru.getMultiple( keys );
+ for ( int i = 0; i < 100; i++ )
+ {
+ assertNull( "Should not have " + i + ":key", elements.get( i + ":key" ) );
+ }
+ for ( int i = 100; i < items; i++ )
+ {
+ ICacheElement<String, String> element = elements.get( i + ":key" );
+ assertNotNull( "element " + i + ":key is missing", element );
+ assertEquals( "value " + i + ":key", region + " data " + i, element.getVal() );
+ }
+
+ // Remove all the items
+ for ( int i = 0; i < items; i++ )
+ {
+ lru.remove( i + ":key" );
+ }
+
+ // Verify removal
+ for ( int i = 0; i < items; i++ )
+ {
+ assertNull( "Removed key should be null: " + i + ":key", lru.get( i + ":key" ) );
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/mru/LRUvsMRUPerformanceTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/mru/LRUvsMRUPerformanceTest.java
new file mode 100644
index 0000000..b2524c7
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/mru/LRUvsMRUPerformanceTest.java
@@ -0,0 +1,185 @@
+package org.apache.commons.jcs3.engine.memory.mru;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache;
+import org.apache.commons.jcs3.engine.memory.mru.MRUMemoryCache;
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Tests the performance difference between the LRU and the MRU. There should be very little.
+ */
+public class LRUvsMRUPerformanceTest
+ extends TestCase
+{
+ /** ration we want */
+ float ratioPut = 0;
+
+ /** ration we want */
+ float ratioGet = 0;
+
+ /** ration we want */
+ float target = 1.20f;
+
+ /** times to run */
+ int loops = 20;
+
+ /** item per run */
+ int tries = 10000;
+
+ /**
+ * A unit test for JUnit
+ * @throws Exception Description of the Exception
+ */
+ public void testSimpleLoad()
+ throws Exception
+ {
+ Log log1 = LogManager.getLog( LRUMemoryCache.class );
+ if ( log1.isDebugEnabled() )
+ {
+ System.out.println( "The log level must be at info or above for the a performance test." );
+ return;
+ }
+ Log log2 = LogManager.getLog( MRUMemoryCache.class );
+ if ( log2.isDebugEnabled() )
+ {
+ System.out.println( "The log level must be at info or above for the a performance test." );
+ return;
+ }
+ doWork();
+
+ // these were when the mru was implemented with the jdk linked list
+ //assertTrue( "Ratio is unacceptible.", this.ratioPut < target );
+ ///assertTrue( "Ratio is unacceptible.", this.ratioGet < target );
+ }
+
+ /**
+ * Runs the test
+ */
+ public void doWork()
+ {
+
+ long start = 0;
+ long end = 0;
+ long time = 0;
+ float tPer = 0;
+
+ long putTotalLRU = 0;
+ long getTotalLRU = 0;
+ long putTotalMRU = 0;
+ long getTotalMRU = 0;
+
+ try
+ {
+
+ JCS.setConfigFilename( "/TestMRUCache.ccf" );
+ CacheAccess<String, String> cache = JCS.getInstance( "lruDefined" );
+ CacheAccess<String, String> mru = JCS.getInstance( "mruDefined" );
+
+ System.out.println( "LRU = " + cache );
+
+ for ( int j = 0; j < loops; j++ )
+ {
+
+ System.out.println( "Beginning loop " + j );
+
+ String name = "LRU ";
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ cache.put( "key:" + i, "data" + i );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ putTotalLRU += time;
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( name + " put time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ cache.get( "key:" + i );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ getTotalLRU += time;
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ // /////////////////////////////////////////////////////////////
+ name = "MRU";
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ mru.put( "key:" + i, "data" + i );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ putTotalMRU += time;
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( name + " put time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ mru.get( "key:" + i );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ getTotalMRU += time;
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ System.out.println( "\n" );
+ }
+
+ }
+ catch ( Exception e )
+ {
+ e.printStackTrace( System.out );
+ System.out.println( e );
+ }
+
+ long putAvJCS = putTotalLRU / loops;
+ long getAvJCS = getTotalLRU / loops;
+ long putAvHashtable = putTotalMRU / loops;
+ long getAvHashtable = getTotalMRU / loops;
+
+ System.out.println( "Finished " + loops + " loops of " + tries + " gets and puts" );
+
+ System.out.println( "\n" );
+ System.out.println( "Put average for JCS = " + putAvJCS );
+ System.out.println( "Put average for MRU = " + putAvHashtable );
+ ratioPut = Float.intBitsToFloat( (int) putAvJCS ) / Float.intBitsToFloat( (int) putAvHashtable );
+ System.out.println( "JCS puts took " + ratioPut + " times the Hashtable, the goal is <" + target + "x" );
+
+ System.out.println( "\n" );
+ System.out.println( "Get average for JCS = " + getAvJCS );
+ System.out.println( "Get average for MRU = " + getAvHashtable );
+ ratioGet = Float.intBitsToFloat( (int) getAvJCS ) / Float.intBitsToFloat( (int) getAvHashtable );
+ System.out.println( "JCS gets took " + ratioGet + " times the Hashtable, the goal is <" + target + "x" );
+ }
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/mru/MRUMemoryCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/mru/MRUMemoryCacheUnitTest.java
new file mode 100644
index 0000000..42ce655
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/mru/MRUMemoryCacheUnitTest.java
@@ -0,0 +1,314 @@
+package org.apache.commons.jcs3.engine.memory.mru;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+import org.apache.commons.jcs3.engine.memory.mru.MRUMemoryCache;
+
+/**
+ * Tests for the test MRU implementation.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class MRUMemoryCacheUnitTest
+ extends TestCase
+{
+ /** Test setup */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestMRUCache.ccf" );
+ }
+
+ /**
+ * Verify that the mru gets used by a non-defined region when it is set as the default in the
+ * default region.
+ * <p>
+ * @throws CacheException
+ */
+ public void testLoadFromCCF()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testPutGet" );
+ String memoryCacheName = cache.getCacheAttributes().getMemoryCacheName();
+ assertTrue( "Cache name should have MRU in it.", memoryCacheName.indexOf( "MRUMemoryCache" ) != -1 );
+ }
+
+ /**
+ * put twice as many as the max. verify that the second half is in the cache.
+ * <p>
+ * @throws CacheException
+ */
+ public void testPutGetThroughHub()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testPutGetThroughHub" );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max * 2;
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.put( i + ":key", "myregion" + " data " + i );
+ }
+
+ // Test that first items are not in the cache
+ for ( int i = max -1; i >= 0; i-- )
+ {
+ String value = cache.get( i + ":key" );
+ assertNull( "Should not have value for key [" + i + ":key" + "] in the cache." + cache.getStats(), value );
+ }
+
+ // Test that last items are in cache
+ // skip 2 for the buffer.
+ for ( int i = max + 2; i < items; i++ )
+ {
+ String value = cache.get( i + ":key" );
+ assertEquals( "myregion" + " data " + i, value );
+ }
+
+ // Test that getMultiple returns all the items remaining in cache and none of the missing ones
+ Set<String> keys = new HashSet<>();
+ for ( int i = 0; i < items; i++ )
+ {
+ keys.add( i + ":key" );
+ }
+
+ Map<String, ICacheElement<String, String>> elements = cache.getCacheElements( keys );
+ for ( int i = max-1; i >= 0; i-- )
+ {
+ assertNull( "Should not have value for key [" + i + ":key" + "] in the cache." + cache.getStats(), elements.get( i + ":key" ) );
+ }
+ for ( int i = max + 2; i < items; i++ )
+ {
+ ICacheElement<String, String> element = elements.get( i + ":key" );
+ assertNotNull( "element " + i + ":key is missing", element );
+ assertEquals( "value " + i + ":key", "myregion" + " data " + i, element.getVal() );
+ }
+ }
+
+ /**
+ * Put twice as many as the max, twice. verify that the second half is in the cache.
+ * <p>
+ * @throws CacheException
+ */
+ public void testPutGetThroughHubTwice()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testPutGetThroughHub" );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max * 2;
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.put( i + ":key", "myregion" + " data " + i );
+ }
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.put( i + ":key", "myregion" + " data " + i );
+ }
+
+ // Test that first items are not in the cache
+ for ( int i = max-1; i >= 0; i-- )
+ {
+ String value = cache.get( i + ":key" );
+ assertNull( "Should not have value for key [" + i + ":key" + "] in the cache.", value );
+ }
+
+ // Test that last items are in cache
+ // skip 2 for the buffer.
+ for ( int i = max + 2; i < items; i++ )
+ {
+ String value = cache.get( i + ":key" );
+ assertEquals( "myregion" + " data " + i, value );
+ }
+
+ }
+
+ /**
+ * put the max and remove each. verify that they are all null.
+ * <p>
+ * @throws CacheException
+ */
+ public void testPutRemoveThroughHub()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testPutGetThroughHub" );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max * 2;
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.put( i + ":key", "myregion" + " data " + i );
+ }
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.remove( i + ":key" );
+ }
+
+ // Test that first items are not in the cache
+ for ( int i = max; i >= 0; i-- )
+ {
+ String value = cache.get( i + ":key" );
+ assertNull( "Should not have value for key [" + i + ":key" + "] in the cache.", value );
+ }
+ }
+
+ /**
+ * put the max and clear. verify that no elements remain.
+ * <p>
+ * @throws CacheException
+ */
+ public void testClearThroughHub()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testPutGetThroughHub" );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max * 2;
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.put( i + ":key", "myregion" + " data " + i );
+ }
+
+ cache.clear();
+
+ // Test that first items are not in the cache
+ for ( int i = max; i >= 0; i-- )
+ {
+ String value = cache.get( i + ":key" );
+ assertNull( "Should not have value for key [" + i + ":key" + "] in the cache.", value );
+ }
+ }
+
+ /**
+ * Get stats.
+ * <p>
+ * @throws CacheException
+ */
+ public void testGetStatsThroughHub()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testGetStatsThroughHub" );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max * 2;
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.put( i + ":key", "myregion" + " data " + i );
+ }
+
+ String stats = cache.getStats();
+
+// System.out.println( stats );
+
+ // TODO improve stats check
+ assertTrue( "Should have 200 puts", stats.indexOf( "2000" ) != -1 );
+ }
+
+ /**
+ * Put half the max and clear. get the key array and verify that it has the correct number of
+ * items.
+ * <p>
+ * @throws Exception
+ */
+ public void testGetKeyArray()
+ throws Exception
+ {
+ CompositeCacheManager cacheMgr = CompositeCacheManager.getUnconfiguredInstance();
+ cacheMgr.configure( "/TestMRUCache.ccf" );
+ CompositeCache<String, String> cache = cacheMgr.getCache( "testGetKeyArray" );
+
+ MRUMemoryCache<String, String> mru = new MRUMemoryCache<>();
+ mru.initialize( cache );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max / 2;
+
+ for ( int i = 0; i < items; i++ )
+ {
+ ICacheElement<String, String> ice = new CacheElement<>( cache.getCacheName(), i + ":key", cache.getCacheName() + " data " + i );
+ ice.setElementAttributes( cache.getElementAttributes() );
+ mru.update( ice );
+ }
+
+ Set<String> keys = mru.getKeySet();
+
+ assertEquals( "Wrong number of keys.", items, keys.size() );
+ }
+
+ /**
+ * Add a few keys with the delimiter. Remove them.
+ * <p>
+ * @throws CacheException
+ */
+ public void testRemovePartialThroughHub()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testGetStatsThroughHub" );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max / 2;
+
+ cache.put( "test", "data" );
+
+ String root = "myroot";
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.put( root + ":" + i + ":key", "myregion" + " data " + i );
+ }
+
+ // Test that last items are in cache
+ for ( int i = 0; i < items; i++ )
+ {
+ String value = cache.get( root + ":" + i + ":key" );
+ assertEquals( "myregion" + " data " + i, value );
+ }
+
+ // remove partial
+ cache.remove( root + ":" );
+
+ for ( int i = 0; i < items; i++ )
+ {
+ assertNull( "Should have been removed by partial loop.", cache.get( root + ":" + i + ":key" ) );
+ }
+
+ assertNotNull( "Other item should be in the cache.", cache.get( "test" ) );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/shrinking/ShrinkerThreadUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/shrinking/ShrinkerThreadUnitTest.java
new file mode 100644
index 0000000..99ee54c
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/shrinking/ShrinkerThreadUnitTest.java
@@ -0,0 +1,338 @@
+package org.apache.commons.jcs3.engine.memory.shrinking;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import org.apache.commons.jcs3.engine.ElementAttributesUtils;
+import org.apache.commons.jcs3.engine.control.event.ElementEventHandlerMockImpl;
+import org.apache.commons.jcs3.engine.memory.MockMemoryCache;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.CompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.ElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.control.event.behavior.ElementEventType;
+import org.apache.commons.jcs3.engine.memory.shrinking.ShrinkerThread;
+
+import java.io.IOException;
+
+/**
+ * This tests the functionality of the shrinker thread.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class ShrinkerThreadUnitTest
+ extends TestCase
+{
+ /** verify the check for removal
+ * <p>
+ * @throws IOException */
+ public void testCheckForRemoval_Expired() throws IOException
+ {
+ // SETUP
+ CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
+ cacheAttr.setCacheName("testRegion");
+ cacheAttr.setMaxMemoryIdleTimeSeconds( 10 );
+ cacheAttr.setMaxSpoolPerRun( 10 );
+
+ CompositeCache<String, String> cache = new CompositeCache<>(cacheAttr, new ElementAttributes());
+
+ String key = "key";
+ String value = "value";
+
+ ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value );
+ ElementAttributes elementAttr = new ElementAttributes();
+ elementAttr.setIsEternal( false );
+ element.setElementAttributes( elementAttr );
+ element.getElementAttributes().setMaxLife(1);
+
+ long now = System.currentTimeMillis();
+ // add two seconds
+ now += 2000;
+
+ // DO WORK
+ boolean result = cache.isExpired( element, now,
+ ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND,
+ ElementEventType.EXCEEDED_IDLETIME_BACKGROUND );
+
+ // VERIFY
+ assertTrue( "Item should have expired.", result );
+ }
+
+ /** verify the check for removal
+ * <p>
+ * @throws IOException */
+ public void testCheckForRemoval_NotExpired() throws IOException
+ {
+ // SETUP
+ CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
+ cacheAttr.setCacheName("testRegion");
+ cacheAttr.setMaxMemoryIdleTimeSeconds( 10 );
+ cacheAttr.setMaxSpoolPerRun( 10 );
+
+ CompositeCache<String, String> cache = new CompositeCache<>(cacheAttr, new ElementAttributes());
+
+ String key = "key";
+ String value = "value";
+
+ ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value );
+ ElementAttributes elementAttr = new ElementAttributes();
+ elementAttr.setIsEternal( false );
+ element.setElementAttributes( elementAttr );
+ element.getElementAttributes().setMaxLife(1);
+
+ long now = System.currentTimeMillis();
+ // subtract two seconds
+ now -= 2000;
+
+ // DO WORK
+ boolean result = cache.isExpired( element, now,
+ ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND,
+ ElementEventType.EXCEEDED_IDLETIME_BACKGROUND );
+
+ // VERIFY
+ assertFalse( "Item should not have expired.", result );
+ }
+
+ /** verify the check for removal
+ * <p>
+ * @throws IOException */
+ public void testCheckForRemoval_IdleTooLong() throws IOException
+ {
+ // SETUP
+ CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
+ cacheAttr.setCacheName("testRegion");
+ cacheAttr.setMaxMemoryIdleTimeSeconds( 10 );
+ cacheAttr.setMaxSpoolPerRun( 10 );
+
+ CompositeCache<String, String> cache = new CompositeCache<>(cacheAttr, new ElementAttributes());
+
+ String key = "key";
+ String value = "value";
+
+ ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value );
+ ElementAttributes elementAttr = new ElementAttributes();
+ elementAttr.setIsEternal( false );
+ element.setElementAttributes( elementAttr );
+ element.getElementAttributes().setMaxLife(100);
+ element.getElementAttributes().setIdleTime( 1 );
+
+ long now = System.currentTimeMillis();
+ // add two seconds
+ now += 2000;
+
+ // DO WORK
+ boolean result = cache.isExpired( element, now,
+ ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND,
+ ElementEventType.EXCEEDED_IDLETIME_BACKGROUND );
+
+ // VERIFY
+ assertTrue( "Item should have expired.", result );
+ }
+
+ /** verify the check for removal
+ * <p>
+ * @throws IOException */
+ public void testCheckForRemoval_NotIdleTooLong() throws IOException
+ {
+ // SETUP
+ CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
+ cacheAttr.setCacheName("testRegion");
+ cacheAttr.setMaxMemoryIdleTimeSeconds( 10 );
+ cacheAttr.setMaxSpoolPerRun( 10 );
+
+ CompositeCache<String, String> cache = new CompositeCache<>(cacheAttr, new ElementAttributes());
+
+ String key = "key";
+ String value = "value";
+
+ ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value );
+ ElementAttributes elementAttr = new ElementAttributes();
+ elementAttr.setIsEternal( false );
+ element.setElementAttributes( elementAttr );
+ element.getElementAttributes().setMaxLife(100);
+ element.getElementAttributes().setIdleTime( 1 );
+
+ long now = System.currentTimeMillis();
+ // subtract two seconds
+ now -= 2000;
+
+ // DO WORK
+ boolean result = cache.isExpired( element, now,
+ ElementEventType.EXCEEDED_MAXLIFE_BACKGROUND,
+ ElementEventType.EXCEEDED_IDLETIME_BACKGROUND );
+
+ // VERIFY
+ assertFalse( "Item should not have expired.", result );
+ }
+
+ /**
+ * Setup cache attributes in mock. Create the shrinker with the mock. Add some elements into the
+ * mock memory cache see that they get spooled.
+ * <p>
+ * @throws Exception
+ */
+ public void testSimpleShrink()
+ throws Exception
+ {
+ // SETUP
+ CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
+ cacheAttr.setCacheName("testRegion");
+ cacheAttr.setMemoryCacheName("org.apache.commons.jcs3.engine.memory.MockMemoryCache");
+ cacheAttr.setMaxMemoryIdleTimeSeconds( 1 );
+ cacheAttr.setMaxSpoolPerRun( 10 );
+
+ CompositeCache<String, String> cache = new CompositeCache<>(cacheAttr, new ElementAttributes());
+ MockMemoryCache<String, String> memory = (MockMemoryCache<String, String>)cache.getMemoryCache();
+
+ String key = "key";
+ String value = "value";
+
+ ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value );
+
+ ElementAttributes elementAttr = new ElementAttributes();
+ elementAttr.setIsEternal( false );
+ element.setElementAttributes( elementAttr );
+ element.getElementAttributes().setMaxLife(1);
+ memory.update( element );
+
+ ICacheElement<String, String> returnedElement1 = memory.get( key );
+ assertNotNull( "We should have received an element", returnedElement1 );
+
+ // set this to 2 seconds ago.
+ ElementAttributesUtils.setLastAccessTime( elementAttr, System.currentTimeMillis() - 2000 );
+
+ // DO WORK
+ ShrinkerThread<String, String> shrinker = new ShrinkerThread<>( cache );
+ shrinker.run();
+
+ Thread.sleep( 500 );
+
+ // VERIFY
+ ICacheElement<String, String> returnedElement2 = memory.get( key );
+ assertTrue( "Waterfall should have been called.", memory.waterfallCallCount > 0 );
+ assertNull( "We not should have received an element. It should have been spooled.", returnedElement2 );
+ }
+
+ /**
+ * Add 10 to the memory cache. Set the spool per run limit to 3.
+ * <p>
+ * @throws Exception
+ */
+ public void testSimpleShrinkMultiple()
+ throws Exception
+ {
+ // SETUP
+ CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
+ cacheAttr.setCacheName("testRegion");
+ cacheAttr.setMemoryCacheName("org.apache.commons.jcs3.engine.memory.MockMemoryCache");
+ cacheAttr.setMaxMemoryIdleTimeSeconds( 1 );
+ cacheAttr.setMaxSpoolPerRun( 3 );
+
+ CompositeCache<String, String> cache = new CompositeCache<>(cacheAttr, new ElementAttributes());
+ MockMemoryCache<String, String> memory = (MockMemoryCache<String, String>)cache.getMemoryCache();
+
+ for ( int i = 0; i < 10; i++ )
+ {
+ String key = "key" + i;
+ String value = "value";
+
+ ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value );
+
+ ElementAttributes elementAttr = new ElementAttributes();
+ elementAttr.setIsEternal( false );
+ element.setElementAttributes( elementAttr );
+ element.getElementAttributes().setMaxLife(1);
+ memory.update( element );
+
+ ICacheElement<String, String> returnedElement1 = memory.get( key );
+ assertNotNull( "We should have received an element", returnedElement1 );
+
+ // set this to 2 seconds ago.
+ ElementAttributesUtils.setLastAccessTime( elementAttr, System.currentTimeMillis() - 2000 );
+ }
+
+ // DO WORK
+ ShrinkerThread<String, String> shrinker = new ShrinkerThread<>( cache );
+ shrinker.run();
+
+ // VERIFY
+ Thread.sleep( 500 );
+ assertEquals( "Waterfall called the wrong number of times.", 3, memory.waterfallCallCount );
+ assertEquals( "Wrong number of elements remain.", 7, memory.getSize() );
+ }
+
+ /**
+ * Add a mock event handler to the items. Verify that it gets called.
+ * <p>
+ * This is only testing the spooled background event
+ * <p>
+ * @throws Exception
+ */
+ public void testSimpleShrinkMultipleWithEventHandler()
+ throws Exception
+ {
+ // SETUP
+ CompositeCacheAttributes cacheAttr = new CompositeCacheAttributes();
+ cacheAttr.setCacheName("testRegion");
+ cacheAttr.setMemoryCacheName("org.apache.commons.jcs3.engine.memory.MockMemoryCache");
+ cacheAttr.setMaxMemoryIdleTimeSeconds( 1 );
+ cacheAttr.setMaxSpoolPerRun( 3 );
+
+ CompositeCache<String, String> cache = new CompositeCache<>(cacheAttr, new ElementAttributes());
+ MockMemoryCache<String, String> memory = (MockMemoryCache<String, String>)cache.getMemoryCache();
+
+ ElementEventHandlerMockImpl handler = new ElementEventHandlerMockImpl();
+
+ for ( int i = 0; i < 10; i++ )
+ {
+ String key = "key" + i;
+ String value = "value";
+
+ ICacheElement<String, String> element = new CacheElement<>( "testRegion", key, value );
+
+ ElementAttributes elementAttr = new ElementAttributes();
+ elementAttr.addElementEventHandler( handler );
+ elementAttr.setIsEternal( false );
+ element.setElementAttributes( elementAttr );
+ element.getElementAttributes().setMaxLife(1);
+ memory.update( element );
+
+ ICacheElement<String, String> returnedElement1 = memory.get( key );
+ assertNotNull( "We should have received an element", returnedElement1 );
+
+ // set this to 2 seconds ago.
+ ElementAttributesUtils.setLastAccessTime( elementAttr, System.currentTimeMillis() - 2000 );
+ }
+
+ // DO WORK
+ ShrinkerThread<String, String> shrinker = new ShrinkerThread<>( cache );
+ shrinker.run();
+
+ // VERIFY
+ Thread.sleep( 500 );
+ assertEquals( "Waterfall called the wrong number of times.", 3, memory.waterfallCallCount );
+ // the shrinker delegates the the composite cache on the memory cache to put the
+ // event on the queue. This make it hard to test. TODO we need to change this to make it easier to verify.
+ //assertEquals( "Event handler ExceededIdleTimeBackground called the wrong number of times.", 3, handler.getExceededIdleTimeBackgroundCount() );
+ assertEquals( "Wrong number of elements remain.", 7, memory.getSize() );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/soft/SoftReferenceMemoryCacheUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/soft/SoftReferenceMemoryCacheUnitTest.java
new file mode 100644
index 0000000..b2aa8c1
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/engine/memory/soft/SoftReferenceMemoryCacheUnitTest.java
@@ -0,0 +1,248 @@
+package org.apache.commons.jcs3.engine.memory.soft;
+
+/*
+ * 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.
+ */
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.jcs3.JCS;
+import org.apache.commons.jcs3.access.CacheAccess;
+import org.apache.commons.jcs3.access.exception.CacheException;
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+import org.apache.commons.jcs3.engine.memory.soft.SoftReferenceMemoryCache;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for the test Soft reference implementation.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class SoftReferenceMemoryCacheUnitTest
+ extends TestCase
+{
+ /** Test setup */
+ @Override
+ public void setUp()
+ {
+ JCS.setConfigFilename( "/TestSoftReferenceCache.ccf" );
+ }
+
+ /**
+ * @see junit.framework.TestCase#tearDown()
+ */
+ @Override
+ protected void tearDown() throws Exception
+ {
+ CompositeCacheManager.getInstance().shutDown();
+ }
+
+ /**
+ * Verify that the cache gets used by a non-defined region when it is set as the default in the
+ * default region.
+ * <p>
+ * @throws CacheException
+ */
+ public void testLoadFromCCF()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testPutGet" );
+ String memoryCacheName = cache.getCacheAttributes().getMemoryCacheName();
+ assertTrue( "Cache name should have SoftReference in it.",
+ memoryCacheName.indexOf( "SoftReferenceMemoryCache" ) != -1 );
+ }
+
+ /**
+ * put twice as many as the max. verify that all are in the cache.
+ * <p>
+ * @throws CacheException
+ */
+ public void testPutGetThroughHub()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testPutGetThroughHub" );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max * 2;
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.put( i + ":key", "myregion" + " data " + i );
+ }
+
+ // Test that all items are in cache
+ for ( int i = 0; i < items; i++ )
+ {
+ String value = cache.get( i + ":key" );
+ assertEquals( "myregion" + " data " + i, value );
+ }
+
+ // Test that getMultiple returns all the items remaining in cache and none of the missing ones
+ Set<String> keys = new HashSet<>();
+ for ( int i = 0; i < items; i++ )
+ {
+ keys.add( i + ":key" );
+ }
+
+ Map<String, ICacheElement<String, String>> elements = cache.getCacheElements( keys );
+ for ( int i = 0; i < items; i++ )
+ {
+ ICacheElement<String, String> element = elements.get( i + ":key" );
+ assertNotNull( "element " + i + ":key is missing", element );
+ assertEquals( "value " + i + ":key", "myregion" + " data " + i, element.getVal() );
+ }
+
+ // System.out.println(cache.getStats());
+ }
+
+ /**
+ * put the max and remove each. verify that they are all null.
+ * <p>
+ * @throws CacheException
+ */
+ public void testPutRemoveThroughHub()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testPutGetThroughHub" );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max * 2;
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.put( i + ":key", "myregion" + " data " + i );
+ }
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.remove( i + ":key" );
+ }
+
+ // Test that first items are not in the cache
+ for ( int i = max; i >= 0; i-- )
+ {
+ String value = cache.get( i + ":key" );
+ assertNull( "Should not have value for key [" + i + ":key" + "] in the cache.", value );
+ }
+ }
+
+ /**
+ * put the max and clear. verify that no elements remain.
+ * <p>
+ * @throws CacheException
+ */
+ public void testClearThroughHub()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testPutGetThroughHub" );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max * 2;
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.put( i + ":key", "myregion" + " data " + i );
+ }
+
+ cache.clear();
+
+ // Test that first items are not in the cache
+ for ( int i = max; i >= 0; i-- )
+ {
+ String value = cache.get( i + ":key" );
+ assertNull( "Should not have value for key [" + i + ":key" + "] in the cache.", value );
+ }
+ }
+
+ /**
+ * Put half the max and clear. get the key array and verify that it has the correct number of
+ * items.
+ * <p>
+ * @throws Exception
+ */
+ public void testGetKeyArray()
+ throws Exception
+ {
+ CompositeCacheManager cacheMgr = CompositeCacheManager.getUnconfiguredInstance();
+ cacheMgr.configure( "/TestSoftReferenceCache.ccf" );
+ CompositeCache<String, String> cache = cacheMgr.getCache( "testGetKeyArray" );
+
+ SoftReferenceMemoryCache<String, String> srmc = new SoftReferenceMemoryCache<>();
+ srmc.initialize( cache );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max / 2;
+
+ for ( int i = 0; i < items; i++ )
+ {
+ ICacheElement<String, String> ice = new CacheElement<>( cache.getCacheName(), i + ":key", cache.getCacheName() + " data " + i );
+ ice.setElementAttributes( cache.getElementAttributes() );
+ srmc.update( ice );
+ }
+
+ Set<String> keys = srmc.getKeySet();
+
+ assertEquals( "Wrong number of keys.", items, keys.size() );
+ }
+
+ /**
+ * Add a few keys with the delimiter. Remove them.
+ * <p>
+ * @throws CacheException
+ */
+ public void testRemovePartialThroughHub()
+ throws CacheException
+ {
+ CacheAccess<String, String> cache = JCS.getInstance( "testGetStatsThroughHub" );
+
+ int max = cache.getCacheAttributes().getMaxObjects();
+ int items = max / 2;
+
+ cache.put( "test", "data" );
+
+ String root = "myroot";
+
+ for ( int i = 0; i < items; i++ )
+ {
+ cache.put( root + ":" + i + ":key", "myregion" + " data " + i );
+ }
+
+ // Test that last items are in cache
+ for ( int i = 0; i < items; i++ )
+ {
+ String value = cache.get( root + ":" + i + ":key" );
+ assertEquals( "myregion" + " data " + i, value );
+ }
+
+ // remove partial
+ cache.remove( root + ":" );
+
+ for ( int i = 0; i < items; i++ )
+ {
+ assertNull( "Should have been removed by partial loop.", cache.get( root + ":" + i + ":key" ) );
+ }
+
+ assertNotNull( "Other item should be in the cache.", cache.get( "test" ) );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/access/JCSWorkerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/access/JCSWorkerUnitTest.java
new file mode 100644
index 0000000..bb78ce8
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/access/JCSWorkerUnitTest.java
@@ -0,0 +1,73 @@
+package org.apache.commons.jcs3.utils.access;
+
+import org.apache.commons.jcs3.utils.access.AbstractJCSWorkerHelper;
+import org.apache.commons.jcs3.utils.access.JCSWorker;
+import org.apache.commons.jcs3.utils.access.JCSWorkerHelper;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Test cases for the JCS worker.
+ *
+ * @author Aaron Smuts
+ *
+ */
+public class JCSWorkerUnitTest
+ extends TestCase
+{
+
+ /**
+ * Test basic worker functionality. This is a serial not a concurrent test.
+ * <p>
+ * Just verify that the worker will go to the cache before asking the helper.
+ *
+ * @throws Exception
+ *
+ */
+ public void testSimpleGet()
+ throws Exception
+ {
+ JCSWorker<String, Long> cachingWorker = new JCSWorker<>( "example region" );
+
+ // This is the helper.
+ JCSWorkerHelper<Long> helper = new AbstractJCSWorkerHelper<Long>()
+ {
+ int timesCalled = 0;
+
+ @Override
+ public Long doWork()
+ {
+ return Long.valueOf( ++timesCalled );
+ }
+ };
+
+ String key = "abc";
+
+ Long result = cachingWorker.getResult( key, helper );
+ assertEquals( "Called the wrong number of times", Long.valueOf( 1 ), result );
+
+ // should get it from the cache.
+ Long result2 = cachingWorker.getResult( key, helper );
+ assertEquals( "Called the wrong number of times", Long.valueOf( 1 ), result2 );
+ }
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/config/PropertySetterUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/config/PropertySetterUnitTest.java
new file mode 100644
index 0000000..36e3fbb
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/config/PropertySetterUnitTest.java
@@ -0,0 +1,62 @@
+package org.apache.commons.jcs3.utils.config;
+
+/*
+ * 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.
+ */
+
+import static org.junit.Assert.*;
+
+import java.io.File;
+
+import org.apache.commons.jcs3.utils.config.PropertySetter;
+import org.junit.Test;
+
+/**
+ * Test property settings
+ *
+ * @author Thomas Vandahl
+ *
+ */
+public class PropertySetterUnitTest
+{
+ enum EnumTest { ONE, TWO, THREE };
+
+ @Test
+ public void testConvertArg()
+ {
+ PropertySetter ps = new PropertySetter(this);
+ Object s = ps.convertArg("test", String.class);
+ assertEquals("Should be a string", "test", s);
+
+ Object i = ps.convertArg("1", Integer.TYPE);
+ assertEquals("Should be an integer", Integer.valueOf(1), i);
+
+ Object l = ps.convertArg("1", Long.TYPE);
+ assertEquals("Should be a long", Long.valueOf(1), l);
+
+ Object b = ps.convertArg("true", Boolean.TYPE);
+ assertEquals("Should be a boolean", Boolean.TRUE, b);
+
+ Object e = ps.convertArg("TWO", EnumTest.class);
+ assertEquals("Should be an enum", EnumTest.TWO, e);
+
+ Object f = ps.convertArg("test.conf", File.class);
+ assertTrue("Should be a file", f instanceof File);
+ }
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/discovery/MockDiscoveryListener.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/discovery/MockDiscoveryListener.java
new file mode 100644
index 0000000..a16fd1d
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/discovery/MockDiscoveryListener.java
@@ -0,0 +1,57 @@
+package org.apache.commons.jcs3.utils.discovery;
+
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.jcs3.utils.discovery.DiscoveredService;
+import org.apache.commons.jcs3.utils.discovery.behavior.IDiscoveryListener;
+
+/** Mock listener, for testing. */
+public class MockDiscoveryListener
+ implements IDiscoveryListener
+{
+ /** discovered services. */
+ public List<DiscoveredService> discoveredServices = new ArrayList<>();
+
+ /**
+ * Adds the entry to a list. I'm not using a set. I want to see if we get dupes.
+ * <p>
+ * @param service
+ */
+ @Override
+ public void addDiscoveredService( DiscoveredService service )
+ {
+ discoveredServices.add( service );
+ }
+
+ /**
+ * Removes it from the list.
+ * <p>
+ * @param service
+ */
+ @Override
+ public void removeDiscoveredService( DiscoveredService service )
+ {
+ discoveredServices.remove( service );
+ }
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoverySenderUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoverySenderUnitTest.java
new file mode 100644
index 0000000..20ed743
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoverySenderUnitTest.java
@@ -0,0 +1,158 @@
+package org.apache.commons.jcs3.utils.discovery;
+
+import java.util.ArrayList;
+
+import org.apache.commons.jcs3.utils.discovery.UDPDiscoveryMessage;
+import org.apache.commons.jcs3.utils.discovery.UDPDiscoveryReceiver;
+import org.apache.commons.jcs3.utils.discovery.UDPDiscoverySender;
+import org.apache.commons.jcs3.utils.discovery.UDPDiscoveryMessage.BroadcastType;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for the sender.
+ */
+public class UDPDiscoverySenderUnitTest
+ extends TestCase
+{
+ /** multicast address to send/receive on */
+ private static final String ADDRESS = "228.4.5.9";
+
+ /** multicast address to send/receive on */
+ private static final int PORT = 5556;
+
+ /** imaginary host address for sending */
+ private static final String SENDING_HOST = "imaginary host address";
+
+ /** imaginary port for sending */
+ private static final int SENDING_PORT = 1;
+
+ /** receiver instance for tests */
+ private UDPDiscoveryReceiver receiver;
+
+ /** sender instance for tests */
+ private UDPDiscoverySender sender;
+
+ /**
+ * Set up the receiver. Maybe better to just code sockets here? Set up the sender for sending
+ * the message.
+ * <p>
+ * @throws Exception on error
+ */
+ @Override
+ protected void setUp()
+ throws Exception
+ {
+ super.setUp();
+ receiver = new UDPDiscoveryReceiver( null, null, ADDRESS, PORT );
+ sender = new UDPDiscoverySender( ADDRESS, PORT, 0 );
+ }
+
+ /**
+ * Kill off the sender and receiver.
+ * <p>
+ * @throws Exception on error
+ */
+ @Override
+ protected void tearDown()
+ throws Exception
+ {
+ receiver.shutdown();
+ sender.close();
+ super.tearDown();
+ }
+
+ /**
+ * Test sending a live messages.
+ * <p>
+ * @throws Exception on error
+ */
+ public void testPassiveBroadcast()
+ throws Exception
+ {
+ // SETUP
+ ArrayList<String> cacheNames = new ArrayList<>();
+
+ // DO WORK
+ sender.passiveBroadcast( SENDING_HOST, SENDING_PORT, cacheNames, 1L );
+
+ // VERIFY
+ // grab the sent message
+ Object obj = receiver.waitForMessage() ;
+
+ assertTrue( "unexpected crap received", obj instanceof UDPDiscoveryMessage );
+
+ UDPDiscoveryMessage msg = (UDPDiscoveryMessage) obj;
+ // disabled test because of JCS-89
+ // assertEquals( "wrong host", SENDING_HOST, msg.getHost() );
+ assertEquals( "wrong port", SENDING_PORT, msg.getPort() );
+ assertEquals( "wrong message type", BroadcastType.PASSIVE, msg.getMessageType() );
+ }
+
+ /**
+ * Test sending a remove broadcast.
+ * <p>
+ * @throws Exception on error
+ */
+ public void testRemoveBroadcast()
+ throws Exception
+ {
+ // SETUP
+ ArrayList<String> cacheNames = new ArrayList<>();
+
+ // DO WORK
+ sender.removeBroadcast( SENDING_HOST, SENDING_PORT, cacheNames, 1L );
+
+ // VERIFY
+ // grab the sent message
+ Object obj = receiver.waitForMessage();
+
+ assertTrue( "unexpected crap received", obj instanceof UDPDiscoveryMessage );
+
+ UDPDiscoveryMessage msg = (UDPDiscoveryMessage) obj;
+ // disabled test because of JCS-89
+ // assertEquals( "wrong host", SENDING_HOST, msg.getHost() );
+ assertEquals( "wrong port", SENDING_PORT, msg.getPort() );
+ assertEquals( "wrong message type", BroadcastType.REMOVE, msg.getMessageType() );
+ }
+
+ /**
+ * Test sending a request broadcast.
+ * <p>
+ * @throws Exception on error
+ */
+ public void testRequestBroadcast()
+ throws Exception
+ {
+ // DO WORK
+ sender.requestBroadcast();
+
+ // VERIFY
+ // grab the sent message
+ Object obj = receiver.waitForMessage();
+
+ assertTrue( "unexpected crap received", obj instanceof UDPDiscoveryMessage );
+
+ UDPDiscoveryMessage msg = (UDPDiscoveryMessage) obj;
+ assertEquals( "wrong message type", BroadcastType.REQUEST, msg.getMessageType() );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryServiceUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryServiceUnitTest.java
new file mode 100644
index 0000000..6fc4a7d
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryServiceUnitTest.java
@@ -0,0 +1,230 @@
+package org.apache.commons.jcs3.utils.discovery;
+
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+
+import org.apache.commons.jcs3.utils.discovery.DiscoveredService;
+import org.apache.commons.jcs3.utils.discovery.UDPDiscoveryAttributes;
+import org.apache.commons.jcs3.utils.discovery.UDPDiscoveryService;
+
+import junit.framework.TestCase;
+
+/** Unit tests for the service. */
+public class UDPDiscoveryServiceUnitTest
+ extends TestCase
+{
+ /** Verify that the list is updated. */
+ public void testAddOrUpdateService_NotInList()
+ {
+ // SETUP
+ String host = "228.5.6.7";
+ int port = 6789;
+ UDPDiscoveryAttributes attributes = new UDPDiscoveryAttributes();
+ attributes.setUdpDiscoveryAddr( host );
+ attributes.setUdpDiscoveryPort( port );
+ attributes.setServicePort( 1000 );
+
+ // create the service
+ UDPDiscoveryService service = new UDPDiscoveryService( attributes );
+ service.startup();
+ service.addParticipatingCacheName( "testCache1" );
+
+ MockDiscoveryListener discoveryListener = new MockDiscoveryListener();
+ service.addDiscoveryListener( discoveryListener );
+
+ DiscoveredService discoveredService = new DiscoveredService();
+ discoveredService.setServiceAddress( host );
+ discoveredService.setCacheNames( new ArrayList<>() );
+ discoveredService.setServicePort( 1000 );
+ discoveredService.setLastHearFromTime( 100 );
+
+ // DO WORK
+ service.addOrUpdateService( discoveredService );
+
+ // VERIFY
+ assertTrue( "Service should be in the service list.", service.getDiscoveredServices()
+ .contains( discoveredService ) );
+ assertTrue( "Service should be in the listener list.", discoveryListener.discoveredServices
+ .contains( discoveredService ) );
+ }
+
+ /** Verify that the list is updated. */
+ public void testAddOrUpdateService_InList_NamesDoNotChange()
+ {
+ // SETUP
+ String host = "228.5.6.7";
+ int port = 6789;
+ UDPDiscoveryAttributes attributes = new UDPDiscoveryAttributes();
+ attributes.setUdpDiscoveryAddr( host );
+ attributes.setUdpDiscoveryPort( port );
+ attributes.setServicePort( 1000 );
+
+ // create the service
+ UDPDiscoveryService service = new UDPDiscoveryService( attributes );
+ service.startup();
+ service.addParticipatingCacheName( "testCache1" );
+
+ MockDiscoveryListener discoveryListener = new MockDiscoveryListener();
+ service.addDiscoveryListener( discoveryListener );
+
+ ArrayList<String> sametCacheNames = new ArrayList<>();
+ sametCacheNames.add( "name1" );
+
+ DiscoveredService discoveredService = new DiscoveredService();
+ discoveredService.setServiceAddress( host );
+ discoveredService.setCacheNames( sametCacheNames );
+ discoveredService.setServicePort( 1000 );
+ discoveredService.setLastHearFromTime( 100 );
+
+
+ DiscoveredService discoveredService2 = new DiscoveredService();
+ discoveredService2.setServiceAddress( host );
+ discoveredService2.setCacheNames( sametCacheNames );
+ discoveredService2.setServicePort( 1000 );
+ discoveredService2.setLastHearFromTime( 500 );
+
+ // DO WORK
+ service.addOrUpdateService( discoveredService );
+ // again
+ service.addOrUpdateService( discoveredService2 );
+
+ // VERIFY
+ assertEquals( "Should only be one in the set.", 1, service.getDiscoveredServices().size() );
+ assertTrue( "Service should be in the service list.", service.getDiscoveredServices()
+ .contains( discoveredService ) );
+ assertTrue( "Service should be in the listener list.", discoveryListener.discoveredServices
+ .contains( discoveredService ) );
+
+ // need to update the time this sucks. add has no effect convert to a map
+ for (DiscoveredService service1 : service.getDiscoveredServices())
+ {
+ if ( discoveredService.equals( service1 ) )
+ {
+ assertEquals( "The match should have the new last heard from time.", service1.getLastHearFromTime(),
+ discoveredService2.getLastHearFromTime() );
+ }
+ }
+ // the mock has a list from all add calls.
+ // it should have been called when the list changed.
+ //assertEquals( "Mock should have been called once.", 1, discoveryListener.discoveredServices.size() );
+ // logic changed. it's called every time.
+ assertEquals( "Mock should have been called twice.", 2, discoveryListener.discoveredServices.size() );
+ }
+
+ /** Verify that the list is updated. */
+ public void testAddOrUpdateService_InList_NamesChange()
+ {
+ // SETUP
+ String host = "228.5.6.7";
+ int port = 6789;
+ UDPDiscoveryAttributes attributes = new UDPDiscoveryAttributes();
+ attributes.setUdpDiscoveryAddr( host );
+ attributes.setUdpDiscoveryPort( port );
+ attributes.setServicePort( 1000 );
+
+ // create the service
+ UDPDiscoveryService service = new UDPDiscoveryService( attributes );
+ service.startup();
+ service.addParticipatingCacheName( "testCache1" );
+
+ MockDiscoveryListener discoveryListener = new MockDiscoveryListener();
+ service.addDiscoveryListener( discoveryListener );
+
+ DiscoveredService discoveredService = new DiscoveredService();
+ discoveredService.setServiceAddress( host );
+ discoveredService.setCacheNames( new ArrayList<>() );
+ discoveredService.setServicePort( 1000 );
+ discoveredService.setLastHearFromTime( 100 );
+
+ ArrayList<String> differentCacheNames = new ArrayList<>();
+ differentCacheNames.add( "name1" );
+ DiscoveredService discoveredService2 = new DiscoveredService();
+ discoveredService2.setServiceAddress( host );
+ discoveredService2.setCacheNames( differentCacheNames );
+ discoveredService2.setServicePort( 1000 );
+ discoveredService2.setLastHearFromTime( 500 );
+
+ // DO WORK
+ service.addOrUpdateService( discoveredService );
+ // again
+ service.addOrUpdateService( discoveredService2 );
+
+ // VERIFY
+ assertEquals( "Should only be one in the set.", 1, service.getDiscoveredServices().size() );
+ assertTrue( "Service should be in the service list.", service.getDiscoveredServices()
+ .contains( discoveredService ) );
+ assertTrue( "Service should be in the listener list.", discoveryListener.discoveredServices
+ .contains( discoveredService ) );
+
+ // need to update the time this sucks. add has no effect convert to a map
+ for (DiscoveredService service1 : service.getDiscoveredServices())
+ {
+ if ( discoveredService.equals( service1 ) )
+ {
+ assertEquals( "The match should have the new last heard from time.", service1.getLastHearFromTime(),
+ discoveredService2.getLastHearFromTime() );
+ assertEquals( "The names should be updated.", service1.getCacheNames() + "", differentCacheNames + "" );
+ }
+ }
+ // the mock has a list from all add calls.
+ // it should have been called when the list changed.
+ assertEquals( "Mock should have been called twice.", 2, discoveryListener.discoveredServices.size() );
+ assertEquals( "The second mock listener add should be discoveredService2", discoveredService2,
+ discoveryListener.discoveredServices.get( 1 ) );
+ }
+
+ /** Verify that the list is updated. */
+ public void testRemoveDiscoveredService()
+ {
+ // SETUP
+ String host = "228.5.6.7";
+ int port = 6789;
+ UDPDiscoveryAttributes attributes = new UDPDiscoveryAttributes();
+ attributes.setUdpDiscoveryAddr( host );
+ attributes.setUdpDiscoveryPort( port );
+ attributes.setServicePort( 1000 );
+
+ // create the service
+ UDPDiscoveryService service = new UDPDiscoveryService( attributes );
+ service.startup();
+ service.addParticipatingCacheName( "testCache1" );
+
+ MockDiscoveryListener discoveryListener = new MockDiscoveryListener();
+ service.addDiscoveryListener( discoveryListener );
+
+ DiscoveredService discoveredService = new DiscoveredService();
+ discoveredService.setServiceAddress( host );
+ discoveredService.setCacheNames( new ArrayList<>() );
+ discoveredService.setServicePort( 1000 );
+ discoveredService.setLastHearFromTime( 100 );
+
+ service.addOrUpdateService( discoveredService );
+
+ // DO WORK
+ service.removeDiscoveredService( discoveredService );
+
+ // VERIFY
+ assertFalse( "Service should not be in the service list.", service.getDiscoveredServices()
+ .contains( discoveredService ) );
+ assertFalse( "Service should not be in the listener list.", discoveryListener.discoveredServices
+ .contains( discoveredService ) );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryUnitTest.java
new file mode 100644
index 0000000..0980193
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/discovery/UDPDiscoveryUnitTest.java
@@ -0,0 +1,101 @@
+package org.apache.commons.jcs3.utils.discovery;
+
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+
+import org.apache.commons.jcs3.utils.timing.SleepUtil;
+import org.apache.commons.jcs3.utils.discovery.UDPDiscoveryAttributes;
+import org.apache.commons.jcs3.utils.discovery.UDPDiscoveryReceiver;
+import org.apache.commons.jcs3.utils.discovery.UDPDiscoverySender;
+import org.apache.commons.jcs3.utils.discovery.UDPDiscoveryService;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for discovery
+ */
+public class UDPDiscoveryUnitTest
+ extends TestCase
+{
+ /**
+ * <p>
+ * @throws Exception
+ */
+ public void testSimpleUDPDiscovery()
+ throws Exception
+ {
+ UDPDiscoveryAttributes attributes = new UDPDiscoveryAttributes();
+ attributes.setUdpDiscoveryAddr( /*"FF7E:230::1234"*/ "228.5.6.7" );
+ attributes.setUdpDiscoveryPort( 6789 );
+ attributes.setServicePort( 1000 );
+
+ // create the service
+ UDPDiscoveryService service = new UDPDiscoveryService( attributes );
+ service.startup();
+ service.addParticipatingCacheName( "testCache1" );
+
+ MockDiscoveryListener discoveryListener = new MockDiscoveryListener();
+ service.addDiscoveryListener( discoveryListener );
+
+ // create a receiver with the service
+ UDPDiscoveryReceiver receiver = new UDPDiscoveryReceiver( service,
+ null,
+ attributes.getUdpDiscoveryAddr(),
+ attributes.getUdpDiscoveryPort() );
+ Thread t = new Thread( receiver );
+ t.start();
+
+ // create a sender
+ UDPDiscoverySender sender = new UDPDiscoverySender(
+ attributes.getUdpDiscoveryAddr(),
+ attributes.getUdpDiscoveryPort(),
+ 4 /* datagram TTL */);
+
+ // create more names than we have no wait facades for
+ // the only one that gets added should be testCache1
+ ArrayList<String> cacheNames = new ArrayList<>();
+ int numJunk = 10;
+ for ( int i = 0; i < numJunk; i++ )
+ {
+ cacheNames.add( "junkCacheName" + i );
+ }
+ cacheNames.add( "testCache1" );
+
+ // send max messages
+ int max = 10;
+ int cnt = 0;
+ for ( ; cnt < max; cnt++ )
+ {
+ sender.passiveBroadcast( "localhost", 1111, cacheNames, 1 );
+ SleepUtil.sleepAtLeast( 20 );
+ }
+
+ SleepUtil.sleepAtLeast( 200 );
+
+ // check to see that we got 10 messages
+ //System.out.println( "Receiver count = " + receiver.getCnt() );
+
+ // request braodcasts change things.
+ assertTrue( "Receiver count [" + receiver.getCnt() + "] should be the at least the number sent [" + cnt + "].",
+ cnt <= receiver.getCnt() );
+ sender.close();
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/net/HostNameUtilUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/net/HostNameUtilUnitTest.java
new file mode 100644
index 0000000..5810cc3
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/net/HostNameUtilUnitTest.java
@@ -0,0 +1,46 @@
+package org.apache.commons.jcs3.utils.net;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import java.net.UnknownHostException;
+
+import org.apache.commons.jcs3.utils.net.HostNameUtil;
+
+/** Tests for the host name util. */
+public class HostNameUtilUnitTest
+ extends TestCase
+{
+ /**
+ * It's nearly impossible to unit test the getLocalHostLANAddress method.
+ * <p>
+ * @throws UnknownHostException
+ */
+ public void testGetLocalHostAddress_Simple() throws UnknownHostException
+ {
+ // DO WORK
+ String result = HostNameUtil.getLocalHostAddress();
+
+ // VERIFY
+ //System.out.print( result );
+ assertNotNull( "Should have a host address.", result );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/props/PropertyLoader.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/props/PropertyLoader.java
new file mode 100644
index 0000000..e15ce28
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/props/PropertyLoader.java
@@ -0,0 +1,160 @@
+package org.apache.commons.jcs3.utils.props;
+
+import java.io.IOException;
+
+/*
+ * 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.
+ */
+
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * I modified this class to work with .ccf files in particular. I also removed
+ * the resource bundle functionality.
+ * <p>
+ * A simple class for loading java.util.Properties backed by .ccf files deployed
+ * as classpath resources. See individual methods for details.
+ * <p>
+ * The original source is from:
+ * <p>
+ * @author (C) <a
+ * href="http://www.javaworld.com/columns/jw-qna-index.shtml">Vlad
+ * Roubtsov </a>, 2003
+ */
+public abstract class PropertyLoader
+{
+ /** throw an error if we can load the file */
+ private static final boolean THROW_ON_LOAD_FAILURE = true;
+
+ /** File suffix. */
+ private static final String SUFFIX = ".ccf";
+
+ /** property suffix */
+ private static final String SUFFIX_PROPERTIES = ".properties";
+
+ /**
+ * Looks up a resource named 'name' in the classpath. The resource must map
+ * to a file with .ccf extention. The name is assumed to be absolute and can
+ * use either "/" or "." for package segment separation with an optional
+ * leading "/" and optional ".ccf" suffix.
+ * <p>
+ * The suffix ".ccf" will be appended if it is not set. This can also handle
+ * .properties files
+ * <p>
+ * Thus, the following names refer to the same resource:
+ *
+ * <pre>
+ *
+ * some.pkg.Resource
+ * some.pkg.Resource.ccf
+ * some/pkg/Resource
+ * some/pkg/Resource.ccf
+ * /some/pkg/Resource
+ * /some/pkg/Resource.ccf
+ * </pre>
+ *
+ * @param name
+ * classpath resource name [may not be null]
+ * @param loader
+ * classloader through which to load the resource [null is
+ * equivalent to the application loader]
+ * @return resource converted to java.util.properties [may be null if the
+ * resource was not found and THROW_ON_LOAD_FAILURE is false]
+ * @throws IllegalArgumentException
+ * if the resource was not found and THROW_ON_LOAD_FAILURE is
+ * true
+ */
+ public static Properties loadProperties( String name, ClassLoader loader )
+ {
+ boolean isCCFSuffix = true;
+
+ if ( name == null )
+ {
+ throw new IllegalArgumentException( "null input: name" );
+ }
+
+ ClassLoader classLoader = ( loader == null ) ? ClassLoader.getSystemClassLoader() : loader;
+
+ String fileName = name.startsWith( "/" ) ? name.substring( 1 ) : name;
+
+ if ( fileName.endsWith( SUFFIX ) )
+ {
+ fileName = fileName.substring( 0, fileName.length() - SUFFIX.length() );
+ }
+
+ if ( fileName.endsWith( SUFFIX_PROPERTIES ) )
+ {
+ fileName = fileName.substring( 0, fileName.length() - SUFFIX_PROPERTIES.length() );
+ isCCFSuffix = false;
+ }
+
+ fileName = fileName.replace( '.', '/' );
+
+ if ( !fileName.endsWith( SUFFIX ) && isCCFSuffix )
+ {
+ fileName = fileName.concat( SUFFIX );
+ }
+ else if ( !fileName.endsWith( SUFFIX_PROPERTIES ) && !isCCFSuffix )
+ {
+ fileName = fileName.concat( SUFFIX_PROPERTIES );
+ }
+
+ Properties result = null;
+
+ try (InputStream in = classLoader.getResourceAsStream( fileName ))
+ {
+ result = new Properties();
+ result.load( in ); // can throw IOException
+ }
+ catch ( IOException e )
+ {
+ result = null;
+ }
+
+ if ( THROW_ON_LOAD_FAILURE && result == null )
+ {
+ throw new IllegalArgumentException( "could not load [" + fileName + "]" + " as " + "a classloader resource" );
+ }
+
+ return result;
+ }
+
+ /**
+ * A convenience overload of {@link #loadProperties(String, ClassLoader)}
+ * that uses the current thread's context classloader. A better strategy
+ * would be to use techniques shown in
+ * http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html
+ * <p>
+ * @param name
+ * @return Properties
+ */
+ public static Properties loadProperties( final String name )
+ {
+ return loadProperties( name, Thread.currentThread().getContextClassLoader() );
+ }
+
+ /**
+ * Can't use this one.
+ */
+ private PropertyLoader()
+ {
+ super();
+ } // this class is not extentible
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/serialization/CompressingSerializerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/serialization/CompressingSerializerUnitTest.java
new file mode 100644
index 0000000..8ea76ee
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/serialization/CompressingSerializerUnitTest.java
@@ -0,0 +1,122 @@
+package org.apache.commons.jcs3.utils.serialization;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.utils.serialization.CompressingSerializer;
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+
+/**
+ * Tests the compressing serializer.
+ */
+public class CompressingSerializerUnitTest
+ extends TestCase
+{
+ /**
+ * Verify that we don't get any erorrs for null input.
+ * <p>
+ * @throws ClassNotFoundException
+ * @throws IOException
+ */
+ public void testDeserialize_NullInput()
+ throws IOException, ClassNotFoundException
+ {
+ // SETUP
+ CompressingSerializer serializer = new CompressingSerializer();
+
+ // DO WORK
+ Object result = serializer.deSerialize( null, null );
+
+ // VERIFY
+ assertNull( "Should have nothing.", result );
+ }
+
+ /**
+ * Test simple back and forth with a string.
+ * <p>
+ * ))<=>((
+ * <p>
+ * @throws Exception on error
+ */
+ public void testSimpleBackAndForth()
+ throws Exception
+ {
+ // SETUP
+ CompressingSerializer serializer = new CompressingSerializer();
+
+ // DO WORK
+ String before = "adsfdsafdsafdsafdsafdsafdsafdsagfdsafdsafdsfdsafdsafsa333 31231";
+ String after = (String) serializer.deSerialize( serializer.serialize( before ), null );
+
+ // VERIFY
+ assertEquals( "Before and after should be the same.", before, after );
+ }
+
+ /**
+ * Test serialization with a null object. Verify that we don't get an error.
+ * <p>
+ * @throws Exception on error
+ */
+ public void testSerialize_NullInput()
+ throws Exception
+ {
+ // SETUP
+ CompressingSerializer serializer = new CompressingSerializer();
+
+ String before = null;
+
+ // DO WORK
+ byte[] serialized = serializer.serialize( before );
+ String after = (String) serializer.deSerialize( serialized, null );
+
+ // VERIFY
+ assertNull( "Should have nothing. after =" + after, after );
+ }
+
+ /**
+ * Verify that the compressed is smaller.
+ * <p>
+ * @throws Exception on error
+ */
+ public void testSerialize_CompareCompressedAndUncompressed()
+ throws Exception
+ {
+ // SETUP
+ CompressingSerializer serializer = new CompressingSerializer();
+
+ // I hate for loops.
+ String before = "adsfdsafdsafdsafdsafdsafdsafdsagfdsafdsafdssaf dsaf sadf dsaf dsaf dsaf "
+ + "dsafdsa fdsaf dsaf dsafdsa dsaf dsaf dsaf dsaf dsafdsa76f dsa798f dsa6fdsa 087f "
+ + "gh 987dsahb dsahbuhbfnui nufdsa hbv87 f8vhdsgbnfv h8fdg8dfjvn8fdwgj fdsgjb9fdsjbv"
+ + "jvhjv hg98f-dsaghj j9fdsb gfsb 9fdshjbgb987fdsbfdwgh ujbhjbhb hbfdsgh fdshb "
+ + "Ofdsgyfesgyfdsafdsafsa333 31231";
+
+ // DO WORK
+ byte[] compressed = serializer.serialize( before );
+ byte[] nonCompressed = new StandardSerializer().serialize( before );
+
+ // VERIFY
+ assertTrue( "Compressed should be smaller. compressed size = " + compressed.length + "nonCompressed size = "
+ + nonCompressed.length, compressed.length < nonCompressed.length );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/serialization/SerializationConversionUtilUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/serialization/SerializationConversionUtilUnitTest.java
new file mode 100644
index 0000000..af7d0c8
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/serialization/SerializationConversionUtilUnitTest.java
@@ -0,0 +1,198 @@
+package org.apache.commons.jcs3.utils.serialization;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.ElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICacheElementSerialized;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.utils.serialization.SerializationConversionUtil;
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+
+/**
+ * Tests the serialization conversion util.
+ * <p>
+ * @author Aaron Smuts
+ */
+public class SerializationConversionUtilUnitTest
+ extends TestCase
+{
+ /**
+ * Verify null for null.
+ * <p>
+ * @throws IOException
+ */
+ public void testgGetSerializedCacheElement_null()
+ throws IOException
+ {
+ // SETUP
+ IElementSerializer elementSerializer = new StandardSerializer();
+ ICacheElement<String, String> before = null;
+
+ // DO WORK
+ ICacheElementSerialized<String, String> result =
+ SerializationConversionUtil.getSerializedCacheElement( before, elementSerializer );
+
+ // VERIFY
+ assertNull( "Should get null for null", result );
+ }
+
+ /**
+ * Verify null for null.
+ * <p>
+ * @throws Exception
+ */
+ public void testgGetDeSerializedCacheElement_null()
+ throws Exception
+ {
+ // SETUP
+ IElementSerializer elementSerializer = new StandardSerializer();
+ ICacheElementSerialized<String, String> before = null;
+
+ // DO WORK
+ ICacheElement<String, String> result =
+ SerializationConversionUtil.getDeSerializedCacheElement( before, elementSerializer );
+
+ // VERIFY
+ assertNull( "Should get null for null", result );
+ }
+
+ /**
+ * Verify that we can go back and forth with the simplest of objects.
+ * <p>
+ * @throws Exception
+ */
+ public void testSimpleConversion()
+ throws Exception
+ {
+ // SETUP
+ String cacheName = "testName";
+ String key = "key";
+ String value = "value fdsadf dsafdsa fdsaf dsafdsaf dsafdsaf dsaf dsaf dsaf dsafa dsaf dsaf dsafdsaf";
+
+ IElementSerializer elementSerializer = new StandardSerializer();
+
+ IElementAttributes attr = new ElementAttributes();
+ attr.setMaxLife(34);
+
+ ICacheElement<String, String> before = new CacheElement<>( cacheName, key, value );
+ before.setElementAttributes( attr );
+
+ // DO WORK
+ ICacheElementSerialized<String, String> serialized =
+ SerializationConversionUtil.getSerializedCacheElement( before, elementSerializer );
+
+ // VERIFY
+ assertNotNull( "Should have a serialized object.", serialized );
+
+ // DO WORK
+ ICacheElement<String, String> after =
+ SerializationConversionUtil.getDeSerializedCacheElement( serialized, elementSerializer );
+
+ // VERIFY
+ assertNotNull( "Should have a deserialized object.", after );
+ assertEquals( "Values should be the same.", before.getVal(), after.getVal() );
+ assertEquals( "Attributes should be the same.", before.getElementAttributes().getMaxLife(), after
+ .getElementAttributes().getMaxLife() );
+ assertEquals( "Keys should be the same.", before.getKey(), after.getKey() );
+ assertEquals( "Cache name should be the same.", before.getCacheName(), after.getCacheName() );
+ }
+
+ /**
+ * Verify that we can go back and forth with the simplest of objects.
+ *<p>
+ * @throws Exception
+ */
+ public void testAccidentalDoubleConversion()
+ throws Exception
+ {
+ // SETUP
+ String cacheName = "testName";
+ String key = "key";
+ String value = "value fdsadf dsafdsa fdsaf dsafdsaf dsafdsaf dsaf dsaf dsaf dsafa dsaf dsaf dsafdsaf";
+
+ IElementSerializer elementSerializer = new StandardSerializer();
+
+ IElementAttributes attr = new ElementAttributes();
+ attr.setMaxLife(34);
+
+ ICacheElement<String, String> before = new CacheElement<>( cacheName, key, value );
+ before.setElementAttributes( attr );
+
+ // DO WORK
+ ICacheElementSerialized<String, String> alreadySerialized =
+ SerializationConversionUtil.getSerializedCacheElement( before, elementSerializer );
+ ICacheElementSerialized<String, String> serialized =
+ SerializationConversionUtil.getSerializedCacheElement( alreadySerialized, elementSerializer );
+
+ // VERIFY
+ assertNotNull( "Should have a serialized object.", serialized );
+
+ // DO WORK
+ ICacheElement<String, String> after =
+ SerializationConversionUtil.getDeSerializedCacheElement( serialized, elementSerializer );
+
+ // VERIFY
+ assertNotNull( "Should have a deserialized object.", after );
+ assertEquals( "Values should be the same.", before.getVal(), after.getVal() );
+ assertEquals( "Attributes should be the same.", before.getElementAttributes().getMaxLife(), after
+ .getElementAttributes().getMaxLife() );
+ assertEquals( "Keys should be the same.", before.getKey(), after.getKey() );
+ assertEquals( "Cache name should be the same.", before.getCacheName(), after.getCacheName() );
+ }
+
+ /**
+ * Verify that we get an IOException for a null serializer.
+ */
+ public void testNullSerializerConversion()
+ {
+ // SETUP
+ String cacheName = "testName";
+ String key = "key";
+ String value = "value fdsadf dsafdsa fdsaf dsafdsaf dsafdsaf dsaf dsaf dsaf dsafa dsaf dsaf dsafdsaf";
+
+ IElementSerializer elementSerializer = null;// new StandardSerializer();
+
+ IElementAttributes attr = new ElementAttributes();
+ attr.setMaxLife(34);
+
+ ICacheElement<String, String> before = new CacheElement<>( cacheName, key, value );
+ before.setElementAttributes( attr );
+
+ // DO WORK
+ try
+ {
+ SerializationConversionUtil.getSerializedCacheElement( before, elementSerializer );
+
+ // VERIFY
+ fail( "We should have received an IOException." );
+ }
+ catch ( IOException e )
+ {
+ // expected
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/serialization/StandardSerializerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/serialization/StandardSerializerUnitTest.java
new file mode 100644
index 0000000..cfa38ce
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/serialization/StandardSerializerUnitTest.java
@@ -0,0 +1,104 @@
+package org.apache.commons.jcs3.utils.serialization;
+
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ * Tests the standard serializer.
+ *<p>
+ * @author Aaron Smuts
+ */
+public class StandardSerializerUnitTest
+ extends TestCase
+{
+ /**
+ * Test simple back and forth with a string.
+ *<p>
+ * @throws Exception
+ */
+ public void testSimpleBackAndForth()
+ throws Exception
+ {
+ // SETUP
+ StandardSerializer serializer = new StandardSerializer();
+
+ String before = "adsfdsafdsafdsafdsafdsafdsafdsagfdsafdsafdsfdsafdsafsa333 31231";
+
+ // DO WORK
+ String after = (String) serializer.deSerialize( serializer.serialize( before ), null );
+
+ // VERIFY
+ assertEquals( "Before and after should be the same.", before, after );
+ }
+
+ /**
+ * Test serialization with a null object. Verify that we don't get an error.
+ *<p>
+ * @throws Exception
+ */
+ public void testNullInput()
+ throws Exception
+ {
+ // SETUP
+ StandardSerializer serializer = new StandardSerializer();
+
+ String before = null;
+
+ // DO WORK
+ byte[] serialized = serializer.serialize( before );
+ //System.out.println( "testNullInput " + serialized );
+
+ String after = (String) serializer.deSerialize( serialized, null );
+ //System.out.println( "testNullInput " + after );
+
+ // VERIFY
+ assertNull( "Should have nothing.", after );
+ }
+
+ /**
+ * Test simple back and forth with a string.
+ *<p>
+ * @throws Exception
+ */
+ public void testBigStringBackAndForth()
+ throws Exception
+ {
+ // SETUP
+ StandardSerializer serializer = new StandardSerializer();
+
+ String string = "This is my big string ABCDEFGH";
+ StringBuilder sb = new StringBuilder();
+ sb.append( string );
+ for ( int i = 0; i < 4; i++ )
+ {
+ sb.append( " " + i + sb.toString() ); // big string
+ }
+ String before = sb.toString();
+
+ // DO WORK
+ String after = (String) serializer.deSerialize( serializer.serialize( before ), null );
+
+ // VERIFY
+ assertEquals( "Before and after should be the same.", before, after );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/struct/DoubleLinkedListDumpUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/struct/DoubleLinkedListDumpUnitTest.java
new file mode 100644
index 0000000..2aa4a11
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/struct/DoubleLinkedListDumpUnitTest.java
@@ -0,0 +1,60 @@
+package org.apache.commons.jcs3.utils.struct;
+
+import java.io.StringWriter;
+
+import org.apache.commons.jcs3.TestLogConfigurationUtil;
+import org.apache.commons.jcs3.utils.struct.DoubleLinkedList;
+import org.apache.commons.jcs3.utils.struct.DoubleLinkedListNode;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/** Unit tests for the double linked list. */
+public class DoubleLinkedListDumpUnitTest
+ extends TestCase
+{
+ /** verify that the entries are dumped. */
+ public void testDumpEntries_DebugTrue()
+ {
+ // SETUP
+ StringWriter stringWriter = new StringWriter();
+ TestLogConfigurationUtil.configureLogger( stringWriter, DoubleLinkedList.class.getName() );
+
+ DoubleLinkedList<DoubleLinkedListNode<String>> list = new DoubleLinkedList<>();
+
+ String payload1 = "payload1";
+ DoubleLinkedListNode<String> node1 = new DoubleLinkedListNode<>( payload1 );
+
+ String payload2 = "payload2";
+ DoubleLinkedListNode<String> node2 = new DoubleLinkedListNode<>( payload2 );
+
+ list.addLast( node1 );
+ list.addLast( node2 );
+ list.debugDumpEntries();
+
+ // WO WORK
+ String result = stringWriter.toString();
+
+ // VERIFY
+ assertTrue( "Missing node in log dump", result.indexOf( payload1 ) != -1 );
+ assertTrue( "Missing node in log dump", result.indexOf( payload2 ) != -1 );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/struct/DoubleLinkedListUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/struct/DoubleLinkedListUnitTest.java
new file mode 100644
index 0000000..616ee5e
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/struct/DoubleLinkedListUnitTest.java
@@ -0,0 +1,162 @@
+package org.apache.commons.jcs3.utils.struct;
+
+import org.apache.commons.jcs3.utils.struct.DoubleLinkedList;
+import org.apache.commons.jcs3.utils.struct.DoubleLinkedListNode;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+/** Unit tests for the double linked list. */
+public class DoubleLinkedListUnitTest
+ extends TestCase
+{
+ /** verify that the last is added when the list is empty. */
+ public void testAddLast_Empty()
+ {
+ // SETUP
+ DoubleLinkedList<DoubleLinkedListNode<String>> list = new DoubleLinkedList<>();
+
+ String payload1 = "payload1";
+ DoubleLinkedListNode<String> node1 = new DoubleLinkedListNode<>( payload1 );
+
+ // WO WORK
+ list.addLast( node1 );
+
+ // VERIFY
+ assertEquals( "Wrong last", node1, list.getLast() );
+ }
+
+ /** verify that the last is added when the list is empty. */
+ public void testAddLast_NotEmpty()
+ {
+ // SETUP
+ DoubleLinkedList<DoubleLinkedListNode<String>> list = new DoubleLinkedList<>();
+
+ String payload1 = "payload1";
+ DoubleLinkedListNode<String> node1 = new DoubleLinkedListNode<>( payload1 );
+
+ String payload2 = "payload2";
+ DoubleLinkedListNode<String> node2 = new DoubleLinkedListNode<>( payload2 );
+
+ // WO WORK
+ list.addLast( node1 );
+ list.addLast( node2 );
+
+ // VERIFY
+ assertEquals( "Wrong last", node2, list.getLast() );
+ }
+
+ /** verify that it's added last. */
+ public void testMakeLast_wasFirst()
+ {
+ // SETUP
+ DoubleLinkedList<DoubleLinkedListNode<String>> list = new DoubleLinkedList<>();
+
+ String payload1 = "payload1";
+ DoubleLinkedListNode<String> node1 = new DoubleLinkedListNode<>( payload1 );
+
+ String payload2 = "payload2";
+ DoubleLinkedListNode<String> node2 = new DoubleLinkedListNode<>( payload2 );
+
+ list.addFirst( node2 );
+ list.addFirst( node1 );
+
+ // DO WORK
+ list.makeLast( node1 );
+
+ // VERIFY
+ assertEquals( "Wrong size", 2, list.size() );
+ assertEquals( "Wrong last", node1, list.getLast() );
+ assertEquals( "Wrong first", node2, list.getFirst() );
+ }
+
+ /** verify that it's added last. */
+ public void testMakeLast_wasLast()
+ {
+ // SETUP
+ DoubleLinkedList<DoubleLinkedListNode<String>> list = new DoubleLinkedList<>();
+
+ String payload1 = "payload1";
+ DoubleLinkedListNode<String> node1 = new DoubleLinkedListNode<>( payload1 );
+
+ String payload2 = "payload2";
+ DoubleLinkedListNode<String> node2 = new DoubleLinkedListNode<>( payload2 );
+
+ list.addFirst( node1 );
+ list.addFirst( node2 );
+
+ // DO WORK
+ list.makeLast( node1 );
+
+ // VERIFY
+ assertEquals( "Wrong size", 2, list.size() );
+ assertEquals( "Wrong last", node1, list.getLast() );
+ assertEquals( "Wrong first", node2, list.getFirst() );
+ }
+
+ /** verify that it's added last. */
+ public void testMakeLast_wasAlone()
+ {
+ // SETUP
+ DoubleLinkedList<DoubleLinkedListNode<String>> list = new DoubleLinkedList<>();
+
+ String payload1 = "payload1";
+ DoubleLinkedListNode<String> node1 = new DoubleLinkedListNode<>( payload1 );
+
+ list.addFirst( node1 );
+
+ // DO WORK
+ list.makeLast( node1 );
+
+ // VERIFY
+ assertEquals( "Wrong size", 1, list.size() );
+ assertEquals( "Wrong last", node1, list.getLast() );
+ assertEquals( "Wrong first", node1, list.getFirst() );
+ }
+
+ /** verify that it's added last. */
+ public void testMakeLast_wasInMiddle()
+ {
+ // SETUP
+ DoubleLinkedList<DoubleLinkedListNode<String>> list = new DoubleLinkedList<>();
+
+ String payload1 = "payload1";
+ DoubleLinkedListNode<String> node1 = new DoubleLinkedListNode<>( payload1 );
+
+ String payload2 = "payload2";
+ DoubleLinkedListNode<String> node2 = new DoubleLinkedListNode<>( payload2 );
+
+ String payload3 = "payload3";
+ DoubleLinkedListNode<String> node3 = new DoubleLinkedListNode<>( payload3 );
+
+ list.addFirst( node2 );
+ list.addFirst( node1 );
+ list.addFirst( node3 );
+
+ // DO WORK
+ list.makeLast( node1 );
+
+ // VERIFY
+ assertEquals( "Wrong size", 3, list.size() );
+ assertEquals( "Wrong last", node1, list.getLast() );
+ assertEquals( "Wrong first", node3, list.getFirst() );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/struct/JCSvsCommonsLRUMapPerformanceTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/struct/JCSvsCommonsLRUMapPerformanceTest.java
new file mode 100644
index 0000000..cfc39a3
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/struct/JCSvsCommonsLRUMapPerformanceTest.java
@@ -0,0 +1,180 @@
+package org.apache.commons.jcs3.utils.struct;
+
+/*
+ * 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.
+ */
+
+import java.util.Map;
+
+import org.apache.commons.jcs3.log.Log;
+import org.apache.commons.jcs3.log.LogManager;
+import org.apache.commons.jcs3.utils.struct.LRUMap;
+
+import junit.framework.TestCase;
+
+/**
+ * This ensures that the jcs version of the LRU map is as fast as the commons
+ * version. It has been testing at .6 to .7 times the commons LRU.
+ *
+ */
+public class JCSvsCommonsLRUMapPerformanceTest
+ extends TestCase
+{
+ /** jcs / commons */
+ float ratioPut = 0;
+
+ /** jcs / commons */
+ float ratioGet = 0;
+
+ /** goal */
+ float target = 1.0f;
+
+ /** loops */
+ int loops = 20;
+
+ /** number to test with */
+ int tries = 100000;
+
+ /**
+ * A unit test for JUnit
+ *
+ * @throws Exception
+ * Description of the Exception
+ */
+ public void testSimpleLoad()
+ throws Exception
+ {
+ Log log = LogManager.getLog( LRUMap.class );
+ if ( log.isDebugEnabled() )
+ {
+ System.out.println( "The log level must be at info or above for the a performance test." );
+ return;
+ }
+
+ doWork();
+ assertTrue( this.ratioPut < target );
+ assertTrue( this.ratioGet < target );
+ }
+
+ /**
+ *
+ */
+ public void doWork()
+ {
+ long start = 0;
+ long end = 0;
+ long time = 0;
+ float tPer = 0;
+
+ long putTotalJCS = 0;
+ long getTotalJCS = 0;
+ long putTotalHashtable = 0;
+ long getTotalHashtable = 0;
+
+ String name = "LRUMap";
+ String cache2Name = "";
+
+ try
+ {
+ Map<String, String> cache = new LRUMap<>( tries );
+
+ for ( int j = 0; j < loops; j++ )
+ {
+ name = "JCS ";
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ cache.put( "key:" + i, "data" + i );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ putTotalJCS += time;
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( name + " put time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ cache.get( "key:" + i );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ getTotalJCS += time;
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ // /////////////////////////////////////////////////////////////
+ cache2Name = "Commons ";
+ // or LRUMapJCS
+ Map<String, String> cache2 = new org.apache.commons.collections4.map.LRUMap<>( tries );
+ // cache2Name = "Hashtable";
+ // Hashtable cache2 = new Hashtable();
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ cache2.put( "key:" + i, "data" + i );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ putTotalHashtable += time;
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( cache2Name + " put time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ cache2.get( "key:" + i );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ getTotalHashtable += time;
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( cache2Name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ System.out.println( "\n" );
+ }
+
+ }
+ catch ( Exception e )
+ {
+ e.printStackTrace( System.out );
+ System.out.println( e );
+ }
+
+ long putAvJCS = putTotalJCS / loops;
+ long getAvJCS = getTotalJCS / loops;
+ long putAvHashtable = putTotalHashtable / loops;
+ long getAvHashtable = getTotalHashtable / loops;
+
+ System.out.println( "Finished " + loops + " loops of " + tries + " gets and puts" );
+
+ System.out.println( "\n" );
+ System.out.println( "Put average for LRUMap = " + putAvJCS );
+ System.out.println( "Put average for " + cache2Name + " = " + putAvHashtable );
+ ratioPut = Float.intBitsToFloat( (int) putAvJCS ) / Float.intBitsToFloat( (int) putAvHashtable );
+ System.out.println( name + " puts took " + ratioPut + " times the " + cache2Name + ", the goal is <" + target
+ + "x" );
+
+ System.out.println( "\n" );
+ System.out.println( "Get average for LRUMap = " + getAvJCS );
+ System.out.println( "Get average for " + cache2Name + " = " + getAvHashtable );
+ ratioGet = Float.intBitsToFloat( (int) getAvJCS ) / Float.intBitsToFloat( (int) getAvHashtable );
+ System.out.println( name + " gets took " + ratioGet + " times the " + cache2Name + ", the goal is <" + target
+ + "x" );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/struct/LRUMapConcurrentUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/struct/LRUMapConcurrentUnitTest.java
new file mode 100644
index 0000000..06c9829
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/struct/LRUMapConcurrentUnitTest.java
@@ -0,0 +1,284 @@
+package org.apache.commons.jcs3.utils.struct;
+
+/*
+ * 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.
+ */
+
+import java.util.Iterator;
+
+import org.apache.commons.jcs3.utils.struct.LRUMap;
+
+/*
+ * 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.
+ */
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Tests the LRUMap
+ *
+ */
+public class LRUMapConcurrentUnitTest
+ extends TestCase
+{
+ /** number to test with */
+ private static int items = 20000;
+
+ /**
+ * Constructor for the TestSimpleLoad object
+ * <p>
+ * @param testName
+ * Description of the Parameter
+ */
+ public LRUMapConcurrentUnitTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * A unit test suite for JUnit
+ * <p>
+ * @return The test suite
+ */
+ public static Test suite()
+ {
+ // run the basic tests
+ TestSuite suite = new TestSuite( LRUMapConcurrentUnitTest.class );
+
+ // run concurrent tests
+ final LRUMap<String, String> map = new LRUMap<>( 2000 );
+ suite.addTest( new LRUMapConcurrentUnitTest( "conc1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runConcurrentPutGetTests( map, 2000 );
+ }
+ } );
+ suite.addTest( new LRUMapConcurrentUnitTest( "conc2" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runConcurrentPutGetTests( map, 2000 );
+ }
+ } );
+ suite.addTest( new LRUMapConcurrentUnitTest( "conc3" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runConcurrentPutGetTests( map, 2000 );
+ }
+ } );
+
+ // run more concurrent tests
+ final int max2 = 20000;
+ final LRUMap<String, String> map2 = new LRUMap<>( max2 );
+ suite.addTest( new LRUMapConcurrentUnitTest( "concB1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runConcurrentRangeTests( map2, 10000, max2 );
+ }
+ } );
+ suite.addTest( new LRUMapConcurrentUnitTest( "concB1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runConcurrentRangeTests( map2, 0, 9999 );
+ }
+ } );
+
+ return suite;
+ }
+
+ /**
+ * Just test that we can put, get and remove as expected.
+ * <p>
+ * @throws Exception
+ * Description of the Exception
+ */
+ public void testSimpleLoad()
+ throws Exception
+ {
+ LRUMap<String, String> map = new LRUMap<>( items );
+
+ for ( int i = 0; i < items; i++ )
+ {
+ map.put( i + ":key", "data" + i );
+ }
+
+ for ( int i = items - 1; i >= 0; i-- )
+ {
+ String res = map.get( i + ":key" );
+ assertNotNull( "[" + i + ":key] should not be null", res );
+ }
+
+ // test removal
+ map.remove( "300:key" );
+ assertNull( map.get( "300:key" ) );
+
+ }
+
+ /**
+ * Just make sure that the LRU functions in he most simple case.
+ *
+ * @throws Exception
+ * Description of the Exception
+ */
+ public void testLRURemoval()
+ throws Exception
+ {
+ int total = 10;
+ LRUMap<String, String> map = new LRUMap<>( total );
+
+ // put the max in
+ for ( int i = 0; i < total; i++ )
+ {
+ map.put( i + ":key", "data" + i );
+ }
+
+ Iterator<?> it = map.entrySet().iterator();
+ while ( it.hasNext() )
+ {
+ assertNotNull( it.next() );
+ }
+// System.out.println( map.getStatistics() );
+
+ // get the max out backwards
+ for ( int i = total - 1; i >= 0; i-- )
+ {
+ String res = map.get( i + ":key" );
+ assertNotNull( "[" + i + ":key] should not be null", res );
+ }
+
+// System.out.println( map.getStatistics() );
+
+ //since we got them backwards the total should be at the end.
+ // add one confirm that total is gone.
+ map.put( ( total ) + ":key", "data" + ( total ) );
+ assertNull( map.get( ( total - 1 ) + ":key" ) );
+
+ }
+
+ /**
+ * @throws Exception
+ */
+ public void testLRURemovalAgain()
+ throws Exception
+ {
+ int total = 10000;
+ LRUMap<String, String> map = new LRUMap<>( total );
+
+ // put the max in
+ for ( int i = 0; i < total * 2; i++ )
+ {
+ map.put( i + ":key", "data" + i );
+ }
+
+ // get the total number, these should be null
+ for ( int i = total - 1; i >= 0; i-- )
+ {
+ assertNull( map.get( i + ":key" ) );
+ }
+
+ // get the total to total *2 items out, these should be found.
+ for ( int i = ( total * 2 ) - 1; i >= total; i-- )
+ {
+ String res = map.get( i + ":key" );
+ assertNotNull( "[" + i + ":key] should not be null", res );
+ }
+
+// System.out.println( map.getStatistics() );
+ }
+
+ /**
+ * Just make sure that we can put and get concurrently
+ *
+ * @param map
+ * @param items
+ * @throws Exception
+ */
+ public void runConcurrentPutGetTests( LRUMap<String, String> map, int items )
+ throws Exception
+ {
+ for ( int i = 0; i < items; i++ )
+ {
+ map.put( i + ":key", "data" + i );
+ }
+
+ for ( int i = items - 1; i >= 0; i-- )
+ {
+ String res = map.get( i + ":key" );
+ assertNotNull( "[" + i + ":key] should not be null", res );
+ }
+ }
+
+ /**
+ * Put, get, and remove from a range. This should occur at a range that is
+ * not touched by other tests.
+ * <p>
+ * @param map
+ * @param start
+ * @param end
+ * @throws Exception
+ */
+ public void runConcurrentRangeTests( LRUMap<String, String> map, int start, int end )
+ throws Exception
+ {
+ for ( int i = start; i < end; i++ )
+ {
+ map.put( i + ":key", "data" + i );
+ }
+
+ for ( int i = end - 1; i >= start; i-- )
+ {
+ String res = map.get( i + ":key" );
+ assertNotNull( "[" + i + ":key] should not be null", res );
+ }
+
+ // test removal
+ map.remove( start + ":key" );
+ assertNull( map.get( start + ":key" ) );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/struct/LRUMapPerformanceTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/struct/LRUMapPerformanceTest.java
new file mode 100644
index 0000000..ed9a63f
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/struct/LRUMapPerformanceTest.java
@@ -0,0 +1,178 @@
+package org.apache.commons.jcs3.utils.struct;
+
+/*
+ * 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.
+ */
+
+import java.util.Map;
+
+import org.apache.commons.jcs3.utils.struct.LRUMap;
+
+import junit.framework.TestCase;
+
+/**
+ * This ensures that the jcs version of the LRU map is as fast as the commons
+ * version. It has been testing at .6 to .7 times the commons LRU.
+ * <p>
+ * @author aaronsm
+ *
+ */
+public class LRUMapPerformanceTest
+ extends TestCase
+{
+ /** The put put ration after the test */
+ float ratioPut = 0;
+
+ /** The ratio after the test */
+ float ratioGet = 0;
+
+ /** put jcs / commons ratio */
+ float targetPut = 1.2f;
+
+ /** get jcs / commons ratio */
+ float targetGet = .5f;
+
+ /** Time to loop */
+ int loops = 20;
+
+ /** items to put and get per loop */
+ int tries = 100000;
+
+ /**
+ * A unit test for JUnit
+ *
+ * @throws Exception
+ * Description of the Exception
+ */
+ public void testSimpleLoad()
+ throws Exception
+ {
+ doWork();
+ assertTrue( this.ratioPut < targetPut );
+ assertTrue( this.ratioGet < targetGet );
+ }
+
+ /**
+ *
+ */
+ public void doWork()
+ {
+ long start = 0;
+ long end = 0;
+ long time = 0;
+ float tPer = 0;
+
+ long putTotalJCS = 0;
+ long getTotalJCS = 0;
+ long putTotalHashtable = 0;
+ long getTotalHashtable = 0;
+
+ String name = "LRUMap";
+ String cache2Name = "";
+
+ try
+ {
+ LRUMap<String, String> cache = new LRUMap<>( tries );
+
+ for ( int j = 0; j < loops; j++ )
+ {
+ name = "JCS ";
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ cache.put( "key:" + i, "data" + i );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ putTotalJCS += time;
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( name + " put time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ cache.get( "key:" + i );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ getTotalJCS += time;
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ ///////////////////////////////////////////////////////////////
+ cache2Name = "LRUMap (commons)";
+ //or LRUMapJCS
+ Map<String, String> cache2 = new org.apache.commons.collections4.map.LRUMap<>( tries );
+// Map<String, String> cache2 = new ConcurrentLinkedHashMap.Builder<String, String>()
+// .maximumWeightedCapacity( tries )
+// .build();
+ //cache2Name = "Hashtable";
+ //Hashtable cache2 = new Hashtable();
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ cache2.put( "key:" + i, "data" + i );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ putTotalHashtable += time;
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( cache2Name + " put time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ start = System.currentTimeMillis();
+ for ( int i = 0; i < tries; i++ )
+ {
+ cache2.get( "key:" + i );
+ }
+ end = System.currentTimeMillis();
+ time = end - start;
+ getTotalHashtable += time;
+ tPer = Float.intBitsToFloat( (int) time ) / Float.intBitsToFloat( tries );
+ System.out.println( cache2Name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
+
+ System.out.println( "\n" );
+ }
+ }
+ catch ( Exception e )
+ {
+ e.printStackTrace( System.out );
+ System.out.println( e );
+ }
+
+ long putAvJCS = putTotalJCS / loops;
+ long getAvJCS = getTotalJCS / loops;
+ long putAvHashtable = putTotalHashtable / loops;
+ long getAvHashtable = getTotalHashtable / loops;
+
+ System.out.println( "Finished " + loops + " loops of " + tries + " gets and puts" );
+
+ System.out.println( "\n" );
+ System.out.println( "Put average for LRUMap = " + putAvJCS );
+ System.out.println( "Put average for " + cache2Name + " = " + putAvHashtable );
+ ratioPut = Float.intBitsToFloat( (int) putAvJCS ) / Float.intBitsToFloat( (int) putAvHashtable );
+ System.out.println( name + " puts took " + ratioPut + " times the " + cache2Name + ", the goal is <" + targetPut
+ + "x" );
+
+ System.out.println( "\n" );
+ System.out.println( "Get average for LRUMap = " + getAvJCS );
+ System.out.println( "Get average for " + cache2Name + " = " + getAvHashtable );
+ ratioGet = Float.intBitsToFloat( (int) getAvJCS ) / Float.intBitsToFloat( (int) getAvHashtable );
+ System.out.println( name + " gets took " + ratioGet + " times the " + cache2Name + ", the goal is <" + targetGet
+ + "x" );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/struct/LRUMapUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/struct/LRUMapUnitTest.java
new file mode 100644
index 0000000..c65707f
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/struct/LRUMapUnitTest.java
@@ -0,0 +1,136 @@
+package org.apache.commons.jcs3.utils.struct;
+
+/*
+ * 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.
+ */
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.commons.jcs3.utils.struct.LRUMap;
+
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+/**
+ * Basic unit tests for the LRUMap
+ *
+ * @author Aaron Smuts
+ *
+ */
+public class LRUMapUnitTest
+ extends TestCase
+{
+
+ /**
+ * Put up to the size limit and then make sure they are all there.
+ *
+ */
+ public void testPutWithSizeLimit()
+ {
+ int size = 10;
+ Map<String, String> cache = new LRUMap<>( size );
+
+ for ( int i = 0; i < size; i++ )
+ {
+ cache.put( "key:" + i, "data:" + i );
+ }
+
+ for ( int i = 0; i < size; i++ )
+ {
+ String data = cache.get( "key:" + i );
+ assertEquals( "Data is wrong.", "data:" + i, data );
+ }
+ }
+
+ /**
+ * Put into the lru with no limit and then make sure they are all there.
+ *
+ */
+ public void testPutWithNoSizeLimit()
+ {
+ int size = 10;
+ Map<String, String> cache = new LRUMap<>( );
+
+ for ( int i = 0; i < size; i++ )
+ {
+ cache.put( "key:" + i, "data:" + i );
+ }
+
+ for ( int i = 0; i < size; i++ )
+ {
+ String data = cache.get( "key:" + i );
+ assertEquals( "Data is wrong.", "data:" + i, data );
+ }
+ }
+
+ /**
+ * Put and then remove. Make sure the element is returned.
+ *
+ */
+ public void testPutAndRemove()
+ {
+ int size = 10;
+ Map<String, String> cache = new LRUMap<>( size );
+
+ cache.put( "key:" + 1, "data:" + 1 );
+ String data = cache.remove( "key:" + 1 );
+ assertEquals( "Data is wrong.", "data:" + 1, data );
+ }
+
+ /**
+ * Call remove on an empty map
+ *
+ */
+ public void testRemoveEmpty()
+ {
+ int size = 10;
+ Map<String, String> cache = new LRUMap<>( size );
+
+ Object returned = cache.remove( "key:" + 1 );
+ assertNull( "Shouldn't hvae anything.", returned );
+ }
+
+
+ /**
+ * Add items to the map and then test to see that they come back in the entry set.
+ *
+ */
+ public void testGetEntrySet()
+ {
+ int size = 10;
+ Map<String, String> cache = new LRUMap<>( size );
+
+ for ( int i = 0; i < size; i++ )
+ {
+ cache.put( "key:" + i, "data:" + i );
+ }
+
+ Set<Entry<String, String>> entries = cache.entrySet();
+ assertEquals( "Set contains the wrong number of items.", size, entries.size() );
+
+ // check minimal correctness
+ for (Entry<String, String> data : entries)
+ {
+ assertTrue( "Data is wrong.", data.getValue().indexOf( "data:") != -1 );
+ }
+ }
+
+
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/threadpool/ThreadPoolManagerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/threadpool/ThreadPoolManagerUnitTest.java
new file mode 100644
index 0000000..d68a40f
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/threadpool/ThreadPoolManagerUnitTest.java
@@ -0,0 +1,88 @@
+package org.apache.commons.jcs3.utils.threadpool;
+
+/*
+ * 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.
+ */
+
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+
+import org.apache.commons.jcs3.utils.props.PropertyLoader;
+import org.apache.commons.jcs3.utils.threadpool.ThreadPoolManager;
+
+import junit.framework.TestCase;
+
+/**
+ * Verify that the manager can create pools as intended by the default and
+ * specified file names.
+ *
+ * @author asmuts
+ */
+public class ThreadPoolManagerUnitTest
+ extends TestCase
+{
+
+ /**
+ * Make sure it can load a default cache.ccf file
+ */
+ public void testDefaultConfig()
+ {
+ Properties props = PropertyLoader.loadProperties( "thread_pool.properties" );
+ ThreadPoolManager.setProps( props );
+ ThreadPoolManager mgr = ThreadPoolManager.getInstance();
+ assertNotNull( mgr );
+
+ ExecutorService pool = mgr.getExecutorService( "test1" );
+ assertNotNull( pool );
+ }
+
+ /**
+ * Make sure it can load a certain configuration
+ */
+ public void testSpecialConfig()
+ {
+ Properties props = PropertyLoader.loadProperties( "thread_pool.properties" );
+ ThreadPoolManager.setProps( props );
+ ThreadPoolManager mgr = ThreadPoolManager.getInstance();
+ assertNotNull( mgr );
+
+ ExecutorService pool = mgr.getExecutorService( "aborttest" );
+ assertNotNull( pool );
+ }
+
+ /**
+ * Get a couple pools by name and then see if they are in the list.
+ *
+ */
+ public void testGetPoolNames()
+ {
+ ThreadPoolManager mgr = ThreadPoolManager.getInstance();
+ assertNotNull( mgr );
+
+ String poolName1 = "testGetPoolNames1";
+ mgr.getExecutorService( poolName1 );
+
+ String poolName2 = "testGetPoolNames2";
+ mgr.getExecutorService( poolName2 );
+
+ Set<String> names = mgr.getPoolNames();
+ assertTrue( "Should have name in list.", names.contains( poolName1 ) );
+ assertTrue( "Should have name in list.", names.contains( poolName2 ) );
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/timing/SleepUtil.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/timing/SleepUtil.java
new file mode 100644
index 0000000..fdacaa4
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/timing/SleepUtil.java
@@ -0,0 +1,50 @@
+package org.apache.commons.jcs3.utils.timing;
+
+/*
+ * 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.
+ */
+
+/**
+ * Utility methods to help deal with thread issues.
+ */
+public class SleepUtil
+{
+ /**
+ * Sleep for a specified duration in milliseconds. This method is a
+ * platform-specific workaround for Windows due to its inability to resolve
+ * durations of time less than approximately 10 - 16 ms.
+ * <p>
+ * @param milliseconds the number of milliseconds to sleep
+ */
+ public static void sleepAtLeast( long milliseconds )
+ {
+ long endTime = System.currentTimeMillis() + milliseconds;
+
+ while ( System.currentTimeMillis() <= endTime )
+ {
+ try
+ {
+ Thread.sleep( milliseconds );
+ }
+ catch ( InterruptedException e )
+ {
+ // TODO - Do something here?
+ }
+ }
+ }
+}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/zip/CompressionUtilUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/zip/CompressionUtilUnitTest.java
new file mode 100644
index 0000000..fd3c618
--- /dev/null
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs3/utils/zip/CompressionUtilUnitTest.java
@@ -0,0 +1,99 @@
+package org.apache.commons.jcs3.utils.zip;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.zip.GZIPOutputStream;
+
+import org.apache.commons.jcs3.utils.zip.CompressionUtil;
+
+/** Unit tests for the compression util */
+public class CompressionUtilUnitTest
+ extends TestCase
+{
+ /** Test method for decompressByteArray. */
+ public final void testDecompressByteArray_failure()
+ {
+ try
+ {
+ // DO WORK
+ CompressionUtil.decompressByteArray( null );
+
+ // VERIFY
+ fail( "excepted an IllegalArgumentException" );
+ }
+ catch ( IllegalArgumentException exception )
+ {
+ // expected
+ return;
+ }
+ }
+
+ /**
+ * Test method for decompressByteArray.
+ * <p>
+ * @throws IOException
+ */
+ public final void testCompressDecompressByteArray_success()
+ throws IOException
+ {
+ // SETUP
+ String text = "This is some text to compress, not a lot, just a bit ";
+
+ // DO WORK
+ byte[] compressedText = CompressionUtil.compressByteArray( text.getBytes() );
+ byte[] output = CompressionUtil.decompressByteArray( compressedText );
+
+ // VERIFY
+ String result = new String( output );
+ assertNotNull( "decompressed output stream shouldn't have been null ", output );
+ assertEquals( text, result );
+ }
+
+ /**
+ * Test method for decompressByteArray.
+ * <p>
+ * @throws IOException
+ */
+ public final void testCompressDecompressGzipByteArray_success()
+ throws IOException
+ {
+ // SETUP
+ String text = " This is some text to compress, not a lot, just a bit ";
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ GZIPOutputStream os = new GZIPOutputStream( baos );
+
+ os.write( text.getBytes() );
+ os.flush();
+ os.close();
+
+ // DO WORK
+ byte[] output = CompressionUtil.decompressGzipByteArray( baos.toByteArray() );
+
+ // VERIFY
+ String result = new String( output );
+ assertNotNull( "decompressed output stream shouldn't have been null ", output );
+ assertEquals( text, result );
+ }
+}
diff --git a/commons-jcs-core/src/test/test-conf/TestARCCache.ccf b/commons-jcs-core/src/test/test-conf/TestARCCache.ccf
index bf8c10f..22874bf 100644
--- a/commons-jcs-core/src/test/test-conf/TestARCCache.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestARCCache.ccf
@@ -18,13 +18,13 @@
# with the memory shrinker on.
jcs.default=
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=10
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.arc.ARCMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.arc.ARCMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=1
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=true
jcs.default.elementattributes.MaxLife=600
jcs.default.elementattributes.IdleTime=1800
diff --git a/commons-jcs-core/src/test/test-conf/TestBDBJEDiskCacheCon.ccf b/commons-jcs-core/src/test/test-conf/TestBDBJEDiskCacheCon.ccf
index 914386e..f3efaec 100644
--- a/commons-jcs-core/src/test/test-conf/TestBDBJEDiskCacheCon.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestBDBJEDiskCacheCon.ccf
@@ -18,46 +18,46 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=indexedDiskCache
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# SYSTEM GROUP ID CACHE
jcs.system.groupIdCache=indexedDiskCache
-jcs.system.groupIdCache.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.system.groupIdCache.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.system.groupIdCache.cacheattributes.MaxObjects=10000
-jcs.system.groupIdCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.system.groupIdCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### CACHE REGIONS FOR TEST
jcs.region.indexedRegion1=indexedDiskCache
-jcs.region.indexedRegion1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion1.cacheattributes.MaxObjects=100
-jcs.region.indexedRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.indexedRegion2=indexedDiskCache
-jcs.region.indexedRegion2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion2.cacheattributes.MaxObjects=100
-jcs.region.indexedRegion2.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion2.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.indexedRegion3=indexedDiskCache
-jcs.region.indexedRegion3.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion3.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion3.cacheattributes.MaxObjects=100
-jcs.region.indexedRegion3.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion3.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.indexedRegion4=indexedDiskCache
-jcs.region.indexedRegion4.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion4.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion4.cacheattributes.MaxObjects=100
-jcs.region.indexedRegion4.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion4.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.indexedRegion4.cacheattributes.UseMemoryShrinker=false
# #### AUXILIARY CACHES
# Berkeley DB JE
-jcs.auxiliary.indexedDiskCache=org.apache.commons.jcs.auxiliary.disk.bdbje.BDBJECacheFactory
-jcs.auxiliary.indexedDiskCache.attributes=org.apache.commons.jcs.auxiliary.disk.bdbje.BDBJECacheAttributes
+jcs.auxiliary.indexedDiskCache=org.apache.commons.jcs3.auxiliary.disk.bdbje.BDBJECacheFactory
+jcs.auxiliary.indexedDiskCache.attributes=org.apache.commons.jcs3.auxiliary.disk.bdbje.BDBJECacheAttributes
jcs.auxiliary.indexedDiskCache.attributes.DiskPath=target/test-sandbox/bdbje-disk-cache-conc
# #############################################################
diff --git a/commons-jcs-core/src/test/test-conf/TestBlockDiskCache.ccf b/commons-jcs-core/src/test/test-conf/TestBlockDiskCache.ccf
index 222a693..083f3e5 100644
--- a/commons-jcs-core/src/test/test-conf/TestBlockDiskCache.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestBlockDiskCache.ccf
@@ -18,50 +18,50 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=blockDiskCache
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# SYSTEM GROUP ID CACHE
jcs.system.groupIdCache=blockDiskCache
-jcs.system.groupIdCache.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.system.groupIdCache.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.system.groupIdCache.cacheattributes.MaxObjects=10000
-jcs.system.groupIdCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.system.groupIdCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### CACHE REGIONS FOR TEST
jcs.region.blockRegion1=blockDiskCache
-jcs.region.blockRegion1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.blockRegion1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.blockRegion1.cacheattributes.MaxObjects=100
-jcs.region.blockRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.blockRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.blockRegion2=blockDiskCache
-jcs.region.blockRegion2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.blockRegion2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.blockRegion2.cacheattributes.MaxObjects=100
-jcs.region.blockRegion2.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.blockRegion2.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.blockRegion3=blockDiskCache
-jcs.region.blockRegion3.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.blockRegion3.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.blockRegion3.cacheattributes.MaxObjects=100
-jcs.region.blockRegion3.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.blockRegion3.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.blockRegion4=blockDiskCache2
-jcs.region.blockRegion4.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.blockRegion4.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.blockRegion4.cacheattributes.MaxObjects=100
-jcs.region.blockRegion4.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.blockRegion4.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### AUXILIARY CACHES
# Block Disk Cache
-jcs.auxiliary.blockDiskCache=org.apache.commons.jcs.auxiliary.disk.block.BlockDiskCacheFactory
-jcs.auxiliary.blockDiskCache.attributes=org.apache.commons.jcs.auxiliary.disk.block.BlockDiskCacheAttributes
+jcs.auxiliary.blockDiskCache=org.apache.commons.jcs3.auxiliary.disk.block.BlockDiskCacheFactory
+jcs.auxiliary.blockDiskCache.attributes=org.apache.commons.jcs3.auxiliary.disk.block.BlockDiskCacheAttributes
jcs.auxiliary.blockDiskCache.attributes.DiskPath=target/test-sandbox/block-disk-cache
# Block Disk Cache
-jcs.auxiliary.blockDiskCache2=org.apache.commons.jcs.auxiliary.disk.block.BlockDiskCacheFactory
-jcs.auxiliary.blockDiskCache2.attributes=org.apache.commons.jcs.auxiliary.disk.block.BlockDiskCacheAttributes
+jcs.auxiliary.blockDiskCache2=org.apache.commons.jcs3.auxiliary.disk.block.BlockDiskCacheFactory
+jcs.auxiliary.blockDiskCache2.attributes=org.apache.commons.jcs3.auxiliary.disk.block.BlockDiskCacheAttributes
jcs.auxiliary.blockDiskCache2.attributes.DiskPath=target/test-sandbox/block-disk-cache2
# #############################################################
diff --git a/commons-jcs-core/src/test/test-conf/TestBlockDiskCacheCon.ccf b/commons-jcs-core/src/test/test-conf/TestBlockDiskCacheCon.ccf
index e12d2ec..fc82444 100644
--- a/commons-jcs-core/src/test/test-conf/TestBlockDiskCacheCon.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestBlockDiskCacheCon.ccf
@@ -18,40 +18,40 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=blockDiskCache
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### CACHE REGIONS FOR TEST
jcs.region.blockRegion1=blockDiskCache
-jcs.region.blockRegion1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.blockRegion1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.blockRegion1.cacheattributes.MaxObjects=100
-jcs.region.blockRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.blockRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.blockRegion2=blockDiskCache
-jcs.region.blockRegion2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.blockRegion2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.blockRegion2.cacheattributes.MaxObjects=100
-jcs.region.blockRegion2.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.blockRegion2.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.blockRegion3=blockDiskCache
-jcs.region.blockRegion3.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.blockRegion3.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.blockRegion3.cacheattributes.MaxObjects=100
-jcs.region.blockRegion3.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.blockRegion3.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.blockRegion4=blockDiskCache
-jcs.region.blockRegion4.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.blockRegion4.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.blockRegion4.cacheattributes.MaxObjects=100
-jcs.region.blockRegion4.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.blockRegion4.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### AUXILIARY CACHES
# Block Disk Cache
-jcs.auxiliary.blockDiskCache=org.apache.commons.jcs.auxiliary.disk.block.BlockDiskCacheFactory
-jcs.auxiliary.blockDiskCache.attributes=org.apache.commons.jcs.auxiliary.disk.block.BlockDiskCacheAttributes
+jcs.auxiliary.blockDiskCache=org.apache.commons.jcs3.auxiliary.disk.block.BlockDiskCacheFactory
+jcs.auxiliary.blockDiskCache.attributes=org.apache.commons.jcs3.auxiliary.disk.block.BlockDiskCacheAttributes
jcs.auxiliary.blockDiskCache.attributes.DiskPath=target/test-sandbox/block-disk-cache-conc
jcs.auxiliary.blockDiskCache.attributes.MaxPurgatorySize=10000
jcs.auxiliary.blockDiskCache.attributes.MaxKeySize=10000
diff --git a/commons-jcs-core/src/test/test-conf/TestBlockDiskCacheHuge.ccf b/commons-jcs-core/src/test/test-conf/TestBlockDiskCacheHuge.ccf
index 9106539..b2828e4 100644
--- a/commons-jcs-core/src/test/test-conf/TestBlockDiskCacheHuge.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestBlockDiskCacheHuge.ccf
@@ -18,24 +18,24 @@
# a maximum of 0 objects, so objects should get pushed into the disk cache
jcs.default=blockDiskCache
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=0
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### CACHE REGIONS FOR TEST
jcs.region.blockRegion1=blockDiskCache
-jcs.region.blockRegion1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.blockRegion1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.blockRegion1.cacheattributes.MaxObjects=0
-jcs.region.blockRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.blockRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### AUXILIARY CACHES
# Block Disk Cache
-jcs.auxiliary.blockDiskCache=org.apache.commons.jcs.auxiliary.disk.block.BlockDiskCacheFactory
-jcs.auxiliary.blockDiskCache.attributes=org.apache.commons.jcs.auxiliary.disk.block.BlockDiskCacheAttributes
+jcs.auxiliary.blockDiskCache=org.apache.commons.jcs3.auxiliary.disk.block.BlockDiskCacheFactory
+jcs.auxiliary.blockDiskCache.attributes=org.apache.commons.jcs3.auxiliary.disk.block.BlockDiskCacheAttributes
jcs.auxiliary.blockDiskCache.attributes.DiskPath=target/test-sandbox/block-disk-cache-huge
jcs.auxiliary.blockDiskCache.attributes.MaxPurgatorySize=300000
jcs.auxiliary.blockDiskCache.attributes.MaxKeySize=1000000
diff --git a/commons-jcs-core/src/test/test-conf/TestBlockDiskCacheSteadyLoad.ccf b/commons-jcs-core/src/test/test-conf/TestBlockDiskCacheSteadyLoad.ccf
index 535131d..d2b26e5 100644
--- a/commons-jcs-core/src/test/test-conf/TestBlockDiskCacheSteadyLoad.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestBlockDiskCacheSteadyLoad.ccf
@@ -18,15 +18,15 @@
# DEFAULT CACHE REGION
jcs.default=DC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.DiskUsagePatternName=UPDATE
# AVAILABLE AUXILIARY CACHES
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.block.BlockDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.block.BlockDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.block.BlockDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.block.BlockDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=target/test-sandbox/block-steady-load
jcs.auxiliary.DC.attributes.maxKeySize=20000
jcs.auxiliary.DC.attributes.blockSizeBytes=5000
diff --git a/commons-jcs-core/src/test/test-conf/TestDiskCache.ccf b/commons-jcs-core/src/test/test-conf/TestDiskCache.ccf
index dfdf941..c00452d 100644
--- a/commons-jcs-core/src/test/test-conf/TestDiskCache.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestDiskCache.ccf
@@ -18,50 +18,50 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=indexedDiskCache
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# SYSTEM GROUP ID CACHE
jcs.system.groupIdCache=indexedDiskCache
-jcs.system.groupIdCache.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.system.groupIdCache.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.system.groupIdCache.cacheattributes.MaxObjects=10000
-jcs.system.groupIdCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.system.groupIdCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### CACHE REGIONS FOR TEST
jcs.region.indexedRegion1=indexedDiskCache
-jcs.region.indexedRegion1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion1.cacheattributes.MaxObjects=100
-jcs.region.indexedRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.indexedRegion2=indexedDiskCache
-jcs.region.indexedRegion2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion2.cacheattributes.MaxObjects=100
-jcs.region.indexedRegion2.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion2.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.indexedRegion3=indexedDiskCache
-jcs.region.indexedRegion3.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion3.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion3.cacheattributes.MaxObjects=100
-jcs.region.indexedRegion3.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion3.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.indexedRegion4=indexedDiskCache2
-jcs.region.indexedRegion4.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion4.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion4.cacheattributes.MaxObjects=100
-jcs.region.indexedRegion4.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion4.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### AUXILIARY CACHES
# Indexed Disk Cache
-jcs.auxiliary.indexedDiskCache=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.indexedDiskCache.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.indexedDiskCache=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.indexedDiskCache.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.indexedDiskCache.attributes.DiskPath=target/test-sandbox/indexed-disk-cache
# Indexed Disk Cache
-jcs.auxiliary.indexedDiskCache2=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.indexedDiskCache2.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.indexedDiskCache2=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.indexedDiskCache2.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.indexedDiskCache2.attributes.DiskPath=target/test-sandbox/indexed-disk-cache2
# #############################################################
diff --git a/commons-jcs-core/src/test/test-conf/TestDiskCacheCon.ccf b/commons-jcs-core/src/test/test-conf/TestDiskCacheCon.ccf
index e9b32e6..6aa3384 100644
--- a/commons-jcs-core/src/test/test-conf/TestDiskCacheCon.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestDiskCacheCon.ccf
@@ -18,40 +18,40 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=indexedDiskCache
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### CACHE REGIONS FOR TEST
jcs.region.indexedRegion1=indexedDiskCache
-jcs.region.indexedRegion1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion1.cacheattributes.MaxObjects=100
-jcs.region.indexedRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.indexedRegion2=indexedDiskCache
-jcs.region.indexedRegion2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion2.cacheattributes.MaxObjects=100
-jcs.region.indexedRegion2.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion2.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.indexedRegion3=indexedDiskCache
-jcs.region.indexedRegion3.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion3.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion3.cacheattributes.MaxObjects=100
-jcs.region.indexedRegion3.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion3.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.indexedRegion4=indexedDiskCache
-jcs.region.indexedRegion4.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion4.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion4.cacheattributes.MaxObjects=100
-jcs.region.indexedRegion4.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion4.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### AUXILIARY CACHES
# Indexed Disk Cache
-jcs.auxiliary.indexedDiskCache=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.indexedDiskCache.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.indexedDiskCache=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.indexedDiskCache.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.indexedDiskCache.attributes.DiskPath=target/test-sandbox/indexed-disk-cache-conc
jcs.auxiliary.indexedDiskCache.attributes.MaxPurgatorySize=10000
jcs.auxiliary.indexedDiskCache.attributes.MaxKeySize=10000
diff --git a/commons-jcs-core/src/test/test-conf/TestDiskCacheDefragPerformance.ccf b/commons-jcs-core/src/test/test-conf/TestDiskCacheDefragPerformance.ccf
index dd6b7a6..b0ab3ce 100644
--- a/commons-jcs-core/src/test/test-conf/TestDiskCacheDefragPerformance.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestDiskCacheDefragPerformance.ccf
@@ -18,14 +18,14 @@
# DEFAULT CACHE REGION
jcs.default=DC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
cs.default.cacheattributes.DiskUsagePatterName=UPDATE
# AVAILABLE AUXILIARY CACHES
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=target/test-sandbox/defrag
jcs.auxiliary.DC.attributes.maxKeySize=10000
jcs.auxiliary.DC.attributes.MaxPurgatorySize=5000
diff --git a/commons-jcs-core/src/test/test-conf/TestDiskCacheHuge.ccf b/commons-jcs-core/src/test/test-conf/TestDiskCacheHuge.ccf
index a835210..28362b2 100644
--- a/commons-jcs-core/src/test/test-conf/TestDiskCacheHuge.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestDiskCacheHuge.ccf
@@ -18,24 +18,24 @@
# a maximum of 0 objects, so objects should get pushed into the disk cache
jcs.default=indexedDiskCache
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=0
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### CACHE REGIONS FOR TEST
jcs.region.indexedRegion1=indexedDiskCache
-jcs.region.indexedRegion1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion1.cacheattributes.MaxObjects=0
-jcs.region.indexedRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### AUXILIARY CACHES
# Indexed Disk Cache
-jcs.auxiliary.indexedDiskCache=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.indexedDiskCache.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.indexedDiskCache=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.indexedDiskCache.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.indexedDiskCache.attributes.DiskPath=target/test-sandbox/indexed-disk-cache-conc
jcs.auxiliary.indexedDiskCache.attributes.MaxPurgatorySize=300000
jcs.auxiliary.indexedDiskCache.attributes.MaxKeySize=500000
diff --git a/commons-jcs-core/src/test/test-conf/TestDiskCacheNoMemory.ccf b/commons-jcs-core/src/test/test-conf/TestDiskCacheNoMemory.ccf
index 1d3e1e7..a46b984 100644
--- a/commons-jcs-core/src/test/test-conf/TestDiskCacheNoMemory.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestDiskCacheNoMemory.ccf
@@ -18,50 +18,50 @@
# a maximum of 0 objects, so objects should get pushed into the disk cache
jcs.default=indexedDiskCache
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=0
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# SYSTEM GROUP ID CACHE
jcs.system.groupIdCache=indexedDiskCache
-jcs.system.groupIdCache.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.system.groupIdCache.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.system.groupIdCache.cacheattributes.MaxObjects=0
-jcs.system.groupIdCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.system.groupIdCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### CACHE REGIONS FOR TEST
jcs.region.indexedRegion1=indexedDiskCache
-jcs.region.indexedRegion1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion1.cacheattributes.MaxObjects=0
-jcs.region.indexedRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.indexedRegion2=indexedDiskCache
-jcs.region.indexedRegion2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion2.cacheattributes.MaxObjects=0
-jcs.region.indexedRegion2.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion2.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.indexedRegion3=indexedDiskCache
-jcs.region.indexedRegion3.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion3.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion3.cacheattributes.MaxObjects=0
-jcs.region.indexedRegion3.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion3.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.indexedRegion4=indexedDiskCache2
-jcs.region.indexedRegion4.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.indexedRegion4.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.indexedRegion4.cacheattributes.MaxObjects=0
-jcs.region.indexedRegion4.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.indexedRegion4.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### AUXILIARY CACHES
# Indexed Disk Cache
-jcs.auxiliary.indexedDiskCache=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.indexedDiskCache.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.indexedDiskCache=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.indexedDiskCache.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.indexedDiskCache.attributes.DiskPath=target/test-sandbox/indexed-disk-cache-nomemory
# Indexed Disk Cache
-jcs.auxiliary.indexedDiskCache2=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.indexedDiskCache2.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.indexedDiskCache2=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.indexedDiskCache2.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.indexedDiskCache2.attributes.DiskPath=target/test-sandbox/indexed-disk-cache2-nomemory
# #############################################################
diff --git a/commons-jcs-core/src/test/test-conf/TestDiskCacheSteadyLoad.ccf b/commons-jcs-core/src/test/test-conf/TestDiskCacheSteadyLoad.ccf
index 0b5d3ba..f62d291 100644
--- a/commons-jcs-core/src/test/test-conf/TestDiskCacheSteadyLoad.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestDiskCacheSteadyLoad.ccf
@@ -18,15 +18,15 @@
# DEFAULT CACHE REGION
jcs.default=DC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.DiskUsagePatternName=UPDATE
# AVAILABLE AUXILIARY CACHES
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=target/test-sandbox/steady-load
jcs.auxiliary.DC.attributes.maxKeySize=1000
jcs.auxiliary.DC.attributes.MaxPurgatorySize=1000
diff --git a/commons-jcs-core/src/test/test-conf/TestDiskCacheUsagePattern.ccf b/commons-jcs-core/src/test/test-conf/TestDiskCacheUsagePattern.ccf
index 5f718ae..07c6cb5 100644
--- a/commons-jcs-core/src/test/test-conf/TestDiskCacheUsagePattern.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestDiskCacheUsagePattern.ccf
@@ -18,29 +18,29 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=indexedDiskCache
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### CACHE REGIONS FOR TEST
jcs.region.Swap=indexedDiskCache
-jcs.region.Swap.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.Swap.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.Swap.cacheattributes.MaxObjects=100
-jcs.region.Swap.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.Swap.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.Swap.cacheattributes.DiskUsagePatternName=SWAP
jcs.region.Update=indexedDiskCache
-jcs.region.Update.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.Update.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.Update.cacheattributes.MaxObjects=100
-jcs.region.Update.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.Update.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.Update.cacheattributes.DiskUsagePatternName=UPDATE
# #### AUXILIARY CACHES
# Indexed Disk Cache
-jcs.auxiliary.indexedDiskCache=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.indexedDiskCache.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.indexedDiskCache=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.indexedDiskCache.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.indexedDiskCache.attributes.DiskPath=target/test-sandbox/indexed-disk-cache-conc
jcs.auxiliary.indexedDiskCache.attributes.MaxPurgatorySize=10000
jcs.auxiliary.indexedDiskCache.attributes.MaxKeySize=10000
diff --git a/commons-jcs-core/src/test/test-conf/TestHSQLDiskCache.ccf b/commons-jcs-core/src/test/test-conf/TestHSQLDiskCache.ccf
index e3fe8b9..b75655d 100644
--- a/commons-jcs-core/src/test/test-conf/TestHSQLDiskCache.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestHSQLDiskCache.ccf
@@ -18,13 +18,13 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=HSQL
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=0
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -34,17 +34,17 @@
jcs.region.noRemoveAll=HSQL_NORA
-jcs.region.noRemoveAll.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.noRemoveAll.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.noRemoveAll.cacheattributes.MaxObjects=0
-jcs.region.noRemoveAll.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.noRemoveAll.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# HSQL disk cache
-jcs.auxiliary.HSQL=org.apache.commons.jcs.auxiliary.disk.jdbc.hsql.HSQLDiskCacheFactory
-jcs.auxiliary.HSQL.attributes=org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes
+jcs.auxiliary.HSQL=org.apache.commons.jcs3.auxiliary.disk.jdbc.hsql.HSQLDiskCacheFactory
+jcs.auxiliary.HSQL.attributes=org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes
jcs.auxiliary.HSQL.attributes.userName=sa
jcs.auxiliary.HSQL.attributes.password=
jcs.auxiliary.HSQL.attributes.url=jdbc:hsqldb:target/HSQLDiskCacheUnitTest1
@@ -57,8 +57,8 @@
jcs.auxiliary.HSQL.attributes.EventQueueType=SINGLE
# HSQL disk cache, doesn't allow remove all
-jcs.auxiliary.HSQL_NORA=org.apache.commons.jcs.auxiliary.disk.jdbc.hsql.HSQLDiskCacheFactory
-jcs.auxiliary.HSQL_NORA.attributes=org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes
+jcs.auxiliary.HSQL_NORA=org.apache.commons.jcs3.auxiliary.disk.jdbc.hsql.HSQLDiskCacheFactory
+jcs.auxiliary.HSQL_NORA.attributes=org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes
jcs.auxiliary.HSQL_NORA.attributes.userName=sa
jcs.auxiliary.HSQL_NORA.attributes.password=
jcs.auxiliary.HSQL_NORA.attributes.url=jdbc:hsqldb:target/HSQLDiskCacheUnitTest2
diff --git a/commons-jcs-core/src/test/test-conf/TestHSQLDiskCacheConcurrent.ccf b/commons-jcs-core/src/test/test-conf/TestHSQLDiskCacheConcurrent.ccf
index 8f2eb68..327c13d 100644
--- a/commons-jcs-core/src/test/test-conf/TestHSQLDiskCacheConcurrent.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestHSQLDiskCacheConcurrent.ccf
@@ -18,13 +18,13 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=HSQL
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=0
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -34,17 +34,17 @@
jcs.region.noRemoveAll=HSQL_NORA
-jcs.region.noRemoveAll.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.noRemoveAll.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.noRemoveAll.cacheattributes.MaxObjects=0
-jcs.region.noRemoveAll.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.noRemoveAll.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# HSQL disk cache
-jcs.auxiliary.HSQL=org.apache.commons.jcs.auxiliary.disk.jdbc.hsql.HSQLDiskCacheFactory
-jcs.auxiliary.HSQL.attributes=org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes
+jcs.auxiliary.HSQL=org.apache.commons.jcs3.auxiliary.disk.jdbc.hsql.HSQLDiskCacheFactory
+jcs.auxiliary.HSQL.attributes=org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes
jcs.auxiliary.HSQL.attributes.userName=sa
jcs.auxiliary.HSQL.attributes.password=
jcs.auxiliary.HSQL.attributes.url=jdbc:hsqldb:target/HSQLDiskCacheUnitTest1
@@ -58,8 +58,8 @@
jcs.auxiliary.HSQL.attributes.EventQueuePoolName=disk_cache_event_queue
# HSQL disk cache, doesn't allow remove all
-jcs.auxiliary.HSQL_NORA=org.apache.commons.jcs.auxiliary.disk.jdbc.hsql.HSQLDiskCacheFactory
-jcs.auxiliary.HSQL_NORA.attributes=org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes
+jcs.auxiliary.HSQL_NORA=org.apache.commons.jcs3.auxiliary.disk.jdbc.hsql.HSQLDiskCacheFactory
+jcs.auxiliary.HSQL_NORA.attributes=org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes
jcs.auxiliary.HSQL_NORA.attributes.userName=sa
jcs.auxiliary.HSQL_NORA.attributes.password=
jcs.auxiliary.HSQL_NORA.attributes.url=jdbc:hsqldb:target/HSQLDiskCacheUnitTest2
diff --git a/commons-jcs-core/src/test/test-conf/TestJCS-73.ccf b/commons-jcs-core/src/test/test-conf/TestJCS-73.ccf
index c6220bf..ac6248f 100644
--- a/commons-jcs-core/src/test/test-conf/TestJCS-73.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestJCS-73.ccf
@@ -17,21 +17,21 @@
# Cache configuration for the 'JCSConcurrentCacheAccessUnitTest' test.
jcs.default=CACHE
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=-1
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.DiskUsagePatternName=UPDATE
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=10
jcs.default.cacheattributes.ShrinkerIntervalSeconds=10
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsRemote=false
jcs.default.elementattributes.IsLateral=false
jcs.default.elementattributes.IsSpool=true
jcs.default.elementattributes.IsEternal=true
-jcs.auxiliary.CACHE=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.CACHE.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.CACHE=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.CACHE.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.CACHE.attributes.DiskPath=target/test-sandbox/concurrent_cache
jcs.auxiliary.CACHE.attributes.MaxPurgatorySize=-1
jcs.auxiliary.CACHE.attributes.MaxKeySize=-1
diff --git a/commons-jcs-core/src/test/test-conf/TestJCSvHashtablePerf.ccf b/commons-jcs-core/src/test/test-conf/TestJCSvHashtablePerf.ccf
index 5ef882d..a330518 100644
--- a/commons-jcs-core/src/test/test-conf/TestJCSvHashtablePerf.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestJCSvHashtablePerf.ccf
@@ -18,17 +18,17 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### CACHE REGIONS FOR TEST
jcs.region.testCache1=
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=100000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #############################################################
diff --git a/commons-jcs-core/src/test/test-conf/TestJDBCDiskCache.ccf b/commons-jcs-core/src/test/test-conf/TestJDBCDiskCache.ccf
index 6dab1dd..eee8bed 100644
--- a/commons-jcs-core/src/test/test-conf/TestJDBCDiskCache.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestJDBCDiskCache.ccf
@@ -18,13 +18,13 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=JDBC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -35,8 +35,8 @@
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# JDBC disk cache
-jcs.auxiliary.JDBC=org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheFactory
-jcs.auxiliary.JDBC.attributes=org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes
+jcs.auxiliary.JDBC=org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheFactory
+jcs.auxiliary.JDBC.attributes=org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes
jcs.auxiliary.JDBC.attributes.userName=sa
jcs.auxiliary.JDBC.attributes.password=
jcs.auxiliary.JDBC.attributes.url=jdbc:hsqldb:target/cache_hsql_db
diff --git a/commons-jcs-core/src/test/test-conf/TestJDBCDiskCacheRemoval.ccf b/commons-jcs-core/src/test/test-conf/TestJDBCDiskCacheRemoval.ccf
index b90eb0f..b038ab9 100644
--- a/commons-jcs-core/src/test/test-conf/TestJDBCDiskCacheRemoval.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestJDBCDiskCacheRemoval.ccf
@@ -18,13 +18,13 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=JDBC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=0
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -35,8 +35,8 @@
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# JDBC disk cache
-jcs.auxiliary.JDBC=org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheFactory
-jcs.auxiliary.JDBC.attributes=org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes
+jcs.auxiliary.JDBC=org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheFactory
+jcs.auxiliary.JDBC.attributes=org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes
jcs.auxiliary.JDBC.attributes.userName=sa
jcs.auxiliary.JDBC.attributes.password=
jcs.auxiliary.JDBC.attributes.url=jdbc:hsqldb:target/JDBCDiskCacheRemovalUnitTest
diff --git a/commons-jcs-core/src/test/test-conf/TestJDBCDiskCacheSharedPool.ccf b/commons-jcs-core/src/test/test-conf/TestJDBCDiskCacheSharedPool.ccf
index f73dad5..b40fbcf 100644
--- a/commons-jcs-core/src/test/test-conf/TestJDBCDiskCacheSharedPool.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestJDBCDiskCacheSharedPool.ccf
@@ -18,13 +18,13 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=JDBC_0
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -41,8 +41,8 @@
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# JDBC disk cache
-jcs.auxiliary.JDBC_0=org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheFactory
-jcs.auxiliary.JDBC_0.attributes=org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes
+jcs.auxiliary.JDBC_0=org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheFactory
+jcs.auxiliary.JDBC_0.attributes=org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes
jcs.auxiliary.JDBC_0.attributes.tableName=JCS_STORE_0
jcs.auxiliary.JDBC_0.attributes.testBeforeInsert=false
jcs.auxiliary.JDBC_0.attributes.allowRemoveAll=true
@@ -51,8 +51,8 @@
jcs.auxiliary.JDBC_0.attributes.EventQueueType=POOLED
jcs.auxiliary.JDBC_0.attributes.EventQueuePoolName=disk_cache_event_queue
-jcs.auxiliary.JDBC_1=org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheFactory
-jcs.auxiliary.JDBC_1.attributes=org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes
+jcs.auxiliary.JDBC_1=org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheFactory
+jcs.auxiliary.JDBC_1.attributes=org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes
jcs.auxiliary.JDBC_1.attributes.tableName=JCS_STORE_1
jcs.auxiliary.JDBC_1.attributes.testBeforeInsert=false
jcs.auxiliary.JDBC_1.attributes.allowRemoveAll=true
diff --git a/commons-jcs-core/src/test/test-conf/TestJDBCDiskCacheShrink.ccf b/commons-jcs-core/src/test/test-conf/TestJDBCDiskCacheShrink.ccf
index 5360862..b1a03d8 100644
--- a/commons-jcs-core/src/test/test-conf/TestJDBCDiskCacheShrink.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestJDBCDiskCacheShrink.ccf
@@ -18,13 +18,13 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=JDBC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -35,29 +35,29 @@
# #############################################################
# ################# REGIONS ###################################
jcs.region.expire1Second=JDBC
-jcs.region.expire1Second.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.expire1Second.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.expire1Second.cacheattributes.MaxObjects=0
-jcs.region.expire1Second.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.expire1Second.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.expire1Second.elementattributes.MaxLife=1
jcs.region.expire100Second=JDBC
-jcs.region.expire100Second.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.expire100Second.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.expire100Second.cacheattributes.MaxObjects=0
-jcs.region.expire100Second.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.expire100Second.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.expire100Second.elementattributes.MaxLife=100
jcs.region.eternal=JDBC
-jcs.region.eternal.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.eternal.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.eternal.cacheattributes.MaxObjects=0
-jcs.region.eternal.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.eternal.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.eternal.elementattributes.MaxLife=1
jcs.region.eternal.elementattributes.IsEternal=true
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# JDBC disk cache
-jcs.auxiliary.JDBC=org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheFactory
-jcs.auxiliary.JDBC.attributes=org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes
+jcs.auxiliary.JDBC=org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheFactory
+jcs.auxiliary.JDBC.attributes=org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes
jcs.auxiliary.JDBC.attributes.userName=sa
jcs.auxiliary.JDBC.attributes.password=
jcs.auxiliary.JDBC.attributes.url=jdbc:hsqldb:target/JDBCDiskCacheShrinkUnitTest
diff --git a/commons-jcs-core/src/test/test-conf/TestJispDiskCache.ccf b/commons-jcs-core/src/test/test-conf/TestJispDiskCache.ccf
index 9a135d9..5e3a584 100644
--- a/commons-jcs-core/src/test/test-conf/TestJispDiskCache.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestJispDiskCache.ccf
@@ -18,13 +18,13 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=JDC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -34,7 +34,7 @@
# #### AUXILIARY CACHES
# JISP Disk Cache -- save memory with disk key storage
-jcs.auxiliary.JDC=org.apache.commons.jcs.auxiliary.disk.jisp.JISPCacheFactory
-jcs.auxiliary.JDC.attributes=org.apache.commons.jcs.auxiliary.disk.jisp.JISPCacheAttributes
+jcs.auxiliary.JDC=org.apache.commons.jcs3.auxiliary.disk.jisp.JISPCacheFactory
+jcs.auxiliary.JDC.attributes=org.apache.commons.jcs3.auxiliary.disk.jisp.JISPCacheAttributes
jcs.auxiliary.JDC.attributes.DiskPath=target/test-sandbox/jjisp-disk-cache
jcs.auxiliary.JDC.attributes.ClearOnStart=false
diff --git a/commons-jcs-core/src/test/test-conf/TestLHMLRUCache.ccf b/commons-jcs-core/src/test/test-conf/TestLHMLRUCache.ccf
index ba34a49..ce9fe39 100644
--- a/commons-jcs-core/src/test/test-conf/TestLHMLRUCache.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestLHMLRUCache.ccf
@@ -18,6 +18,6 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LHMLRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LHMLRUMemoryCache
diff --git a/commons-jcs-core/src/test/test-conf/TestMRUCache.ccf b/commons-jcs-core/src/test/test-conf/TestMRUCache.ccf
index 941f689..402a433 100644
--- a/commons-jcs-core/src/test/test-conf/TestMRUCache.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestMRUCache.ccf
@@ -18,13 +18,13 @@
# with the memory shrinker on.
jcs.default=
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=1000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.mru.MRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.mru.MRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=1
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=600
jcs.default.elementattributes.IdleTime=1800
@@ -34,12 +34,12 @@
# Region defined that uses the MRU
jcs.region.mruDefined=
-jcs.region.mruDefined.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.mruDefined.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.mruDefined.cacheattributes.MaxObjects=100000
-jcs.region.mruDefined.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.mru.MRUMemoryCache
+jcs.region.mruDefined.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.mru.MRUMemoryCache
# Region defined that uses the LRU
jcs.region.lruDefined=
-jcs.region.lruDefined.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.lruDefined.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.lruDefined.cacheattributes.MaxObjects=100000
-jcs.region.lruDefined.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.lruDefined.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
diff --git a/commons-jcs-core/src/test/test-conf/TestMySQLDiskCache.ccf b/commons-jcs-core/src/test/test-conf/TestMySQLDiskCache.ccf
index 8f82e2a..7403ceb 100644
--- a/commons-jcs-core/src/test/test-conf/TestMySQLDiskCache.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestMySQLDiskCache.ccf
@@ -20,13 +20,13 @@
# verify that the mysql disk cache works.
jcs.default=MYSQL
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=0
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,8 +37,8 @@
# #############################################################
# ################# AUXILIARY CACHES AVAILABLE ################
# MYSQL disk cache
-jcs.auxiliary.MYSQL=org.apache.commons.jcs.auxiliary.disk.jdbc.mysql.MySQLDiskCacheFactory
-jcs.auxiliary.MYSQL.attributes=org.apache.commons.jcs.auxiliary.disk.jdbc.mysql.MySQLDiskCacheAttributes
+jcs.auxiliary.MYSQL=org.apache.commons.jcs3.auxiliary.disk.jdbc.mysql.MySQLDiskCacheFactory
+jcs.auxiliary.MYSQL.attributes=org.apache.commons.jcs3.auxiliary.disk.jdbc.mysql.MySQLDiskCacheAttributes
jcs.auxiliary.MYSQL.attributes.userName=sa
jcs.auxiliary.MYSQL.attributes.password=
jcs.auxiliary.MYSQL.attributes.url=jdbc:hsqldb:target/MySQLDiskCacheHsqlBackedUnitTest
diff --git a/commons-jcs-core/src/test/test-conf/TestRemoteCacheClientServer.ccf b/commons-jcs-core/src/test/test-conf/TestRemoteCacheClientServer.ccf
index 224e8ed..0256239 100644
--- a/commons-jcs-core/src/test/test-conf/TestRemoteCacheClientServer.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestRemoteCacheClientServer.ccf
@@ -30,9 +30,9 @@
# #############################################################
# ################# DEFAULT CACHE REGION #####################
jcs.default=
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=1000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #############################################################
diff --git a/commons-jcs-core/src/test/test-conf/TestRemoteCacheEventLogging.ccf b/commons-jcs-core/src/test/test-conf/TestRemoteCacheEventLogging.ccf
index 7c2e399..75d4d23 100644
--- a/commons-jcs-core/src/test/test-conf/TestRemoteCacheEventLogging.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestRemoteCacheEventLogging.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=RC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200001
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -33,8 +33,8 @@
jcs.default.elementattributes.IsLateral=true
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RC.attributes.FailoverServers=localhost:1101
jcs.auxiliary.RC.attributes.LocalPort=1201
jcs.auxiliary.RC.attributes.RemoveUponRemotePut=false
@@ -44,4 +44,4 @@
jcs.auxiliary.RC.attributes.GetTimeoutMillis=-1
# jcs.auxiliary.RC.attributes.ThreadPoolName=remote_cache_client
# jcs.auxiliary.RC.attributes.GetOnly=false
-jcs.auxiliary.RC.cacheeventlogger=org.apache.commons.jcs.engine.logging.MockCacheEventLogger
+jcs.auxiliary.RC.cacheeventlogger=org.apache.commons.jcs3.engine.logging.MockCacheEventLogger
diff --git a/commons-jcs-core/src/test/test-conf/TestRemoteCacheServer.ccf b/commons-jcs-core/src/test/test-conf/TestRemoteCacheServer.ccf
index 786ae9f..5880daa 100644
--- a/commons-jcs-core/src/test/test-conf/TestRemoteCacheServer.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestRemoteCacheServer.ccf
@@ -17,6 +17,6 @@
# #############################################################
# ################# DEFAULT CACHE REGION #####################
jcs.default=
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=1000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
diff --git a/commons-jcs-core/src/test/test-conf/TestRemoteClient.ccf b/commons-jcs-core/src/test/test-conf/TestRemoteClient.ccf
index cb53999..49d87f2 100644
--- a/commons-jcs-core/src/test/test-conf/TestRemoteClient.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestRemoteClient.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=RC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200001
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -33,8 +33,8 @@
jcs.default.elementattributes.IsLateral=true
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RC.attributes.FailoverServers=localhost:1101
jcs.auxiliary.RC.attributes.LocalPort=1201
jcs.auxiliary.RC.attributes.RemoveUponRemotePut=false
diff --git a/commons-jcs-core/src/test/test-conf/TestRemoteHttpCache.ccf b/commons-jcs-core/src/test/test-conf/TestRemoteHttpCache.ccf
index 0e0226d..86fbb4c 100644
--- a/commons-jcs-core/src/test/test-conf/TestRemoteHttpCache.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestRemoteHttpCache.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=RC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=0
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -34,6 +34,6 @@
## The Http Remote Cache Client
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.http.client.RemoteHttpCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.http.client.RemoteHttpCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.http.client.RemoteHttpCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.http.client.RemoteHttpCacheAttributes
jcs.auxiliary.RC.attributes.url=http://localhost:8000/jcs-app/RemoteCache
diff --git a/commons-jcs-core/src/test/test-conf/TestRemoteServer.ccf b/commons-jcs-core/src/test/test-conf/TestRemoteServer.ccf
index 7678d8e..bb4246d 100644
--- a/commons-jcs-core/src/test/test-conf/TestRemoteServer.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestRemoteServer.ccf
@@ -28,14 +28,14 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=7000
jcs.default.elementattributes.IdleTime=1800
diff --git a/commons-jcs-core/src/test/test-conf/TestRemoval.ccf b/commons-jcs-core/src/test/test-conf/TestRemoval.ccf
index 5c23490..bb0f410 100644
--- a/commons-jcs-core/src/test/test-conf/TestRemoval.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestRemoval.ccf
@@ -17,19 +17,19 @@
# JCS Config for unit testing, just a simple memory only cache
jcs.default=
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=1000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.system.groupIdCache=
-jcs.system.groupIdCache.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.system.groupIdCache.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.system.groupIdCache.cacheattributes.MaxObjects=10000
-jcs.system.groupIdCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.system.groupIdCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1=
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=1000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #############################################################
diff --git a/commons-jcs-core/src/test/test-conf/TestSimpleEventHandling.ccf b/commons-jcs-core/src/test/test-conf/TestSimpleEventHandling.ccf
index f2df927..4bcd7a3 100644
--- a/commons-jcs-core/src/test/test-conf/TestSimpleEventHandling.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestSimpleEventHandling.ccf
@@ -18,48 +18,48 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### CACHE REGIONS FOR TEST
jcs.region.WithDisk=indexedDiskCache
-jcs.region.WithDisk.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.WithDisk.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.WithDisk.cacheattributes.MaxObjects=0
-jcs.region.WithDisk.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.WithDisk.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.WithDisk.elementattributes.IsSpool=true
jcs.region.NoDisk=
-jcs.region.NoDisk.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.NoDisk.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.NoDisk.cacheattributes.MaxObjects=0
-jcs.region.NoDisk.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.NoDisk.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.NoDisk.elementattributes.IsSpool=true
jcs.region.DiskButNotAllowed=indexedDiskCache
-jcs.region.DiskButNotAllowed.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.DiskButNotAllowed.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.DiskButNotAllowed.cacheattributes.MaxObjects=0
-jcs.region.DiskButNotAllowed.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.DiskButNotAllowed.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.DiskButNotAllowed.elementattributes.IsSpool=false
jcs.region.Maxlife=
-jcs.region.Maxlife.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.Maxlife.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.Maxlife.cacheattributes.MaxObjects=200
-jcs.region.Maxlife.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.Maxlife.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.Maxlife.elementattributes.IsEternal=false
jcs.region.Maxlife.elementattributes.MaxLife=2
jcs.region.Idletime=
-jcs.region.Idletime.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.Idletime.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.Idletime.cacheattributes.MaxObjects=200
-jcs.region.Idletime.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.Idletime.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.Idletime.elementattributes.IsEternal=false
jcs.region.Idletime.elementattributes.MaxLife=300
jcs.region.Idletime.elementattributes.IdleTime=1
# #### AUXILIARY CACHES
# Indexed Disk Cache
-jcs.auxiliary.indexedDiskCache=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.indexedDiskCache.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.indexedDiskCache=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.indexedDiskCache.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.indexedDiskCache.attributes.DiskPath=target/test-sandbox/indexed-disk-cache
diff --git a/commons-jcs-core/src/test/test-conf/TestSimpleLoad.ccf b/commons-jcs-core/src/test/test-conf/TestSimpleLoad.ccf
index 6dcef12..b9c1d14 100644
--- a/commons-jcs-core/src/test/test-conf/TestSimpleLoad.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestSimpleLoad.ccf
@@ -17,12 +17,12 @@
# JCS Config for unit testing, just a simple memory only cache
jcs.default=
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=1000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1=
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=20001
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
diff --git a/commons-jcs-core/src/test/test-conf/TestSoftReferenceCache.ccf b/commons-jcs-core/src/test/test-conf/TestSoftReferenceCache.ccf
index dbbf718..a259823 100644
--- a/commons-jcs-core/src/test/test-conf/TestSoftReferenceCache.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestSoftReferenceCache.ccf
@@ -17,12 +17,12 @@
# JCS Config for unit testing
jcs.default=
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.soft.SoftReferenceMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.soft.SoftReferenceMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=600
jcs.default.elementattributes.IdleTime=1800
@@ -32,6 +32,6 @@
# Region defined that uses the Soft Reference
jcs.region.srDefined=
-jcs.region.srDefined.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.srDefined.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.srDefined.cacheattributes.MaxObjects=100000
-jcs.region.srDefined.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.soft.SoftReferenceMemoryCache
+jcs.region.srDefined.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.soft.SoftReferenceMemoryCache
diff --git a/commons-jcs-core/src/test/test-conf/TestSystemProperties.ccf b/commons-jcs-core/src/test/test-conf/TestSystemProperties.ccf
index cd5701a..cc7debc 100644
--- a/commons-jcs-core/src/test/test-conf/TestSystemProperties.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestSystemProperties.ccf
@@ -18,22 +18,22 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=indexedDiskCache
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=${MY_SYSTEM_PROPERTY_MAX_SIZE}
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.missing=
-jcs.region.missing.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.missing.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.missing.cacheattributes.MaxObjects=${NO_SUCH_PROPERTY}
-jcs.region.missing.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.missing.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### AUXILIARY CACHES
# Indexed Disk Cache
-jcs.auxiliary.indexedDiskCache=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.indexedDiskCache.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.indexedDiskCache=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.indexedDiskCache.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.indexedDiskCache.attributes.DiskPath=target/test-sandbox/${MY_SYSTEM_PROPERTY_DISK_DIR}
diff --git a/commons-jcs-core/src/test/test-conf/TestSystemPropertyUsage.ccf b/commons-jcs-core/src/test/test-conf/TestSystemPropertyUsage.ccf
index 9c68eae..f08adb6 100644
--- a/commons-jcs-core/src/test/test-conf/TestSystemPropertyUsage.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestSystemPropertyUsage.ccf
@@ -15,6 +15,6 @@
# specific language governing permissions and limitations
# under the License.
jcs.default=
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=10
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
diff --git a/commons-jcs-core/src/test/test-conf/TestTCPLateralCache.ccf b/commons-jcs-core/src/test/test-conf/TestTCPLateralCache.ccf
index bf6e941..ecda786 100644
--- a/commons-jcs-core/src/test/test-conf/TestTCPLateralCache.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestTCPLateralCache.ccf
@@ -18,24 +18,24 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=LTCP
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=10000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### CACHE REGIONS FOR TEST
jcs.region.testTcpRegion1=LTCP
-jcs.region.testTcpRegion1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testTcpRegion1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testTcpRegion1.cacheattributes.MaxObjects=10000
-jcs.region.testTcpRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testTcpRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### AUXILIARY CACHES
# simple Lateral TCP auxiliary
-jcs.auxiliary.LTCP=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
-jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
+jcs.auxiliary.LTCP=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
+jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
jcs.auxiliary.LTCP.attributes.TcpServers=localhost:1111
jcs.auxiliary.LTCP.attributes.TcpListenerPort=1110
jcs.auxiliary.LTCP.attributes.TcpListenerHost=localhost
diff --git a/commons-jcs-core/src/test/test-conf/TestTCPLateralCacheConcurrent.ccf b/commons-jcs-core/src/test/test-conf/TestTCPLateralCacheConcurrent.ccf
index 71f4eaa..894ae82 100644
--- a/commons-jcs-core/src/test/test-conf/TestTCPLateralCacheConcurrent.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestTCPLateralCacheConcurrent.ccf
@@ -15,14 +15,14 @@
# specific language governing permissions and limitations
# under the License.
jcs.default=LTCP
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=10000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### AUXILIARY CACHES
# simple Lateral TCP auxiliary
-jcs.auxiliary.LTCP=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
-jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
+jcs.auxiliary.LTCP=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
+jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
jcs.auxiliary.LTCP.attributes.TransmissionTypeName=TCP
# jcs.auxiliary.LTCP.attributes.TcpServers=
jcs.auxiliary.LTCP.attributes.TcpListenerPort=1102
diff --git a/commons-jcs-core/src/test/test-conf/TestTCPLateralIssueRemoveCache.ccf b/commons-jcs-core/src/test/test-conf/TestTCPLateralIssueRemoveCache.ccf
index aee9339..87e41ca 100644
--- a/commons-jcs-core/src/test/test-conf/TestTCPLateralIssueRemoveCache.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestTCPLateralIssueRemoveCache.ccf
@@ -18,24 +18,24 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=LTCP
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=10000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### CACHE REGIONS FOR TEST
jcs.region.testTcpRegion1=LTCP
-jcs.region.testTcpRegion1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testTcpRegion1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testTcpRegion1.cacheattributes.MaxObjects=10000
-jcs.region.testTcpRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testTcpRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### AUXILIARY CACHES
# simple Lateral TCP auxiliary
-jcs.auxiliary.LTCP=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
-jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
+jcs.auxiliary.LTCP=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
+jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
jcs.auxiliary.LTCP.attributes.TcpServers=localhost:1117
jcs.auxiliary.LTCP.attributes.TcpListenerPort=1118
jcs.auxiliary.LTCP.attributes.AllowGet=false
diff --git a/commons-jcs-core/src/test/test-conf/TestTCPLateralRemoveFilter.ccf b/commons-jcs-core/src/test/test-conf/TestTCPLateralRemoveFilter.ccf
index fdfaca4..d3948fb 100644
--- a/commons-jcs-core/src/test/test-conf/TestTCPLateralRemoveFilter.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestTCPLateralRemoveFilter.ccf
@@ -18,24 +18,24 @@
# a maximum of 100 objects, so objects should get pushed into the disk cache
jcs.default=LTCP
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=10000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### CACHE REGIONS FOR TEST
jcs.region.testTcpRegion1=LTCP
-jcs.region.testTcpRegion1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testTcpRegion1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testTcpRegion1.cacheattributes.MaxObjects=10000
-jcs.region.testTcpRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testTcpRegion1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #### AUXILIARY CACHES
# simple Lateral TCP auxiliary
-jcs.auxiliary.LTCP=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
-jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
+jcs.auxiliary.LTCP=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
+jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
jcs.auxiliary.LTCP.attributes.TcpServers=localhost:1117
jcs.auxiliary.LTCP.attributes.TcpListenerPort=2001
jcs.auxiliary.LTCP.attributes.AllowGet=false
diff --git a/commons-jcs-core/src/test/test-conf/TestThrash.ccf b/commons-jcs-core/src/test/test-conf/TestThrash.ccf
index f274d8a..dd0bf35 100644
--- a/commons-jcs-core/src/test/test-conf/TestThrash.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestThrash.ccf
@@ -15,6 +15,6 @@
# specific language governing permissions and limitations
# under the License.
jcs.default=
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=10000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
diff --git a/commons-jcs-core/src/test/test-conf/TestUDPDiscovery.ccf b/commons-jcs-core/src/test/test-conf/TestUDPDiscovery.ccf
index 34b7253..1461d66 100644
--- a/commons-jcs-core/src/test/test-conf/TestUDPDiscovery.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestUDPDiscovery.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=LTCP
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=200001
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=700
jcs.default.elementattributes.IdleTime=1800
@@ -37,28 +37,28 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=LTCP
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=1000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLife=60000
jcs.region.testCache1.elementattributes.IsLateral=true
jcs.region.testCache1.elementattributes.IsRemote=true
jcs.region.testCache2=LTCP2
-jcs.region.testCache2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache2.cacheattributes.MaxObjects=1000
-jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache2.cacheattributes.UseMemoryShrinker=true
jcs.region.testCache2.cacheattributes.ShrinkerIntervalSeconds=30
jcs.region.testCache2.cacheattributes.MaxMemoryIdleTimeSeconds=300
jcs.region.testCache2.cacheattributes.MaxSpoolPerRun=100
-jcs.region.testCache2.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache2.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache2.elementattributes.IsEternal=false
jcs.region.testCache2.elementattributes.MaxLife=60000
jcs.region.testCache2.elementattributes.IsLateral=true
@@ -68,8 +68,8 @@
# ################# AUXILIARY CACHES AVAILABLE ################
# Lateral TCp with UDP discovery enabled
-jcs.auxiliary.LTCP=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
-jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
+jcs.auxiliary.LTCP=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
+jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
jcs.auxiliary.LTCP.attributes.TcpServers=
jcs.auxiliary.LTCP.attributes.TcpListenerPort=1111
jcs.auxiliary.LTCP.attributes.AllowGet=false
@@ -79,8 +79,8 @@
# jcs.auxiliary.LTCP.attributes.Receive=true
# Lateral TCP with UDP discovery disabled
-jcs.auxiliary.LTCP2=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
-jcs.auxiliary.LTCP2.attributes=org.apache.commons.jcs.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
+jcs.auxiliary.LTCP2=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.LateralTCPCacheFactory
+jcs.auxiliary.LTCP2.attributes=org.apache.commons.jcs3.auxiliary.lateral.socket.tcp.TCPLateralCacheAttributes
jcs.auxiliary.LTCP2.attributes.TcpServers=
jcs.auxiliary.LTCP2.attributes.TcpListenerPort=1110
jcs.auxiliary.LTCP2.attributes.AllowGet=false
diff --git a/commons-jcs-core/src/test/test-conf/TestZeroSizeCache.ccf b/commons-jcs-core/src/test/test-conf/TestZeroSizeCache.ccf
index 515cd7c..12faf44 100644
--- a/commons-jcs-core/src/test/test-conf/TestZeroSizeCache.ccf
+++ b/commons-jcs-core/src/test/test-conf/TestZeroSizeCache.ccf
@@ -18,13 +18,13 @@
# with the memory shrinker on.
jcs.default=
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=0
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=1
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=600
jcs.default.elementattributes.IdleTime=1800
diff --git a/commons-jcs-core/src/test/test-conf/cache.ccf b/commons-jcs-core/src/test/test-conf/cache.ccf
index 80790e5..ff41e23 100644
--- a/commons-jcs-core/src/test/test-conf/cache.ccf
+++ b/commons-jcs-core/src/test/test-conf/cache.ccf
@@ -18,14 +18,14 @@
# JCS Config for unit testing, just a simple memory only cache
jcs.default=
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=1000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1=
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=1000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
# #############################################################
diff --git a/commons-jcs-core/src/test/test-conf/cache2.ccf b/commons-jcs-core/src/test/test-conf/cache2.ccf
index c263515..2ef1cf6 100644
--- a/commons-jcs-core/src/test/test-conf/cache2.ccf
+++ b/commons-jcs-core/src/test/test-conf/cache2.ccf
@@ -18,13 +18,13 @@
# ################# DEFAULT CACHE REGION #####################
# sets the default aux value for any non configured caches
jcs.default=DC
-jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=1000
-jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=true
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.MaxLife=7
jcs.default.elementattributes.IdleTime=1800
@@ -35,10 +35,10 @@
# SYSTEM CACHE
# should be defined for the storage of group attribute list
jcs.system.groupIdCache=DC
-jcs.system.groupIdCache.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.system.groupIdCache.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.system.groupIdCache.cacheattributes.MaxObjects=1000
-jcs.system.groupIdCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
-jcs.system.groupIdCache.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.system.groupIdCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
+jcs.system.groupIdCache.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.system.groupIdCache.elementattributes.IsEternal=true
jcs.system.groupIdCache.elementattributes.MaxLife=3600
jcs.system.groupIdCache.elementattributes.IdleTime=1800
@@ -51,26 +51,26 @@
# ################# CACHE REGIONS AVAILABLE ###################
# Regions preconfigured for caching
jcs.region.testCache1=DC,RC
-jcs.region.testCache1.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache1.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache1.cacheattributes.MaxObjects=1000
-jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache1.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache1.cacheattributes.UseMemoryShrinker=false
jcs.region.testCache1.cacheattributes.MaxMemoryIdleTimeSeconds=5000
jcs.region.testCache1.cacheattributes.MaxSpoolPerRun=100
jcs.region.testCache1.cacheattributes.ShrinkerIntervalSeconds=30
-jcs.region.testCache1.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache1.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache1.elementattributes.IsEternal=false
jcs.region.testCache1.elementattributes.MaxLife=6000
jcs.region.testCache1.elementattributes.IsLateral=true
jcs.region.testCache2=
-jcs.region.testCache2.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache2.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache2.cacheattributes.MaxObjects=100
-jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache2.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache2.cacheattributes.UseMemoryShrinker=false
jcs.region.testCache2.cacheattributes.MaxMemoryIdleTimeSeconds=10
jcs.region.testCache2.cacheattributes.ShrinkerIntervalSeconds=6
-jcs.region.testCache2.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache2.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache2.elementattributes.IsEternal=false
jcs.region.testCache2.elementattributes.MaxLife=600
jcs.region.testCache2.elementattributes.IsSpool=true
@@ -78,13 +78,13 @@
jcs.region.testCache2.elementattributes.IsLateral=true
jcs.region.testCache3=
-jcs.region.testCache3.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.testCache3.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache3.cacheattributes.MaxObjects=100000
-jcs.region.testCache3.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.testCache3.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.testCache3.cacheattributes.UseMemoryShrinker=false
jcs.region.testCache3.cacheattributes.MaxMemoryIdleTimeSeconds=10
jcs.region.testCache3.cacheattributes.ShrinkerIntervalSeconds=60
-jcs.region.testCache3.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.testCache3.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.testCache3.elementattributes.IsEternal=false
jcs.region.testCache3.elementattributes.MaxLife=3600
jcs.region.testCache3.elementattributes.IsSpool=true
@@ -96,51 +96,51 @@
# ################# AUXILIARY CACHES AVAILABLE ################
# Remote RMI cache without failover
-jcs.auxiliary.RGroup=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RGroup.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RGroup=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RGroup.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RGroup.attributes.RemoteTypeName=LOCAL
jcs.auxiliary.RGroup.attributes.RemoteHost=localhost
jcs.auxiliary.RGroup.attributes.RemotePort=1102
jcs.auxiliary.RGroup.attributes.GetOnly=true
# Remote RMI Cache set up to failover
-jcs.auxiliary.RFailover=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RFailover.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RFailover=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RFailover.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RFailover.attributes.RemoteTypeName=LOCAL
jcs.auxiliary.RFailover.attributes.FailoverServers=localhost:1102
jcs.auxiliary.RFailover.attributes.GetOnly=false
# Primary Disk Cache-- faster than the rest because of memory key storage
-jcs.auxiliary.DC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
-jcs.auxiliary.DC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=target/test-sandbox/raf
# new disk cache parameter.
jcs.auxiliary.DC.attributes.maxKeySize=100000
jcs.auxiliary.DC.attributes.optimizeAtRemoveCount=300
# Berkeley DB JE
-jcs.auxiliary.JE=org.apache.commons.jcs.auxiliary.disk.bdbje.BDBJECacheFactory
-jcs.auxiliary.JE.attributes=org.apache.commons.jcs.auxiliary.disk.bdbje.BDBJECacheAttributes
+jcs.auxiliary.JE=org.apache.commons.jcs3.auxiliary.disk.bdbje.BDBJECacheFactory
+jcs.auxiliary.JE.attributes=org.apache.commons.jcs3.auxiliary.disk.bdbje.BDBJECacheAttributes
jcs.auxiliary.JE.attributes.DiskPath=target/test-sandbox/bdbje-disk-cache-conc
# the minimum cache size is 1024
jcs.auxiliary.indexedDiskCache.attributes.CacheSize=1024
# jcs.auxiliary.indexedDiskCache.attributes.CachePercent=0
# HSQL Disk Cache -- too slow as is
-jcs.auxiliary.HDC=org.apache.commons.jcs.auxiliary.disk.hsql.HSQLCacheFactory
-jcs.auxiliary.HDC.attributes=org.apache.commons.jcs.auxiliary.disk.hsql.HSQLCacheAttributes
+jcs.auxiliary.HDC=org.apache.commons.jcs3.auxiliary.disk.hsql.HSQLCacheFactory
+jcs.auxiliary.HDC.attributes=org.apache.commons.jcs3.auxiliary.disk.hsql.HSQLCacheAttributes
jcs.auxiliary.HDC.attributes.DiskPath=@project_home_f@hsql
# JISP Disk Cache -- save memory with disk key storage
-jcs.auxiliary.JDC=org.apache.commons.jcs.auxiliary.disk.jisp.JISPCacheFactory
-jcs.auxiliary.JDC.attributes=org.apache.commons.jcs.auxiliary.disk.jisp.JISPCacheAttributes
+jcs.auxiliary.JDC=org.apache.commons.jcs3.auxiliary.disk.jisp.JISPCacheFactory
+jcs.auxiliary.JDC.attributes=org.apache.commons.jcs3.auxiliary.disk.jisp.JISPCacheAttributes
jcs.auxiliary.JDC.attributes.DiskPath=@project_home_f@raf
jcs.auxiliary.JDC.attributes.ClearOnStart=false
# need to make put or invalidate an option
# just a remove lock to add
-jcs.auxiliary.RC=org.apache.commons.jcs.auxiliary.remote.RemoteCacheFactory
-jcs.auxiliary.RC.attributes=org.apache.commons.jcs.auxiliary.remote.RemoteCacheAttributes
+jcs.auxiliary.RC=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
+jcs.auxiliary.RC.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RC.attributes.RemoteHost=10.21.209.150
jcs.auxiliary.RC.attributes.RemotePort=1102
# jcs.auxiliary.RC.attributes.LocalPort=1103
@@ -152,42 +152,42 @@
jcs.auxiliary.RC.attributes.ThreadPoolName=remote_cache_client
# unreliable
-jcs.auxiliary.LUDP=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LUDP.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LUDP=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LUDP.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LUDP.attributes.TransmissionTypeName=UDP
jcs.auxiliary.LUDP.attributes.UdpMulticastAddr=228.5.6.7
jcs.auxiliary.LUDP.attributes.UdpMulticastPort=6789
-jcs.auxiliary.LJG=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LJG.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LJG=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LJG.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LJG.attributes.TransmissionTypeName=JAVAGROUPS
jcs.auxiliary.LJG.attributes.PutOnlyMode=true
jcs.auxiliary.LJG.attributes.JGChannelProperties = UDP(mcast_addr=224.0.0.100;mcast_port=751):PING(timeout=3000):FD:STABLE:NAKACK:UNICAST:FRAG:FLUSH:GMS:VIEW_ENFORCER:QUEUE
-jcs.auxiliary.JG = org.apache.commons.jcs.auxiliary.javagroups.JavaGroupsCacheFactory
-jcs.auxiliary.JG.attributes = org.apache.commons.jcs.auxiliary.javagroups.JavaGroupsCacheAttributes
+jcs.auxiliary.JG = org.apache.commons.jcs3.auxiliary.javagroups.JavaGroupsCacheFactory
+jcs.auxiliary.JG.attributes = org.apache.commons.jcs3.auxiliary.javagroups.JavaGroupsCacheAttributes
jcs.auxiliary.JG.attributes.ChannelFactoryClassName = org.javagroups.JChannelFactory
jcs.auxiliary.JG.attributes.ChannelProperties = UDP(mcast_addr=224.0.0.100;mcast_port=7501):PING:FD:STABLE:NAKACK:UNICAST:FRAG:FLUSH:GMS:VIEW_ENFORCER:QUEUE
# almost complete
-jcs.auxiliary.LTCP=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LTCP=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LTCP.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LTCP.attributes.TransmissionTypeName=TCP
jcs.auxiliary.LTCP.attributes.TcpServers=localhost:1112
jcs.auxiliary.LTCP.attributes.TcpListenerPort=1111
jcs.auxiliary.LTCP.attributes.PutOnlyMode=false
-jcs.auxiliary.LTCP2=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LTCP2.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LTCP2=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LTCP2.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LTCP2.attributes.TransmissionTypeName=TCP
jcs.auxiliary.LTCP2.attributes.TcpServers=localhost:1112
jcs.auxiliary.LTCP2.attributes.TcpListenerPort=1111
jcs.auxiliary.LTCP2.attributes.PutOnlyMode=true
-jcs.auxiliary.XMLRPC=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.XMLRPC.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.XMLRPC=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.XMLRPC.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.XMLRPC.attributes.TransmissionTypeName=XMLRPC
jcs.auxiliary.XMLRPC.attributes.HttpServers=localhost:8182
jcs.auxiliary.XMLRPC.attributes.HttpListenerPort=8181
@@ -196,8 +196,8 @@
# example of how to configure the http version of the lateral cache
# not converteed to new cache
-jcs.auxiliary.LCHTTP=org.apache.commons.jcs.auxiliary.lateral.LateralCacheFactory
-jcs.auxiliary.LCHTTP.attributes=org.apache.commons.jcs.auxiliary.lateral.LateralCacheAttributes
+jcs.auxiliary.LCHTTP=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheFactory
+jcs.auxiliary.LCHTTP.attributes=org.apache.commons.jcs3.auxiliary.lateral.LateralCacheAttributes
jcs.auxiliary.LCHTTP.attributes.TransmissionType=HTTP
jcs.auxiliary.LCHTTP.attributes.httpServers=localhost:8080,localhost:7001,localhost:80
jcs.auxiliary.LCHTTP.attributes.httpReceiveServlet=/cache/LateralCacheReceiverServlet
diff --git a/commons-jcs-core/src/test/test-conf/log4j2-test.xml b/commons-jcs-core/src/test/test-conf/log4j2-test.xml
index 2fc4fac..9bed1fd 100644
--- a/commons-jcs-core/src/test/test-conf/log4j2-test.xml
+++ b/commons-jcs-core/src/test/test-conf/log4j2-test.xml
@@ -24,7 +24,7 @@
</File>
</Appenders>
<Loggers>
- <Logger name="org.apache.commons.jcs" additivity="false" level="INFO">
+ <Logger name="org.apache.commons.jcs3" additivity="false" level="INFO">
<AppenderRef ref="jcs"/>
</Logger>
<Root level="ERROR"><!-- log4j 1.2 has DEBUG -->
diff --git a/commons-jcs-dist/pom.xml b/commons-jcs-dist/pom.xml
index a1acab2..598a033 100644
--- a/commons-jcs-dist/pom.xml
+++ b/commons-jcs-dist/pom.xml
@@ -19,13 +19,13 @@
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
- <artifactId>commons-jcs</artifactId>
+ <artifactId>commons-jcs3</artifactId>
<groupId>org.apache.commons</groupId>
<version>3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
- <artifactId>commons-jcs-dist</artifactId>
+ <artifactId>commons-jcs3-dist</artifactId>
<version>3.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Apache Commons JCS :: Distribution</name>
@@ -43,7 +43,7 @@
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
- <artifactId>commons-jcs-core</artifactId>
+ <artifactId>commons-jcs3-core</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
diff --git a/commons-jcs-dist/src/assembly/bin.xml b/commons-jcs-dist/src/assembly/bin.xml
index 9f56c1f..22ba2e1 100644
--- a/commons-jcs-dist/src/assembly/bin.xml
+++ b/commons-jcs-dist/src/assembly/bin.xml
@@ -25,11 +25,11 @@
<moduleSet>
<useAllReactorProjects>true</useAllReactorProjects>
<includes>
- <include>org.apache.commons:commons-jcs-core</include>
- <include>org.apache.commons:commons-jcs-jcache</include>
- <include>org.apache.commons:commons-jcs-jcache-tck</include>
- <include>org.apache.commons:commons-jcs-jcache-extras</include>
- <include>org.apache.commons:commons-jcs-jcache-openjpa</include>
+ <include>org.apache.commons:commons-jcs3-core</include>
+ <include>org.apache.commons:commons-jcs3-jcache</include>
+ <include>org.apache.commons:commons-jcs3-jcache-tck</include>
+ <include>org.apache.commons:commons-jcs3-jcache-extras</include>
+ <include>org.apache.commons:commons-jcs3-jcache-openjpa</include>
</includes>
<binaries>
<includeDependencies>false</includeDependencies>
diff --git a/commons-jcs-dist/src/assembly/src.xml b/commons-jcs-dist/src/assembly/src.xml
index 03cfb2a..f2780b9 100644
--- a/commons-jcs-dist/src/assembly/src.xml
+++ b/commons-jcs-dist/src/assembly/src.xml
@@ -25,12 +25,12 @@
<moduleSet>
<useAllReactorProjects>true</useAllReactorProjects>
<includes>
- <include>org.apache.commons:commons-jcs-core</include>
- <include>org.apache.commons:commons-jcs-dist</include>
- <include>org.apache.commons:commons-jcs-jcache</include>
- <include>org.apache.commons:commons-jcs-jcache-tck</include>
- <include>org.apache.commons:commons-jcs-jcache-extras</include>
- <include>org.apache.commons:commons-jcs-jcache-openjpa</include>
+ <include>org.apache.commons:commons-jcs3-core</include>
+ <include>org.apache.commons:commons-jcs3-dist</include>
+ <include>org.apache.commons:commons-jcs3-jcache</include>
+ <include>org.apache.commons:commons-jcs3-jcache-tck</include>
+ <include>org.apache.commons:commons-jcs3-jcache-extras</include>
+ <include>org.apache.commons:commons-jcs3-jcache-openjpa</include>
</includes>
<sources>
<outputDirectoryMapping>${module.basedir.name}</outputDirectoryMapping>
diff --git a/commons-jcs-jcache-extras/pom.xml b/commons-jcs-jcache-extras/pom.xml
index 9031fa4..55a5379 100644
--- a/commons-jcs-jcache-extras/pom.xml
+++ b/commons-jcs-jcache-extras/pom.xml
@@ -19,13 +19,13 @@
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
- <artifactId>commons-jcs</artifactId>
+ <artifactId>commons-jcs3</artifactId>
<groupId>org.apache.commons</groupId>
<version>3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
- <artifactId>commons-jcs-jcache-extras</artifactId>
+ <artifactId>commons-jcs3-jcache-extras</artifactId>
<version>3.0-SNAPSHOT</version>
<name>Apache Commons JCS :: JCache Extras</name>
@@ -73,7 +73,7 @@
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
- <artifactId>commons-jcs-jcache</artifactId>
+ <artifactId>commons-jcs3-jcache</artifactId>
<scope>test</scope>
</dependency>
<dependency>
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/cdi/AnyLiteral.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/cdi/AnyLiteral.java
deleted file mode 100644
index 9f9459d..0000000
--- a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/cdi/AnyLiteral.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.cdi;
-
-import javax.enterprise.inject.Any;
-import javax.enterprise.util.AnnotationLiteral;
-
-public class AnyLiteral extends AnnotationLiteral<Any> implements Any
-{
- public static final AnyLiteral INSTANCE = new AnyLiteral();
-
- @Override
- public String toString()
- {
- return "@javax.enterprise.inject.Any()";
- }
-}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/cdi/CacheManagerBean.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/cdi/CacheManagerBean.java
deleted file mode 100644
index 68a9fa6..0000000
--- a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/cdi/CacheManagerBean.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.cdi;
-
-import javax.cache.CacheManager;
-import javax.enterprise.context.ApplicationScoped;
-import javax.enterprise.context.spi.CreationalContext;
-import javax.enterprise.inject.spi.Bean;
-import javax.enterprise.inject.spi.InjectionPoint;
-import javax.enterprise.inject.spi.PassivationCapable;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.util.HashSet;
-import java.util.Set;
-
-import static java.util.Collections.emptySet;
-
-public class CacheManagerBean implements Bean<CacheManager>, PassivationCapable
-{
- private final Set<Type> types;
- private final Set<Annotation> qualifiers;
- private final CacheManager manager;
- private final String id;
-
- public CacheManagerBean(final CacheManager cacheManager)
- {
- manager = cacheManager;
- id = getClass().getName() + "-" + hashCode();
-
- types = new HashSet<Type>();
- types.add(CacheManager.class);
- types.add(Object.class);
-
- qualifiers = new HashSet<Annotation>();
- qualifiers.add(DefaultLiteral.INSTANCE);
- qualifiers.add(AnyLiteral.INSTANCE);
- }
-
- @Override
- public Set<Type> getTypes()
- {
- return types;
- }
-
- @Override
- public Set<Annotation> getQualifiers()
- {
- return qualifiers;
- }
-
- @Override
- public Class<? extends Annotation> getScope()
- {
- return ApplicationScoped.class;
- }
-
- @Override
- public String getName()
- {
- return null;
- }
-
- @Override
- public boolean isNullable()
- {
- return false;
- }
-
- @Override
- public Set<InjectionPoint> getInjectionPoints()
- {
- return emptySet();
- }
-
- @Override
- public Class<?> getBeanClass()
- {
- return CacheManager.class;
- }
-
- @Override
- public Set<Class<? extends Annotation>> getStereotypes()
- {
- return emptySet();
- }
-
- @Override
- public boolean isAlternative()
- {
- return false;
- }
-
- @Override
- public CacheManager create(CreationalContext<CacheManager> cacheManagerCreationalContext)
- {
- return manager;
- }
-
- @Override
- public void destroy(CacheManager cacheManager, CreationalContext<CacheManager> cacheManagerCreationalContext)
- {
- manager.close();
- }
-
- @Override
- public String getId()
- {
- return id;
- }
-}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/cdi/CacheProviderBean.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/cdi/CacheProviderBean.java
deleted file mode 100644
index f520664..0000000
--- a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/cdi/CacheProviderBean.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.cdi;
-
-import javax.cache.spi.CachingProvider;
-import javax.enterprise.context.ApplicationScoped;
-import javax.enterprise.context.spi.CreationalContext;
-import javax.enterprise.inject.spi.Bean;
-import javax.enterprise.inject.spi.InjectionPoint;
-import javax.enterprise.inject.spi.PassivationCapable;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.util.HashSet;
-import java.util.Set;
-
-import static java.util.Collections.emptySet;
-
-public class CacheProviderBean implements Bean<CachingProvider>, PassivationCapable
-{
- private final Set<Type> types;
- private final Set<Annotation> qualifiers;
- private final CachingProvider provider;
- private final String id;
-
- public CacheProviderBean(final CachingProvider cacheManager)
- {
- provider = cacheManager;
- id = getClass().getName() + "-" + hashCode();
-
- types = new HashSet<Type>();
- types.add(CachingProvider.class);
- types.add(Object.class);
-
- qualifiers = new HashSet<Annotation>();
- qualifiers.add(DefaultLiteral.INSTANCE);
- qualifiers.add(AnyLiteral.INSTANCE);
- }
-
- @Override
- public Set<Type> getTypes()
- {
- return types;
- }
-
- @Override
- public Set<Annotation> getQualifiers()
- {
- return qualifiers;
- }
-
- @Override
- public Class<? extends Annotation> getScope()
- {
- return ApplicationScoped.class;
- }
-
- @Override
- public String getName()
- {
- return null;
- }
-
- @Override
- public boolean isNullable()
- {
- return false;
- }
-
- @Override
- public Set<InjectionPoint> getInjectionPoints()
- {
- return emptySet();
- }
-
- @Override
- public Class<?> getBeanClass()
- {
- return CachingProvider.class;
- }
-
- @Override
- public Set<Class<? extends Annotation>> getStereotypes()
- {
- return emptySet();
- }
-
- @Override
- public boolean isAlternative()
- {
- return false;
- }
-
- @Override
- public CachingProvider create(final CreationalContext<CachingProvider> cacheManagerCreationalContext)
- {
- return provider;
- }
-
- @Override
- public void destroy(final CachingProvider cacheProvider, final CreationalContext<CachingProvider> cacheManagerCreationalContext)
- {
- provider.close();
- }
-
- @Override
- public String getId()
- {
- return id;
- }
-}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/cdi/DefaultLiteral.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/cdi/DefaultLiteral.java
deleted file mode 100644
index aebe476..0000000
--- a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/cdi/DefaultLiteral.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.cdi;
-
-import javax.enterprise.inject.Default;
-import javax.enterprise.util.AnnotationLiteral;
-
-public class DefaultLiteral extends AnnotationLiteral<Default> implements Default
-{
- public static final DefaultLiteral INSTANCE = new DefaultLiteral();
-
- @Override
- public String toString()
- {
- return "@javax.enterprise.inject.Default()";
- }
-}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/cdi/ExtraJCacheExtension.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/cdi/ExtraJCacheExtension.java
deleted file mode 100644
index 225abeb..0000000
--- a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/cdi/ExtraJCacheExtension.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.cdi;
-
-import javax.cache.CacheManager;
-import javax.cache.Caching;
-import javax.cache.spi.CachingProvider;
-import javax.enterprise.event.Observes;
-import javax.enterprise.inject.spi.AfterBeanDiscovery;
-import javax.enterprise.inject.spi.Bean;
-import javax.enterprise.inject.spi.BeforeShutdown;
-import javax.enterprise.inject.spi.Extension;
-import javax.enterprise.inject.spi.ProcessBean;
-import java.util.Properties;
-
-// add default CacheProvider and CacheManager
-public class ExtraJCacheExtension implements Extension
-{
- private static final boolean ACTIVATED = "true".equals(System.getProperty("org.apache.jcs.extra.cdi", "true"));
-
- private boolean cacheManagerFound = false;
- private boolean cacheProviderFound = false;
- private CacheManager cacheManager;
- private CachingProvider cachingProvider;
-
- public <A> void processBean(final @Observes ProcessBean<A> processBeanEvent)
- {
- if (!ACTIVATED)
- {
- return;
- }
-
- if (cacheManagerFound && cacheProviderFound)
- {
- return;
- }
-
- final Bean<A> bean = processBeanEvent.getBean();
- if (CacheManagerBean.class.isInstance(bean) || CacheProviderBean.class.isInstance(bean))
- {
- return;
- }
-
- if (!cacheManagerFound)
- {
- cacheManagerFound = bean.getTypes().contains(CacheManager.class);
- }
- if (!cacheProviderFound)
- {
- cacheProviderFound = bean.getTypes().contains(CachingProvider.class);
- }
- }
-
- public void addJCacheBeans(final @Observes AfterBeanDiscovery afterBeanDiscovery)
- {
- if (!ACTIVATED)
- {
- return;
- }
-
- if (cacheManagerFound && cacheProviderFound) {
- return;
- }
-
- cachingProvider = Caching.getCachingProvider();
- if (!cacheManagerFound)
- {
- cacheManager = cachingProvider.getCacheManager(
- cachingProvider.getDefaultURI(),
- cachingProvider.getDefaultClassLoader(),
- new Properties());
- afterBeanDiscovery.addBean(new CacheManagerBean(cacheManager));
- }
- if (!cacheProviderFound)
- {
- afterBeanDiscovery.addBean(new CacheProviderBean(cachingProvider));
- }
- }
-
- public void destroyIfCreated(final @Observes BeforeShutdown beforeShutdown)
- {
- if (cacheManager != null)
- {
- cacheManager.close();
- }
- if (cachingProvider != null)
- {
- cachingProvider.close();
- }
- }
-}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/closeable/Closeables.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/closeable/Closeables.java
deleted file mode 100644
index c8d4c96..0000000
--- a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/closeable/Closeables.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.closeable;
-
-import java.io.Closeable;
-import java.io.IOException;
-
-public class Closeables
-{
- public static void close(final Object... closeables) throws IOException
- {
- IOException e = null;
- for (final Object closeable : closeables)
- {
- if (Closeable.class.isInstance(closeable))
- {
- try
- {
- Closeable.class.cast(closeable).close();
- } catch (final IOException ex) {
- if (e == null)
- {
- e = ex;
- }
- }
- }
- }
- if (e != null)
- {
- throw e;
- }
- }
-
- private Closeables()
- {
- // no-op
- }
-}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/loader/CacheLoaderAdapter.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/loader/CacheLoaderAdapter.java
deleted file mode 100644
index c30b0f1..0000000
--- a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/loader/CacheLoaderAdapter.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.loader;
-
-import javax.cache.configuration.Factory;
-import javax.cache.integration.CacheLoader;
-import javax.cache.integration.CacheLoaderException;
-import java.util.HashMap;
-import java.util.Map;
-
-public abstract class CacheLoaderAdapter<K, V> implements CacheLoader<K, V>, Factory<CacheLoader<K, V>>
-{
- @Override
- public Map<K, V> loadAll(final Iterable<? extends K> keys) throws CacheLoaderException
- {
- final Map<K, V> result = new HashMap<K, V>();
- for (final K k : keys)
- {
- final V v = load(k);
- if (v != null)
- {
- result.put(k, v);
- }
- }
- return result;
- }
-
- @Override
- public CacheLoader<K, V> create()
- {
- return this;
- }
-}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/loader/CompositeCacheLoader.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/loader/CompositeCacheLoader.java
deleted file mode 100644
index 560f5d1..0000000
--- a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/loader/CompositeCacheLoader.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.loader;
-
-import org.apache.commons.jcs.jcache.extras.closeable.Closeables;
-
-import javax.cache.configuration.Factory;
-import javax.cache.integration.CacheLoader;
-import javax.cache.integration.CacheLoaderException;
-import java.io.Closeable;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-public class CompositeCacheLoader<K, V> implements CacheLoader<K, V>, Closeable, Factory<CacheLoader<K, V>>
-{
- private final CacheLoader<K, V>[] delegates;
-
- public CompositeCacheLoader(final CacheLoader<K, V>... delegates)
- {
- this.delegates = delegates;
- }
-
- @Override
- public V load(final K key) throws CacheLoaderException
- {
- for (final CacheLoader<K, V> delegate : delegates)
- {
- final V v = delegate.load(key);
- if (v != null)
- {
- return v;
- }
- }
- return null;
- }
-
- @Override
- public Map<K, V> loadAll(final Iterable<? extends K> keys) throws CacheLoaderException
- {
- final Collection<K> list = new ArrayList<K>();
- for (final K k : keys)
- {
- list.add(k);
- }
-
- final Map<K, V> result = new HashMap<K, V>();
- for (final CacheLoader<K, V> delegate : delegates)
- {
- final Map<K, V> v = delegate.loadAll(list);
- if (v != null)
- {
- result.putAll(v);
- list.removeAll(v.keySet());
- if (list.isEmpty())
- {
- return v;
- }
- }
- }
-
- return result;
- }
-
- @Override
- public void close() throws IOException
- {
- Closeables.close(delegates);
- }
-
- @Override
- public CacheLoader<K, V> create()
- {
- return this;
- }
-}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/web/InMemoryResponse.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/web/InMemoryResponse.java
deleted file mode 100644
index d381248..0000000
--- a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/web/InMemoryResponse.java
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.web;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.concurrent.CopyOnWriteArraySet;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpServletResponseWrapper;
-
-public class InMemoryResponse extends HttpServletResponseWrapper implements Serializable
-{
- private final OutputStream buffer;
-
- private final Collection<Cookie> cookies = new CopyOnWriteArraySet<Cookie>();
- private final Map<String, List<Serializable>> headers = new TreeMap<String, List<Serializable>>(String.CASE_INSENSITIVE_ORDER);
- private int status = SC_OK;
- private String contentType = null;
- private PrintWriter writer;
- private int contentLength;
-
- public InMemoryResponse(final HttpServletResponse response, final OutputStream baos)
- {
- super(response);
- this.buffer = baos;
- }
-
- private List<Serializable> ensureHeaderExists(final String s)
- {
- List<Serializable> values = headers.get(s);
- if (values == null) {
- values = new LinkedList<Serializable>();
- headers.put(s, values);
- }
- return values;
- }
-
- @Override
- public void addCookie(final Cookie cookie)
- {
- super.addCookie(cookie);
- cookies.add(cookie);
- }
-
- @Override
- public void addDateHeader(final String s, final long l)
- {
- super.addDateHeader(s, l);
- ensureHeaderExists(s).add(l);
- }
-
- @Override
- public void addHeader(final String s, final String s2)
- {
- super.addHeader(s, s2);
- ensureHeaderExists(s).add(s2);
- }
-
- @Override
- public void addIntHeader(final String s, final int i)
- {
- super.addIntHeader(s, i);
- ensureHeaderExists(s).add(i);
- }
-
- @Override
- public boolean containsHeader(final String s)
- {
- return headers.containsKey(s);
- }
-
- @Override
- public String getHeader(final String s)
- {
- final List<Serializable> serializables = headers.get(s);
- if (serializables.isEmpty())
- {
- return null;
- }
- return serializables.iterator().next().toString();
- }
-
- @Override
- public Collection<String> getHeaderNames()
- {
- return headers.keySet();
- }
-
- @Override
- public Collection<String> getHeaders(final String s)
- {
- final List<Serializable> serializables = headers.get(s);
- final Collection<String> strings = new ArrayList<String>(serializables.size());
- for (final Serializable ser : serializables)
- {
- strings.add(ser.toString());
- }
- return strings;
- }
-
- @Override
- public int getStatus()
- {
- return status;
- }
-
- @Override
- public void sendError(final int i) throws IOException
- {
- status = i;
- super.sendError(i);
- }
-
- @Override
- public void sendError(final int i, final String s) throws IOException
- {
- status = i;
- super.sendError(i, s);
- }
-
- @Override
- public void sendRedirect(final String s) throws IOException
- {
- status = SC_MOVED_TEMPORARILY;
- super.sendRedirect(s);
- }
-
- @Override
- public void setDateHeader(final String s, final long l)
- {
- super.setDateHeader(s, l);
- final List<Serializable> serializables = ensureHeaderExists(s);
- serializables.clear();
- serializables.add(l);
- }
-
- @Override
- public void setHeader(final String s, final String s2)
- {
- super.setHeader(s, s2);
- final List<Serializable> serializables = ensureHeaderExists(s);
- serializables.clear();
- serializables.add(s2);
- }
-
- @Override
- public void setIntHeader(final String s, final int i)
- {
- super.setIntHeader(s, i);
- final List<Serializable> serializables = ensureHeaderExists(s);
- serializables.clear();
- serializables.add(i);
- }
-
- @Override
- public void setStatus(int i)
- {
- status = i;
- super.setStatus(i);
- }
-
- @Override
- public void setStatus(final int i, final String s)
- {
- status = i;
- super.setStatus(i, s);
- }
-
- @Override
- public String getContentType()
- {
- return contentType;
- }
-
- @Override
- public ServletOutputStream getOutputStream() throws IOException
- {
- return new ServletOutputStream()
- {
- @Override
- public void write(final int b) throws IOException
- {
- buffer.write(b);
- }
- };
- }
-
- @Override
- public PrintWriter getWriter() throws IOException
- {
- if (writer == null) {
- writer = new PrintWriter(new OutputStreamWriter(buffer, getCharacterEncoding()), true);
- }
- return writer;
- }
-
- @Override
- public void reset()
- {
- super.reset();
- status = SC_OK;
- headers.clear();
- cookies.clear();
- contentType = null;
- contentLength = 0;
- }
-
- @Override
- public void setContentLength(final int i)
- {
- super.setContentLength(i);
- contentLength = i;
- }
-
- @Override
- public void setContentType(final String s)
- {
- contentType = s;
- super.setContentType(s);
- }
-
- @Override
- public void flushBuffer() throws IOException
- {
- if (writer != null)
- {
- writer.flush();
- }
- else
- {
- buffer.flush();
- }
- }
-
- public int getContentLength()
- {
- return contentLength;
- }
-
- public Collection<Cookie> getCookies()
- {
- return cookies;
- }
-
- public Map<String, List<Serializable>> getHeaders()
- {
- return headers;
- }
-}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/web/JCacheFilter.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/web/JCacheFilter.java
deleted file mode 100644
index cdfc644..0000000
--- a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/web/JCacheFilter.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.web;
-
-import javax.cache.Cache;
-import javax.cache.CacheManager;
-import javax.cache.Caching;
-import javax.cache.configuration.FactoryBuilder;
-import javax.cache.configuration.MutableConfiguration;
-import javax.cache.expiry.ExpiryPolicy;
-import javax.cache.integration.CacheLoader;
-import javax.cache.integration.CacheWriter;
-import javax.cache.spi.CachingProvider;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.Serializable;
-import java.net.URI;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.zip.GZIPOutputStream;
-
-import static java.util.Collections.list;
-import static javax.servlet.http.HttpServletResponse.SC_OK;
-
-public class JCacheFilter implements Filter
-{
- private Cache<PageKey, Page> cache;
- private CachingProvider provider;
- private CacheManager manager;
-
- @Override
- public void init(final FilterConfig filterConfig) throws ServletException
- {
- final ClassLoader classLoader = filterConfig.getServletContext().getClassLoader();
- provider = Caching.getCachingProvider(classLoader);
-
- String uri = filterConfig.getInitParameter("configuration");
- if (uri == null)
- {
- uri = provider.getDefaultURI().toString();
- }
- final Properties properties = new Properties();
- for (final String key : list(filterConfig.getInitParameterNames()))
- {
- final String value = filterConfig.getInitParameter(key);
- if (value != null)
- {
- properties.put(key, value);
- }
- }
- manager = provider.getCacheManager(URI.create(uri), classLoader, properties);
-
- String cacheName = filterConfig.getInitParameter("cache-name");
- if (cacheName == null)
- {
- cacheName = JCacheFilter.class.getName();
- }
- cache = manager.getCache(cacheName);
- if (cache == null)
- {
- final MutableConfiguration<PageKey, Page> configuration = new MutableConfiguration<PageKey, Page>()
- .setStoreByValue(false);
- configuration.setReadThrough("true".equals(properties.getProperty("read-through", "false")));
- configuration.setWriteThrough("true".equals(properties.getProperty("write-through", "false")));
- if (configuration.isReadThrough())
- {
- configuration.setCacheLoaderFactory(new FactoryBuilder.ClassFactory<CacheLoader<PageKey, Page>>(properties.getProperty("cache-loader-factory")));
- }
- if (configuration.isWriteThrough())
- {
- configuration.setCacheWriterFactory(new FactoryBuilder.ClassFactory<CacheWriter<? super PageKey, ? super Page>>(properties.getProperty("cache-writer-factory")));
- }
- final String expirtyPolicy = properties.getProperty("expiry-policy-factory");
- if (expirtyPolicy != null)
- {
- configuration.setExpiryPolicyFactory(new FactoryBuilder.ClassFactory<ExpiryPolicy>(expirtyPolicy));
- }
- configuration.setManagementEnabled("true".equals(properties.getProperty("management-enabled", "false")));
- configuration.setStatisticsEnabled("true".equals(properties.getProperty("statistics-enabled", "false")));
- cache = manager.createCache(cacheName, configuration);
- }
- }
-
- @Override
- public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException
- {
- boolean gzip = false;
- if (HttpServletRequest.class.isInstance(servletRequest))
- {
- final Enumeration<String> acceptEncoding = HttpServletRequest.class.cast(servletRequest).getHeaders("Accept-Encoding");
- while (acceptEncoding != null && acceptEncoding.hasMoreElements())
- {
- if ("gzip".equals(acceptEncoding.nextElement()))
- {
- gzip = true;
- break;
- }
- }
- }
-
- final HttpServletResponse httpServletResponse = HttpServletResponse.class.cast(servletResponse);
- checkResponse(httpServletResponse);
-
- final PageKey key = new PageKey(key(servletRequest), gzip);
- Page page = cache.get(key);
- if (page == null)
- {
- final ByteArrayOutputStream baos = new ByteArrayOutputStream();
- final InMemoryResponse response;
- if (gzip)
- {
- response = new InMemoryResponse(httpServletResponse, new GZIPOutputStream(baos));
- }
- else
- {
- response = new InMemoryResponse(httpServletResponse, baos);
- }
- filterChain.doFilter(servletRequest, response);
- response.flushBuffer();
-
- page = new Page(
- response.getStatus(),
- response.getContentType(),
- response.getContentLength(),
- response.getCookies(),
- response.getHeaders(),
- baos.toByteArray());
- cache.put(key, page);
- }
-
- if (page.status == SC_OK) {
- checkResponse(httpServletResponse);
-
- if (gzip)
- {
- httpServletResponse.setHeader("Content-Encoding", "gzip");
- }
-
- httpServletResponse.setStatus(page.status);
- if (page.contentType != null)
- {
- httpServletResponse.setContentType(page.contentType);
- }
- if (page.contentLength > 0)
- {
- httpServletResponse.setContentLength(page.contentLength);
- }
- for (final Cookie c : page.cookies)
- {
- httpServletResponse.addCookie(c);
- }
- for (final Map.Entry<String, List<Serializable>> entry : page.headers.entrySet())
- {
- for (final Serializable value : entry.getValue())
- {
- if (Integer.class.isInstance(value))
- {
- httpServletResponse.addIntHeader(entry.getKey(), Integer.class.cast(value));
- }
- else if (String.class.isInstance(value))
- {
- httpServletResponse.addHeader(entry.getKey(), String.class.cast(value));
- }
- else if (Long.class.isInstance(value))
- {
- httpServletResponse.addDateHeader(entry.getKey(), Long.class.cast(value));
- }
- }
- }
- httpServletResponse.setContentLength(page.out.length);
- final BufferedOutputStream bos = new BufferedOutputStream(httpServletResponse.getOutputStream());
- if (page.out.length != 0)
- {
- bos.write(page.out);
- }
- else
- {
- bos.write(new byte[0]);
- }
- bos.flush();
- }
- }
-
- protected String key(final ServletRequest servletRequest)
- {
- if (HttpServletRequest.class.isInstance(servletRequest))
- {
- final HttpServletRequest request = HttpServletRequest.class.cast(servletRequest);
- return request.getMethod() + '_' + request.getRequestURI() + '_' + request.getQueryString();
- }
- return servletRequest.toString();
- }
-
- private void checkResponse(final ServletResponse servletResponse)
- {
- if (servletResponse.isCommitted()) {
- throw new IllegalStateException("Response committed");
- }
- }
-
- @Override
- public void destroy()
- {
- if (!cache.isClosed())
- {
- cache.close();
- }
- if (!manager.isClosed())
- {
- manager.close();
- }
- provider.close();
- }
-
- protected static class PageKey implements Serializable {
- private final String uri;
- private boolean gzip;
-
- public PageKey(final String uri, final boolean gzip)
- {
- this.uri = uri;
- this.gzip = gzip;
- }
-
- public void setGzip(final boolean gzip)
- {
- this.gzip = gzip;
- }
-
- @Override
- public boolean equals(final Object o)
- {
- if (this == o)
- {
- return true;
- }
- if (o == null || getClass() != o.getClass())
- {
- return false;
- }
-
- final PageKey pageKey = PageKey.class.cast(o);
- return gzip == pageKey.gzip && uri.equals(pageKey.uri);
-
- }
-
- @Override
- public int hashCode()
- {
- int result = uri.hashCode();
- result = 31 * result + (gzip ? 1 : 0);
- return result;
- }
- }
-
- protected static class Page implements Serializable {
- private final int status;
- private final String contentType;
- private final int contentLength;
- private final Collection<Cookie> cookies;
- private final Map<String, List<Serializable>> headers;
- private final byte[] out;
-
- public Page(final int status,
- final String contentType, final int contentLength,
- final Collection<Cookie> cookies, final Map<String, List<Serializable>> headers,
- final byte[] out)
- {
- this.status = status;
- this.contentType = contentType;
- this.contentLength = contentLength;
- this.cookies = cookies;
- this.headers = headers;
- this.out = out;
- }
-
- @Override
- public boolean equals(final Object o)
- {
- if (this == o)
- {
- return true;
- }
- if (o == null || getClass() != o.getClass())
- {
- return false;
- }
-
- final Page page = Page.class.cast(o);
- return contentLength == page.contentLength
- && status == page.status
- && !(contentType != null ? !contentType.equals(page.contentType) : page.contentType != null)
- && cookies.equals(page.cookies)
- && headers.equals(page.headers)
- && Arrays.equals(out, page.out);
-
- }
-
- @Override
- public int hashCode()
- {
- int result = status;
- result = 31 * result + (contentType != null ? contentType.hashCode() : 0);
- result = 31 * result + contentLength;
- result = 31 * result + cookies.hashCode();
- result = 31 * result + headers.hashCode();
- result = 31 * result + Arrays.hashCode(out);
- return result;
- }
- }
-}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/writer/AsyncCacheWriter.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/writer/AsyncCacheWriter.java
deleted file mode 100644
index 53d2530..0000000
--- a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/writer/AsyncCacheWriter.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.writer;
-
-import javax.cache.Cache;
-import javax.cache.configuration.Factory;
-import javax.cache.integration.CacheWriter;
-import javax.cache.integration.CacheWriterException;
-import java.io.Closeable;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-public class AsyncCacheWriter<K, V> implements CacheWriter<K, V>, Closeable, Factory<CacheWriter<K, V>>
-{
- private static final Logger LOGGER = Logger.getLogger(AsyncCacheWriter.class.getName());
-
- private final CacheWriter<K, V> writer;
- private final ExecutorService pool;
-
- public AsyncCacheWriter(final CacheWriter<K, V> delegate, final int poolSize)
- {
- writer = delegate;
- pool = Executors.newFixedThreadPool(
- poolSize, new DaemonThreadFactory(delegate.getClass().getName() + "-" + delegate.hashCode() + "-"));
- }
-
- @Override
- public void write(final Cache.Entry<? extends K, ? extends V> entry) throws CacheWriterException
- {
- pool.submit(new ExceptionProtectionRunnable()
- {
- @Override
- public void doRun()
- {
- writer.write(entry);
- }
- });
- }
-
- @Override
- public void writeAll(final Collection<Cache.Entry<? extends K, ? extends V>> entries) throws CacheWriterException
- {
- pool.submit(new ExceptionProtectionRunnable()
- {
- @Override
- public void doRun()
- {
- writer.writeAll(entries);
- }
- });
- }
-
- @Override
- public void delete(final Object key) throws CacheWriterException
- {
- pool.submit(new ExceptionProtectionRunnable()
- {
- @Override
- public void doRun()
- {
- writer.delete(key);
- }
- });
- }
-
- @Override
- public void deleteAll(final Collection<?> keys) throws CacheWriterException
- {
- pool.submit(new ExceptionProtectionRunnable()
- {
- @Override
- public void doRun()
- {
- writer.deleteAll(keys);
- }
- });
- }
-
- @Override
- public void close() throws IOException
- {
- final List<Runnable> runnables = pool.shutdownNow();
- for (final Runnable r : runnables)
- {
- r.run();
- }
- }
-
- @Override
- public CacheWriter<K, V> create()
- {
- return this;
- }
-
- // avoid dep on impl
- private static class DaemonThreadFactory implements ThreadFactory
- {
- private final AtomicInteger index = new AtomicInteger(1);
- private final String prefix;
-
- public DaemonThreadFactory(final String prefix)
- {
- this.prefix = prefix;
- }
-
- @Override
- public Thread newThread( final Runnable runner )
- {
- final Thread t = new Thread( runner );
- t.setName(prefix + index.getAndIncrement());
- t.setDaemon(true);
- return t;
- }
- }
-
- private static abstract class ExceptionProtectionRunnable implements Runnable
- {
- @Override
- public void run()
- {
- try
- {
- doRun();
- }
- catch (final Exception e)
- {
- LOGGER.log(Level.SEVERE, e.getMessage(), e);
- }
- }
-
- protected abstract void doRun();
- }
-}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/writer/CacheWriterAdapter.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/writer/CacheWriterAdapter.java
deleted file mode 100644
index 79b59b9..0000000
--- a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/writer/CacheWriterAdapter.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.writer;
-
-import javax.cache.Cache;
-import javax.cache.configuration.Factory;
-import javax.cache.integration.CacheWriter;
-import javax.cache.integration.CacheWriterException;
-import java.util.Collection;
-
-public abstract class CacheWriterAdapter<K, V> implements CacheWriter<K, V>, Factory<CacheWriter<K, V>>
-{
- @Override
- public void writeAll(final Collection<Cache.Entry<? extends K, ? extends V>> entries) throws CacheWriterException
- {
- for (final Cache.Entry<? extends K, ? extends V> entry : entries)
- {
- write(entry);
- }
- }
-
- @Override
- public void deleteAll(final Collection<?> keys) throws CacheWriterException
- {
- for (final Object k : keys)
- {
- delete(k);
- }
- }
-
- @Override
- public CacheWriter<K, V> create()
- {
- return this;
- }
-}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/writer/CompositeCacheWriter.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/writer/CompositeCacheWriter.java
deleted file mode 100644
index 970ab13..0000000
--- a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs/jcache/extras/writer/CompositeCacheWriter.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.writer;
-
-import org.apache.commons.jcs.jcache.extras.closeable.Closeables;
-
-import javax.cache.Cache;
-import javax.cache.configuration.Factory;
-import javax.cache.integration.CacheWriter;
-import javax.cache.integration.CacheWriterException;
-import java.io.Closeable;
-import java.io.IOException;
-import java.util.Collection;
-
-public class CompositeCacheWriter<K, V> implements CacheWriter<K, V>, Closeable, Factory<CacheWriter<K, V>>
-{
- private final CacheWriter<K, V>[] writers;
-
- public CompositeCacheWriter(final CacheWriter<K, V>... writers)
- {
- this.writers = writers;
- }
-
- @Override
- public void write(final Cache.Entry<? extends K, ? extends V> entry) throws CacheWriterException
- {
- CacheWriterException e = null;
- for (final CacheWriter<K, V> writer : writers)
- {
- try
- {
- writer.write(entry);
- }
- catch (final CacheWriterException ex)
- {
- if (e == null)
- {
- e = ex;
- }
- }
- }
- if (e != null)
- {
- throw e;
- }
- }
-
- @Override
- public void writeAll(final Collection<Cache.Entry<? extends K, ? extends V>> entries) throws CacheWriterException
- {
- CacheWriterException e = null;
- for (final CacheWriter<K, V> writer : writers)
- {
- try
- {
- writer.writeAll(entries);
- }
- catch (final CacheWriterException ex)
- {
- if (e == null)
- {
- e = ex;
- }
- }
- }
- if (e != null)
- {
- throw e;
- }
- }
-
- @Override
- public void delete(final Object key) throws CacheWriterException
- {
- CacheWriterException e = null;
- for (final CacheWriter<K, V> writer : writers)
- {
- try
- {
- writer.delete(key);
- }
- catch (final CacheWriterException ex)
- {
- if (e == null)
- {
- e = ex;
- }
- }
- }
- if (e != null)
- {
- throw e;
- }
- }
-
- @Override
- public void deleteAll(final Collection<?> keys) throws CacheWriterException
- {
- CacheWriterException e = null;
- for (final CacheWriter<K, V> writer : writers)
- {
- try
- {
- writer.deleteAll(keys);
- }
- catch (final CacheWriterException ex)
- {
- if (e == null)
- {
- e = ex;
- }
- }
- }
- if (e != null)
- {
- throw e;
- }
- }
-
- @Override
- public CacheWriter<K, V> create()
- {
- return this;
- }
-
- @Override
- public void close() throws IOException
- {
- Closeables.close(writers);
- }
-}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/cdi/AnyLiteral.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/cdi/AnyLiteral.java
new file mode 100644
index 0000000..2371cdf
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/cdi/AnyLiteral.java
@@ -0,0 +1,33 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.cdi;
+
+import javax.enterprise.inject.Any;
+import javax.enterprise.util.AnnotationLiteral;
+
+public class AnyLiteral extends AnnotationLiteral<Any> implements Any
+{
+ public static final AnyLiteral INSTANCE = new AnyLiteral();
+
+ @Override
+ public String toString()
+ {
+ return "@javax.enterprise.inject.Any()";
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/cdi/CacheManagerBean.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/cdi/CacheManagerBean.java
new file mode 100644
index 0000000..18b600f
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/cdi/CacheManagerBean.java
@@ -0,0 +1,126 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.cdi;
+
+import javax.cache.CacheManager;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.enterprise.inject.spi.PassivationCapable;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.HashSet;
+import java.util.Set;
+
+import static java.util.Collections.emptySet;
+
+public class CacheManagerBean implements Bean<CacheManager>, PassivationCapable
+{
+ private final Set<Type> types;
+ private final Set<Annotation> qualifiers;
+ private final CacheManager manager;
+ private final String id;
+
+ public CacheManagerBean(final CacheManager cacheManager)
+ {
+ manager = cacheManager;
+ id = getClass().getName() + "-" + hashCode();
+
+ types = new HashSet<Type>();
+ types.add(CacheManager.class);
+ types.add(Object.class);
+
+ qualifiers = new HashSet<Annotation>();
+ qualifiers.add(DefaultLiteral.INSTANCE);
+ qualifiers.add(AnyLiteral.INSTANCE);
+ }
+
+ @Override
+ public Set<Type> getTypes()
+ {
+ return types;
+ }
+
+ @Override
+ public Set<Annotation> getQualifiers()
+ {
+ return qualifiers;
+ }
+
+ @Override
+ public Class<? extends Annotation> getScope()
+ {
+ return ApplicationScoped.class;
+ }
+
+ @Override
+ public String getName()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isNullable()
+ {
+ return false;
+ }
+
+ @Override
+ public Set<InjectionPoint> getInjectionPoints()
+ {
+ return emptySet();
+ }
+
+ @Override
+ public Class<?> getBeanClass()
+ {
+ return CacheManager.class;
+ }
+
+ @Override
+ public Set<Class<? extends Annotation>> getStereotypes()
+ {
+ return emptySet();
+ }
+
+ @Override
+ public boolean isAlternative()
+ {
+ return false;
+ }
+
+ @Override
+ public CacheManager create(CreationalContext<CacheManager> cacheManagerCreationalContext)
+ {
+ return manager;
+ }
+
+ @Override
+ public void destroy(CacheManager cacheManager, CreationalContext<CacheManager> cacheManagerCreationalContext)
+ {
+ manager.close();
+ }
+
+ @Override
+ public String getId()
+ {
+ return id;
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/cdi/CacheProviderBean.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/cdi/CacheProviderBean.java
new file mode 100644
index 0000000..e9bd965
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/cdi/CacheProviderBean.java
@@ -0,0 +1,126 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.cdi;
+
+import javax.cache.spi.CachingProvider;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.enterprise.inject.spi.PassivationCapable;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.HashSet;
+import java.util.Set;
+
+import static java.util.Collections.emptySet;
+
+public class CacheProviderBean implements Bean<CachingProvider>, PassivationCapable
+{
+ private final Set<Type> types;
+ private final Set<Annotation> qualifiers;
+ private final CachingProvider provider;
+ private final String id;
+
+ public CacheProviderBean(final CachingProvider cacheManager)
+ {
+ provider = cacheManager;
+ id = getClass().getName() + "-" + hashCode();
+
+ types = new HashSet<Type>();
+ types.add(CachingProvider.class);
+ types.add(Object.class);
+
+ qualifiers = new HashSet<Annotation>();
+ qualifiers.add(DefaultLiteral.INSTANCE);
+ qualifiers.add(AnyLiteral.INSTANCE);
+ }
+
+ @Override
+ public Set<Type> getTypes()
+ {
+ return types;
+ }
+
+ @Override
+ public Set<Annotation> getQualifiers()
+ {
+ return qualifiers;
+ }
+
+ @Override
+ public Class<? extends Annotation> getScope()
+ {
+ return ApplicationScoped.class;
+ }
+
+ @Override
+ public String getName()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isNullable()
+ {
+ return false;
+ }
+
+ @Override
+ public Set<InjectionPoint> getInjectionPoints()
+ {
+ return emptySet();
+ }
+
+ @Override
+ public Class<?> getBeanClass()
+ {
+ return CachingProvider.class;
+ }
+
+ @Override
+ public Set<Class<? extends Annotation>> getStereotypes()
+ {
+ return emptySet();
+ }
+
+ @Override
+ public boolean isAlternative()
+ {
+ return false;
+ }
+
+ @Override
+ public CachingProvider create(final CreationalContext<CachingProvider> cacheManagerCreationalContext)
+ {
+ return provider;
+ }
+
+ @Override
+ public void destroy(final CachingProvider cacheProvider, final CreationalContext<CachingProvider> cacheManagerCreationalContext)
+ {
+ provider.close();
+ }
+
+ @Override
+ public String getId()
+ {
+ return id;
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/cdi/DefaultLiteral.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/cdi/DefaultLiteral.java
new file mode 100644
index 0000000..fbf7d5d
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/cdi/DefaultLiteral.java
@@ -0,0 +1,33 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.cdi;
+
+import javax.enterprise.inject.Default;
+import javax.enterprise.util.AnnotationLiteral;
+
+public class DefaultLiteral extends AnnotationLiteral<Default> implements Default
+{
+ public static final DefaultLiteral INSTANCE = new DefaultLiteral();
+
+ @Override
+ public String toString()
+ {
+ return "@javax.enterprise.inject.Default()";
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/cdi/ExtraJCacheExtension.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/cdi/ExtraJCacheExtension.java
new file mode 100644
index 0000000..75a7c3d
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/cdi/ExtraJCacheExtension.java
@@ -0,0 +1,107 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.cdi;
+
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+import javax.cache.spi.CachingProvider;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AfterBeanDiscovery;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeforeShutdown;
+import javax.enterprise.inject.spi.Extension;
+import javax.enterprise.inject.spi.ProcessBean;
+import java.util.Properties;
+
+// add default CacheProvider and CacheManager
+public class ExtraJCacheExtension implements Extension
+{
+ private static final boolean ACTIVATED = "true".equals(System.getProperty("org.apache.jcs.extra.cdi", "true"));
+
+ private boolean cacheManagerFound = false;
+ private boolean cacheProviderFound = false;
+ private CacheManager cacheManager;
+ private CachingProvider cachingProvider;
+
+ public <A> void processBean(final @Observes ProcessBean<A> processBeanEvent)
+ {
+ if (!ACTIVATED)
+ {
+ return;
+ }
+
+ if (cacheManagerFound && cacheProviderFound)
+ {
+ return;
+ }
+
+ final Bean<A> bean = processBeanEvent.getBean();
+ if (CacheManagerBean.class.isInstance(bean) || CacheProviderBean.class.isInstance(bean))
+ {
+ return;
+ }
+
+ if (!cacheManagerFound)
+ {
+ cacheManagerFound = bean.getTypes().contains(CacheManager.class);
+ }
+ if (!cacheProviderFound)
+ {
+ cacheProviderFound = bean.getTypes().contains(CachingProvider.class);
+ }
+ }
+
+ public void addJCacheBeans(final @Observes AfterBeanDiscovery afterBeanDiscovery)
+ {
+ if (!ACTIVATED)
+ {
+ return;
+ }
+
+ if (cacheManagerFound && cacheProviderFound) {
+ return;
+ }
+
+ cachingProvider = Caching.getCachingProvider();
+ if (!cacheManagerFound)
+ {
+ cacheManager = cachingProvider.getCacheManager(
+ cachingProvider.getDefaultURI(),
+ cachingProvider.getDefaultClassLoader(),
+ new Properties());
+ afterBeanDiscovery.addBean(new CacheManagerBean(cacheManager));
+ }
+ if (!cacheProviderFound)
+ {
+ afterBeanDiscovery.addBean(new CacheProviderBean(cachingProvider));
+ }
+ }
+
+ public void destroyIfCreated(final @Observes BeforeShutdown beforeShutdown)
+ {
+ if (cacheManager != null)
+ {
+ cacheManager.close();
+ }
+ if (cachingProvider != null)
+ {
+ cachingProvider.close();
+ }
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/closeable/Closeables.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/closeable/Closeables.java
new file mode 100644
index 0000000..27b076e
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/closeable/Closeables.java
@@ -0,0 +1,54 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.closeable;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+public class Closeables
+{
+ public static void close(final Object... closeables) throws IOException
+ {
+ IOException e = null;
+ for (final Object closeable : closeables)
+ {
+ if (Closeable.class.isInstance(closeable))
+ {
+ try
+ {
+ Closeable.class.cast(closeable).close();
+ } catch (final IOException ex) {
+ if (e == null)
+ {
+ e = ex;
+ }
+ }
+ }
+ }
+ if (e != null)
+ {
+ throw e;
+ }
+ }
+
+ private Closeables()
+ {
+ // no-op
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/loader/CacheLoaderAdapter.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/loader/CacheLoaderAdapter.java
new file mode 100644
index 0000000..7e77c4a
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/loader/CacheLoaderAdapter.java
@@ -0,0 +1,49 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.loader;
+
+import javax.cache.configuration.Factory;
+import javax.cache.integration.CacheLoader;
+import javax.cache.integration.CacheLoaderException;
+import java.util.HashMap;
+import java.util.Map;
+
+public abstract class CacheLoaderAdapter<K, V> implements CacheLoader<K, V>, Factory<CacheLoader<K, V>>
+{
+ @Override
+ public Map<K, V> loadAll(final Iterable<? extends K> keys) throws CacheLoaderException
+ {
+ final Map<K, V> result = new HashMap<K, V>();
+ for (final K k : keys)
+ {
+ final V v = load(k);
+ if (v != null)
+ {
+ result.put(k, v);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public CacheLoader<K, V> create()
+ {
+ return this;
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/loader/CompositeCacheLoader.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/loader/CompositeCacheLoader.java
new file mode 100644
index 0000000..767e177
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/loader/CompositeCacheLoader.java
@@ -0,0 +1,95 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.loader;
+
+import javax.cache.configuration.Factory;
+import javax.cache.integration.CacheLoader;
+import javax.cache.integration.CacheLoaderException;
+
+import org.apache.commons.jcs3.jcache.extras.closeable.Closeables;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+public class CompositeCacheLoader<K, V> implements CacheLoader<K, V>, Closeable, Factory<CacheLoader<K, V>>
+{
+ private final CacheLoader<K, V>[] delegates;
+
+ public CompositeCacheLoader(final CacheLoader<K, V>... delegates)
+ {
+ this.delegates = delegates;
+ }
+
+ @Override
+ public V load(final K key) throws CacheLoaderException
+ {
+ for (final CacheLoader<K, V> delegate : delegates)
+ {
+ final V v = delegate.load(key);
+ if (v != null)
+ {
+ return v;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Map<K, V> loadAll(final Iterable<? extends K> keys) throws CacheLoaderException
+ {
+ final Collection<K> list = new ArrayList<K>();
+ for (final K k : keys)
+ {
+ list.add(k);
+ }
+
+ final Map<K, V> result = new HashMap<K, V>();
+ for (final CacheLoader<K, V> delegate : delegates)
+ {
+ final Map<K, V> v = delegate.loadAll(list);
+ if (v != null)
+ {
+ result.putAll(v);
+ list.removeAll(v.keySet());
+ if (list.isEmpty())
+ {
+ return v;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ Closeables.close(delegates);
+ }
+
+ @Override
+ public CacheLoader<K, V> create()
+ {
+ return this;
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/web/InMemoryResponse.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/web/InMemoryResponse.java
new file mode 100644
index 0000000..0f468d7
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/web/InMemoryResponse.java
@@ -0,0 +1,276 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.web;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+public class InMemoryResponse extends HttpServletResponseWrapper implements Serializable
+{
+ private final OutputStream buffer;
+
+ private final Collection<Cookie> cookies = new CopyOnWriteArraySet<Cookie>();
+ private final Map<String, List<Serializable>> headers = new TreeMap<String, List<Serializable>>(String.CASE_INSENSITIVE_ORDER);
+ private int status = SC_OK;
+ private String contentType = null;
+ private PrintWriter writer;
+ private int contentLength;
+
+ public InMemoryResponse(final HttpServletResponse response, final OutputStream baos)
+ {
+ super(response);
+ this.buffer = baos;
+ }
+
+ private List<Serializable> ensureHeaderExists(final String s)
+ {
+ List<Serializable> values = headers.get(s);
+ if (values == null) {
+ values = new LinkedList<Serializable>();
+ headers.put(s, values);
+ }
+ return values;
+ }
+
+ @Override
+ public void addCookie(final Cookie cookie)
+ {
+ super.addCookie(cookie);
+ cookies.add(cookie);
+ }
+
+ @Override
+ public void addDateHeader(final String s, final long l)
+ {
+ super.addDateHeader(s, l);
+ ensureHeaderExists(s).add(l);
+ }
+
+ @Override
+ public void addHeader(final String s, final String s2)
+ {
+ super.addHeader(s, s2);
+ ensureHeaderExists(s).add(s2);
+ }
+
+ @Override
+ public void addIntHeader(final String s, final int i)
+ {
+ super.addIntHeader(s, i);
+ ensureHeaderExists(s).add(i);
+ }
+
+ @Override
+ public boolean containsHeader(final String s)
+ {
+ return headers.containsKey(s);
+ }
+
+ @Override
+ public String getHeader(final String s)
+ {
+ final List<Serializable> serializables = headers.get(s);
+ if (serializables.isEmpty())
+ {
+ return null;
+ }
+ return serializables.iterator().next().toString();
+ }
+
+ @Override
+ public Collection<String> getHeaderNames()
+ {
+ return headers.keySet();
+ }
+
+ @Override
+ public Collection<String> getHeaders(final String s)
+ {
+ final List<Serializable> serializables = headers.get(s);
+ final Collection<String> strings = new ArrayList<String>(serializables.size());
+ for (final Serializable ser : serializables)
+ {
+ strings.add(ser.toString());
+ }
+ return strings;
+ }
+
+ @Override
+ public int getStatus()
+ {
+ return status;
+ }
+
+ @Override
+ public void sendError(final int i) throws IOException
+ {
+ status = i;
+ super.sendError(i);
+ }
+
+ @Override
+ public void sendError(final int i, final String s) throws IOException
+ {
+ status = i;
+ super.sendError(i, s);
+ }
+
+ @Override
+ public void sendRedirect(final String s) throws IOException
+ {
+ status = SC_MOVED_TEMPORARILY;
+ super.sendRedirect(s);
+ }
+
+ @Override
+ public void setDateHeader(final String s, final long l)
+ {
+ super.setDateHeader(s, l);
+ final List<Serializable> serializables = ensureHeaderExists(s);
+ serializables.clear();
+ serializables.add(l);
+ }
+
+ @Override
+ public void setHeader(final String s, final String s2)
+ {
+ super.setHeader(s, s2);
+ final List<Serializable> serializables = ensureHeaderExists(s);
+ serializables.clear();
+ serializables.add(s2);
+ }
+
+ @Override
+ public void setIntHeader(final String s, final int i)
+ {
+ super.setIntHeader(s, i);
+ final List<Serializable> serializables = ensureHeaderExists(s);
+ serializables.clear();
+ serializables.add(i);
+ }
+
+ @Override
+ public void setStatus(int i)
+ {
+ status = i;
+ super.setStatus(i);
+ }
+
+ @Override
+ public void setStatus(final int i, final String s)
+ {
+ status = i;
+ super.setStatus(i, s);
+ }
+
+ @Override
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ @Override
+ public ServletOutputStream getOutputStream() throws IOException
+ {
+ return new ServletOutputStream()
+ {
+ @Override
+ public void write(final int b) throws IOException
+ {
+ buffer.write(b);
+ }
+ };
+ }
+
+ @Override
+ public PrintWriter getWriter() throws IOException
+ {
+ if (writer == null) {
+ writer = new PrintWriter(new OutputStreamWriter(buffer, getCharacterEncoding()), true);
+ }
+ return writer;
+ }
+
+ @Override
+ public void reset()
+ {
+ super.reset();
+ status = SC_OK;
+ headers.clear();
+ cookies.clear();
+ contentType = null;
+ contentLength = 0;
+ }
+
+ @Override
+ public void setContentLength(final int i)
+ {
+ super.setContentLength(i);
+ contentLength = i;
+ }
+
+ @Override
+ public void setContentType(final String s)
+ {
+ contentType = s;
+ super.setContentType(s);
+ }
+
+ @Override
+ public void flushBuffer() throws IOException
+ {
+ if (writer != null)
+ {
+ writer.flush();
+ }
+ else
+ {
+ buffer.flush();
+ }
+ }
+
+ public int getContentLength()
+ {
+ return contentLength;
+ }
+
+ public Collection<Cookie> getCookies()
+ {
+ return cookies;
+ }
+
+ public Map<String, List<Serializable>> getHeaders()
+ {
+ return headers;
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/web/JCacheFilter.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/web/JCacheFilter.java
new file mode 100644
index 0000000..ce8782d
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/web/JCacheFilter.java
@@ -0,0 +1,341 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.web;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+import javax.cache.configuration.FactoryBuilder;
+import javax.cache.configuration.MutableConfiguration;
+import javax.cache.expiry.ExpiryPolicy;
+import javax.cache.integration.CacheLoader;
+import javax.cache.integration.CacheWriter;
+import javax.cache.spi.CachingProvider;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.zip.GZIPOutputStream;
+
+import static java.util.Collections.list;
+import static javax.servlet.http.HttpServletResponse.SC_OK;
+
+public class JCacheFilter implements Filter
+{
+ private Cache<PageKey, Page> cache;
+ private CachingProvider provider;
+ private CacheManager manager;
+
+ @Override
+ public void init(final FilterConfig filterConfig) throws ServletException
+ {
+ final ClassLoader classLoader = filterConfig.getServletContext().getClassLoader();
+ provider = Caching.getCachingProvider(classLoader);
+
+ String uri = filterConfig.getInitParameter("configuration");
+ if (uri == null)
+ {
+ uri = provider.getDefaultURI().toString();
+ }
+ final Properties properties = new Properties();
+ for (final String key : list(filterConfig.getInitParameterNames()))
+ {
+ final String value = filterConfig.getInitParameter(key);
+ if (value != null)
+ {
+ properties.put(key, value);
+ }
+ }
+ manager = provider.getCacheManager(URI.create(uri), classLoader, properties);
+
+ String cacheName = filterConfig.getInitParameter("cache-name");
+ if (cacheName == null)
+ {
+ cacheName = JCacheFilter.class.getName();
+ }
+ cache = manager.getCache(cacheName);
+ if (cache == null)
+ {
+ final MutableConfiguration<PageKey, Page> configuration = new MutableConfiguration<PageKey, Page>()
+ .setStoreByValue(false);
+ configuration.setReadThrough("true".equals(properties.getProperty("read-through", "false")));
+ configuration.setWriteThrough("true".equals(properties.getProperty("write-through", "false")));
+ if (configuration.isReadThrough())
+ {
+ configuration.setCacheLoaderFactory(new FactoryBuilder.ClassFactory<CacheLoader<PageKey, Page>>(properties.getProperty("cache-loader-factory")));
+ }
+ if (configuration.isWriteThrough())
+ {
+ configuration.setCacheWriterFactory(new FactoryBuilder.ClassFactory<CacheWriter<? super PageKey, ? super Page>>(properties.getProperty("cache-writer-factory")));
+ }
+ final String expirtyPolicy = properties.getProperty("expiry-policy-factory");
+ if (expirtyPolicy != null)
+ {
+ configuration.setExpiryPolicyFactory(new FactoryBuilder.ClassFactory<ExpiryPolicy>(expirtyPolicy));
+ }
+ configuration.setManagementEnabled("true".equals(properties.getProperty("management-enabled", "false")));
+ configuration.setStatisticsEnabled("true".equals(properties.getProperty("statistics-enabled", "false")));
+ cache = manager.createCache(cacheName, configuration);
+ }
+ }
+
+ @Override
+ public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException
+ {
+ boolean gzip = false;
+ if (HttpServletRequest.class.isInstance(servletRequest))
+ {
+ final Enumeration<String> acceptEncoding = HttpServletRequest.class.cast(servletRequest).getHeaders("Accept-Encoding");
+ while (acceptEncoding != null && acceptEncoding.hasMoreElements())
+ {
+ if ("gzip".equals(acceptEncoding.nextElement()))
+ {
+ gzip = true;
+ break;
+ }
+ }
+ }
+
+ final HttpServletResponse httpServletResponse = HttpServletResponse.class.cast(servletResponse);
+ checkResponse(httpServletResponse);
+
+ final PageKey key = new PageKey(key(servletRequest), gzip);
+ Page page = cache.get(key);
+ if (page == null)
+ {
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ final InMemoryResponse response;
+ if (gzip)
+ {
+ response = new InMemoryResponse(httpServletResponse, new GZIPOutputStream(baos));
+ }
+ else
+ {
+ response = new InMemoryResponse(httpServletResponse, baos);
+ }
+ filterChain.doFilter(servletRequest, response);
+ response.flushBuffer();
+
+ page = new Page(
+ response.getStatus(),
+ response.getContentType(),
+ response.getContentLength(),
+ response.getCookies(),
+ response.getHeaders(),
+ baos.toByteArray());
+ cache.put(key, page);
+ }
+
+ if (page.status == SC_OK) {
+ checkResponse(httpServletResponse);
+
+ if (gzip)
+ {
+ httpServletResponse.setHeader("Content-Encoding", "gzip");
+ }
+
+ httpServletResponse.setStatus(page.status);
+ if (page.contentType != null)
+ {
+ httpServletResponse.setContentType(page.contentType);
+ }
+ if (page.contentLength > 0)
+ {
+ httpServletResponse.setContentLength(page.contentLength);
+ }
+ for (final Cookie c : page.cookies)
+ {
+ httpServletResponse.addCookie(c);
+ }
+ for (final Map.Entry<String, List<Serializable>> entry : page.headers.entrySet())
+ {
+ for (final Serializable value : entry.getValue())
+ {
+ if (Integer.class.isInstance(value))
+ {
+ httpServletResponse.addIntHeader(entry.getKey(), Integer.class.cast(value));
+ }
+ else if (String.class.isInstance(value))
+ {
+ httpServletResponse.addHeader(entry.getKey(), String.class.cast(value));
+ }
+ else if (Long.class.isInstance(value))
+ {
+ httpServletResponse.addDateHeader(entry.getKey(), Long.class.cast(value));
+ }
+ }
+ }
+ httpServletResponse.setContentLength(page.out.length);
+ final BufferedOutputStream bos = new BufferedOutputStream(httpServletResponse.getOutputStream());
+ if (page.out.length != 0)
+ {
+ bos.write(page.out);
+ }
+ else
+ {
+ bos.write(new byte[0]);
+ }
+ bos.flush();
+ }
+ }
+
+ protected String key(final ServletRequest servletRequest)
+ {
+ if (HttpServletRequest.class.isInstance(servletRequest))
+ {
+ final HttpServletRequest request = HttpServletRequest.class.cast(servletRequest);
+ return request.getMethod() + '_' + request.getRequestURI() + '_' + request.getQueryString();
+ }
+ return servletRequest.toString();
+ }
+
+ private void checkResponse(final ServletResponse servletResponse)
+ {
+ if (servletResponse.isCommitted()) {
+ throw new IllegalStateException("Response committed");
+ }
+ }
+
+ @Override
+ public void destroy()
+ {
+ if (!cache.isClosed())
+ {
+ cache.close();
+ }
+ if (!manager.isClosed())
+ {
+ manager.close();
+ }
+ provider.close();
+ }
+
+ protected static class PageKey implements Serializable {
+ private final String uri;
+ private boolean gzip;
+
+ public PageKey(final String uri, final boolean gzip)
+ {
+ this.uri = uri;
+ this.gzip = gzip;
+ }
+
+ public void setGzip(final boolean gzip)
+ {
+ this.gzip = gzip;
+ }
+
+ @Override
+ public boolean equals(final Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass())
+ {
+ return false;
+ }
+
+ final PageKey pageKey = PageKey.class.cast(o);
+ return gzip == pageKey.gzip && uri.equals(pageKey.uri);
+
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int result = uri.hashCode();
+ result = 31 * result + (gzip ? 1 : 0);
+ return result;
+ }
+ }
+
+ protected static class Page implements Serializable {
+ private final int status;
+ private final String contentType;
+ private final int contentLength;
+ private final Collection<Cookie> cookies;
+ private final Map<String, List<Serializable>> headers;
+ private final byte[] out;
+
+ public Page(final int status,
+ final String contentType, final int contentLength,
+ final Collection<Cookie> cookies, final Map<String, List<Serializable>> headers,
+ final byte[] out)
+ {
+ this.status = status;
+ this.contentType = contentType;
+ this.contentLength = contentLength;
+ this.cookies = cookies;
+ this.headers = headers;
+ this.out = out;
+ }
+
+ @Override
+ public boolean equals(final Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass())
+ {
+ return false;
+ }
+
+ final Page page = Page.class.cast(o);
+ return contentLength == page.contentLength
+ && status == page.status
+ && !(contentType != null ? !contentType.equals(page.contentType) : page.contentType != null)
+ && cookies.equals(page.cookies)
+ && headers.equals(page.headers)
+ && Arrays.equals(out, page.out);
+
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int result = status;
+ result = 31 * result + (contentType != null ? contentType.hashCode() : 0);
+ result = 31 * result + contentLength;
+ result = 31 * result + cookies.hashCode();
+ result = 31 * result + headers.hashCode();
+ result = 31 * result + Arrays.hashCode(out);
+ return result;
+ }
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/writer/AsyncCacheWriter.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/writer/AsyncCacheWriter.java
new file mode 100644
index 0000000..0abc65b
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/writer/AsyncCacheWriter.java
@@ -0,0 +1,156 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.writer;
+
+import javax.cache.Cache;
+import javax.cache.configuration.Factory;
+import javax.cache.integration.CacheWriter;
+import javax.cache.integration.CacheWriterException;
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class AsyncCacheWriter<K, V> implements CacheWriter<K, V>, Closeable, Factory<CacheWriter<K, V>>
+{
+ private static final Logger LOGGER = Logger.getLogger(AsyncCacheWriter.class.getName());
+
+ private final CacheWriter<K, V> writer;
+ private final ExecutorService pool;
+
+ public AsyncCacheWriter(final CacheWriter<K, V> delegate, final int poolSize)
+ {
+ writer = delegate;
+ pool = Executors.newFixedThreadPool(
+ poolSize, new DaemonThreadFactory(delegate.getClass().getName() + "-" + delegate.hashCode() + "-"));
+ }
+
+ @Override
+ public void write(final Cache.Entry<? extends K, ? extends V> entry) throws CacheWriterException
+ {
+ pool.submit(new ExceptionProtectionRunnable()
+ {
+ @Override
+ public void doRun()
+ {
+ writer.write(entry);
+ }
+ });
+ }
+
+ @Override
+ public void writeAll(final Collection<Cache.Entry<? extends K, ? extends V>> entries) throws CacheWriterException
+ {
+ pool.submit(new ExceptionProtectionRunnable()
+ {
+ @Override
+ public void doRun()
+ {
+ writer.writeAll(entries);
+ }
+ });
+ }
+
+ @Override
+ public void delete(final Object key) throws CacheWriterException
+ {
+ pool.submit(new ExceptionProtectionRunnable()
+ {
+ @Override
+ public void doRun()
+ {
+ writer.delete(key);
+ }
+ });
+ }
+
+ @Override
+ public void deleteAll(final Collection<?> keys) throws CacheWriterException
+ {
+ pool.submit(new ExceptionProtectionRunnable()
+ {
+ @Override
+ public void doRun()
+ {
+ writer.deleteAll(keys);
+ }
+ });
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ final List<Runnable> runnables = pool.shutdownNow();
+ for (final Runnable r : runnables)
+ {
+ r.run();
+ }
+ }
+
+ @Override
+ public CacheWriter<K, V> create()
+ {
+ return this;
+ }
+
+ // avoid dep on impl
+ private static class DaemonThreadFactory implements ThreadFactory
+ {
+ private final AtomicInteger index = new AtomicInteger(1);
+ private final String prefix;
+
+ public DaemonThreadFactory(final String prefix)
+ {
+ this.prefix = prefix;
+ }
+
+ @Override
+ public Thread newThread( final Runnable runner )
+ {
+ final Thread t = new Thread( runner );
+ t.setName(prefix + index.getAndIncrement());
+ t.setDaemon(true);
+ return t;
+ }
+ }
+
+ private static abstract class ExceptionProtectionRunnable implements Runnable
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ doRun();
+ }
+ catch (final Exception e)
+ {
+ LOGGER.log(Level.SEVERE, e.getMessage(), e);
+ }
+ }
+
+ protected abstract void doRun();
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/writer/CacheWriterAdapter.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/writer/CacheWriterAdapter.java
new file mode 100644
index 0000000..cbcd3e5
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/writer/CacheWriterAdapter.java
@@ -0,0 +1,52 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.writer;
+
+import javax.cache.Cache;
+import javax.cache.configuration.Factory;
+import javax.cache.integration.CacheWriter;
+import javax.cache.integration.CacheWriterException;
+import java.util.Collection;
+
+public abstract class CacheWriterAdapter<K, V> implements CacheWriter<K, V>, Factory<CacheWriter<K, V>>
+{
+ @Override
+ public void writeAll(final Collection<Cache.Entry<? extends K, ? extends V>> entries) throws CacheWriterException
+ {
+ for (final Cache.Entry<? extends K, ? extends V> entry : entries)
+ {
+ write(entry);
+ }
+ }
+
+ @Override
+ public void deleteAll(final Collection<?> keys) throws CacheWriterException
+ {
+ for (final Object k : keys)
+ {
+ delete(k);
+ }
+ }
+
+ @Override
+ public CacheWriter<K, V> create()
+ {
+ return this;
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/writer/CompositeCacheWriter.java b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/writer/CompositeCacheWriter.java
new file mode 100644
index 0000000..3fad841
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/main/java/org/apache/commons/jcs3/jcache/extras/writer/CompositeCacheWriter.java
@@ -0,0 +1,148 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.writer;
+
+import javax.cache.Cache;
+import javax.cache.configuration.Factory;
+import javax.cache.integration.CacheWriter;
+import javax.cache.integration.CacheWriterException;
+
+import org.apache.commons.jcs3.jcache.extras.closeable.Closeables;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Collection;
+
+public class CompositeCacheWriter<K, V> implements CacheWriter<K, V>, Closeable, Factory<CacheWriter<K, V>>
+{
+ private final CacheWriter<K, V>[] writers;
+
+ public CompositeCacheWriter(final CacheWriter<K, V>... writers)
+ {
+ this.writers = writers;
+ }
+
+ @Override
+ public void write(final Cache.Entry<? extends K, ? extends V> entry) throws CacheWriterException
+ {
+ CacheWriterException e = null;
+ for (final CacheWriter<K, V> writer : writers)
+ {
+ try
+ {
+ writer.write(entry);
+ }
+ catch (final CacheWriterException ex)
+ {
+ if (e == null)
+ {
+ e = ex;
+ }
+ }
+ }
+ if (e != null)
+ {
+ throw e;
+ }
+ }
+
+ @Override
+ public void writeAll(final Collection<Cache.Entry<? extends K, ? extends V>> entries) throws CacheWriterException
+ {
+ CacheWriterException e = null;
+ for (final CacheWriter<K, V> writer : writers)
+ {
+ try
+ {
+ writer.writeAll(entries);
+ }
+ catch (final CacheWriterException ex)
+ {
+ if (e == null)
+ {
+ e = ex;
+ }
+ }
+ }
+ if (e != null)
+ {
+ throw e;
+ }
+ }
+
+ @Override
+ public void delete(final Object key) throws CacheWriterException
+ {
+ CacheWriterException e = null;
+ for (final CacheWriter<K, V> writer : writers)
+ {
+ try
+ {
+ writer.delete(key);
+ }
+ catch (final CacheWriterException ex)
+ {
+ if (e == null)
+ {
+ e = ex;
+ }
+ }
+ }
+ if (e != null)
+ {
+ throw e;
+ }
+ }
+
+ @Override
+ public void deleteAll(final Collection<?> keys) throws CacheWriterException
+ {
+ CacheWriterException e = null;
+ for (final CacheWriter<K, V> writer : writers)
+ {
+ try
+ {
+ writer.deleteAll(keys);
+ }
+ catch (final CacheWriterException ex)
+ {
+ if (e == null)
+ {
+ e = ex;
+ }
+ }
+ }
+ if (e != null)
+ {
+ throw e;
+ }
+ }
+
+ @Override
+ public CacheWriter<K, V> create()
+ {
+ return this;
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ Closeables.close(writers);
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/commons-jcs-jcache-extras/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
index 287f237..5abd701 100644
--- a/commons-jcs-jcache-extras/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
+++ b/commons-jcs-jcache-extras/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
@@ -1 +1,18 @@
-org.apache.commons.jcs.jcache.extras.cdi.ExtraJCacheExtension
+# 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.
+
+org.apache.commons.jcs3.jcache.extras.cdi.ExtraJCacheExtension
diff --git a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/InternalCacheRule.java b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/InternalCacheRule.java
deleted file mode 100644
index f02c2f3..0000000
--- a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/InternalCacheRule.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import javax.cache.Cache;
-import javax.cache.CacheManager;
-import javax.cache.Caching;
-import javax.cache.configuration.CompleteConfiguration;
-import javax.cache.configuration.Configuration;
-import javax.cache.spi.CachingProvider;
-import java.lang.reflect.Field;
-
-// TODO: *if needed* define @CacheDeifnition instead of relying on field types
-public class InternalCacheRule implements TestRule
-{
- private final Object test;
-
- public InternalCacheRule(final Object test)
- {
- this.test = test;
- }
-
- @Override
- public Statement apply(final Statement base, final Description description)
- {
- return new Statement()
- {
- @Override
- public void evaluate() throws Throwable
- {
- final CachingProvider provider = Caching.getCachingProvider();
- final CacheManager manager = provider.getCacheManager();
- try
- {
- Field cache = null;
- CompleteConfiguration<?, ?> config = null;
- for (final Field f : test.getClass().getDeclaredFields())
- {
- if (Cache.class.isAssignableFrom(f.getType()))
- {
- f.setAccessible(true);
- cache = f;
- }
- else if (Configuration.class.isAssignableFrom(f.getType()))
- {
- f.setAccessible(true);
- config = (CompleteConfiguration<?, ?>) f.get(test);
- }
- }
- if (cache != null)
- {
- if (config == null)
- {
- throw new IllegalStateException("Define a Configuration field");
- }
- cache.set(test, manager.createCache(cache.getName(), config));
- }
- base.evaluate();
- }
- finally
- {
- manager.close();
- provider.close();
- }
- }
- };
- }
-}
diff --git a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/cdi/ExtraJCacheExtensionTest.java b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/cdi/ExtraJCacheExtensionTest.java
deleted file mode 100644
index e3ae271..0000000
--- a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/cdi/ExtraJCacheExtensionTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.cdi;
-
-import org.apache.webbeans.config.WebBeansContext;
-import org.apache.webbeans.container.BeanManagerImpl;
-import org.apache.webbeans.inject.OWBInjector;
-import org.apache.webbeans.spi.ContainerLifecycle;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import javax.cache.CacheManager;
-import javax.cache.spi.CachingProvider;
-import javax.inject.Inject;
-
-import static org.junit.Assert.assertNotNull;
-
-public class ExtraJCacheExtensionTest
-{
- private static BeanManagerImpl bm;
- private static ContainerLifecycle lifecycle;
-
- @BeforeClass
- public static void startContainer()
- {
- final WebBeansContext webBeansContext = WebBeansContext.currentInstance();
- lifecycle = webBeansContext.getService(ContainerLifecycle.class);
- lifecycle.startApplication(null);
- bm = webBeansContext.getBeanManagerImpl();
- }
-
- @AfterClass
- public static void stopContainer()
- {
- lifecycle.stopApplication(null);
- }
-
- @Before
- public void inject() throws Exception
- {
- OWBInjector.inject(bm, this, bm.createCreationalContext(null));
- }
-
- @Inject
- private BeanWithInjections bean;
-
- @Test
- public void defaultCacheManager()
- {
- assertNotNull(bean.getMgr());
- }
-
- @Test
- public void defaultCacheProvider()
- {
- assertNotNull(bean.getProvider());
- }
-
- public static class BeanWithInjections {
- @Inject
- private CacheManager mgr;
-
- @Inject
- private CachingProvider provider;
-
- public CacheManager getMgr()
- {
- return mgr;
- }
-
- public CachingProvider getProvider()
- {
- return provider;
- }
- }
-}
diff --git a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/loader/CacheLoaderAdapterTest.java b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/loader/CacheLoaderAdapterTest.java
deleted file mode 100644
index 3c6767b..0000000
--- a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/loader/CacheLoaderAdapterTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.loader;
-
-import org.apache.commons.jcs.jcache.extras.InternalCacheRule;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.cache.Cache;
-import javax.cache.configuration.Configuration;
-import javax.cache.configuration.MutableConfiguration;
-import javax.cache.integration.CacheLoaderException;
-import java.util.HashSet;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import static java.util.Arrays.asList;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-
-public class CacheLoaderAdapterTest
-{
- @Rule
- public final InternalCacheRule rule = new InternalCacheRule(this);
-
- private final AtomicInteger count = new AtomicInteger(0);
- private final Configuration<?, ?> config = new MutableConfiguration<String, String>().setStoreByValue(false).setReadThrough(true).setCacheLoaderFactory(new CacheLoaderAdapter<String, String>()
- {
- @Override
- public String load(final String key) throws CacheLoaderException
- {
- count.incrementAndGet();
- return key;
- }
- });
- private Cache<String, String> cache;
-
- @Test
- public void checkLoadAll()
- {
- assertFalse(cache.iterator().hasNext());
- assertEquals("foo", cache.get("foo"));
-
- count.decrementAndGet();
- cache.loadAll(new HashSet<String>(asList("a", "b")), true, null);
- int retries = 100;
- while (retries-- > 0 && count.get() != 2)
- {
- try
- {
- Thread.sleep(20);
- }
- catch (final InterruptedException e)
- {
- Thread.interrupted();
- }
- }
- assertEquals(2, count.get());
- assertEquals("a", cache.get("a"));
- assertEquals("b", cache.get("b"));
- assertEquals(2, count.get());
- }
-}
diff --git a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/loader/CompositeCacheLoaderTest.java b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/loader/CompositeCacheLoaderTest.java
deleted file mode 100644
index 08d1d7a..0000000
--- a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/loader/CompositeCacheLoaderTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.loader;
-
-import org.apache.commons.jcs.jcache.extras.InternalCacheRule;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.cache.Cache;
-import javax.cache.configuration.Configuration;
-import javax.cache.configuration.MutableConfiguration;
-import javax.cache.integration.CacheLoaderException;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import static org.junit.Assert.assertEquals;
-
-public class CompositeCacheLoaderTest
-{
- @Rule
- public final InternalCacheRule rule = new InternalCacheRule(this);
-
- private final AtomicInteger count = new AtomicInteger(0);
-
- private final CacheLoaderAdapter<String, String> loader1 = new CacheLoaderAdapter<String, String>()
- {
- @Override
- public String load(String key) throws CacheLoaderException
- {
- count.incrementAndGet();
- return null;
- }
- };
- private final CacheLoaderAdapter<String, String> loader2 = new CacheLoaderAdapter<String, String>()
- {
- @Override
- public String load(String key) throws CacheLoaderException
- {
- count.incrementAndGet();
- return null;
- }
- };
- private final Configuration<?, ?> config = new MutableConfiguration<String, String>()
- .setStoreByValue(false)
- .setReadThrough(true)
- .setCacheLoaderFactory(new CompositeCacheLoader<String, String>(loader1, loader2));
- private Cache<String, String> cache;
-
- @Test
- public void checkComposite()
- {
- cache.get("foo");
- assertEquals(2, count.get());
- }
-}
diff --git a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/web/JCacheFilterTest.java b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/web/JCacheFilterTest.java
deleted file mode 100644
index 3c514d1..0000000
--- a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/web/JCacheFilterTest.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.web;
-
-import static org.junit.Assert.assertEquals;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URL;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.catalina.Context;
-import org.apache.catalina.LifecycleException;
-import org.apache.catalina.LifecycleState;
-import org.apache.catalina.core.StandardContext;
-import org.apache.catalina.deploy.FilterDef;
-import org.apache.catalina.deploy.FilterMap;
-import org.apache.catalina.startup.Tomcat;
-import org.apache.commons.io.IOUtils;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-public class JCacheFilterTest
-{
- private static File docBase;
-
- @BeforeClass
- public static void createEmptyDir() {
- docBase = new File("target/missing/");
- docBase.mkdirs();
- docBase.deleteOnExit();
- }
-
- @Test
- public void testFilterNoOutput() throws Exception
- {
- Empty.COUNTER.set(0);
- final Tomcat tomcat = new Tomcat();
- tomcat.setHostname("localhost");
- tomcat.setPort(0);
- try {
- tomcat.getEngine();
- tomcat.start();
- final Context ctx = tomcat.addWebapp("/sample", docBase.getAbsolutePath());
- Tomcat.addServlet(ctx, "empty", Empty.class.getName());
- ctx.addServletMapping("/", "empty");
- addJcsFilter(ctx);
- StandardContext.class.cast(ctx).filterStart();
-
- final URL url = new URL("http://localhost:" + tomcat.getConnector().getLocalPort() + "/sample/");
-
- assertEquals("", IOUtils.toString(url.openStream()));
- assertEquals(1, Empty.COUNTER.get());
-
- assertEquals("", IOUtils.toString(url.openStream()));
- assertEquals(1, Empty.COUNTER.get());
- } finally {
- stop(tomcat);
- }
- }
-
- @Test
- public void testFilter() throws Exception
- {
- Hello.COUNTER.set(0);
- final Tomcat tomcat = new Tomcat();
- tomcat.setPort(0);
- try {
- tomcat.getEngine();
- tomcat.start();
- final Context ctx = tomcat.addContext("/sample", docBase.getAbsolutePath());
- Tomcat.addServlet(ctx, "hello", Hello.class.getName());
- ctx.addServletMapping("/", "hello");
- addJcsFilter(ctx);
- StandardContext.class.cast(ctx).filterStart();
-
- final URL url = new URL("http://localhost:" + tomcat.getConnector().getLocalPort() + "/sample/");
- assertEquals("hello", IOUtils.toString(url.openStream()));
- assertEquals(1, Hello.COUNTER.get());
-
- assertEquals("hello", IOUtils.toString(url.openStream()));
- assertEquals(1, Hello.COUNTER.get());
- } finally {
- stop(tomcat);
- }
- }
-
- private void stop(final Tomcat tomcat) throws LifecycleException {
- if (LifecycleState.STARTED.equals(tomcat.getServer().getState())) {
- tomcat.stop();
- tomcat.destroy();
- }
- }
-
- private void addJcsFilter(final Context ctx) {
- final FilterDef filterDef = new FilterDef();
- filterDef.setFilterName("jcs");
- filterDef.setFilterClass(JCacheFilter.class.getName());
- ctx.addFilterDef(filterDef);
-
- final FilterMap filterMap = new FilterMap();
- filterMap.setFilterName(filterDef.getFilterName());
- filterMap.addURLPattern("/*");
- ctx.addFilterMap(filterMap);
- }
-
- public static class Hello extends HttpServlet {
- public static final AtomicInteger COUNTER = new AtomicInteger();
-
- @Override
- protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
- resp.getWriter().write("hello");
- COUNTER.incrementAndGet();
- }
- }
-
- public static class Empty extends HttpServlet {
- public static final AtomicInteger COUNTER = new AtomicInteger();
-
- @Override
- protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
- resp.getWriter().write("");
- COUNTER.incrementAndGet();
- }
- }
-}
diff --git a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/writer/CacheWriterAdapterTest.java b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/writer/CacheWriterAdapterTest.java
deleted file mode 100644
index 190edc1..0000000
--- a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/writer/CacheWriterAdapterTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.writer;
-
-import org.apache.commons.jcs.jcache.extras.InternalCacheRule;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.cache.Cache;
-import javax.cache.configuration.Configuration;
-import javax.cache.configuration.MutableConfiguration;
-import javax.cache.integration.CacheWriterException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-
-import static java.util.Arrays.asList;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class CacheWriterAdapterTest
-{
- @Rule
- public final InternalCacheRule rule = new InternalCacheRule(this);
-
- private final Map<String, String> copy = new HashMap<String, String>();
- private final Configuration<?, ?> config = new MutableConfiguration<String, String>()
- .setStoreByValue(false).setReadThrough(true)
- .setCacheWriterFactory(new CacheWriterAdapter<String, String>()
- {
- @Override
- public void write(final Cache.Entry<? extends String, ? extends String> entry) throws CacheWriterException
- {
- copy.put(entry.getKey(), entry.getValue());
- }
-
- @Override
- public void delete(final Object key) throws CacheWriterException
- {
- copy.remove(key);
- }
- });
- private Cache<String, String> cache;
-
- @Test
- public void checkWriteAllAndDeleteAll()
- {
- assertTrue(copy.isEmpty());
- assertFalse(cache.iterator().hasNext());
- cache.put("foo", "bar");
- assertEquals(1, copy.size());
- cache.remove("foo");
- assertTrue(copy.isEmpty());
-
- cache.putAll(new HashMap<String, String>() {{
- put("a", "b");
- put("b", "c");
- }});
- assertEquals(2, copy.size());
- cache.removeAll(new HashSet<String>(asList("a", "b")));
- assertTrue(copy.isEmpty());
- }
-}
diff --git a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/writer/CompositeCacheWriterTest.java b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/writer/CompositeCacheWriterTest.java
deleted file mode 100644
index 1ba9612..0000000
--- a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs/jcache/extras/writer/CompositeCacheWriterTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.extras.writer;
-
-import org.apache.commons.jcs.jcache.extras.InternalCacheRule;
-import org.junit.Rule;
-import org.junit.Test;
-
-import javax.cache.Cache;
-import javax.cache.configuration.Configuration;
-import javax.cache.configuration.MutableConfiguration;
-import javax.cache.integration.CacheWriterException;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-public class CompositeCacheWriterTest
-{
- @Rule
- public final InternalCacheRule rule = new InternalCacheRule(this);
-
-
- private final Map<String, String> copy1 = new HashMap<String, String>();
- private final Map<String, String> copy2 = new HashMap<String, String>();
-
- private final CacheWriterAdapter<String, String> writer1 = new CacheWriterAdapter<String, String>()
- {
- @Override
- public void write(final Cache.Entry<? extends String, ? extends String> entry) throws CacheWriterException
- {
- copy1.put(entry.getKey(), entry.getValue());
- }
-
- @Override
- public void delete(final Object key) throws CacheWriterException
- {
- copy1.remove(key);
- }
- };
- private final CacheWriterAdapter<String, String> writer2 = new CacheWriterAdapter<String, String>()
- {
- @Override
- public void write(final Cache.Entry<? extends String, ? extends String> entry) throws CacheWriterException
- {
- copy2.put(entry.getKey(), entry.getValue());
- }
-
- @Override
- public void delete(final Object key) throws CacheWriterException
- {
- copy2.remove(key);
- }
- };
- private final Configuration<?, ?> config = new MutableConfiguration<String, String>()
- .setStoreByValue(false)
- .setWriteThrough(true)
- .setCacheWriterFactory(new CompositeCacheWriter<String, String>(writer1, writer2));
- private Cache<String, String> cache;
-
- @Test
- public void checkComposite()
- {
- cache.put("a", "b");
- assertEquals("b", copy1.get("a"));
- assertEquals("b", copy2.get("a"));
- assertEquals(1, copy1.size());
- assertEquals(1, copy2.size());
- cache.remove("a");
- assertTrue(copy1.isEmpty());
- assertTrue(copy2.isEmpty());
- }
-}
diff --git a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/InternalCacheRule.java b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/InternalCacheRule.java
new file mode 100644
index 0000000..cc34f97
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/InternalCacheRule.java
@@ -0,0 +1,88 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+import javax.cache.configuration.CompleteConfiguration;
+import javax.cache.configuration.Configuration;
+import javax.cache.spi.CachingProvider;
+import java.lang.reflect.Field;
+
+// TODO: *if needed* define @CacheDeifnition instead of relying on field types
+public class InternalCacheRule implements TestRule
+{
+ private final Object test;
+
+ public InternalCacheRule(final Object test)
+ {
+ this.test = test;
+ }
+
+ @Override
+ public Statement apply(final Statement base, final Description description)
+ {
+ return new Statement()
+ {
+ @Override
+ public void evaluate() throws Throwable
+ {
+ final CachingProvider provider = Caching.getCachingProvider();
+ final CacheManager manager = provider.getCacheManager();
+ try
+ {
+ Field cache = null;
+ CompleteConfiguration<?, ?> config = null;
+ for (final Field f : test.getClass().getDeclaredFields())
+ {
+ if (Cache.class.isAssignableFrom(f.getType()))
+ {
+ f.setAccessible(true);
+ cache = f;
+ }
+ else if (Configuration.class.isAssignableFrom(f.getType()))
+ {
+ f.setAccessible(true);
+ config = (CompleteConfiguration<?, ?>) f.get(test);
+ }
+ }
+ if (cache != null)
+ {
+ if (config == null)
+ {
+ throw new IllegalStateException("Define a Configuration field");
+ }
+ cache.set(test, manager.createCache(cache.getName(), config));
+ }
+ base.evaluate();
+ }
+ finally
+ {
+ manager.close();
+ provider.close();
+ }
+ }
+ };
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/cdi/ExtraJCacheExtensionTest.java b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/cdi/ExtraJCacheExtensionTest.java
new file mode 100644
index 0000000..08ac990
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/cdi/ExtraJCacheExtensionTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.cdi;
+
+import org.apache.webbeans.config.WebBeansContext;
+import org.apache.webbeans.container.BeanManagerImpl;
+import org.apache.webbeans.inject.OWBInjector;
+import org.apache.webbeans.spi.ContainerLifecycle;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.cache.CacheManager;
+import javax.cache.spi.CachingProvider;
+import javax.inject.Inject;
+
+import static org.junit.Assert.assertNotNull;
+
+public class ExtraJCacheExtensionTest
+{
+ private static BeanManagerImpl bm;
+ private static ContainerLifecycle lifecycle;
+
+ @BeforeClass
+ public static void startContainer()
+ {
+ final WebBeansContext webBeansContext = WebBeansContext.currentInstance();
+ lifecycle = webBeansContext.getService(ContainerLifecycle.class);
+ lifecycle.startApplication(null);
+ bm = webBeansContext.getBeanManagerImpl();
+ }
+
+ @AfterClass
+ public static void stopContainer()
+ {
+ lifecycle.stopApplication(null);
+ }
+
+ @Before
+ public void inject() throws Exception
+ {
+ OWBInjector.inject(bm, this, bm.createCreationalContext(null));
+ }
+
+ @Inject
+ private BeanWithInjections bean;
+
+ @Test
+ public void defaultCacheManager()
+ {
+ assertNotNull(bean.getMgr());
+ }
+
+ @Test
+ public void defaultCacheProvider()
+ {
+ assertNotNull(bean.getProvider());
+ }
+
+ public static class BeanWithInjections {
+ @Inject
+ private CacheManager mgr;
+
+ @Inject
+ private CachingProvider provider;
+
+ public CacheManager getMgr()
+ {
+ return mgr;
+ }
+
+ public CachingProvider getProvider()
+ {
+ return provider;
+ }
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/loader/CacheLoaderAdapterTest.java b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/loader/CacheLoaderAdapterTest.java
new file mode 100644
index 0000000..8494462
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/loader/CacheLoaderAdapterTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.loader;
+
+import org.apache.commons.jcs3.jcache.extras.InternalCacheRule;
+import org.apache.commons.jcs3.jcache.extras.loader.CacheLoaderAdapter;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.cache.Cache;
+import javax.cache.configuration.Configuration;
+import javax.cache.configuration.MutableConfiguration;
+import javax.cache.integration.CacheLoaderException;
+import java.util.HashSet;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+public class CacheLoaderAdapterTest
+{
+ @Rule
+ public final InternalCacheRule rule = new InternalCacheRule(this);
+
+ private final AtomicInteger count = new AtomicInteger(0);
+ private final Configuration<?, ?> config = new MutableConfiguration<String, String>().setStoreByValue(false).setReadThrough(true).setCacheLoaderFactory(new CacheLoaderAdapter<String, String>()
+ {
+ @Override
+ public String load(final String key) throws CacheLoaderException
+ {
+ count.incrementAndGet();
+ return key;
+ }
+ });
+ private Cache<String, String> cache;
+
+ @Test
+ public void checkLoadAll()
+ {
+ assertFalse(cache.iterator().hasNext());
+ assertEquals("foo", cache.get("foo"));
+
+ count.decrementAndGet();
+ cache.loadAll(new HashSet<String>(asList("a", "b")), true, null);
+ int retries = 100;
+ while (retries-- > 0 && count.get() != 2)
+ {
+ try
+ {
+ Thread.sleep(20);
+ }
+ catch (final InterruptedException e)
+ {
+ Thread.interrupted();
+ }
+ }
+ assertEquals(2, count.get());
+ assertEquals("a", cache.get("a"));
+ assertEquals("b", cache.get("b"));
+ assertEquals(2, count.get());
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/loader/CompositeCacheLoaderTest.java b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/loader/CompositeCacheLoaderTest.java
new file mode 100644
index 0000000..872d54c
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/loader/CompositeCacheLoaderTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.loader;
+
+import org.apache.commons.jcs3.jcache.extras.InternalCacheRule;
+import org.apache.commons.jcs3.jcache.extras.loader.CacheLoaderAdapter;
+import org.apache.commons.jcs3.jcache.extras.loader.CompositeCacheLoader;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.cache.Cache;
+import javax.cache.configuration.Configuration;
+import javax.cache.configuration.MutableConfiguration;
+import javax.cache.integration.CacheLoaderException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.junit.Assert.assertEquals;
+
+public class CompositeCacheLoaderTest
+{
+ @Rule
+ public final InternalCacheRule rule = new InternalCacheRule(this);
+
+ private final AtomicInteger count = new AtomicInteger(0);
+
+ private final CacheLoaderAdapter<String, String> loader1 = new CacheLoaderAdapter<String, String>()
+ {
+ @Override
+ public String load(String key) throws CacheLoaderException
+ {
+ count.incrementAndGet();
+ return null;
+ }
+ };
+ private final CacheLoaderAdapter<String, String> loader2 = new CacheLoaderAdapter<String, String>()
+ {
+ @Override
+ public String load(String key) throws CacheLoaderException
+ {
+ count.incrementAndGet();
+ return null;
+ }
+ };
+ private final Configuration<?, ?> config = new MutableConfiguration<String, String>()
+ .setStoreByValue(false)
+ .setReadThrough(true)
+ .setCacheLoaderFactory(new CompositeCacheLoader<String, String>(loader1, loader2));
+ private Cache<String, String> cache;
+
+ @Test
+ public void checkComposite()
+ {
+ cache.get("foo");
+ assertEquals(2, count.get());
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/web/JCacheFilterTest.java b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/web/JCacheFilterTest.java
new file mode 100644
index 0000000..9e1e5b8
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/web/JCacheFilterTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.web;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleState;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.deploy.FilterDef;
+import org.apache.catalina.deploy.FilterMap;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.jcs3.jcache.extras.web.JCacheFilter;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class JCacheFilterTest
+{
+ private static File docBase;
+
+ @BeforeClass
+ public static void createEmptyDir() {
+ docBase = new File("target/missing/");
+ docBase.mkdirs();
+ docBase.deleteOnExit();
+ }
+
+ @Test
+ public void testFilterNoOutput() throws Exception
+ {
+ Empty.COUNTER.set(0);
+ final Tomcat tomcat = new Tomcat();
+ tomcat.setHostname("localhost");
+ tomcat.setPort(0);
+ try {
+ tomcat.getEngine();
+ tomcat.start();
+ final Context ctx = tomcat.addWebapp("/sample", docBase.getAbsolutePath());
+ Tomcat.addServlet(ctx, "empty", Empty.class.getName());
+ ctx.addServletMapping("/", "empty");
+ addJcsFilter(ctx);
+ StandardContext.class.cast(ctx).filterStart();
+
+ final URL url = new URL("http://localhost:" + tomcat.getConnector().getLocalPort() + "/sample/");
+
+ assertEquals("", IOUtils.toString(url.openStream()));
+ assertEquals(1, Empty.COUNTER.get());
+
+ assertEquals("", IOUtils.toString(url.openStream()));
+ assertEquals(1, Empty.COUNTER.get());
+ } finally {
+ stop(tomcat);
+ }
+ }
+
+ @Test
+ public void testFilter() throws Exception
+ {
+ Hello.COUNTER.set(0);
+ final Tomcat tomcat = new Tomcat();
+ tomcat.setPort(0);
+ try {
+ tomcat.getEngine();
+ tomcat.start();
+ final Context ctx = tomcat.addContext("/sample", docBase.getAbsolutePath());
+ Tomcat.addServlet(ctx, "hello", Hello.class.getName());
+ ctx.addServletMapping("/", "hello");
+ addJcsFilter(ctx);
+ StandardContext.class.cast(ctx).filterStart();
+
+ final URL url = new URL("http://localhost:" + tomcat.getConnector().getLocalPort() + "/sample/");
+ assertEquals("hello", IOUtils.toString(url.openStream()));
+ assertEquals(1, Hello.COUNTER.get());
+
+ assertEquals("hello", IOUtils.toString(url.openStream()));
+ assertEquals(1, Hello.COUNTER.get());
+ } finally {
+ stop(tomcat);
+ }
+ }
+
+ private void stop(final Tomcat tomcat) throws LifecycleException {
+ if (LifecycleState.STARTED.equals(tomcat.getServer().getState())) {
+ tomcat.stop();
+ tomcat.destroy();
+ }
+ }
+
+ private void addJcsFilter(final Context ctx) {
+ final FilterDef filterDef = new FilterDef();
+ filterDef.setFilterName("jcs");
+ filterDef.setFilterClass(JCacheFilter.class.getName());
+ ctx.addFilterDef(filterDef);
+
+ final FilterMap filterMap = new FilterMap();
+ filterMap.setFilterName(filterDef.getFilterName());
+ filterMap.addURLPattern("/*");
+ ctx.addFilterMap(filterMap);
+ }
+
+ public static class Hello extends HttpServlet {
+ public static final AtomicInteger COUNTER = new AtomicInteger();
+
+ @Override
+ protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
+ resp.getWriter().write("hello");
+ COUNTER.incrementAndGet();
+ }
+ }
+
+ public static class Empty extends HttpServlet {
+ public static final AtomicInteger COUNTER = new AtomicInteger();
+
+ @Override
+ protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
+ resp.getWriter().write("");
+ COUNTER.incrementAndGet();
+ }
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/writer/CacheWriterAdapterTest.java b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/writer/CacheWriterAdapterTest.java
new file mode 100644
index 0000000..5300832
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/writer/CacheWriterAdapterTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.writer;
+
+import org.apache.commons.jcs3.jcache.extras.InternalCacheRule;
+import org.apache.commons.jcs3.jcache.extras.writer.CacheWriterAdapter;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.cache.Cache;
+import javax.cache.configuration.Configuration;
+import javax.cache.configuration.MutableConfiguration;
+import javax.cache.integration.CacheWriterException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class CacheWriterAdapterTest
+{
+ @Rule
+ public final InternalCacheRule rule = new InternalCacheRule(this);
+
+ private final Map<String, String> copy = new HashMap<String, String>();
+ private final Configuration<?, ?> config = new MutableConfiguration<String, String>()
+ .setStoreByValue(false).setReadThrough(true)
+ .setCacheWriterFactory(new CacheWriterAdapter<String, String>()
+ {
+ @Override
+ public void write(final Cache.Entry<? extends String, ? extends String> entry) throws CacheWriterException
+ {
+ copy.put(entry.getKey(), entry.getValue());
+ }
+
+ @Override
+ public void delete(final Object key) throws CacheWriterException
+ {
+ copy.remove(key);
+ }
+ });
+ private Cache<String, String> cache;
+
+ @Test
+ public void checkWriteAllAndDeleteAll()
+ {
+ assertTrue(copy.isEmpty());
+ assertFalse(cache.iterator().hasNext());
+ cache.put("foo", "bar");
+ assertEquals(1, copy.size());
+ cache.remove("foo");
+ assertTrue(copy.isEmpty());
+
+ cache.putAll(new HashMap<String, String>() {{
+ put("a", "b");
+ put("b", "c");
+ }});
+ assertEquals(2, copy.size());
+ cache.removeAll(new HashSet<String>(asList("a", "b")));
+ assertTrue(copy.isEmpty());
+ }
+}
diff --git a/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/writer/CompositeCacheWriterTest.java b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/writer/CompositeCacheWriterTest.java
new file mode 100644
index 0000000..a9b1609
--- /dev/null
+++ b/commons-jcs-jcache-extras/src/test/java/org/apache/commons/jcs3/jcache/extras/writer/CompositeCacheWriterTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.apache.commons.jcs3.jcache.extras.writer;
+
+import org.apache.commons.jcs3.jcache.extras.InternalCacheRule;
+import org.apache.commons.jcs3.jcache.extras.writer.CacheWriterAdapter;
+import org.apache.commons.jcs3.jcache.extras.writer.CompositeCacheWriter;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.cache.Cache;
+import javax.cache.configuration.Configuration;
+import javax.cache.configuration.MutableConfiguration;
+import javax.cache.integration.CacheWriterException;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class CompositeCacheWriterTest
+{
+ @Rule
+ public final InternalCacheRule rule = new InternalCacheRule(this);
+
+
+ private final Map<String, String> copy1 = new HashMap<String, String>();
+ private final Map<String, String> copy2 = new HashMap<String, String>();
+
+ private final CacheWriterAdapter<String, String> writer1 = new CacheWriterAdapter<String, String>()
+ {
+ @Override
+ public void write(final Cache.Entry<? extends String, ? extends String> entry) throws CacheWriterException
+ {
+ copy1.put(entry.getKey(), entry.getValue());
+ }
+
+ @Override
+ public void delete(final Object key) throws CacheWriterException
+ {
+ copy1.remove(key);
+ }
+ };
+ private final CacheWriterAdapter<String, String> writer2 = new CacheWriterAdapter<String, String>()
+ {
+ @Override
+ public void write(final Cache.Entry<? extends String, ? extends String> entry) throws CacheWriterException
+ {
+ copy2.put(entry.getKey(), entry.getValue());
+ }
+
+ @Override
+ public void delete(final Object key) throws CacheWriterException
+ {
+ copy2.remove(key);
+ }
+ };
+ private final Configuration<?, ?> config = new MutableConfiguration<String, String>()
+ .setStoreByValue(false)
+ .setWriteThrough(true)
+ .setCacheWriterFactory(new CompositeCacheWriter<String, String>(writer1, writer2));
+ private Cache<String, String> cache;
+
+ @Test
+ public void checkComposite()
+ {
+ cache.put("a", "b");
+ assertEquals("b", copy1.get("a"));
+ assertEquals("b", copy2.get("a"));
+ assertEquals(1, copy1.size());
+ assertEquals(1, copy2.size());
+ cache.remove("a");
+ assertTrue(copy1.isEmpty());
+ assertTrue(copy2.isEmpty());
+ }
+}
diff --git a/commons-jcs-jcache-openjpa/pom.xml b/commons-jcs-jcache-openjpa/pom.xml
index 2109498..46570df 100644
--- a/commons-jcs-jcache-openjpa/pom.xml
+++ b/commons-jcs-jcache-openjpa/pom.xml
@@ -19,13 +19,13 @@
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
- <artifactId>commons-jcs</artifactId>
+ <artifactId>commons-jcs3</artifactId>
<groupId>org.apache.commons</groupId>
<version>3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
- <artifactId>commons-jcs-jcache-openjpa</artifactId>
+ <artifactId>commons-jcs3-jcache-openjpa</artifactId>
<version>3.0-SNAPSHOT</version>
<name>Apache Commons JCS :: JCache OpenJPA</name>
@@ -66,7 +66,7 @@
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
- <artifactId>commons-jcs-jcache</artifactId>
+ <artifactId>commons-jcs3-jcache</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
diff --git a/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs/jcache/openjpa/OpenJPAJCacheDataCache.java b/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs/jcache/openjpa/OpenJPAJCacheDataCache.java
deleted file mode 100644
index 5c125c8..0000000
--- a/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs/jcache/openjpa/OpenJPAJCacheDataCache.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.openjpa;
-
-import org.apache.openjpa.datacache.AbstractDataCache;
-import org.apache.openjpa.datacache.DataCacheManager;
-import org.apache.openjpa.datacache.DataCachePCData;
-import org.apache.openjpa.util.OpenJPAId;
-
-import javax.cache.Cache;
-import javax.cache.CacheManager;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-public class OpenJPAJCacheDataCache extends AbstractDataCache
-{
- private static final String OPENJPA_PREFIX = "openjpa.datacache.";
-
- private final Lock lock = new ReentrantLock();
- private OpenJPAJCacheDataCacheManager manager;
-
- @Override
- public void initialize(final DataCacheManager manager)
- {
- super.initialize(manager);
- this.manager = OpenJPAJCacheDataCacheManager.class.cast(manager);
- }
-
- @Override
- protected DataCachePCData getInternal(final Object oid)
- {
- Object result = null;
- if (OpenJPAId.class.isInstance(oid))
- {
- final Class<?> cls = OpenJPAId.class.cast(oid).getType();
- Cache<Object, Object> cache = manager.getOrCreateCache(OPENJPA_PREFIX, cls.getName());
- if (cache == null)
- {
- return null;
- }
- else
- {
- result = cache.get(oid);
- }
- }
- else
- {
- final CacheManager cacheManager = manager.getCacheManager();
- for (final String cacheName : cacheManager.getCacheNames())
- {
- if (!cacheName.startsWith(OPENJPA_PREFIX))
- {
- continue;
- }
-
- result = cacheManager.getCache(cacheName).get(oid);
- if (result != null)
- {
- break;
- }
- }
- }
- if (result == null)
- {
- return null;
- }
- return DataCachePCData.class.cast(result);
- }
-
- @Override
- protected DataCachePCData putInternal(final Object oid, final DataCachePCData pc)
- {
- manager.getOrCreateCache(OPENJPA_PREFIX, pc.getType().getName()).put(oid, pc);
- return pc;
- }
-
- @Override
- protected DataCachePCData removeInternal(final Object oid)
- {
- if (OpenJPAId.class.isInstance(oid))
- {
- final Object remove = manager.getOrCreateCache(OPENJPA_PREFIX, OpenJPAId.class.cast(oid).getType().getName()).getAndRemove(oid);
- if (remove == null)
- {
- return null;
- }
- return DataCachePCData.class.cast(remove);
- }
- return null;
- }
-
- @Override
- protected void removeAllInternal(final Class<?> cls, final boolean subclasses)
- {
- final String name;
- if (subclasses)
- {
- name = cls.getSuperclass().getName();
- }
- else
- {
- name = cls.getName();
- }
- manager.getOrCreateCache(OPENJPA_PREFIX, name).removeAll();
- }
-
- @Override
- protected void clearInternal()
- {
- final CacheManager cacheManager = manager.getCacheManager();
- for (final String cacheName : cacheManager.getCacheNames())
- {
- if (!cacheName.startsWith(OPENJPA_PREFIX))
- {
- continue;
- }
- cacheManager.getCache(cacheName).clear();
- }
- }
-
- @Override
- protected boolean pinInternal(final Object oid)
- {
- throw new UnsupportedOperationException();
- }
-
- @Override
- protected boolean unpinInternal(final Object oid)
- {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void writeLock()
- {
- lock.lock();
- }
-
- @Override
- public void writeUnlock()
- {
- lock.unlock();
- }
-}
diff --git a/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs/jcache/openjpa/OpenJPAJCacheDataCacheManager.java b/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs/jcache/openjpa/OpenJPAJCacheDataCacheManager.java
deleted file mode 100644
index cc9fc85..0000000
--- a/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs/jcache/openjpa/OpenJPAJCacheDataCacheManager.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.openjpa;
-
-import org.apache.openjpa.conf.OpenJPAConfiguration;
-import org.apache.openjpa.datacache.DataCacheManagerImpl;
-import org.apache.openjpa.lib.conf.ObjectValue;
-
-import javax.cache.Cache;
-import javax.cache.CacheManager;
-import javax.cache.Caching;
-import javax.cache.configuration.FactoryBuilder;
-import javax.cache.configuration.MutableConfiguration;
-import javax.cache.expiry.CreatedExpiryPolicy;
-import javax.cache.expiry.Duration;
-import javax.cache.expiry.ExpiryPolicy;
-import javax.cache.integration.CacheLoader;
-import javax.cache.integration.CacheWriter;
-import javax.cache.spi.CachingProvider;
-import java.net.URI;
-import java.util.Map;
-import java.util.Properties;
-
-public class OpenJPAJCacheDataCacheManager extends DataCacheManagerImpl
-{
- private CachingProvider provider;
- private CacheManager cacheManager;
-
- @Override
- public void initialize(final OpenJPAConfiguration conf, final ObjectValue dataCache, final ObjectValue queryCache)
- {
- super.initialize(conf, dataCache, queryCache);
- provider = Caching.getCachingProvider();
-
- final Properties properties = new Properties();
- final Map<String, Object> props = conf.toProperties(false);
- if (props != null)
- {
- for (final Map.Entry<?, ?> entry : props.entrySet())
- {
- if (entry.getKey() != null && entry.getValue() != null)
- {
- properties.setProperty(entry.getKey().toString(), entry.getValue().toString());
- }
- }
- }
-
- final String uri = properties.getProperty("jcache.uri", provider.getDefaultURI().toString());
- cacheManager = provider.getCacheManager(URI.create(uri), provider.getDefaultClassLoader(), properties);
- }
-
- @Override
- public void close()
- {
- super.close();
- if (!cacheManager.isClosed())
- {
- cacheManager.close();
- }
- provider.close();
- }
-
- Cache<Object, Object> getOrCreateCache(final String prefix, final String entity)
- {
- final String internalName = prefix + entity;
- Cache<Object, Object> cache = cacheManager.getCache(internalName);
- if (cache == null)
- {
- final Properties properties = cacheManager.getProperties();
- final MutableConfiguration<Object, Object> configuration = new MutableConfiguration<Object, Object>()
- .setStoreByValue("true".equalsIgnoreCase(properties.getProperty("jcache.store-by-value", "false")));
-
- configuration.setReadThrough("true".equals(properties.getProperty("jcache.read-through", "false")));
- configuration.setWriteThrough("true".equals(properties.getProperty("jcache.write-through", "false")));
- if (configuration.isReadThrough())
- {
- configuration.setCacheLoaderFactory(new FactoryBuilder.ClassFactory<CacheLoader<Object, Object>>(properties.getProperty("jcache.cache-loader-factory")));
- }
- if (configuration.isWriteThrough())
- {
- configuration.setCacheWriterFactory(new FactoryBuilder.ClassFactory<CacheWriter<Object, Object>>(properties.getProperty("jcache.cache-writer-factory")));
- }
- final String expirtyPolicy = properties.getProperty("jcache.expiry-policy-factory");
- if (expirtyPolicy != null)
- {
- configuration.setExpiryPolicyFactory(new FactoryBuilder.ClassFactory<ExpiryPolicy>(expirtyPolicy));
- }
- else
- {
- configuration.setExpiryPolicyFactory(new FactoryBuilder.SingletonFactory<ExpiryPolicy>(new CreatedExpiryPolicy(Duration.FIVE_MINUTES)));
- }
- configuration.setManagementEnabled("true".equals(properties.getProperty("jcache.management-enabled", "false")));
- configuration.setStatisticsEnabled("true".equals(properties.getProperty("jcache.statistics-enabled", "false")));
-
- cache = cacheManager.createCache(internalName, configuration);
- }
- return cache;
- }
-
- CacheManager getCacheManager()
- {
- return cacheManager;
- }
-}
diff --git a/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs/jcache/openjpa/OpenJPAJCacheDerivation.java b/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs/jcache/openjpa/OpenJPAJCacheDerivation.java
deleted file mode 100644
index 4990bb0..0000000
--- a/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs/jcache/openjpa/OpenJPAJCacheDerivation.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.openjpa;
-
-import org.apache.openjpa.conf.OpenJPAConfiguration;
-import org.apache.openjpa.conf.OpenJPAConfigurationImpl;
-import org.apache.openjpa.event.SingleJVMRemoteCommitProvider;
-import org.apache.openjpa.lib.conf.AbstractProductDerivation;
-import org.apache.openjpa.lib.conf.Configuration;
-import org.apache.openjpa.lib.conf.ConfigurationProvider;
-import org.apache.openjpa.lib.conf.Configurations;
-
-import java.util.Map;
-
-public class OpenJPAJCacheDerivation extends AbstractProductDerivation
-{
- private static final String JCACHE_NAME = "jcache";
-
- @Override
- public boolean beforeConfigurationLoad(final Configuration conf)
- {
- if (OpenJPAConfiguration.class.isInstance(conf)) {
- final OpenJPAConfigurationImpl oconf = OpenJPAConfigurationImpl.class.cast(conf);
- oconf.dataCacheManagerPlugin.setAlias(JCACHE_NAME, OpenJPAJCacheDataCacheManager.class.getName());
- oconf.dataCachePlugin.setAlias(JCACHE_NAME, OpenJPAJCacheDataCache.class.getName());
- oconf.queryCachePlugin.setAlias(JCACHE_NAME, OpenJPAJCacheQueryCache.class.getName());
- }
- return super.beforeConfigurationLoad(conf);
- }
-
- @Override
- public boolean beforeConfigurationConstruct(final ConfigurationProvider cp)
- {
- final Map<?, ?> props = cp.getProperties();
- final Object dcm = Configurations.getProperty("DataCacheManager", props);
- if (dcm != null && JCACHE_NAME.equals(dcm))
- {
- if (Configurations.getProperty("DataCache", props) == null)
- {
- cp.addProperty("openjpa.DataCache", JCACHE_NAME);
- }
- if (Configurations.getProperty("QueryCache", props) == null)
- {
- cp.addProperty("openjpa.QueryCache", JCACHE_NAME);
- }
- if (Configurations.getProperty("RemoteCommitProvider", props) == null)
- {
- cp.addProperty("openjpa.RemoteCommitProvider", SingleJVMRemoteCommitProvider.class.getName());
- }
- }
- return super.beforeConfigurationConstruct(cp);
- }
-
- @Override
- public int getType()
- {
- return TYPE_FEATURE;
- }
-}
diff --git a/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs/jcache/openjpa/OpenJPAJCacheQueryCache.java b/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs/jcache/openjpa/OpenJPAJCacheQueryCache.java
deleted file mode 100644
index 7ac021a..0000000
--- a/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs/jcache/openjpa/OpenJPAJCacheQueryCache.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.openjpa;
-
-import org.apache.openjpa.datacache.AbstractQueryCache;
-import org.apache.openjpa.datacache.DataCacheManager;
-import org.apache.openjpa.datacache.QueryKey;
-import org.apache.openjpa.datacache.QueryResult;
-
-import javax.cache.Cache;
-import javax.cache.CacheManager;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-public class OpenJPAJCacheQueryCache extends AbstractQueryCache
-{
- private static final String OPENJPA_PREFIX = "openjpa.querycache.";
- private static final String QUERY_CACHE_NAME = "query";
-
- private final Lock lock = new ReentrantLock();
- private OpenJPAJCacheDataCacheManager manager;
-
- @Override
- public void initialize(final DataCacheManager manager)
- {
- super.initialize(manager);
- this.manager = OpenJPAJCacheDataCacheManager.class.cast(manager);
- }
-
- @Override
- protected void clearInternal()
- {
- final CacheManager cacheManager = manager.getCacheManager();
- for (final String cacheName : cacheManager.getCacheNames())
- {
- if (!cacheName.startsWith(OPENJPA_PREFIX))
- {
- continue;
- }
- cacheManager.getCache(cacheName).clear();
- }
- }
-
- @Override
- protected Collection keySet()
- {
- final Collection<QueryKey> keys = new LinkedList<QueryKey>();
- for (final Cache.Entry<Object, Object> entry : queryCache())
- {
- keys.add(QueryKey.class.cast(entry.getKey()));
- }
- return keys;
- }
-
- @Override
- protected QueryResult getInternal(final QueryKey qk)
- {
- return QueryResult.class.cast(queryCache().get(qk));
- }
-
- private Cache<Object, Object> queryCache()
- {
- return manager.getOrCreateCache(OPENJPA_PREFIX, QUERY_CACHE_NAME);
- }
-
- @Override
- protected QueryResult putInternal(final QueryKey qk, final QueryResult oids)
- {
- queryCache().put(qk, oids);
- return oids;
- }
-
- @Override
- protected QueryResult removeInternal(final QueryKey qk)
- {
- final Object remove = queryCache().getAndRemove(qk);
- if (remove == null)
- {
- return null;
- }
- return QueryResult.class.cast(remove);
- }
-
- @Override
- protected boolean pinInternal(final QueryKey qk)
- {
- throw new UnsupportedOperationException();
- }
-
- @Override
- protected boolean unpinInternal(final QueryKey qk)
- {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void writeLock()
- {
- lock.lock();
- }
-
- @Override
- public void writeUnlock()
- {
- lock.unlock();
- }
-}
diff --git a/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs3/jcache/openjpa/OpenJPAJCacheDataCache.java b/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs3/jcache/openjpa/OpenJPAJCacheDataCache.java
new file mode 100644
index 0000000..8025b36
--- /dev/null
+++ b/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs3/jcache/openjpa/OpenJPAJCacheDataCache.java
@@ -0,0 +1,160 @@
+/*
+ * 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.apache.commons.jcs3.jcache.openjpa;
+
+import org.apache.openjpa.datacache.AbstractDataCache;
+import org.apache.openjpa.datacache.DataCacheManager;
+import org.apache.openjpa.datacache.DataCachePCData;
+import org.apache.openjpa.util.OpenJPAId;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class OpenJPAJCacheDataCache extends AbstractDataCache
+{
+ private static final String OPENJPA_PREFIX = "openjpa.datacache.";
+
+ private final Lock lock = new ReentrantLock();
+ private OpenJPAJCacheDataCacheManager manager;
+
+ @Override
+ public void initialize(final DataCacheManager manager)
+ {
+ super.initialize(manager);
+ this.manager = OpenJPAJCacheDataCacheManager.class.cast(manager);
+ }
+
+ @Override
+ protected DataCachePCData getInternal(final Object oid)
+ {
+ Object result = null;
+ if (OpenJPAId.class.isInstance(oid))
+ {
+ final Class<?> cls = OpenJPAId.class.cast(oid).getType();
+ Cache<Object, Object> cache = manager.getOrCreateCache(OPENJPA_PREFIX, cls.getName());
+ if (cache == null)
+ {
+ return null;
+ }
+ else
+ {
+ result = cache.get(oid);
+ }
+ }
+ else
+ {
+ final CacheManager cacheManager = manager.getCacheManager();
+ for (final String cacheName : cacheManager.getCacheNames())
+ {
+ if (!cacheName.startsWith(OPENJPA_PREFIX))
+ {
+ continue;
+ }
+
+ result = cacheManager.getCache(cacheName).get(oid);
+ if (result != null)
+ {
+ break;
+ }
+ }
+ }
+ if (result == null)
+ {
+ return null;
+ }
+ return DataCachePCData.class.cast(result);
+ }
+
+ @Override
+ protected DataCachePCData putInternal(final Object oid, final DataCachePCData pc)
+ {
+ manager.getOrCreateCache(OPENJPA_PREFIX, pc.getType().getName()).put(oid, pc);
+ return pc;
+ }
+
+ @Override
+ protected DataCachePCData removeInternal(final Object oid)
+ {
+ if (OpenJPAId.class.isInstance(oid))
+ {
+ final Object remove = manager.getOrCreateCache(OPENJPA_PREFIX, OpenJPAId.class.cast(oid).getType().getName()).getAndRemove(oid);
+ if (remove == null)
+ {
+ return null;
+ }
+ return DataCachePCData.class.cast(remove);
+ }
+ return null;
+ }
+
+ @Override
+ protected void removeAllInternal(final Class<?> cls, final boolean subclasses)
+ {
+ final String name;
+ if (subclasses)
+ {
+ name = cls.getSuperclass().getName();
+ }
+ else
+ {
+ name = cls.getName();
+ }
+ manager.getOrCreateCache(OPENJPA_PREFIX, name).removeAll();
+ }
+
+ @Override
+ protected void clearInternal()
+ {
+ final CacheManager cacheManager = manager.getCacheManager();
+ for (final String cacheName : cacheManager.getCacheNames())
+ {
+ if (!cacheName.startsWith(OPENJPA_PREFIX))
+ {
+ continue;
+ }
+ cacheManager.getCache(cacheName).clear();
+ }
+ }
+
+ @Override
+ protected boolean pinInternal(final Object oid)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected boolean unpinInternal(final Object oid)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void writeLock()
+ {
+ lock.lock();
+ }
+
+ @Override
+ public void writeUnlock()
+ {
+ lock.unlock();
+ }
+}
diff --git a/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs3/jcache/openjpa/OpenJPAJCacheDataCacheManager.java b/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs3/jcache/openjpa/OpenJPAJCacheDataCacheManager.java
new file mode 100644
index 0000000..50bbdaa
--- /dev/null
+++ b/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs3/jcache/openjpa/OpenJPAJCacheDataCacheManager.java
@@ -0,0 +1,120 @@
+/*
+ * 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.apache.commons.jcs3.jcache.openjpa;
+
+import org.apache.openjpa.conf.OpenJPAConfiguration;
+import org.apache.openjpa.datacache.DataCacheManagerImpl;
+import org.apache.openjpa.lib.conf.ObjectValue;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+import javax.cache.configuration.FactoryBuilder;
+import javax.cache.configuration.MutableConfiguration;
+import javax.cache.expiry.CreatedExpiryPolicy;
+import javax.cache.expiry.Duration;
+import javax.cache.expiry.ExpiryPolicy;
+import javax.cache.integration.CacheLoader;
+import javax.cache.integration.CacheWriter;
+import javax.cache.spi.CachingProvider;
+import java.net.URI;
+import java.util.Map;
+import java.util.Properties;
+
+public class OpenJPAJCacheDataCacheManager extends DataCacheManagerImpl
+{
+ private CachingProvider provider;
+ private CacheManager cacheManager;
+
+ @Override
+ public void initialize(final OpenJPAConfiguration conf, final ObjectValue dataCache, final ObjectValue queryCache)
+ {
+ super.initialize(conf, dataCache, queryCache);
+ provider = Caching.getCachingProvider();
+
+ final Properties properties = new Properties();
+ final Map<String, Object> props = conf.toProperties(false);
+ if (props != null)
+ {
+ for (final Map.Entry<?, ?> entry : props.entrySet())
+ {
+ if (entry.getKey() != null && entry.getValue() != null)
+ {
+ properties.setProperty(entry.getKey().toString(), entry.getValue().toString());
+ }
+ }
+ }
+
+ final String uri = properties.getProperty("jcache.uri", provider.getDefaultURI().toString());
+ cacheManager = provider.getCacheManager(URI.create(uri), provider.getDefaultClassLoader(), properties);
+ }
+
+ @Override
+ public void close()
+ {
+ super.close();
+ if (!cacheManager.isClosed())
+ {
+ cacheManager.close();
+ }
+ provider.close();
+ }
+
+ Cache<Object, Object> getOrCreateCache(final String prefix, final String entity)
+ {
+ final String internalName = prefix + entity;
+ Cache<Object, Object> cache = cacheManager.getCache(internalName);
+ if (cache == null)
+ {
+ final Properties properties = cacheManager.getProperties();
+ final MutableConfiguration<Object, Object> configuration = new MutableConfiguration<Object, Object>()
+ .setStoreByValue("true".equalsIgnoreCase(properties.getProperty("jcache.store-by-value", "false")));
+
+ configuration.setReadThrough("true".equals(properties.getProperty("jcache.read-through", "false")));
+ configuration.setWriteThrough("true".equals(properties.getProperty("jcache.write-through", "false")));
+ if (configuration.isReadThrough())
+ {
+ configuration.setCacheLoaderFactory(new FactoryBuilder.ClassFactory<CacheLoader<Object, Object>>(properties.getProperty("jcache.cache-loader-factory")));
+ }
+ if (configuration.isWriteThrough())
+ {
+ configuration.setCacheWriterFactory(new FactoryBuilder.ClassFactory<CacheWriter<Object, Object>>(properties.getProperty("jcache.cache-writer-factory")));
+ }
+ final String expirtyPolicy = properties.getProperty("jcache.expiry-policy-factory");
+ if (expirtyPolicy != null)
+ {
+ configuration.setExpiryPolicyFactory(new FactoryBuilder.ClassFactory<ExpiryPolicy>(expirtyPolicy));
+ }
+ else
+ {
+ configuration.setExpiryPolicyFactory(new FactoryBuilder.SingletonFactory<ExpiryPolicy>(new CreatedExpiryPolicy(Duration.FIVE_MINUTES)));
+ }
+ configuration.setManagementEnabled("true".equals(properties.getProperty("jcache.management-enabled", "false")));
+ configuration.setStatisticsEnabled("true".equals(properties.getProperty("jcache.statistics-enabled", "false")));
+
+ cache = cacheManager.createCache(internalName, configuration);
+ }
+ return cache;
+ }
+
+ CacheManager getCacheManager()
+ {
+ return cacheManager;
+ }
+}
diff --git a/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs3/jcache/openjpa/OpenJPAJCacheDerivation.java b/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs3/jcache/openjpa/OpenJPAJCacheDerivation.java
new file mode 100644
index 0000000..97575a4
--- /dev/null
+++ b/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs3/jcache/openjpa/OpenJPAJCacheDerivation.java
@@ -0,0 +1,75 @@
+/*
+ * 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.apache.commons.jcs3.jcache.openjpa;
+
+import org.apache.openjpa.conf.OpenJPAConfiguration;
+import org.apache.openjpa.conf.OpenJPAConfigurationImpl;
+import org.apache.openjpa.event.SingleJVMRemoteCommitProvider;
+import org.apache.openjpa.lib.conf.AbstractProductDerivation;
+import org.apache.openjpa.lib.conf.Configuration;
+import org.apache.openjpa.lib.conf.ConfigurationProvider;
+import org.apache.openjpa.lib.conf.Configurations;
+
+import java.util.Map;
+
+public class OpenJPAJCacheDerivation extends AbstractProductDerivation
+{
+ private static final String JCACHE_NAME = "jcache";
+
+ @Override
+ public boolean beforeConfigurationLoad(final Configuration conf)
+ {
+ if (OpenJPAConfiguration.class.isInstance(conf)) {
+ final OpenJPAConfigurationImpl oconf = OpenJPAConfigurationImpl.class.cast(conf);
+ oconf.dataCacheManagerPlugin.setAlias(JCACHE_NAME, OpenJPAJCacheDataCacheManager.class.getName());
+ oconf.dataCachePlugin.setAlias(JCACHE_NAME, OpenJPAJCacheDataCache.class.getName());
+ oconf.queryCachePlugin.setAlias(JCACHE_NAME, OpenJPAJCacheQueryCache.class.getName());
+ }
+ return super.beforeConfigurationLoad(conf);
+ }
+
+ @Override
+ public boolean beforeConfigurationConstruct(final ConfigurationProvider cp)
+ {
+ final Map<?, ?> props = cp.getProperties();
+ final Object dcm = Configurations.getProperty("DataCacheManager", props);
+ if (dcm != null && JCACHE_NAME.equals(dcm))
+ {
+ if (Configurations.getProperty("DataCache", props) == null)
+ {
+ cp.addProperty("openjpa.DataCache", JCACHE_NAME);
+ }
+ if (Configurations.getProperty("QueryCache", props) == null)
+ {
+ cp.addProperty("openjpa.QueryCache", JCACHE_NAME);
+ }
+ if (Configurations.getProperty("RemoteCommitProvider", props) == null)
+ {
+ cp.addProperty("openjpa.RemoteCommitProvider", SingleJVMRemoteCommitProvider.class.getName());
+ }
+ }
+ return super.beforeConfigurationConstruct(cp);
+ }
+
+ @Override
+ public int getType()
+ {
+ return TYPE_FEATURE;
+ }
+}
diff --git a/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs3/jcache/openjpa/OpenJPAJCacheQueryCache.java b/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs3/jcache/openjpa/OpenJPAJCacheQueryCache.java
new file mode 100644
index 0000000..27818a3
--- /dev/null
+++ b/commons-jcs-jcache-openjpa/src/main/java/org/apache/commons/jcs3/jcache/openjpa/OpenJPAJCacheQueryCache.java
@@ -0,0 +1,125 @@
+/*
+ * 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.apache.commons.jcs3.jcache.openjpa;
+
+import org.apache.openjpa.datacache.AbstractQueryCache;
+import org.apache.openjpa.datacache.DataCacheManager;
+import org.apache.openjpa.datacache.QueryKey;
+import org.apache.openjpa.datacache.QueryResult;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class OpenJPAJCacheQueryCache extends AbstractQueryCache
+{
+ private static final String OPENJPA_PREFIX = "openjpa.querycache.";
+ private static final String QUERY_CACHE_NAME = "query";
+
+ private final Lock lock = new ReentrantLock();
+ private OpenJPAJCacheDataCacheManager manager;
+
+ @Override
+ public void initialize(final DataCacheManager manager)
+ {
+ super.initialize(manager);
+ this.manager = OpenJPAJCacheDataCacheManager.class.cast(manager);
+ }
+
+ @Override
+ protected void clearInternal()
+ {
+ final CacheManager cacheManager = manager.getCacheManager();
+ for (final String cacheName : cacheManager.getCacheNames())
+ {
+ if (!cacheName.startsWith(OPENJPA_PREFIX))
+ {
+ continue;
+ }
+ cacheManager.getCache(cacheName).clear();
+ }
+ }
+
+ @Override
+ protected Collection keySet()
+ {
+ final Collection<QueryKey> keys = new LinkedList<QueryKey>();
+ for (final Cache.Entry<Object, Object> entry : queryCache())
+ {
+ keys.add(QueryKey.class.cast(entry.getKey()));
+ }
+ return keys;
+ }
+
+ @Override
+ protected QueryResult getInternal(final QueryKey qk)
+ {
+ return QueryResult.class.cast(queryCache().get(qk));
+ }
+
+ private Cache<Object, Object> queryCache()
+ {
+ return manager.getOrCreateCache(OPENJPA_PREFIX, QUERY_CACHE_NAME);
+ }
+
+ @Override
+ protected QueryResult putInternal(final QueryKey qk, final QueryResult oids)
+ {
+ queryCache().put(qk, oids);
+ return oids;
+ }
+
+ @Override
+ protected QueryResult removeInternal(final QueryKey qk)
+ {
+ final Object remove = queryCache().getAndRemove(qk);
+ if (remove == null)
+ {
+ return null;
+ }
+ return QueryResult.class.cast(remove);
+ }
+
+ @Override
+ protected boolean pinInternal(final QueryKey qk)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected boolean unpinInternal(final QueryKey qk)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void writeLock()
+ {
+ lock.lock();
+ }
+
+ @Override
+ public void writeUnlock()
+ {
+ lock.unlock();
+ }
+}
diff --git a/commons-jcs-jcache-openjpa/src/main/resources/META-INF/services/org.apache.openjpa.lib.conf.ProductDerivation b/commons-jcs-jcache-openjpa/src/main/resources/META-INF/services/org.apache.openjpa.lib.conf.ProductDerivation
index 092e0cc..f39722f 100644
--- a/commons-jcs-jcache-openjpa/src/main/resources/META-INF/services/org.apache.openjpa.lib.conf.ProductDerivation
+++ b/commons-jcs-jcache-openjpa/src/main/resources/META-INF/services/org.apache.openjpa.lib.conf.ProductDerivation
@@ -1 +1,18 @@
-org.apache.commons.jcs.jcache.openjpa.OpenJPAJCacheDerivation
+# 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.
+
+org.apache.commons.jcs3.jcache.openjpa.OpenJPAJCacheDerivation
diff --git a/commons-jcs-jcache-openjpa/src/test/java/org/apache/commons/jcs/jcache/openjpa/OpenJPAJCacheDataCacheTest.java b/commons-jcs-jcache-openjpa/src/test/java/org/apache/commons/jcs/jcache/openjpa/OpenJPAJCacheDataCacheTest.java
deleted file mode 100644
index 28eba88..0000000
--- a/commons-jcs-jcache-openjpa/src/test/java/org/apache/commons/jcs/jcache/openjpa/OpenJPAJCacheDataCacheTest.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.openjpa;
-
-import org.apache.derby.jdbc.EmbeddedDriver;
-import org.apache.openjpa.conf.OpenJPAConfiguration;
-import org.apache.openjpa.datacache.QueryKey;
-import org.apache.openjpa.persistence.JPAFacadeHelper;
-import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
-import org.junit.Test;
-
-import javax.persistence.Entity;
-import javax.persistence.EntityManager;
-import javax.persistence.EntityManagerFactory;
-import javax.persistence.GeneratedValue;
-import javax.persistence.Id;
-import javax.persistence.Persistence;
-import javax.persistence.Query;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-public class OpenJPAJCacheDataCacheTest
-{
- private static final Properties props = new Properties()
- {{
- setProperty("openjpa.MetaDataFactory", "jpa(Types=" + MyEntity.class.getName() + ")");
- setProperty("openjpa.ConnectionDriverName", EmbeddedDriver.class.getName());
- setProperty("openjpa.ConnectionURL", "jdbc:derby:memory:test;create=true");
- setProperty("openjpa.jdbc.SynchronizeMappings", "buildSchema");
- setProperty("openjpa.DataCacheManager", "jcache");
- setProperty("openjpa.RuntimeUnenhancedClasses", "supported");
-
- // implicit
- // setProperty("openjpa.DataCache", "jcache");
- // setProperty("openjpa.QueryCache", "jcache");
- }};
-
- @Test
- public void entity()
- {
- final EntityManagerFactory emf = Persistence.createEntityManagerFactory("test-jcache", props);
- final OpenJPAConfiguration conf = OpenJPAEntityManagerFactorySPI.class.cast(emf).getConfiguration();
-
- final EntityManager em = emf.createEntityManager();
-
- final MyEntity entity = new MyEntity();
- entity.setName("cacheMe1");
- em.getTransaction().begin();
- em.persist(entity);
- em.getTransaction().commit();
- assertNotNull(conf.getDataCacheManagerInstance().getDataCache("default"));
-
- assertThat(conf.getDataCacheManagerInstance(), instanceOf(OpenJPAJCacheDataCacheManager.class));
- assertThat(conf.getDataCacheManagerInstance().getDataCache("default"), instanceOf(OpenJPAJCacheDataCache.class));
- assertTrue(conf.getDataCacheManagerInstance().getDataCache("default").contains(JPAFacadeHelper.toOpenJPAObjectId(conf.getMetaDataRepositoryInstance().getCachedMetaData(MyEntity.class), entity.getId())));
-
- em.close();
-
- emf.close();
- }
-
- @Test
- public void query()
- {
- final EntityManagerFactory emf = Persistence.createEntityManagerFactory("test-jcache", props);
- final OpenJPAConfiguration conf = OpenJPAEntityManagerFactorySPI.class.cast(emf).getConfiguration();
-
- final EntityManager em = emf.createEntityManager();
-
- final MyEntity entity = new MyEntity();
- entity.setName("cacheMe1");
- em.getTransaction().begin();
- em.persist(entity);
- em.getTransaction().commit();
- final Query query = em.createQuery("select e from OpenJPAJCacheDataCacheTest$MyEntity e where e.id = :id");
- assertEquals(1, query.setParameter("id", entity.getId()).getResultList().size());
- assertNotNull(conf.getDataCacheManagerInstance().getDataCache("default"));
-
- assertThat(conf.getDataCacheManagerInstance(), instanceOf(OpenJPAJCacheDataCacheManager.class));
- assertThat(conf.getDataCacheManagerInstance().getDataCache("default"), instanceOf(OpenJPAJCacheDataCache.class));
- assertTrue(conf.getDataCacheManagerInstance().getDataCache("default").contains(JPAFacadeHelper.toOpenJPAObjectId(conf.getMetaDataRepositoryInstance().getCachedMetaData(MyEntity.class), entity.getId())));
-
- final Map<Object, Object> args = new HashMap<Object, Object>()
- {{
- put("id", entity.getId());
- }};
- final QueryKey qk = QueryKey.newInstance(query.unwrap(org.apache.openjpa.kernel.Query.class), args);
- assertNotNull(conf.getDataCacheManagerInstance().getSystemQueryCache().get(qk));
-
- em.close();
-
- emf.close();
- }
-
- @Entity
- public static class MyEntity
- {
- @Id
- @GeneratedValue
- private long id;
- private String name;
-
- public long getId()
- {
- return id;
- }
-
- public String getName()
- {
- return name;
- }
-
- public void setName(final String name)
- {
- this.name = name;
- }
- }
-}
diff --git a/commons-jcs-jcache-openjpa/src/test/java/org/apache/commons/jcs3/jcache/openjpa/OpenJPAJCacheDataCacheTest.java b/commons-jcs-jcache-openjpa/src/test/java/org/apache/commons/jcs3/jcache/openjpa/OpenJPAJCacheDataCacheTest.java
new file mode 100644
index 0000000..21a447e
--- /dev/null
+++ b/commons-jcs-jcache-openjpa/src/test/java/org/apache/commons/jcs3/jcache/openjpa/OpenJPAJCacheDataCacheTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.apache.commons.jcs3.jcache.openjpa;
+
+import org.apache.commons.jcs3.jcache.openjpa.OpenJPAJCacheDataCache;
+import org.apache.commons.jcs3.jcache.openjpa.OpenJPAJCacheDataCacheManager;
+import org.apache.derby.jdbc.EmbeddedDriver;
+import org.apache.openjpa.conf.OpenJPAConfiguration;
+import org.apache.openjpa.datacache.QueryKey;
+import org.apache.openjpa.persistence.JPAFacadeHelper;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.junit.Test;
+
+import javax.persistence.Entity;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Persistence;
+import javax.persistence.Query;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+public class OpenJPAJCacheDataCacheTest
+{
+ private static final Properties props = new Properties()
+ {{
+ setProperty("openjpa.MetaDataFactory", "jpa(Types=" + MyEntity.class.getName() + ")");
+ setProperty("openjpa.ConnectionDriverName", EmbeddedDriver.class.getName());
+ setProperty("openjpa.ConnectionURL", "jdbc:derby:memory:test;create=true");
+ setProperty("openjpa.jdbc.SynchronizeMappings", "buildSchema");
+ setProperty("openjpa.DataCacheManager", "jcache");
+ setProperty("openjpa.RuntimeUnenhancedClasses", "supported");
+
+ // implicit
+ // setProperty("openjpa.DataCache", "jcache");
+ // setProperty("openjpa.QueryCache", "jcache");
+ }};
+
+ @Test
+ public void entity()
+ {
+ final EntityManagerFactory emf = Persistence.createEntityManagerFactory("test-jcache", props);
+ final OpenJPAConfiguration conf = OpenJPAEntityManagerFactorySPI.class.cast(emf).getConfiguration();
+
+ final EntityManager em = emf.createEntityManager();
+
+ final MyEntity entity = new MyEntity();
+ entity.setName("cacheMe1");
+ em.getTransaction().begin();
+ em.persist(entity);
+ em.getTransaction().commit();
+ assertNotNull(conf.getDataCacheManagerInstance().getDataCache("default"));
+
+ assertThat(conf.getDataCacheManagerInstance(), instanceOf(OpenJPAJCacheDataCacheManager.class));
+ assertThat(conf.getDataCacheManagerInstance().getDataCache("default"), instanceOf(OpenJPAJCacheDataCache.class));
+ assertTrue(conf.getDataCacheManagerInstance().getDataCache("default").contains(JPAFacadeHelper.toOpenJPAObjectId(conf.getMetaDataRepositoryInstance().getCachedMetaData(MyEntity.class), entity.getId())));
+
+ em.close();
+
+ emf.close();
+ }
+
+ @Test
+ public void query()
+ {
+ final EntityManagerFactory emf = Persistence.createEntityManagerFactory("test-jcache", props);
+ final OpenJPAConfiguration conf = OpenJPAEntityManagerFactorySPI.class.cast(emf).getConfiguration();
+
+ final EntityManager em = emf.createEntityManager();
+
+ final MyEntity entity = new MyEntity();
+ entity.setName("cacheMe1");
+ em.getTransaction().begin();
+ em.persist(entity);
+ em.getTransaction().commit();
+ final Query query = em.createQuery("select e from OpenJPAJCacheDataCacheTest$MyEntity e where e.id = :id");
+ assertEquals(1, query.setParameter("id", entity.getId()).getResultList().size());
+ assertNotNull(conf.getDataCacheManagerInstance().getDataCache("default"));
+
+ assertThat(conf.getDataCacheManagerInstance(), instanceOf(OpenJPAJCacheDataCacheManager.class));
+ assertThat(conf.getDataCacheManagerInstance().getDataCache("default"), instanceOf(OpenJPAJCacheDataCache.class));
+ assertTrue(conf.getDataCacheManagerInstance().getDataCache("default").contains(JPAFacadeHelper.toOpenJPAObjectId(conf.getMetaDataRepositoryInstance().getCachedMetaData(MyEntity.class), entity.getId())));
+
+ final Map<Object, Object> args = new HashMap<Object, Object>()
+ {{
+ put("id", entity.getId());
+ }};
+ final QueryKey qk = QueryKey.newInstance(query.unwrap(org.apache.openjpa.kernel.Query.class), args);
+ assertNotNull(conf.getDataCacheManagerInstance().getSystemQueryCache().get(qk));
+
+ em.close();
+
+ emf.close();
+ }
+
+ @Entity
+ public static class MyEntity
+ {
+ @Id
+ @GeneratedValue
+ private long id;
+ private String name;
+
+ public long getId()
+ {
+ return id;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(final String name)
+ {
+ this.name = name;
+ }
+ }
+}
diff --git a/commons-jcs-jcache/pom.xml b/commons-jcs-jcache/pom.xml
index 9e4eb46..555c59a 100644
--- a/commons-jcs-jcache/pom.xml
+++ b/commons-jcs-jcache/pom.xml
@@ -22,12 +22,12 @@
<parent>
<groupId>org.apache.commons</groupId>
- <artifactId>commons-jcs</artifactId>
+ <artifactId>commons-jcs3</artifactId>
<version>3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
- <artifactId>commons-jcs-jcache</artifactId>
+ <artifactId>commons-jcs3-jcache</artifactId>
<version>3.0-SNAPSHOT</version>
<name>Apache Commons JCS :: JCache</name>
@@ -61,7 +61,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
- <artifactId>commons-jcs-core</artifactId>
+ <artifactId>commons-jcs3-core</artifactId>
</dependency>
<dependency>
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/Asserts.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/Asserts.java
deleted file mode 100644
index 57d746a..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/Asserts.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.apache.commons.jcs.jcache;
-
-/*
- * 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.
- */
-
-public class Asserts
-{
- public static void assertNotNull(final Object value, final String name)
- {
- if (value == null)
- {
- throw new NullPointerException(name + " is null");
- }
- }
-
- private Asserts()
- {
- // no-op
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/EvictionListener.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/EvictionListener.java
deleted file mode 100644
index a8ecbc2..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/EvictionListener.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import org.apache.commons.jcs.engine.control.event.behavior.IElementEvent;
-import org.apache.commons.jcs.engine.control.event.behavior.IElementEventHandler;
-
-public class EvictionListener implements IElementEventHandler
-{
- private final Statistics stats;
-
- public EvictionListener(final Statistics statistics)
- {
- this.stats = statistics;
- }
-
- @Override
- public void handleElementEvent(final IElementEvent event)
- {
- switch (event.getElementEvent())
- {
- case EXCEEDED_MAXLIFE_BACKGROUND:
- case EXCEEDED_MAXLIFE_ONREQUEST:
- case EXCEEDED_IDLETIME_ONREQUEST:
- case EXCEEDED_IDLETIME_BACKGROUND:
- stats.increaseEvictions(1);
- break;
- }
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/ExpiryAwareCache.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/ExpiryAwareCache.java
deleted file mode 100644
index d4691ec..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/ExpiryAwareCache.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import java.util.Arrays;
-import java.util.Map;
-
-import javax.cache.Cache;
-import javax.cache.configuration.CacheEntryListenerConfiguration;
-import javax.cache.event.CacheEntryEvent;
-import javax.cache.event.EventType;
-
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-
-// allows us to plug some lifecycle callbacks on the core cache without impacting too much the core
-public class ExpiryAwareCache<A, B> extends CompositeCache<A, B>
-{
- private Map<CacheEntryListenerConfiguration<A, B>, JCSListener<A, B>> listeners;
- private Cache<A, B> cacheRef;
-
- ExpiryAwareCache(final ICompositeCacheAttributes cattr, final IElementAttributes attr)
- {
- super(cattr, attr);
- }
-
- @Override
- protected void doExpires(final ICacheElement<A, B> element)
- {
- super.doExpires(element);
- for (final JCSListener<A, B> listener : listeners.values())
- {
- listener.onExpired(Arrays.<CacheEntryEvent<? extends A, ? extends B>> asList(new JCSCacheEntryEvent<A, B>(
- cacheRef, EventType.REMOVED, null, element.getKey(), element.getVal())));
- }
- }
-
- void init(final Cache<A, B> cache, final Map<CacheEntryListenerConfiguration<A, B>, JCSListener<A, B>> listeners)
- {
- this.cacheRef = cache;
- this.listeners = listeners;
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/ImmutableIterable.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/ImmutableIterable.java
deleted file mode 100644
index c4390e9..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/ImmutableIterable.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-
-public class ImmutableIterable<T> implements Iterable<T>
-{
- private final Collection<T> delegate;
-
- public ImmutableIterable(final Collection<T> delegate)
- {
- this.delegate = new ArrayList<T>(delegate);
- }
-
- @Override
- public Iterator<T> iterator()
- {
- return new ImmutableIterator<T>(delegate.iterator());
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/ImmutableIterator.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/ImmutableIterator.java
deleted file mode 100644
index 55c9942..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/ImmutableIterator.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import java.util.Iterator;
-
-public class ImmutableIterator<T> implements Iterator<T>
-{
- private final Iterator<T> delegate;
-
- public ImmutableIterator(final Iterator<T> delegate)
- {
- this.delegate = delegate;
- }
-
- @Override
- public boolean hasNext()
- {
- return delegate.hasNext();
- }
-
- @Override
- public T next()
- {
- return delegate.next();
- }
-
- @Override
- public void remove()
- {
- throw new UnsupportedOperationException("this iterator is immutable");
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSCache.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSCache.java
deleted file mode 100644
index baa1ff5..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSCache.java
+++ /dev/null
@@ -1,1014 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.ElementAttributes;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-import org.apache.commons.jcs.jcache.jmx.JCSCacheMXBean;
-import org.apache.commons.jcs.jcache.jmx.JCSCacheStatisticsMXBean;
-import org.apache.commons.jcs.jcache.jmx.JMXs;
-import org.apache.commons.jcs.jcache.proxy.ExceptionWrapperHandler;
-import org.apache.commons.jcs.jcache.thread.DaemonThreadFactory;
-import org.apache.commons.jcs.utils.serialization.StandardSerializer;
-
-import javax.cache.Cache;
-import javax.cache.CacheException;
-import javax.cache.CacheManager;
-import javax.cache.configuration.CacheEntryListenerConfiguration;
-import javax.cache.configuration.Configuration;
-import javax.cache.configuration.Factory;
-import javax.cache.event.CacheEntryEvent;
-import javax.cache.event.EventType;
-import javax.cache.expiry.Duration;
-import javax.cache.expiry.EternalExpiryPolicy;
-import javax.cache.expiry.ExpiryPolicy;
-import javax.cache.integration.CacheLoader;
-import javax.cache.integration.CacheLoaderException;
-import javax.cache.integration.CacheWriter;
-import javax.cache.integration.CacheWriterException;
-import javax.cache.integration.CompletionListener;
-import javax.cache.processor.EntryProcessor;
-import javax.cache.processor.EntryProcessorException;
-import javax.cache.processor.EntryProcessorResult;
-import javax.management.ObjectName;
-import java.io.Closeable;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import static org.apache.commons.jcs.jcache.Asserts.assertNotNull;
-import static org.apache.commons.jcs.jcache.serialization.Serializations.copy;
-
-// TODO: configure serializer
-public class JCSCache<K, V> implements Cache<K, V>
-{
- private final ExpiryAwareCache<K, V> delegate;
- private final JCSCachingManager manager;
- private final JCSConfiguration<K, V> config;
- private final CacheLoader<K, V> loader;
- private final CacheWriter<? super K, ? super V> writer;
- private final ExpiryPolicy expiryPolicy;
- private final ObjectName cacheConfigObjectName;
- private final ObjectName cacheStatsObjectName;
- private final String name;
- private volatile boolean closed = false;
- private final Map<CacheEntryListenerConfiguration<K, V>, JCSListener<K, V>> listeners = new ConcurrentHashMap<CacheEntryListenerConfiguration<K, V>, JCSListener<K, V>>();
- private final Statistics statistics = new Statistics();
- private final ExecutorService pool;
- private final IElementSerializer serializer; // using json/xml should work as well -> don't force Serializable
-
-
- public JCSCache(final ClassLoader classLoader, final JCSCachingManager mgr,
- final String cacheName, final JCSConfiguration<K, V> configuration,
- final Properties properties, final ExpiryAwareCache<K, V> cache)
- {
- manager = mgr;
-
- name = cacheName;
-
- delegate = cache;
- if (delegate.getElementAttributes() == null)
- {
- delegate.setElementAttributes(new ElementAttributes());
- }
- delegate.getElementAttributes().addElementEventHandler(new EvictionListener(statistics));
-
- config = configuration;
-
- final int poolSize = Integer.parseInt(property(properties, cacheName, "pool.size", "3"));
- final DaemonThreadFactory threadFactory = new DaemonThreadFactory("JCS-JCache-" + cacheName + "-");
- pool = poolSize > 0 ? Executors.newFixedThreadPool(poolSize, threadFactory) : Executors.newCachedThreadPool(threadFactory);
-
- try
- {
- serializer = IElementSerializer.class.cast(classLoader.loadClass(property(properties, "serializer", cacheName, StandardSerializer.class.getName())).newInstance());
- }
- catch (final Exception e)
- {
- throw new IllegalArgumentException(e);
- }
-
- final Factory<CacheLoader<K, V>> cacheLoaderFactory = configuration.getCacheLoaderFactory();
- if (cacheLoaderFactory == null)
- {
- loader = NoLoader.INSTANCE;
- }
- else
- {
- loader = ExceptionWrapperHandler
- .newProxy(classLoader, cacheLoaderFactory.create(), CacheLoaderException.class, CacheLoader.class);
- }
-
- final Factory<CacheWriter<? super K, ? super V>> cacheWriterFactory = configuration.getCacheWriterFactory();
- if (cacheWriterFactory == null)
- {
- writer = NoWriter.INSTANCE;
- }
- else
- {
- writer = ExceptionWrapperHandler
- .newProxy(classLoader, cacheWriterFactory.create(), CacheWriterException.class, CacheWriter.class);
- }
-
- final Factory<ExpiryPolicy> expiryPolicyFactory = configuration.getExpiryPolicyFactory();
- if (expiryPolicyFactory == null)
- {
- expiryPolicy = new EternalExpiryPolicy();
- }
- else
- {
- expiryPolicy = expiryPolicyFactory.create();
- }
-
- for (final CacheEntryListenerConfiguration<K, V> listener : config.getCacheEntryListenerConfigurations())
- {
- listeners.put(listener, new JCSListener<K, V>(listener));
- }
- delegate.init(this, listeners);
-
- statistics.setActive(config.isStatisticsEnabled());
-
- final String mgrStr = manager.getURI().toString().replaceAll(",|:|=|\n", ".");
- final String cacheStr = name.replaceAll(",|:|=|\n", ".");
- try
- {
- cacheConfigObjectName = new ObjectName("javax.cache:type=CacheConfiguration,"
- + "CacheManager=" + mgrStr + "," + "Cache=" + cacheStr);
- cacheStatsObjectName = new ObjectName("javax.cache:type=CacheStatistics,"
- + "CacheManager=" + mgrStr + "," + "Cache=" + cacheStr);
- }
- catch (final Exception e)
- {
- throw new IllegalArgumentException(e);
- }
- if (config.isManagementEnabled())
- {
- JMXs.register(cacheConfigObjectName, new JCSCacheMXBean<K, V>(this));
- }
- if (config.isStatisticsEnabled())
- {
- JMXs.register(cacheStatsObjectName, new JCSCacheStatisticsMXBean(statistics));
- }
- }
-
- private static String property(final Properties properties, final String cacheName, final String name, final String defaultValue)
- {
- return properties.getProperty(cacheName + "." + name, properties.getProperty(name, defaultValue));
- }
-
- private void assertNotClosed()
- {
- if (isClosed())
- {
- throw new IllegalStateException("cache closed");
- }
- }
-
- @Override
- public V get(final K key)
- {
- assertNotClosed();
- assertNotNull(key, "key");
- final long getStart = Times.now(false);
- return doGetControllingExpiry(getStart, key, true, false, false, true);
- }
-
- private V doLoad(final K key, final boolean update, final long now, final boolean propagateLoadException)
- {
- V v = null;
- try
- {
- v = loader.load(key);
- }
- catch (final CacheLoaderException e)
- {
- if (propagateLoadException)
- {
- throw e;
- }
- }
- if (v != null)
- {
- final Duration duration = update ? expiryPolicy.getExpiryForUpdate() : expiryPolicy.getExpiryForCreation();
- if (isNotZero(duration))
- {
- final IElementAttributes clone = delegate.getElementAttributes().clone();
- if (ElementAttributes.class.isInstance(clone))
- {
- ElementAttributes.class.cast(clone).setCreateTime();
- }
- final ICacheElement<K, V> element = updateElement(key, v, duration, clone);
- try
- {
- delegate.update(element);
- }
- catch (final IOException e)
- {
- throw new CacheException(e);
- }
- }
- }
- return v;
- }
-
- private ICacheElement<K, V> updateElement(final K key, final V v, final Duration duration, final IElementAttributes attrs)
- {
- final ICacheElement<K, V> element = new CacheElement<K, V>(name, key, v);
- if (duration != null)
- {
- attrs.setTimeFactorForMilliseconds(1);
- final boolean eternal = duration.isEternal();
- attrs.setIsEternal(eternal);
- if (!eternal)
- {
- attrs.setLastAccessTimeNow();
- }
- // MaxLife = -1 to use IdleTime excepted if jcache.ccf asked for something else
- }
- element.setElementAttributes(attrs);
- return element;
- }
-
- private void touch(final K key, final ICacheElement<K, V> element)
- {
- if (config.isStoreByValue())
- {
- final K copy = copy(serializer, manager.getClassLoader(), key);
- try
- {
- delegate.update(new CacheElement<K, V>(name, copy, element.getVal(), element.getElementAttributes()));
- }
- catch (final IOException e)
- {
- throw new CacheException(e);
- }
- }
- }
-
- @Override
- public Map<K, V> getAll(final Set<? extends K> keys)
- {
- assertNotClosed();
- for (final K k : keys)
- {
- assertNotNull(k, "key");
- }
-
- final long now = Times.now(false);
- final Map<K, V> result = new HashMap<K, V>();
- for (final K key : keys) {
- assertNotNull(key, "key");
-
- final ICacheElement<K, V> elt = delegate.get(key);
- V val = elt != null ? elt.getVal() : null;
- if (val == null && config.isReadThrough())
- {
- val = doLoad(key, false, now, false);
- if (val != null)
- {
- result.put(key, val);
- }
- }
- else if (elt != null)
- {
- final Duration expiryForAccess = expiryPolicy.getExpiryForAccess();
- if (isNotZero(expiryForAccess))
- {
- touch(key, elt);
- result.put(key, val);
- }
- else
- {
- forceExpires(key);
- }
- }
- }
- return result;
- }
-
- @Override
- public boolean containsKey(final K key)
- {
- assertNotClosed();
- assertNotNull(key, "key");
- return delegate.get(key) != null;
- }
-
- @Override
- public void put(final K key, final V rawValue)
- {
- assertNotClosed();
- assertNotNull(key, "key");
- assertNotNull(rawValue, "value");
-
- final ICacheElement<K, V> oldElt = delegate.get(key);
- final V old = oldElt != null ? oldElt.getVal() : null;
-
- final boolean storeByValue = config.isStoreByValue();
- final V value = storeByValue ? copy(serializer, manager.getClassLoader(), rawValue) : rawValue;
-
- final boolean created = old == null;
- final Duration duration = created ? expiryPolicy.getExpiryForCreation() : expiryPolicy.getExpiryForUpdate();
- if (isNotZero(duration))
- {
- final boolean statisticsEnabled = config.isStatisticsEnabled();
- final long start = Times.now(false);
-
- final K jcsKey = storeByValue ? copy(serializer, manager.getClassLoader(), key) : key;
- final ICacheElement<K, V> element = updateElement( // reuse it to create basic structure
- jcsKey, value, created ? null : duration,
- oldElt != null ? oldElt.getElementAttributes() : delegate.getElementAttributes().clone());
- if (created && duration != null) { // set maxLife
- final IElementAttributes copy = element.getElementAttributes();
- copy.setTimeFactorForMilliseconds(1);
- final boolean eternal = duration.isEternal();
- copy.setIsEternal(eternal);
- if (ElementAttributes.class.isInstance(copy)) {
- ElementAttributes.class.cast(copy).setCreateTime();
- }
- if (!eternal)
- {
- copy.setIsEternal(false);
- if (duration == expiryPolicy.getExpiryForAccess())
- {
- element.getElementAttributes().setIdleTime(duration.getTimeUnit().toMillis(duration.getDurationAmount()));
- }
- else
- {
- element.getElementAttributes().setMaxLife(duration.getTimeUnit().toMillis(duration.getDurationAmount()));
- }
- }
- element.setElementAttributes(copy);
- }
- writer.write(new JCSEntry<K, V>(jcsKey, value));
- try
- {
- delegate.update(element);
- }
- catch (final IOException e)
- {
- throw new CacheException(e);
- }
- for (final JCSListener<K, V> listener : listeners.values())
- {
- if (created)
- {
- listener.onCreated(Arrays.<CacheEntryEvent<? extends K, ? extends V>> asList(new JCSCacheEntryEvent<K, V>(this,
- EventType.CREATED, null, key, value)));
- }
- else
- {
- listener.onUpdated(Arrays.<CacheEntryEvent<? extends K, ? extends V>> asList(new JCSCacheEntryEvent<K, V>(this,
- EventType.UPDATED, old, key, value)));
- }
- }
-
- if (statisticsEnabled)
- {
- statistics.increasePuts(1);
- statistics.addPutTime(System.currentTimeMillis() - start);
- }
- }
- else
- {
- if (!created)
- {
- forceExpires(key);
- }
- }
- }
-
- private static boolean isNotZero(final Duration duration)
- {
- return duration == null || !duration.isZero();
- }
-
- private void forceExpires(final K cacheKey)
- {
- final ICacheElement<K, V> elt = delegate.get(cacheKey);
- delegate.remove(cacheKey);
- for (final JCSListener<K, V> listener : listeners.values())
- {
- listener.onExpired(Arrays.<CacheEntryEvent<? extends K, ? extends V>> asList(new JCSCacheEntryEvent<K, V>(this,
- EventType.REMOVED, null, cacheKey, elt.getVal())));
- }
- }
-
- @Override
- public V getAndPut(final K key, final V value)
- {
- assertNotClosed();
- assertNotNull(key, "key");
- assertNotNull(value, "value");
- final long getStart = Times.now(false);
- final V v = doGetControllingExpiry(getStart, key, false, false, true, false);
- put(key, value);
- return v;
- }
-
- @Override
- public void putAll(final Map<? extends K, ? extends V> map)
- {
- assertNotClosed();
- final TempStateCacheView<K, V> view = new TempStateCacheView<K, V>(this);
- for (final Map.Entry<? extends K, ? extends V> e : map.entrySet())
- {
- view.put(e.getKey(), e.getValue());
- }
- view.merge();
- }
-
- @Override
- public boolean putIfAbsent(final K key, final V value)
- {
- if (!containsKey(key))
- {
- put(key, value);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean remove(final K key)
- {
- assertNotClosed();
- assertNotNull(key, "key");
-
- final boolean statisticsEnabled = config.isStatisticsEnabled();
- final long start = Times.now(!statisticsEnabled);
-
- writer.delete(key);
- final K cacheKey = key;
-
- final ICacheElement<K, V> v = delegate.get(cacheKey);
- delegate.remove(cacheKey);
-
- final V value = v != null && v.getVal() != null ? v.getVal() : null;
- boolean remove = v != null;
- for (final JCSListener<K, V> listener : listeners.values())
- {
- listener.onRemoved(Arrays.<CacheEntryEvent<? extends K, ? extends V>> asList(new JCSCacheEntryEvent<K, V>(this,
- EventType.REMOVED, null, key, value)));
- }
- if (remove && statisticsEnabled)
- {
- statistics.increaseRemovals(1);
- statistics.addRemoveTime(Times.now(false) - start);
- }
- return remove;
- }
-
- @Override
- public boolean remove(final K key, final V oldValue)
- {
- assertNotClosed();
- assertNotNull(key, "key");
- assertNotNull(oldValue, "oldValue");
- final long getStart = Times.now(false);
- final V v = doGetControllingExpiry(getStart, key, false, false, false, false);
- if (oldValue.equals(v))
- {
- remove(key);
- return true;
- }
- else if (v != null)
- {
- // weird but just for stats to be right (org.jsr107.tck.expiry.CacheExpiryTest.removeSpecifiedEntryShouldNotCallExpiryPolicyMethods())
- expiryPolicy.getExpiryForAccess();
- }
- return false;
- }
-
- @Override
- public V getAndRemove(final K key)
- {
- assertNotClosed();
- assertNotNull(key, "key");
- final long getStart = Times.now(false);
- final V v = doGetControllingExpiry(getStart, key, false, false, true, false);
- remove(key);
- return v;
- }
-
- private V doGetControllingExpiry(final long getStart, final K key, final boolean updateAcess, final boolean forceDoLoad, final boolean skipLoad,
- final boolean propagateLoadException)
- {
- final boolean statisticsEnabled = config.isStatisticsEnabled();
- final ICacheElement<K, V> elt = delegate.get(key);
- V v = elt != null ? elt.getVal() : null;
- if (v == null && (config.isReadThrough() || forceDoLoad))
- {
- if (!skipLoad)
- {
- v = doLoad(key, false, getStart, propagateLoadException);
- }
- }
- else if (statisticsEnabled)
- {
- if (v != null)
- {
- statistics.increaseHits(1);
- }
- else
- {
- statistics.increaseMisses(1);
- }
- }
-
- if (updateAcess && elt != null)
- {
- final Duration expiryForAccess = expiryPolicy.getExpiryForAccess();
- if (!isNotZero(expiryForAccess))
- {
- forceExpires(key);
- }
- else if (expiryForAccess != null && (!elt.getElementAttributes().getIsEternal() || !expiryForAccess.isEternal()))
- {
- try
- {
- delegate.update(updateElement(key, elt.getVal(), expiryForAccess, elt.getElementAttributes()));
- }
- catch (final IOException e)
- {
- throw new CacheException(e);
- }
- }
- }
- if (statisticsEnabled && v != null)
- {
- statistics.addGetTime(Times.now(false) - getStart);
- }
- return v;
- }
-
- @Override
- public boolean replace(final K key, final V oldValue, final V newValue)
- {
- assertNotClosed();
- assertNotNull(key, "key");
- assertNotNull(oldValue, "oldValue");
- assertNotNull(newValue, "newValue");
- final boolean statisticsEnabled = config.isStatisticsEnabled();
- final ICacheElement<K, V> elt = delegate.get(key);
- if (elt != null)
- {
- V value = elt.getVal();
- if (value != null && statisticsEnabled)
- {
- statistics.increaseHits(1);
- }
- if (value == null && config.isReadThrough())
- {
- value = doLoad(key, false, Times.now(false), false);
- }
- if (value != null && value.equals(oldValue))
- {
- put(key, newValue);
- return true;
- }
- else if (value != null)
- {
- final Duration expiryForAccess = expiryPolicy.getExpiryForAccess();
- if (expiryForAccess != null && (!elt.getElementAttributes().getIsEternal() || !expiryForAccess.isEternal()))
- {
- try
- {
- delegate.update(updateElement(key, elt.getVal(), expiryForAccess, elt.getElementAttributes()));
- }
- catch (final IOException e)
- {
- throw new CacheException(e);
- }
- }
- }
- }
- else if (statisticsEnabled)
- {
- statistics.increaseMisses(1);
- }
- return false;
- }
-
- @Override
- public boolean replace(final K key, final V value)
- {
- assertNotClosed();
- assertNotNull(key, "key");
- assertNotNull(value, "value");
- boolean statisticsEnabled = config.isStatisticsEnabled();
- if (containsKey(key))
- {
- if (statisticsEnabled)
- {
- statistics.increaseHits(1);
- }
- put(key, value);
- return true;
- }
- else if (statisticsEnabled)
- {
- statistics.increaseMisses(1);
- }
- return false;
- }
-
- @Override
- public V getAndReplace(final K key, final V value)
- {
- assertNotClosed();
- assertNotNull(key, "key");
- assertNotNull(value, "value");
-
- final boolean statisticsEnabled = config.isStatisticsEnabled();
-
- final ICacheElement<K, V> elt = delegate.get(key);
- if (elt != null)
- {
- V oldValue = elt.getVal();
- if (oldValue == null && config.isReadThrough())
- {
- oldValue = doLoad(key, false, Times.now(false), false);
- }
- else if (statisticsEnabled)
- {
- statistics.increaseHits(1);
- }
- put(key, value);
- return oldValue;
- }
- else if (statisticsEnabled)
- {
- statistics.increaseMisses(1);
- }
- return null;
- }
-
- @Override
- public void removeAll(final Set<? extends K> keys)
- {
- assertNotClosed();
- assertNotNull(keys, "keys");
- for (final K k : keys)
- {
- remove(k);
- }
- }
-
- @Override
- public void removeAll()
- {
- assertNotClosed();
- for (final K k : delegate.getKeySet())
- {
- remove(k);
- }
- }
-
- @Override
- public void clear()
- {
- assertNotClosed();
- try
- {
- delegate.removeAll();
- }
- catch (final IOException e)
- {
- throw new CacheException(e);
- }
- }
-
- @Override
- public <C2 extends Configuration<K, V>> C2 getConfiguration(final Class<C2> clazz)
- {
- assertNotClosed();
- return clazz.cast(config);
- }
-
- @Override
- public void loadAll(final Set<? extends K> keys, final boolean replaceExistingValues, final CompletionListener completionListener)
- {
- assertNotClosed();
- assertNotNull(keys, "keys");
- for (final K k : keys)
- {
- assertNotNull(k, "a key");
- }
- pool.submit(new Runnable()
- {
- @Override
- public void run()
- {
- doLoadAll(keys, replaceExistingValues, completionListener);
- }
- });
- }
-
- private void doLoadAll(final Set<? extends K> keys, final boolean replaceExistingValues, final CompletionListener completionListener)
- {
- try
- {
- final long now = Times.now(false);
- for (final K k : keys)
- {
- if (replaceExistingValues)
- {
- doLoad(k, containsKey(k), now, completionListener != null);
- continue;
- }
- else if (containsKey(k))
- {
- continue;
- }
- doGetControllingExpiry(now, k, true, true, false, completionListener != null);
- }
- }
- catch (final RuntimeException e)
- {
- if (completionListener != null)
- {
- completionListener.onException(e);
- return;
- }
- }
- if (completionListener != null)
- {
- completionListener.onCompletion();
- }
- }
-
- @Override
- public <T> T invoke(final K key, final EntryProcessor<K, V, T> entryProcessor, final Object... arguments) throws EntryProcessorException
- {
- final TempStateCacheView<K, V> view = new TempStateCacheView<K, V>(this);
- final T t = doInvoke(view, key, entryProcessor, arguments);
- view.merge();
- return t;
- }
-
- private <T> T doInvoke(final TempStateCacheView<K, V> view, final K key, final EntryProcessor<K, V, T> entryProcessor,
- final Object... arguments)
- {
- assertNotClosed();
- assertNotNull(entryProcessor, "entryProcessor");
- assertNotNull(key, "key");
- try
- {
- if (config.isStatisticsEnabled())
- {
- if (containsKey(key))
- {
- statistics.increaseHits(1);
- }
- else
- {
- statistics.increaseMisses(1);
- }
- }
- return entryProcessor.process(new JCSMutableEntry<K, V>(view, key), arguments);
- }
- catch (final Exception ex)
- {
- return throwEntryProcessorException(ex);
- }
- }
-
- private static <T> T throwEntryProcessorException(final Exception ex)
- {
- if (EntryProcessorException.class.isInstance(ex))
- {
- throw EntryProcessorException.class.cast(ex);
- }
- throw new EntryProcessorException(ex);
- }
-
- @Override
- public <T> Map<K, EntryProcessorResult<T>> invokeAll(final Set<? extends K> keys, final EntryProcessor<K, V, T> entryProcessor,
- final Object... arguments)
- {
- assertNotClosed();
- assertNotNull(entryProcessor, "entryProcessor");
- final Map<K, EntryProcessorResult<T>> results = new HashMap<K, EntryProcessorResult<T>>();
- for (final K k : keys)
- {
- try
- {
- final T invoke = invoke(k, entryProcessor, arguments);
- if (invoke != null)
- {
- results.put(k, new EntryProcessorResult<T>()
- {
- @Override
- public T get() throws EntryProcessorException
- {
- return invoke;
- }
- });
- }
- }
- catch (final Exception e)
- {
- results.put(k, new EntryProcessorResult<T>()
- {
- @Override
- public T get() throws EntryProcessorException
- {
- return throwEntryProcessorException(e);
- }
- });
- }
- }
- return results;
- }
-
- @Override
- public void registerCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
- {
- assertNotClosed();
- if (listeners.containsKey(cacheEntryListenerConfiguration))
- {
- throw new IllegalArgumentException(cacheEntryListenerConfiguration + " already registered");
- }
- listeners.put(cacheEntryListenerConfiguration, new JCSListener<K, V>(cacheEntryListenerConfiguration));
- config.addListener(cacheEntryListenerConfiguration);
- }
-
- @Override
- public void deregisterCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
- {
- assertNotClosed();
- listeners.remove(cacheEntryListenerConfiguration);
- config.removeListener(cacheEntryListenerConfiguration);
- }
-
- @Override
- public Iterator<Entry<K, V>> iterator()
- {
- assertNotClosed();
- final Iterator<K> keys = new HashSet<K>(delegate.getKeySet()).iterator();
- return new Iterator<Entry<K, V>>()
- {
- private K lastKey = null;
-
- @Override
- public boolean hasNext()
- {
- return keys.hasNext();
- }
-
- @Override
- public Entry<K, V> next()
- {
- lastKey = keys.next();
- return new JCSEntry<K, V>(lastKey, get(lastKey));
- }
-
- @Override
- public void remove()
- {
- if (isClosed() || lastKey == null)
- {
- throw new IllegalStateException(isClosed() ? "cache closed" : "call next() before remove()");
- }
- JCSCache.this.remove(lastKey);
- }
- };
- }
-
- @Override
- public String getName()
- {
- assertNotClosed();
- return name;
- }
-
- @Override
- public CacheManager getCacheManager()
- {
- assertNotClosed();
- return manager;
- }
-
- @Override
- public synchronized void close()
- {
- if (isClosed())
- {
- return;
- }
-
- for (final Runnable task : pool.shutdownNow()) {
- task.run();
- }
-
- manager.release(getName());
- closed = true;
- close(loader);
- close(writer);
- close(expiryPolicy);
- for (final JCSListener<K, V> listener : listeners.values())
- {
- close(listener);
- }
- listeners.clear();
- JMXs.unregister(cacheConfigObjectName);
- JMXs.unregister(cacheStatsObjectName);
- try
- {
- delegate.removeAll();
- }
- catch (final IOException e)
- {
- throw new CacheException(e);
- }
- }
-
- private static void close(final Object potentiallyCloseable)
- {
- if (Closeable.class.isInstance(potentiallyCloseable))
- {
- Closeable.class.cast(potentiallyCloseable);
- }
- }
-
- @Override
- public boolean isClosed()
- {
- return closed;
- }
-
- @Override
- public <T> T unwrap(final Class<T> clazz)
- {
- assertNotClosed();
- if (clazz.isInstance(this))
- {
- return clazz.cast(this);
- }
- if (clazz.isAssignableFrom(Map.class) || clazz.isAssignableFrom(ConcurrentMap.class))
- {
- return clazz.cast(delegate);
- }
- throw new IllegalArgumentException(clazz.getName() + " not supported in unwrap");
- }
-
- public Statistics getStatistics()
- {
- return statistics;
- }
-
- public void enableManagement()
- {
- config.managementEnabled();
- JMXs.register(cacheConfigObjectName, new JCSCacheMXBean<K, V>(this));
- }
-
- public void disableManagement()
- {
- config.managementDisabled();
- JMXs.unregister(cacheConfigObjectName);
- }
-
- public void enableStatistics()
- {
- config.statisticsEnabled();
- statistics.setActive(true);
- JMXs.register(cacheStatsObjectName, new JCSCacheStatisticsMXBean(statistics));
- }
-
- public void disableStatistics()
- {
- config.statisticsDisabled();
- statistics.setActive(false);
- JMXs.unregister(cacheStatsObjectName);
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSCacheEntryEvent.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSCacheEntryEvent.java
deleted file mode 100644
index 54a6f87..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSCacheEntryEvent.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import javax.cache.Cache;
-import javax.cache.event.CacheEntryEvent;
-import javax.cache.event.EventType;
-
-public class JCSCacheEntryEvent<K, V> extends CacheEntryEvent<K, V>
-{
- /** Serial version */
- private static final long serialVersionUID = 4761272981003897488L;
-
- private final V old;
- private final K key;
- private final V value;
-
- public JCSCacheEntryEvent(final Cache<K, V> source, final EventType eventType, final V old, final K key, final V value)
- {
- super(source, eventType);
- this.old = old;
- this.key = key;
- this.value = value;
- }
-
- @Override
- public V getOldValue()
- {
- return old;
- }
-
- @Override
- public boolean isOldValueAvailable()
- {
- return old != null;
- }
-
- @Override
- public K getKey()
- {
- return key;
- }
-
- @Override
- public V getValue()
- {
- return value;
- }
-
- @Override
- public <T> T unwrap(final Class<T> clazz)
- {
- if (clazz.isInstance(this))
- {
- return clazz.cast(this);
- }
- throw new IllegalArgumentException(clazz.getName() + " not supported in unwrap");
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSCachingManager.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSCachingManager.java
deleted file mode 100644
index c764eb3..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSCachingManager.java
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
-import org.apache.commons.jcs.engine.behavior.IElementAttributes;
-import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.control.CompositeCacheConfigurator;
-import org.apache.commons.jcs.engine.control.CompositeCacheManager;
-import org.apache.commons.jcs.jcache.lang.Subsitutor;
-import org.apache.commons.jcs.jcache.proxy.ClassLoaderAwareCache;
-
-import javax.cache.Cache;
-import javax.cache.CacheManager;
-import javax.cache.configuration.Configuration;
-import javax.cache.spi.CachingProvider;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.Map;
-import java.util.Properties;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import static org.apache.commons.jcs.jcache.Asserts.assertNotNull;
-
-public class JCSCachingManager implements CacheManager
-{
- private static final Subsitutor SUBSTITUTOR = Subsitutor.Helper.INSTANCE;
- private static final String DEFAULT_CONFIG =
- "jcs.default=DC\n" +
- "jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes\n" +
- "jcs.default.cacheattributes.MaxObjects=200001\n" +
- "jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache\n" +
- "jcs.default.cacheattributes.UseMemoryShrinker=true\n" +
- "jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600\n" +
- "jcs.default.cacheattributes.ShrinkerIntervalSeconds=60\n" +
- "jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes\n" +
- "jcs.default.elementattributes.IsEternal=false\n" +
- "jcs.default.elementattributes.MaxLife=700\n" +
- "jcs.default.elementattributes.IdleTime=1800\n" +
- "jcs.default.elementattributes.IsSpool=true\n" +
- "jcs.default.elementattributes.IsRemote=true\n" +
- "jcs.default.elementattributes.IsLateral=true\n";
-
- private static class InternalManager extends CompositeCacheManager
- {
- protected static InternalManager create()
- {
- return new InternalManager();
- }
-
- protected CompositeCacheConfigurator newConfigurator()
- {
- return new CompositeCacheConfigurator()
- {
- @Override
- protected <K, V> CompositeCache<K, V> newCache(
- final ICompositeCacheAttributes cca, final IElementAttributes ea)
- {
- return new ExpiryAwareCache<K, V>( cca, ea );
- }
- };
- }
-
- @Override // needed to call it from JCSCachingManager
- protected void initialize() {
- super.initialize();
- }
- }
-
- private final CachingProvider provider;
- private final URI uri;
- private final ClassLoader loader;
- private final Properties properties;
- private final ConcurrentMap<String, Cache<?, ?>> caches = new ConcurrentHashMap<String, Cache<?, ?>>();
- private final Properties configProperties;
- private volatile boolean closed = false;
- private InternalManager delegate = InternalManager.create();
-
- public JCSCachingManager(final CachingProvider provider, final URI uri, final ClassLoader loader, final Properties properties)
- {
- this.provider = provider;
- this.uri = uri;
- this.loader = loader;
- this.properties = readConfig(uri, loader, properties);
- this.configProperties = properties;
-
- delegate.setJmxName(CompositeCacheManager.JMX_OBJECT_NAME
- + ",provider=" + provider.hashCode()
- + ",uri=" + uri.toString().replaceAll(",|:|=|\n", ".")
- + ",classloader=" + loader.hashCode()
- + ",properties=" + this.properties.hashCode());
- delegate.initialize();
- delegate.configure(this.properties);
- }
-
- private Properties readConfig(final URI uri, final ClassLoader loader, final Properties properties) {
- final Properties props = new Properties();
- try {
- if (JCSCachingProvider.DEFAULT_URI.toString().equals(uri.toString()) || uri.toURL().getProtocol().equals("jcs"))
- {
-
- final Enumeration<URL> resources = loader.getResources(uri.getPath());
- if (!resources.hasMoreElements()) // default
- {
- props.load(new ByteArrayInputStream(DEFAULT_CONFIG.getBytes("UTF-8")));
- }
- else
- {
- do
- {
- addProperties(resources.nextElement(), props);
- }
- while (resources.hasMoreElements());
- }
- }
- else
- {
- props.load(uri.toURL().openStream());
- }
- } catch (final IOException e) {
- throw new IllegalStateException(e);
- }
-
- if (properties != null)
- {
- props.putAll(properties);
- }
-
- for (final Map.Entry<Object, Object> entry : props.entrySet()) {
- if (entry.getValue() == null)
- {
- continue;
- }
- final String substitute = SUBSTITUTOR.substitute(entry.getValue().toString());
- if (!substitute.equals(entry.getValue()))
- {
- entry.setValue(substitute);
- }
- }
- return props;
- }
-
- private void addProperties(final URL url, final Properties aggregator)
- {
- InputStream inStream = null;
- try
- {
- inStream = url.openStream();
- aggregator.load(inStream);
- }
- catch (final IOException e)
- {
- throw new IllegalArgumentException(e);
- }
- finally
- {
- if (inStream != null)
- {
- try
- {
- inStream.close();
- }
- catch (final IOException e)
- {
- // no-op
- }
- }
- }
- }
-
- private void assertNotClosed()
- {
- if (isClosed())
- {
- throw new IllegalStateException("cache manager closed");
- }
- }
-
- @Override
- // TODO: use configuration + handle not serializable key/values
- public <K, V, C extends Configuration<K, V>> Cache<K, V> createCache(final String cacheName, final C configuration)
- throws IllegalArgumentException
- {
- assertNotClosed();
- assertNotNull(cacheName, "cacheName");
- assertNotNull(configuration, "configuration");
- final Class<?> keyType = configuration == null ? Object.class : configuration.getKeyType();
- final Class<?> valueType = configuration == null ? Object.class : configuration.getValueType();
- if (!caches.containsKey(cacheName))
- {
- final Cache<K, V> cache = ClassLoaderAwareCache.wrap(loader,
- new JCSCache/*<K, V>*/(
- loader, this, cacheName,
- new JCSConfiguration/*<K, V>*/(configuration, keyType, valueType),
- properties,
- ExpiryAwareCache.class.cast(delegate.getCache(cacheName))));
- caches.putIfAbsent(cacheName, cache);
- }
- else
- {
- throw new javax.cache.CacheException("cache " + cacheName + " already exists");
- }
- return (Cache<K, V>) getCache(cacheName, keyType, valueType);
- }
-
- @Override
- public void destroyCache(final String cacheName)
- {
- assertNotClosed();
- assertNotNull(cacheName, "cacheName");
- final Cache<?, ?> cache = caches.remove(cacheName);
- if (cache != null && !cache.isClosed())
- {
- cache.clear();
- cache.close();
- }
- }
-
- @Override
- public void enableManagement(final String cacheName, final boolean enabled)
- {
- assertNotClosed();
- assertNotNull(cacheName, "cacheName");
- final JCSCache<?, ?> cache = getJCSCache(cacheName);
- if (cache != null)
- {
- if (enabled)
- {
- cache.enableManagement();
- }
- else
- {
- cache.disableManagement();
- }
- }
- }
-
- private JCSCache<?, ?> getJCSCache(final String cacheName)
- {
- final Cache<?, ?> cache = caches.get(cacheName);
- return JCSCache.class.cast(ClassLoaderAwareCache.getDelegate(cache));
- }
-
- @Override
- public void enableStatistics(final String cacheName, final boolean enabled)
- {
- assertNotClosed();
- assertNotNull(cacheName, "cacheName");
- final JCSCache<?, ?> cache = getJCSCache(cacheName);
- if (cache != null)
- {
- if (enabled)
- {
- cache.enableStatistics();
- }
- else
- {
- cache.disableStatistics();
- }
- }
- }
-
- @Override
- public synchronized void close()
- {
- if (isClosed())
- {
- return;
- }
-
- assertNotClosed();
- for (final Cache<?, ?> c : caches.values())
- {
- c.close();
- }
- caches.clear();
- closed = true;
- if (JCSCachingProvider.class.isInstance(provider))
- {
- JCSCachingProvider.class.cast(provider).remove(this);
- }
- delegate.shutDown();
- }
-
- @Override
- public <T> T unwrap(final Class<T> clazz)
- {
- if (clazz.isInstance(this))
- {
- return clazz.cast(this);
- }
- throw new IllegalArgumentException(clazz.getName() + " not supported in unwrap");
- }
-
- @Override
- public boolean isClosed()
- {
- return closed;
- }
-
- @Override
- public <K, V> Cache<K, V> getCache(final String cacheName)
- {
- assertNotClosed();
- assertNotNull(cacheName, "cacheName");
- return (Cache<K, V>) doGetCache(cacheName, Object.class, Object.class);
- }
-
- @Override
- public Iterable<String> getCacheNames()
- {
- return new ImmutableIterable<String>(caches.keySet());
- }
-
- @Override
- public <K, V> Cache<K, V> getCache(final String cacheName, final Class<K> keyType, final Class<V> valueType)
- {
- assertNotClosed();
- assertNotNull(cacheName, "cacheName");
- assertNotNull(keyType, "keyType");
- assertNotNull(valueType, "valueType");
- try
- {
- return doGetCache(cacheName, keyType, valueType);
- }
- catch (final IllegalArgumentException iae)
- {
- throw new ClassCastException(iae.getMessage());
- }
- }
-
- private <K, V> Cache<K, V> doGetCache(final String cacheName, final Class<K> keyType, final Class<V> valueType)
- {
- final Cache<K, V> cache = (Cache<K, V>) caches.get(cacheName);
- if (cache == null)
- {
- return null;
- }
-
- final Configuration<K, V> config = cache.getConfiguration(Configuration.class);
- if ((keyType != null && !config.getKeyType().isAssignableFrom(keyType))
- || (valueType != null && !config.getValueType().isAssignableFrom(valueType)))
- {
- throw new IllegalArgumentException("this cache is <" + config.getKeyType().getName() + ", " + config.getValueType().getName()
- + "> " + " and not <" + keyType.getName() + ", " + valueType.getName() + ">");
- }
- return cache;
- }
-
- @Override
- public CachingProvider getCachingProvider()
- {
- return provider;
- }
-
- @Override
- public URI getURI()
- {
- return uri;
- }
-
- @Override
- public ClassLoader getClassLoader()
- {
- return loader;
- }
-
- @Override
- public Properties getProperties()
- {
- return configProperties;
- }
-
- public void release(final String name) {
- caches.remove(name);
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSCachingProvider.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSCachingProvider.java
deleted file mode 100644
index 128de3a..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSCachingProvider.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import javax.cache.CacheManager;
-import javax.cache.configuration.OptionalFeature;
-import javax.cache.spi.CachingProvider;
-import java.net.URI;
-import java.util.Map;
-import java.util.Properties;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-public class JCSCachingProvider implements CachingProvider
-{
- public static final URI DEFAULT_URI = URI.create("jcs://jcache.ccf");
-
- private final ConcurrentMap<ClassLoader, ConcurrentMap<URI, CacheManager>> cacheManagersByLoader = new ConcurrentHashMap<ClassLoader, ConcurrentMap<URI, CacheManager>>();
-
- @Override
- public CacheManager getCacheManager(final URI inUri, final ClassLoader inClassLoader, final Properties properties)
- {
- final URI uri = inUri != null ? inUri : getDefaultURI();
- final ClassLoader classLoader = inClassLoader != null ? inClassLoader : getDefaultClassLoader();
-
- ConcurrentMap<URI, CacheManager> managers = cacheManagersByLoader.get(classLoader);
- if (managers == null)
- {
- managers = new ConcurrentHashMap<URI, CacheManager>();
- final ConcurrentMap<URI, CacheManager> existingManagers = cacheManagersByLoader.putIfAbsent(classLoader, managers);
- if (existingManagers != null)
- {
- managers = existingManagers;
- }
- }
-
- CacheManager mgr = managers.get(uri);
- if (mgr == null)
- {
- mgr = new JCSCachingManager(this, uri, classLoader, properties);
- final CacheManager existing = managers.putIfAbsent(uri, mgr);
- if (existing != null)
- {
- mgr = existing;
- }
- }
-
- return mgr;
- }
-
- @Override
- public URI getDefaultURI()
- {
- return DEFAULT_URI;
- }
-
- @Override
- public void close()
- {
- for (final Map<URI, CacheManager> v : cacheManagersByLoader.values())
- {
- for (final CacheManager m : v.values())
- {
- m.close();
- }
- v.clear();
- }
- cacheManagersByLoader.clear();
- }
-
- @Override
- public void close(final ClassLoader classLoader)
- {
- final Map<URI, CacheManager> cacheManagers = cacheManagersByLoader.remove(classLoader);
- if (cacheManagers != null)
- {
- for (final CacheManager mgr : cacheManagers.values())
- {
- mgr.close();
- }
- cacheManagers.clear();
- }
- }
-
- @Override
- public void close(final URI uri, final ClassLoader classLoader)
- {
- final Map<URI, CacheManager> cacheManagers = cacheManagersByLoader.remove(classLoader);
- if (cacheManagers != null)
- {
- final CacheManager mgr = cacheManagers.remove(uri);
- if (mgr != null)
- {
- mgr.close();
- }
- }
- }
-
- @Override
- public CacheManager getCacheManager(final URI uri, final ClassLoader classLoader)
- {
- return getCacheManager(uri, classLoader, getDefaultProperties());
- }
-
- @Override
- public CacheManager getCacheManager()
- {
- return getCacheManager(getDefaultURI(), getDefaultClassLoader());
- }
-
- @Override
- public boolean isSupported(final OptionalFeature optionalFeature)
- {
- return optionalFeature == OptionalFeature.STORE_BY_REFERENCE;
- }
-
- @Override
- public ClassLoader getDefaultClassLoader()
- {
- return JCSCachingProvider.class.getClassLoader();
- }
-
- @Override
- public Properties getDefaultProperties()
- {
- return new Properties();
- }
-
- void remove(final CacheManager mgr)
- {
- final ClassLoader classLoader = mgr.getClassLoader();
- final Map<URI, CacheManager> mgrs = cacheManagersByLoader.get(classLoader);
- if (mgrs != null)
- {
- mgrs.remove(mgr.getURI());
- if (mgrs.isEmpty())
- {
- cacheManagersByLoader.remove(classLoader);
- }
- }
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSConfiguration.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSConfiguration.java
deleted file mode 100644
index 9dffdba..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSConfiguration.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * 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.
- */
-/**
- * Copyright 2003-2010 Terracotta, Inc.
- *
- * Licensed 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.apache.commons.jcs.jcache;
-
-import javax.cache.configuration.CacheEntryListenerConfiguration;
-import javax.cache.configuration.CompleteConfiguration;
-import javax.cache.configuration.Configuration;
-import javax.cache.configuration.Factory;
-import javax.cache.expiry.EternalExpiryPolicy;
-import javax.cache.expiry.ExpiryPolicy;
-import javax.cache.integration.CacheLoader;
-import javax.cache.integration.CacheWriter;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-public class JCSConfiguration<K, V> implements CompleteConfiguration<K, V>
-{
-
- private final Class<K> keyType;
- private final Class<V> valueType;
- private final boolean storeByValue;
- private final boolean readThrough;
- private final boolean writeThrough;
- private final Factory<CacheLoader<K, V>> cacheLoaderFactory;
- private final Factory<CacheWriter<? super K, ? super V>> cacheWristerFactory;
- private final Factory<ExpiryPolicy> expiryPolicyFactory;
- private final Set<CacheEntryListenerConfiguration<K, V>> cacheEntryListenerConfigurations;
-
- private volatile boolean statisticsEnabled;
- private volatile boolean managementEnabled;
-
- public JCSConfiguration(final Configuration<K, V> configuration, final Class<K> keyType, final Class<V> valueType)
- {
- this.keyType = keyType;
- this.valueType = valueType;
- if (configuration instanceof CompleteConfiguration)
- {
- final CompleteConfiguration<K, V> cConfiguration = (CompleteConfiguration<K, V>) configuration;
- storeByValue = configuration.isStoreByValue();
- readThrough = cConfiguration.isReadThrough();
- writeThrough = cConfiguration.isWriteThrough();
- statisticsEnabled = cConfiguration.isStatisticsEnabled();
- managementEnabled = cConfiguration.isManagementEnabled();
- cacheLoaderFactory = cConfiguration.getCacheLoaderFactory();
- cacheWristerFactory = cConfiguration.getCacheWriterFactory();
- this.expiryPolicyFactory = cConfiguration.getExpiryPolicyFactory();
- cacheEntryListenerConfigurations = new HashSet<CacheEntryListenerConfiguration<K, V>>();
-
- final Iterable<CacheEntryListenerConfiguration<K, V>> entryListenerConfigurations = cConfiguration
- .getCacheEntryListenerConfigurations();
- if (entryListenerConfigurations != null)
- {
- for (final CacheEntryListenerConfiguration<K, V> kvCacheEntryListenerConfiguration : entryListenerConfigurations)
- {
- cacheEntryListenerConfigurations.add(kvCacheEntryListenerConfiguration);
- }
- }
- }
- else
- {
- expiryPolicyFactory = EternalExpiryPolicy.factoryOf();
- storeByValue = true;
- readThrough = false;
- writeThrough = false;
- statisticsEnabled = false;
- managementEnabled = false;
- cacheLoaderFactory = null;
- cacheWristerFactory = null;
- cacheEntryListenerConfigurations = new HashSet<CacheEntryListenerConfiguration<K, V>>();
- }
- }
-
- @Override
- public Class<K> getKeyType()
- {
- return keyType == null ? (Class<K>) Object.class : keyType;
- }
-
- @Override
- public Class<V> getValueType()
- {
- return valueType == null ? (Class<V>) Object.class : valueType;
- }
-
- @Override
- public boolean isStoreByValue()
- {
- return storeByValue;
- }
-
- @Override
- public boolean isReadThrough()
- {
- return readThrough;
- }
-
- @Override
- public boolean isWriteThrough()
- {
- return writeThrough;
- }
-
- @Override
- public boolean isStatisticsEnabled()
- {
- return statisticsEnabled;
- }
-
- @Override
- public boolean isManagementEnabled()
- {
- return managementEnabled;
- }
-
- @Override
- public Iterable<CacheEntryListenerConfiguration<K, V>> getCacheEntryListenerConfigurations()
- {
- return Collections.unmodifiableSet(cacheEntryListenerConfigurations);
- }
-
- @Override
- public Factory<CacheLoader<K, V>> getCacheLoaderFactory()
- {
- return cacheLoaderFactory;
- }
-
- @Override
- public Factory<CacheWriter<? super K, ? super V>> getCacheWriterFactory()
- {
- return cacheWristerFactory;
- }
-
- @Override
- public Factory<ExpiryPolicy> getExpiryPolicyFactory()
- {
- return expiryPolicyFactory;
- }
-
- public synchronized void addListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
- {
- cacheEntryListenerConfigurations.add(cacheEntryListenerConfiguration);
- }
-
- public synchronized void removeListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
- {
- cacheEntryListenerConfigurations.remove(cacheEntryListenerConfiguration);
- }
-
- public void statisticsEnabled()
- {
- statisticsEnabled = true;
- }
-
- public void managementEnabled()
- {
- managementEnabled = true;
- }
-
- public void statisticsDisabled()
- {
- statisticsEnabled = false;
- }
-
- public void managementDisabled()
- {
- managementEnabled = false;
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSEntry.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSEntry.java
deleted file mode 100644
index b0382ac..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSEntry.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import javax.cache.Cache;
-
-public class JCSEntry<K, V> implements Cache.Entry<K, V>
-{
- private final K key;
- private final V value;
-
- public JCSEntry(final K key, final V value)
- {
- this.key = key;
- this.value = value;
- }
-
- @Override
- public K getKey()
- {
- return key;
- }
-
- @Override
- public V getValue()
- {
- return value;
- }
-
- @Override
- public <T> T unwrap(final Class<T> clazz)
- {
- if (clazz.isInstance(this))
- {
- return clazz.cast(this);
- }
- throw new UnsupportedOperationException();
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSListener.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSListener.java
deleted file mode 100644
index 930a533..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSListener.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import javax.cache.configuration.CacheEntryListenerConfiguration;
-import javax.cache.configuration.Factory;
-import javax.cache.event.CacheEntryCreatedListener;
-import javax.cache.event.CacheEntryEvent;
-import javax.cache.event.CacheEntryEventFilter;
-import javax.cache.event.CacheEntryExpiredListener;
-import javax.cache.event.CacheEntryListener;
-import javax.cache.event.CacheEntryListenerException;
-import javax.cache.event.CacheEntryRemovedListener;
-import javax.cache.event.CacheEntryUpdatedListener;
-import java.io.Closeable;
-import java.util.ArrayList;
-import java.util.List;
-
-public class JCSListener<K, V> implements Closeable
-{
- private final boolean oldValue;
- private final boolean synchronous;
- private final CacheEntryEventFilter<? super K, ? super V> filter;
- private final CacheEntryListener<? super K, ? super V> delegate;
- private final boolean remove;
- private final boolean expire;
- private final boolean update;
- private final boolean create;
-
- public JCSListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
- {
- oldValue = cacheEntryListenerConfiguration.isOldValueRequired();
- synchronous = cacheEntryListenerConfiguration.isSynchronous();
-
- final Factory<CacheEntryEventFilter<? super K, ? super V>> filterFactory = cacheEntryListenerConfiguration
- .getCacheEntryEventFilterFactory();
- if (filterFactory == null)
- {
- filter = NoFilter.INSTANCE;
- }
- else
- {
- filter = filterFactory.create();
- }
-
- delegate = cacheEntryListenerConfiguration.getCacheEntryListenerFactory().create();
- remove = CacheEntryRemovedListener.class.isInstance(delegate);
- expire = CacheEntryExpiredListener.class.isInstance(delegate);
- update = CacheEntryUpdatedListener.class.isInstance(delegate);
- create = CacheEntryCreatedListener.class.isInstance(delegate);
- }
-
- public void onRemoved(final List<CacheEntryEvent<? extends K, ? extends V>> events) throws CacheEntryListenerException
- {
- if (remove)
- {
- CacheEntryRemovedListener.class.cast(delegate).onRemoved(filter(events));
- }
- }
-
- public void onExpired(final List<CacheEntryEvent<? extends K, ? extends V>> events) throws CacheEntryListenerException
- {
- if (expire)
- {
- CacheEntryExpiredListener.class.cast(delegate).onExpired(filter(events));
- }
- }
-
- public void onUpdated(final List<CacheEntryEvent<? extends K, ? extends V>> events) throws CacheEntryListenerException
- {
- if (update)
- {
- CacheEntryUpdatedListener.class.cast(delegate).onUpdated(filter(events));
- }
- }
-
- public void onCreated(final List<CacheEntryEvent<? extends K, ? extends V>> events) throws CacheEntryListenerException
- {
- if (create)
- {
- CacheEntryCreatedListener.class.cast(delegate).onCreated(filter(events));
- }
- }
-
- private Iterable<CacheEntryEvent<? extends K, ? extends V>> filter(final List<CacheEntryEvent<? extends K, ? extends V>> events)
- {
- if (filter == NoFilter.INSTANCE)
- {
- return events;
- }
-
- final List<CacheEntryEvent<? extends K, ? extends V>> filtered = new ArrayList<CacheEntryEvent<? extends K, ? extends V>>(
- events.size());
- for (final CacheEntryEvent<? extends K, ? extends V> event : events)
- {
- if (filter.evaluate(event))
- {
- filtered.add(event);
- }
- }
- return filtered;
- }
-
- @Override
- public void close()
- {
- if (Closeable.class.isInstance(delegate)) {
- Closeable.class.cast(delegate);
- }
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSMutableEntry.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSMutableEntry.java
deleted file mode 100644
index a90ae85..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/JCSMutableEntry.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import javax.cache.Cache;
-import javax.cache.processor.MutableEntry;
-
-public class JCSMutableEntry<K, V> implements MutableEntry<K, V>
-{
- private final Cache<K, V> cache;
- private final K key;
-
- public JCSMutableEntry(final Cache<K, V> cache, final K key)
- {
- this.cache = cache;
- this.key = key;
- }
-
- @Override
- public boolean exists()
- {
- return cache.containsKey(key);
- }
-
- @Override
- public void remove()
- {
- cache.remove(key);
- }
-
- @Override
- public void setValue(final V value)
- {
- cache.put(key, value);
- }
-
- @Override
- public K getKey()
- {
- return key;
- }
-
- @Override
- public V getValue()
- {
- return cache.get(key);
- }
-
- @Override
- public <T> T unwrap(final Class<T> clazz)
- {
- if (clazz.isInstance(this))
- {
- return clazz.cast(this);
- }
- throw new IllegalArgumentException(clazz.getName() + " not supported in unwrap");
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/NoFilter.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/NoFilter.java
deleted file mode 100644
index 3315992..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/NoFilter.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import javax.cache.event.CacheEntryEvent;
-import javax.cache.event.CacheEntryEventFilter;
-import javax.cache.event.CacheEntryListenerException;
-
-public class NoFilter implements CacheEntryEventFilter<Object, Object>
-{
- public static final CacheEntryEventFilter<Object, Object> INSTANCE = new NoFilter();
-
- private NoFilter()
- {
- // no-op
- }
-
- @Override
- public boolean evaluate(final CacheEntryEvent<?, ?> event) throws CacheEntryListenerException
- {
- return true;
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/NoLoader.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/NoLoader.java
deleted file mode 100644
index 740cac1..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/NoLoader.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import javax.cache.integration.CacheLoader;
-import javax.cache.integration.CacheLoaderException;
-import java.util.HashMap;
-import java.util.Map;
-
-public class NoLoader<K, V> implements CacheLoader<K, V>
-{
- public static final NoLoader INSTANCE = new NoLoader();
-
- private NoLoader()
- {
- // no-op
- }
-
- @Override
- public V load(K key) throws CacheLoaderException
- {
- return null;
- }
-
- @Override
- public Map<K, V> loadAll(final Iterable<? extends K> keys) throws CacheLoaderException
- {
- final Map<K, V> entries = new HashMap<K, V>();
- for (final K k : keys)
- {
- entries.put(k, null);
- }
- return entries;
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/NoWriter.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/NoWriter.java
deleted file mode 100644
index 8aeba89..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/NoWriter.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import javax.cache.Cache;
-import javax.cache.integration.CacheWriter;
-import javax.cache.integration.CacheWriterException;
-import java.util.Collection;
-
-public class NoWriter<K, V> implements CacheWriter<K, V>
-{
- public static final NoWriter INSTANCE = new NoWriter();
-
- @Override
- public void write(final Cache.Entry<? extends K, ? extends V> entry) throws CacheWriterException
- {
- // no-op
- }
-
- @Override
- public void delete(final Object key) throws CacheWriterException
- {
- // no-op
- }
-
- @Override
- public void writeAll(final Collection<Cache.Entry<? extends K, ? extends V>> entries) throws CacheWriterException
- {
- for (final Cache.Entry<? extends K, ? extends V> entry : entries)
- {
- write(entry);
- }
- }
-
- @Override
- public void deleteAll(final Collection<?> keys) throws CacheWriterException
- {
- for (final Object k : keys)
- {
- delete(k);
- }
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/Statistics.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/Statistics.java
deleted file mode 100644
index 61ec0e9..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/Statistics.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import java.util.concurrent.atomic.AtomicLong;
-
-public class Statistics
-{
- private volatile boolean active = true;
-
- private final AtomicLong removals = new AtomicLong();
- private final AtomicLong expiries = new AtomicLong();
- private final AtomicLong puts = new AtomicLong();
- private final AtomicLong hits = new AtomicLong();
- private final AtomicLong misses = new AtomicLong();
- private final AtomicLong evictions = new AtomicLong();
- private final AtomicLong putTimeTaken = new AtomicLong();
- private final AtomicLong getTimeTaken = new AtomicLong();
- private final AtomicLong removeTimeTaken = new AtomicLong();
-
- public long getHits()
- {
- return hits.get();
- }
-
- public long getMisses()
- {
- return misses.get();
- }
-
- public long getPuts()
- {
- return puts.get();
- }
-
- public long getRemovals()
- {
- return removals.get();
- }
-
- public long getEvictions()
- {
- return evictions.get();
- }
-
- public long getTimeTakenForGets()
- {
- return getTimeTaken.get();
- }
-
- public long getTimeTakenForPuts()
- {
- return putTimeTaken.get();
- }
-
- public long getTimeTakenForRemovals()
- {
- return removeTimeTaken.get();
- }
-
- public void increaseRemovals(final long number)
- {
- increment(removals, number);
- }
-
- public void increaseExpiries(final long number)
- {
- increment(expiries, number);
- }
-
- public void increasePuts(final long number)
- {
- increment(puts, number);
- }
-
- public void increaseHits(final long number)
- {
- increment(hits, number);
- }
-
- public void increaseMisses(final long number)
- {
- increment(misses, number);
- }
-
- public void increaseEvictions(final long number)
- {
- increment(evictions, number);
- }
-
- public void addGetTime(final long duration)
- {
- increment(duration, getTimeTaken);
- }
-
- public void addPutTime(final long duration)
- {
- increment(duration, putTimeTaken);
- }
-
- public void addRemoveTime(final long duration)
- {
- increment(duration, removeTimeTaken);
- }
-
- private void increment(final AtomicLong counter, final long number)
- {
- if (!active)
- {
- return;
- }
- counter.addAndGet(number);
- }
-
- private void increment(final long duration, final AtomicLong counter)
- {
- if (!active)
- {
- return;
- }
-
- if (counter.get() < Long.MAX_VALUE - duration)
- {
- counter.addAndGet(duration);
- }
- else
- {
- reset();
- counter.set(duration);
- }
- }
-
- public void reset()
- {
- puts.set(0);
- misses.set(0);
- removals.set(0);
- expiries.set(0);
- hits.set(0);
- evictions.set(0);
- getTimeTaken.set(0);
- putTimeTaken.set(0);
- removeTimeTaken.set(0);
- }
-
- public void setActive(final boolean active)
- {
- this.active = active;
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/TempStateCacheView.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/TempStateCacheView.java
deleted file mode 100644
index 0b8db82..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/TempStateCacheView.java
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import javax.cache.Cache;
-import javax.cache.CacheManager;
-import javax.cache.configuration.CacheEntryListenerConfiguration;
-import javax.cache.configuration.CompleteConfiguration;
-import javax.cache.configuration.Configuration;
-import javax.cache.integration.CompletionListener;
-import javax.cache.processor.EntryProcessor;
-import javax.cache.processor.EntryProcessorException;
-import javax.cache.processor.EntryProcessorResult;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.Set;
-
-import static org.apache.commons.jcs.jcache.Asserts.assertNotNull;
-
-// kind of transactional view for a Cache<K, V>, to use with EntryProcessor
-public class TempStateCacheView<K, V> implements Cache<K, V>
-{
- private final JCSCache<K, V> cache;
- private final Map<K, V> put = new HashMap<K, V>();
- private final Collection<K> remove = new LinkedList<K>();
- private boolean removeAll = false;
- private boolean clear = false;
-
- public TempStateCacheView(final JCSCache<K, V> entries)
- {
- this.cache = entries;
- }
-
- public V get(final K key)
- {
- if (ignoreKey(key))
- {
- return null;
- }
-
- final V v = put.get(key);
- if (v != null)
- {
- return v;
- }
-
- // for an EntryProcessor we already incremented stats - to enhance
- // surely
- if (cache.getConfiguration(CompleteConfiguration.class).isStatisticsEnabled())
- {
- final Statistics statistics = cache.getStatistics();
- if (cache.containsKey(key))
- {
- statistics.increaseHits(-1);
- }
- else
- {
- statistics.increaseMisses(-1);
- }
- }
- return cache.get(key);
- }
-
- private boolean ignoreKey(final K key)
- {
- return removeAll || clear || remove.contains(key);
- }
-
- public Map<K, V> getAll(final Set<? extends K> keys)
- {
- final Map<K, V> v = new HashMap<K, V>(keys.size());
- final Set<K> missing = new HashSet<K>();
- for (final K k : keys)
- {
- final V value = put.get(k);
- if (value != null)
- {
- v.put(k, value);
- }
- else if (!ignoreKey(k))
- {
- missing.add(k);
- }
- }
- if (!missing.isEmpty())
- {
- v.putAll(cache.getAll(missing));
- }
- return v;
- }
-
- public boolean containsKey(final K key)
- {
- return !ignoreKey(key) && (put.containsKey(key) || cache.containsKey(key));
- }
-
- public void loadAll(final Set<? extends K> keys, final boolean replaceExistingValues, final CompletionListener completionListener)
- {
- cache.loadAll(keys, replaceExistingValues, completionListener);
- }
-
- public void put(final K key, final V value)
- {
- assertNotNull(key, "key");
- assertNotNull(value, "value");
- put.put(key, value);
- remove.remove(key);
- }
-
- public V getAndPut(final K key, final V value)
- {
- final V v = get(key);
- put(key, value);
- return v;
- }
-
- public void putAll(final Map<? extends K, ? extends V> map)
- {
- put.putAll(map);
- for (final K k : map.keySet())
- {
- remove.remove(k);
- }
- }
-
- public boolean putIfAbsent(final K key, final V value)
- {
- if (!put.containsKey(key))
- {
- put.put(key, value);
- remove.remove(key);
- return true;
- }
- return false;
- }
-
- public boolean remove(final K key)
- {
- final boolean noop = put.containsKey(key);
- put.remove(key);
- if (!ignoreKey(key))
- {
- if (!noop)
- {
- remove.add(key);
- }
- return true;
- }
- return false;
- }
-
- public boolean remove(final K key, final V oldValue)
- {
- put.remove(key);
- if (!ignoreKey(key) && oldValue.equals(cache.get(key)))
- {
- remove.add(key);
- return true;
- }
- return false;
- }
-
- public V getAndRemove(final K key)
- {
- final V v = get(key);
- remove.add(key);
- put.remove(key);
- return v;
- }
-
- public boolean replace(final K key, final V oldValue, final V newValue)
- {
- if (oldValue.equals(get(key)))
- {
- put(key, newValue);
- return true;
- }
- return false;
- }
-
- public boolean replace(final K key, final V value)
- {
- if (containsKey(key))
- {
- remove(key);
- return true;
- }
- return false;
- }
-
- public V getAndReplace(final K key, final V value)
- {
- if (containsKey(key))
- {
- final V oldValue = get(key);
- put(key, value);
- return oldValue;
- }
- return null;
- }
-
- public void removeAll(final Set<? extends K> keys)
- {
- remove.addAll(keys);
- for (final K k : keys)
- {
- put.remove(k);
- }
- }
-
- @Override
- public void removeAll()
- {
- removeAll = true;
- put.clear();
- remove.clear();
- }
-
- @Override
- public void clear()
- {
- clear = true;
- put.clear();
- remove.clear();
- }
-
- public <C extends Configuration<K, V>> C getConfiguration(final Class<C> clazz)
- {
- return cache.getConfiguration(clazz);
- }
-
- public <T> T invoke(final K key, final EntryProcessor<K, V, T> entryProcessor, final Object... arguments) throws EntryProcessorException
- {
- return cache.invoke(key, entryProcessor, arguments);
- }
-
- public <T> Map<K, EntryProcessorResult<T>> invokeAll(Set<? extends K> keys, final EntryProcessor<K, V, T> entryProcessor,
- final Object... arguments)
- {
- return cache.invokeAll(keys, entryProcessor, arguments);
- }
-
- @Override
- public String getName()
- {
- return cache.getName();
- }
-
- @Override
- public CacheManager getCacheManager()
- {
- return cache.getCacheManager();
- }
-
- @Override
- public void close()
- {
- cache.close();
- }
-
- @Override
- public boolean isClosed()
- {
- return cache.isClosed();
- }
-
- @Override
- public <T> T unwrap(final Class<T> clazz)
- {
- return cache.unwrap(clazz);
- }
-
- public void registerCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
- {
- cache.registerCacheEntryListener(cacheEntryListenerConfiguration);
- }
-
- public void deregisterCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
- {
- cache.deregisterCacheEntryListener(cacheEntryListenerConfiguration);
- }
-
- @Override
- public Iterator<Entry<K, V>> iterator()
- {
- return cache.iterator();
- }
-
- public void merge()
- {
- if (removeAll)
- {
- cache.removeAll();
- }
- if (clear)
- {
- cache.clear();
- }
-
- for (final Map.Entry<K, V> entry : put.entrySet())
- {
- cache.put(entry.getKey(), entry.getValue());
- }
- put.clear();
- for (final K entry : remove)
- {
- cache.remove(entry);
- }
- remove.clear();
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/Times.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/Times.java
deleted file mode 100644
index 66cd992..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/Times.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.apache.commons.jcs.jcache;
-
-/*
- * 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.
- */
-
-public class Times
-{
- public static long now(final boolean ignore)
- {
- if (ignore)
- {
- return -1;
- }
- return System.nanoTime() / 1000;
- }
-
- private Times()
- {
- // no-op
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CDIJCacheHelper.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CDIJCacheHelper.java
deleted file mode 100644
index 4ec5731..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CDIJCacheHelper.java
+++ /dev/null
@@ -1,670 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.cdi;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.logging.Logger;
-
-import javax.annotation.PreDestroy;
-import javax.cache.annotation.CacheDefaults;
-import javax.cache.annotation.CacheKey;
-import javax.cache.annotation.CacheKeyGenerator;
-import javax.cache.annotation.CachePut;
-import javax.cache.annotation.CacheRemove;
-import javax.cache.annotation.CacheRemoveAll;
-import javax.cache.annotation.CacheResolverFactory;
-import javax.cache.annotation.CacheResult;
-import javax.cache.annotation.CacheValue;
-import javax.enterprise.context.ApplicationScoped;
-import javax.enterprise.context.spi.CreationalContext;
-import javax.enterprise.inject.spi.Bean;
-import javax.enterprise.inject.spi.BeanManager;
-import javax.inject.Inject;
-import javax.interceptor.InvocationContext;
-
-@ApplicationScoped
-public class CDIJCacheHelper
-{
- private static final Logger LOGGER = Logger.getLogger(CDIJCacheHelper.class.getName());
- private static final boolean CLOSE_CACHE = !Boolean.getBoolean("org.apache.commons.jcs.jcache.cdi.skip-close");
-
- private volatile CacheResolverFactoryImpl defaultCacheResolverFactory = null; // lazy to not create any cache if not needed
- private final CacheKeyGeneratorImpl defaultCacheKeyGenerator = new CacheKeyGeneratorImpl();
-
- private final Collection<CreationalContext<?>> toRelease = new ArrayList<CreationalContext<?>>();
- private final ConcurrentMap<MethodKey, MethodMeta> methods = new ConcurrentHashMap<MethodKey, MethodMeta>();
-
- @Inject
- private BeanManager beanManager;
-
- @PreDestroy
- private void release() {
- if (CLOSE_CACHE && defaultCacheResolverFactory != null)
- {
- defaultCacheResolverFactory.release();
- }
- for (final CreationalContext<?> cc : toRelease)
- {
- try
- {
- cc.release();
- }
- catch (final RuntimeException re)
- {
- LOGGER.warning(re.getMessage());
- }
- }
- }
-
- public MethodMeta findMeta(final InvocationContext ic)
- {
- final Method mtd = ic.getMethod();
- final Class<?> refType = findKeyType(ic.getTarget());
- final MethodKey key = new MethodKey(refType, mtd);
- MethodMeta methodMeta = methods.get(key);
- if (methodMeta == null)
- {
- synchronized (this)
- {
- methodMeta = methods.get(key);
- if (methodMeta == null)
- {
- methodMeta = createMeta(ic);
- methods.put(key, methodMeta);
- }
- }
- }
- return methodMeta;
- }
-
- private Class<?> findKeyType(final Object target)
- {
- if (null == target)
- {
- return null;
- }
- return target.getClass();
- }
-
- // it is unlikely we have all annotations but for now we have a single meta model
- private MethodMeta createMeta(final InvocationContext ic)
- {
- final CacheDefaults defaults = findDefaults(ic.getTarget() == null ? null : ic.getTarget()
- .getClass(), ic.getMethod());
-
- final Class<?>[] parameterTypes = ic.getMethod().getParameterTypes();
- final Annotation[][] parameterAnnotations = ic.getMethod().getParameterAnnotations();
- final List<Set<Annotation>> annotations = new ArrayList<Set<Annotation>>();
- for (final Annotation[] parameterAnnotation : parameterAnnotations)
- {
- final Set<Annotation> set = new HashSet<Annotation>(parameterAnnotation.length);
- set.addAll(Arrays.asList(parameterAnnotation));
- annotations.add(set);
- }
-
- final Set<Annotation> mtdAnnotations = new HashSet<Annotation>();
- mtdAnnotations.addAll(Arrays.asList(ic.getMethod().getAnnotations()));
-
- final CacheResult cacheResult = ic.getMethod().getAnnotation(CacheResult.class);
- final String cacheResultCacheResultName = cacheResult == null ? null : defaultName(ic.getMethod(), defaults, cacheResult.cacheName());
- final CacheResolverFactory cacheResultCacheResolverFactory = cacheResult == null ?
- null : cacheResolverFactoryFor(defaults, cacheResult.cacheResolverFactory());
- final CacheKeyGenerator cacheResultCacheKeyGenerator = cacheResult == null ?
- null : cacheKeyGeneratorFor(defaults, cacheResult.cacheKeyGenerator());
-
- final CachePut cachePut = ic.getMethod().getAnnotation(CachePut.class);
- final String cachePutCachePutName = cachePut == null ? null : defaultName(ic.getMethod(), defaults, cachePut.cacheName());
- final CacheResolverFactory cachePutCacheResolverFactory = cachePut == null ?
- null : cacheResolverFactoryFor(defaults, cachePut.cacheResolverFactory());
- final CacheKeyGenerator cachePutCacheKeyGenerator = cachePut == null ?
- null : cacheKeyGeneratorFor(defaults, cachePut.cacheKeyGenerator());
-
- final CacheRemove cacheRemove = ic.getMethod().getAnnotation(CacheRemove.class);
- final String cacheRemoveCacheRemoveName = cacheRemove == null ? null : defaultName(ic.getMethod(), defaults, cacheRemove.cacheName());
- final CacheResolverFactory cacheRemoveCacheResolverFactory = cacheRemove == null ?
- null : cacheResolverFactoryFor(defaults, cacheRemove.cacheResolverFactory());
- final CacheKeyGenerator cacheRemoveCacheKeyGenerator = cacheRemove == null ?
- null : cacheKeyGeneratorFor(defaults, cacheRemove.cacheKeyGenerator());
-
- final CacheRemoveAll cacheRemoveAll = ic.getMethod().getAnnotation(CacheRemoveAll.class);
- final String cacheRemoveAllCacheRemoveAllName = cacheRemoveAll == null ? null : defaultName(ic.getMethod(), defaults, cacheRemoveAll.cacheName());
- final CacheResolverFactory cacheRemoveAllCacheResolverFactory = cacheRemoveAll == null ?
- null : cacheResolverFactoryFor(defaults, cacheRemoveAll.cacheResolverFactory());
-
- return new MethodMeta(
- parameterTypes,
- annotations,
- mtdAnnotations,
- keyParameterIndexes(ic.getMethod()),
- getValueParameter(annotations),
- getKeyParameters(annotations),
- cacheResultCacheResultName,
- cacheResultCacheResolverFactory,
- cacheResultCacheKeyGenerator,
- cacheResult,
- cachePutCachePutName,
- cachePutCacheResolverFactory,
- cachePutCacheKeyGenerator,
- cachePut != null && cachePut.afterInvocation(),
- cachePut,
- cacheRemoveCacheRemoveName,
- cacheRemoveCacheResolverFactory,
- cacheRemoveCacheKeyGenerator,
- cacheRemove != null && cacheRemove.afterInvocation(),
- cacheRemove,
- cacheRemoveAllCacheRemoveAllName,
- cacheRemoveAllCacheResolverFactory,
- cacheRemoveAll != null && cacheRemoveAll.afterInvocation(),
- cacheRemoveAll);
- }
-
- private Integer[] getKeyParameters(final List<Set<Annotation>> annotations)
- {
- final Collection<Integer> list = new ArrayList<Integer>();
- int idx = 0;
- for (final Set<Annotation> set : annotations)
- {
- for (final Annotation a : set)
- {
- if (a.annotationType() == CacheKey.class)
- {
- list.add(idx);
- }
- }
- idx++;
- }
- if (list.isEmpty())
- {
- for (int i = 0; i < annotations.size(); i++)
- {
- list.add(i);
- }
- }
- return list.toArray(new Integer[list.size()]);
- }
-
- private Integer getValueParameter(final List<Set<Annotation>> annotations)
- {
- int idx = 0;
- for (final Set<Annotation> set : annotations)
- {
- for (final Annotation a : set)
- {
- if (a.annotationType() == CacheValue.class)
- {
- return idx;
- }
- }
- }
- return -1;
- }
-
- private String defaultName(final Method method, final CacheDefaults defaults, final String cacheName)
- {
- if (!cacheName.isEmpty())
- {
- return cacheName;
- }
- if (defaults != null)
- {
- final String name = defaults.cacheName();
- if (!name.isEmpty())
- {
- return name;
- }
- }
-
- final StringBuilder name = new StringBuilder(method.getDeclaringClass().getName());
- name.append(".");
- name.append(method.getName());
- name.append("(");
- final Class<?>[] parameterTypes = method.getParameterTypes();
- for (int pIdx = 0; pIdx < parameterTypes.length; pIdx++)
- {
- name.append(parameterTypes[pIdx].getName());
- if ((pIdx + 1) < parameterTypes.length)
- {
- name.append(",");
- }
- }
- name.append(")");
- return name.toString();
- }
-
- private CacheDefaults findDefaults(final Class<?> targetType, final Method method)
- {
- if (Proxy.isProxyClass(targetType)) // target doesnt hold annotations
- {
- final Class<?> api = method.getDeclaringClass();
- for (final Class<?> type : targetType
- .getInterfaces())
- {
- if (!api.isAssignableFrom(type))
- {
- continue;
- }
- return extractDefaults(type);
- }
- }
- return extractDefaults(targetType);
- }
-
- private CacheDefaults extractDefaults(final Class<?> type)
- {
- CacheDefaults annotation = null;
- Class<?> clazz = type;
- while (clazz != null && clazz != Object.class)
- {
- annotation = clazz.getAnnotation(CacheDefaults.class);
- if (annotation != null)
- {
- break;
- }
- clazz = clazz.getSuperclass();
- }
- return annotation;
- }
-
- public boolean isIncluded(final Class<?> aClass, final Class<?>[] in, final Class<?>[] out)
- {
- if (in.length == 0 && out.length == 0)
- {
- return false;
- }
- for (final Class<?> potentialIn : in)
- {
- if (potentialIn.isAssignableFrom(aClass))
- {
- for (final Class<?> potentialOut : out)
- {
- if (potentialOut.isAssignableFrom(aClass))
- {
- return false;
- }
- }
- return true;
- }
- }
- return false;
- }
-
- private CacheKeyGenerator cacheKeyGeneratorFor(final CacheDefaults defaults, final Class<? extends CacheKeyGenerator> cacheKeyGenerator)
- {
- if (!CacheKeyGenerator.class.equals(cacheKeyGenerator))
- {
- return instance(cacheKeyGenerator);
- }
- if (defaults != null)
- {
- final Class<? extends CacheKeyGenerator> defaultCacheKeyGenerator = defaults.cacheKeyGenerator();
- if (!CacheKeyGenerator.class.equals(defaultCacheKeyGenerator))
- {
- return instance(defaultCacheKeyGenerator);
- }
- }
- return defaultCacheKeyGenerator;
- }
-
- private CacheResolverFactory cacheResolverFactoryFor(final CacheDefaults defaults, final Class<? extends CacheResolverFactory> cacheResolverFactory)
- {
- if (!CacheResolverFactory.class.equals(cacheResolverFactory))
- {
- return instance(cacheResolverFactory);
- }
- if (defaults != null)
- {
- final Class<? extends CacheResolverFactory> defaultCacheResolverFactory = defaults.cacheResolverFactory();
- if (!CacheResolverFactory.class.equals(defaultCacheResolverFactory))
- {
- return instance(defaultCacheResolverFactory);
- }
- }
- return defaultCacheResolverFactory();
- }
-
- private <T> T instance(final Class<T> type)
- {
- final Set<Bean<?>> beans = beanManager.getBeans(type);
- if (beans.isEmpty())
- {
- if (CacheKeyGenerator.class == type) {
- return (T) defaultCacheKeyGenerator;
- }
- if (CacheResolverFactory.class == type) {
- return (T) defaultCacheResolverFactory();
- }
- return null;
- }
- final Bean<?> bean = beanManager.resolve(beans);
- final CreationalContext<?> context = beanManager.createCreationalContext(bean);
- final Class<? extends Annotation> scope = bean.getScope();
- final boolean normalScope = beanManager.isNormalScope(scope);
- try
- {
- final Object reference = beanManager.getReference(bean, bean.getBeanClass(), context);
- if (!normalScope)
- {
- toRelease.add(context);
- }
- return (T) reference;
- }
- finally
- {
- if (normalScope)
- { // TODO: release at the right moment, @PreDestroy? question is: do we assume it is thread safe?
- context.release();
- }
- }
- }
-
- private CacheResolverFactoryImpl defaultCacheResolverFactory()
- {
- if (defaultCacheResolverFactory != null) {
- return defaultCacheResolverFactory;
- }
- synchronized (this) {
- if (defaultCacheResolverFactory != null) {
- return defaultCacheResolverFactory;
- }
- defaultCacheResolverFactory = new CacheResolverFactoryImpl();
- }
- return defaultCacheResolverFactory;
- }
-
- private Integer[] keyParameterIndexes(final Method method)
- {
- final List<Integer> keys = new LinkedList<Integer>();
- final Annotation[][] parameterAnnotations = method.getParameterAnnotations();
-
- // first check if keys are specified explicitely
- for (int i = 0; i < method.getParameterTypes().length; i++)
- {
- final Annotation[] annotations = parameterAnnotations[i];
- for (final Annotation a : annotations)
- {
- if (a.annotationType().equals(CacheKey.class))
- {
- keys.add(i);
- break;
- }
- }
- }
-
- // if not then use all parameters but value ones
- if (keys.isEmpty())
- {
- for (int i = 0; i < method.getParameterTypes().length; i++)
- {
- final Annotation[] annotations = parameterAnnotations[i];
- boolean value = false;
- for (final Annotation a : annotations)
- {
- if (a.annotationType().equals(CacheValue.class))
- {
- value = true;
- break;
- }
- }
- if (!value) {
- keys.add(i);
- }
- }
- }
- return keys.toArray(new Integer[keys.size()]);
- }
-
- private static final class MethodKey
- {
- private final Class<?> base;
- private final Method delegate;
- private final int hash;
-
- private MethodKey(final Class<?> base, final Method delegate)
- {
- this.base = base; // we need a class to ensure inheritance don't fall in the same key
- this.delegate = delegate;
- this.hash = 31 * delegate.hashCode() + (base == null ? 0 : base.hashCode());
- }
-
- @Override
- public boolean equals(final Object o)
- {
- if (this == o)
- {
- return true;
- }
- if (o == null || getClass() != o.getClass())
- {
- return false;
- }
- final MethodKey classKey = MethodKey.class.cast(o);
- return delegate.equals(classKey.delegate) && ((base == null && classKey.base == null) || (base != null && base.equals(classKey.base)));
- }
-
- @Override
- public int hashCode()
- {
- return hash;
- }
- }
-
- // TODO: split it in 5?
- public static class MethodMeta
- {
- private final Class<?>[] parameterTypes;
- private final List<Set<Annotation>> parameterAnnotations;
- private final Set<Annotation> annotations;
- private final Integer[] keysIndices;
- private final Integer valueIndex;
- private final Integer[] parameterIndices;
-
- private final String cacheResultCacheName;
- private final CacheResolverFactory cacheResultResolverFactory;
- private final CacheKeyGenerator cacheResultKeyGenerator;
- private final CacheResult cacheResult;
-
- private final String cachePutCacheName;
- private final CacheResolverFactory cachePutResolverFactory;
- private final CacheKeyGenerator cachePutKeyGenerator;
- private final boolean cachePutAfter;
- private final CachePut cachePut;
-
- private final String cacheRemoveCacheName;
- private final CacheResolverFactory cacheRemoveResolverFactory;
- private final CacheKeyGenerator cacheRemoveKeyGenerator;
- private final boolean cacheRemoveAfter;
- private final CacheRemove cacheRemove;
-
- private final String cacheRemoveAllCacheName;
- private final CacheResolverFactory cacheRemoveAllResolverFactory;
- private final boolean cacheRemoveAllAfter;
- private final CacheRemoveAll cacheRemoveAll;
-
- public MethodMeta(Class<?>[] parameterTypes, List<Set<Annotation>> parameterAnnotations, Set<Annotation>
- annotations, Integer[] keysIndices, Integer valueIndex, Integer[] parameterIndices, String
- cacheResultCacheName, CacheResolverFactory cacheResultResolverFactory, CacheKeyGenerator
- cacheResultKeyGenerator, CacheResult cacheResult, String cachePutCacheName, CacheResolverFactory
- cachePutResolverFactory, CacheKeyGenerator cachePutKeyGenerator, boolean cachePutAfter, CachePut cachePut, String
- cacheRemoveCacheName, CacheResolverFactory cacheRemoveResolverFactory, CacheKeyGenerator
- cacheRemoveKeyGenerator, boolean cacheRemoveAfter, CacheRemove cacheRemove, String cacheRemoveAllCacheName,
- CacheResolverFactory cacheRemoveAllResolverFactory, boolean
- cacheRemoveAllAfter, CacheRemoveAll cacheRemoveAll)
- {
- this.parameterTypes = parameterTypes;
- this.parameterAnnotations = parameterAnnotations;
- this.annotations = annotations;
- this.keysIndices = keysIndices;
- this.valueIndex = valueIndex;
- this.parameterIndices = parameterIndices;
- this.cacheResultCacheName = cacheResultCacheName;
- this.cacheResultResolverFactory = cacheResultResolverFactory;
- this.cacheResultKeyGenerator = cacheResultKeyGenerator;
- this.cacheResult = cacheResult;
- this.cachePutCacheName = cachePutCacheName;
- this.cachePutResolverFactory = cachePutResolverFactory;
- this.cachePutKeyGenerator = cachePutKeyGenerator;
- this.cachePutAfter = cachePutAfter;
- this.cachePut = cachePut;
- this.cacheRemoveCacheName = cacheRemoveCacheName;
- this.cacheRemoveResolverFactory = cacheRemoveResolverFactory;
- this.cacheRemoveKeyGenerator = cacheRemoveKeyGenerator;
- this.cacheRemoveAfter = cacheRemoveAfter;
- this.cacheRemove = cacheRemove;
- this.cacheRemoveAllCacheName = cacheRemoveAllCacheName;
- this.cacheRemoveAllResolverFactory = cacheRemoveAllResolverFactory;
- this.cacheRemoveAllAfter = cacheRemoveAllAfter;
- this.cacheRemoveAll = cacheRemoveAll;
- }
-
- public boolean isCacheRemoveAfter()
- {
- return cacheRemoveAfter;
- }
-
- public boolean isCachePutAfter()
- {
- return cachePutAfter;
- }
-
- public Class<?>[] getParameterTypes()
- {
- return parameterTypes;
- }
-
- public List<Set<Annotation>> getParameterAnnotations()
- {
- return parameterAnnotations;
- }
-
- public String getCacheResultCacheName()
- {
- return cacheResultCacheName;
- }
-
- public CacheResolverFactory getCacheResultResolverFactory()
- {
- return cacheResultResolverFactory;
- }
-
- public CacheKeyGenerator getCacheResultKeyGenerator()
- {
- return cacheResultKeyGenerator;
- }
-
- public CacheResult getCacheResult() {
- return cacheResult;
- }
-
- public Integer[] getParameterIndices()
- {
- return parameterIndices;
- }
-
- public Set<Annotation> getAnnotations()
- {
- return annotations;
- }
-
- public Integer[] getKeysIndices()
- {
- return keysIndices;
- }
-
- public Integer getValuesIndex()
- {
- return valueIndex;
- }
-
- public Integer getValueIndex()
- {
- return valueIndex;
- }
-
- public String getCachePutCacheName()
- {
- return cachePutCacheName;
- }
-
- public CacheResolverFactory getCachePutResolverFactory()
- {
- return cachePutResolverFactory;
- }
-
- public CacheKeyGenerator getCachePutKeyGenerator()
- {
- return cachePutKeyGenerator;
- }
-
- public CachePut getCachePut()
- {
- return cachePut;
- }
-
- public String getCacheRemoveCacheName()
- {
- return cacheRemoveCacheName;
- }
-
- public CacheResolverFactory getCacheRemoveResolverFactory()
- {
- return cacheRemoveResolverFactory;
- }
-
- public CacheKeyGenerator getCacheRemoveKeyGenerator()
- {
- return cacheRemoveKeyGenerator;
- }
-
- public CacheRemove getCacheRemove()
- {
- return cacheRemove;
- }
-
- public String getCacheRemoveAllCacheName()
- {
- return cacheRemoveAllCacheName;
- }
-
- public CacheResolverFactory getCacheRemoveAllResolverFactory()
- {
- return cacheRemoveAllResolverFactory;
- }
-
- public boolean isCacheRemoveAllAfter()
- {
- return cacheRemoveAllAfter;
- }
-
- public CacheRemoveAll getCacheRemoveAll()
- {
- return cacheRemoveAll;
- }
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheInvocationContextImpl.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheInvocationContextImpl.java
deleted file mode 100644
index c013a73..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheInvocationContextImpl.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.cdi;
-
-import java.lang.annotation.Annotation;
-import java.util.List;
-import java.util.Set;
-
-import javax.cache.annotation.CacheInvocationContext;
-import javax.cache.annotation.CacheInvocationParameter;
-import javax.interceptor.InvocationContext;
-
-public class CacheInvocationContextImpl<A extends Annotation> extends CacheMethodDetailsImpl<A> implements CacheInvocationContext<A>
-{
- private static final Object[] EMPTY_ARGS = new Object[0];
-
- private CacheInvocationParameter[] parameters = null;
-
- public CacheInvocationContextImpl(final InvocationContext delegate, final A cacheAnnotation, final String cacheName,
- final CDIJCacheHelper.MethodMeta meta)
- {
- super(delegate, cacheAnnotation, cacheName, meta);
- }
-
- @Override
- public Object getTarget()
- {
- return delegate.getTarget();
- }
-
- @Override
- public CacheInvocationParameter[] getAllParameters()
- {
- if (parameters == null)
- {
- parameters = doGetAllParameters(null);
- }
- return parameters;
- }
-
- @Override
- public <T> T unwrap(final Class<T> cls)
- {
- if (cls.isAssignableFrom(getClass()))
- {
- return cls.cast(this);
- }
- throw new IllegalArgumentException(cls.getName());
- }
-
- protected CacheInvocationParameter[] doGetAllParameters(final Integer[] indexes)
- {
- final Object[] parameters = delegate.getParameters();
- final Object[] args = parameters == null ? EMPTY_ARGS : parameters;
- final Class<?>[] parameterTypes = meta.getParameterTypes();
- final List<Set<Annotation>> parameterAnnotations = meta.getParameterAnnotations();
-
- final CacheInvocationParameter[] parametersAsArray = new CacheInvocationParameter[indexes == null ? args.length : indexes.length];
- if (indexes == null)
- {
- for (int i = 0; i < args.length; i++)
- {
- parametersAsArray[i] = newCacheInvocationParameterImpl(parameterTypes[i], args[i], parameterAnnotations.get(i), i);
- }
- }
- else
- {
- int outIdx = 0;
- for (int idx = 0; idx < indexes.length; idx++)
- {
- final int i = indexes[idx];
- parametersAsArray[outIdx] = newCacheInvocationParameterImpl(parameterTypes[i], args[i], parameterAnnotations.get(i), i);
- outIdx++;
- }
- }
- return parametersAsArray;
- }
-
- private CacheInvocationParameterImpl newCacheInvocationParameterImpl(final Class<?> type, final Object arg,
- final Set<Annotation> annotations, final int i) {
- return new CacheInvocationParameterImpl(type, arg, annotations, i);
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheInvocationParameterImpl.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheInvocationParameterImpl.java
deleted file mode 100644
index 9944d4b..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheInvocationParameterImpl.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.cdi;
-
-import javax.cache.annotation.CacheInvocationParameter;
-import java.lang.annotation.Annotation;
-import java.util.Set;
-
-public class CacheInvocationParameterImpl implements CacheInvocationParameter
-{
- private final Class<?> type;
- private final Object value;
- private final Set<Annotation> annotations;
- private final int position;
-
- public CacheInvocationParameterImpl(final Class<?> type, final Object value, final Set<Annotation> annotations, final int position)
- {
- this.type = type;
- this.value = value;
- this.annotations = annotations;
- this.position = position;
- }
-
- @Override
- public Class<?> getRawType()
- {
- return type;
- }
-
- @Override
- public Object getValue()
- {
- return value;
- }
-
- @Override
- public Set<Annotation> getAnnotations()
- {
- return annotations;
- }
-
- @Override
- public int getParameterPosition()
- {
- return position;
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheKeyGeneratorImpl.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheKeyGeneratorImpl.java
deleted file mode 100644
index 06eaa4b..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheKeyGeneratorImpl.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.cdi;
-
-import javax.cache.annotation.CacheInvocationParameter;
-import javax.cache.annotation.CacheKeyGenerator;
-import javax.cache.annotation.CacheKeyInvocationContext;
-import javax.cache.annotation.GeneratedCacheKey;
-import java.lang.annotation.Annotation;
-
-public class CacheKeyGeneratorImpl implements CacheKeyGenerator
-{
- @Override
- public GeneratedCacheKey generateCacheKey(final CacheKeyInvocationContext<? extends Annotation> cacheKeyInvocationContext)
- {
- final CacheInvocationParameter[] keyParameters = cacheKeyInvocationContext.getKeyParameters();
- final Object[] parameters = new Object[keyParameters.length];
- for (int index = 0; index < keyParameters.length; index++)
- {
- parameters[index] = keyParameters[index].getValue();
- }
- return new GeneratedCacheKeyImpl(parameters);
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheKeyInvocationContextImpl.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheKeyInvocationContextImpl.java
deleted file mode 100644
index 6d87d26..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheKeyInvocationContextImpl.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.cdi;
-
-import java.lang.annotation.Annotation;
-
-import javax.cache.annotation.CacheInvocationParameter;
-import javax.cache.annotation.CacheKeyInvocationContext;
-import javax.interceptor.InvocationContext;
-
-public class CacheKeyInvocationContextImpl<A extends Annotation> extends CacheInvocationContextImpl<A> implements CacheKeyInvocationContext<A>
-{
- private CacheInvocationParameter[] keyParams = null;
- private CacheInvocationParameter valueParam = null;
-
- public CacheKeyInvocationContextImpl(final InvocationContext delegate, final A annotation, final String name,
- final CDIJCacheHelper.MethodMeta methodMeta)
- {
- super(delegate, annotation, name, methodMeta);
- }
-
- @Override
- public CacheInvocationParameter[] getKeyParameters()
- {
- if (keyParams == null)
- {
- keyParams = doGetAllParameters(meta.getKeysIndices());
- }
- return keyParams;
- }
-
- @Override
- public CacheInvocationParameter getValueParameter()
- {
- if (valueParam == null)
- {
- valueParam = meta.getValueIndex() >= 0 ? doGetAllParameters(new Integer[]{meta.getValueIndex()})[0] : null;
- }
- return valueParam;
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheMethodDetailsImpl.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheMethodDetailsImpl.java
deleted file mode 100644
index 349b27b..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheMethodDetailsImpl.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.cdi;
-
-import javax.cache.annotation.CacheMethodDetails;
-import javax.interceptor.InvocationContext;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.util.HashSet;
-import java.util.Set;
-
-import static java.util.Arrays.asList;
-
-public class CacheMethodDetailsImpl<A extends Annotation> implements CacheMethodDetails<A>
-{
- protected final InvocationContext delegate;
- private final Set<Annotation> annotations;
- private final A cacheAnnotation;
- private final String cacheName;
- protected final CDIJCacheHelper.MethodMeta meta;
-
- public CacheMethodDetailsImpl(final InvocationContext delegate, final A cacheAnnotation, final String cacheName,
- final CDIJCacheHelper.MethodMeta meta)
- {
- this.delegate = delegate;
- this.annotations = meta.getAnnotations();
- this.cacheAnnotation = cacheAnnotation;
- this.cacheName = cacheName;
- this.meta = meta;
- }
-
- @Override
- public Method getMethod()
- {
- return delegate.getMethod();
- }
-
- @Override
- public Set<Annotation> getAnnotations()
- {
- return annotations;
- }
-
- @Override
- public A getCacheAnnotation()
- {
- return cacheAnnotation;
- }
-
- @Override
- public String getCacheName()
- {
- return cacheName;
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CachePutInterceptor.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CachePutInterceptor.java
deleted file mode 100644
index 67b9d40..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CachePutInterceptor.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.cdi;
-
-import java.io.Serializable;
-
-import javax.annotation.Priority;
-import javax.cache.Cache;
-import javax.cache.annotation.CacheKeyInvocationContext;
-import javax.cache.annotation.CachePut;
-import javax.cache.annotation.CacheResolver;
-import javax.cache.annotation.CacheResolverFactory;
-import javax.cache.annotation.GeneratedCacheKey;
-import javax.inject.Inject;
-import javax.interceptor.AroundInvoke;
-import javax.interceptor.Interceptor;
-import javax.interceptor.InvocationContext;
-
-@CachePut
-@Interceptor
-@Priority(/*LIBRARY_BEFORE*/1000)
-public class CachePutInterceptor implements Serializable
-{
- @Inject
- private CDIJCacheHelper helper;
-
- @AroundInvoke
- public Object cache(final InvocationContext ic) throws Throwable
- {
- final CDIJCacheHelper.MethodMeta methodMeta = helper.findMeta(ic);
-
- final String cacheName = methodMeta.getCachePutCacheName();
-
- final CacheResolverFactory cacheResolverFactory = methodMeta.getCachePutResolverFactory();
- final CacheKeyInvocationContext<CachePut> context = new CacheKeyInvocationContextImpl<CachePut>(
- ic, methodMeta.getCachePut(), cacheName, methodMeta);
- final CacheResolver cacheResolver = cacheResolverFactory.getCacheResolver(context);
- final Cache<Object, Object> cache = cacheResolver.resolveCache(context);
-
- final GeneratedCacheKey cacheKey = methodMeta.getCachePutKeyGenerator().generateCacheKey(context);
- final CachePut cachePut = methodMeta.getCachePut();
- final boolean afterInvocation = methodMeta.isCachePutAfter();
-
- if (!afterInvocation)
- {
- cache.put(cacheKey, context.getValueParameter());
- }
-
- final Object result;
- try
- {
- result = ic.proceed();
- }
- catch (final Throwable t)
- {
- if (afterInvocation)
- {
- if (helper.isIncluded(t.getClass(), cachePut.cacheFor(), cachePut.noCacheFor()))
- {
- cache.put(cacheKey, context.getValueParameter());
- }
- }
-
- throw t;
- }
-
- if (afterInvocation)
- {
- cache.put(cacheKey, context.getValueParameter());
- }
-
- return result;
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheRemoveAllInterceptor.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheRemoveAllInterceptor.java
deleted file mode 100644
index a86cab8..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheRemoveAllInterceptor.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.cdi;
-
-import java.io.Serializable;
-
-import javax.annotation.Priority;
-import javax.cache.Cache;
-import javax.cache.annotation.CacheKeyInvocationContext;
-import javax.cache.annotation.CacheRemoveAll;
-import javax.cache.annotation.CacheResolver;
-import javax.cache.annotation.CacheResolverFactory;
-import javax.inject.Inject;
-import javax.interceptor.AroundInvoke;
-import javax.interceptor.Interceptor;
-import javax.interceptor.InvocationContext;
-
-@CacheRemoveAll
-@Interceptor
-@Priority(/*LIBRARY_BEFORE*/1000)
-public class CacheRemoveAllInterceptor implements Serializable
-{
- @Inject
- private CDIJCacheHelper helper;
-
- @AroundInvoke
- public Object cache(final InvocationContext ic) throws Throwable
- {
- final CDIJCacheHelper.MethodMeta methodMeta = helper.findMeta(ic);
-
- final String cacheName = methodMeta.getCacheRemoveAllCacheName();
-
- final CacheResolverFactory cacheResolverFactory = methodMeta.getCacheRemoveAllResolverFactory();
- final CacheKeyInvocationContext<CacheRemoveAll> context = new CacheKeyInvocationContextImpl<CacheRemoveAll>(
- ic, methodMeta.getCacheRemoveAll(), cacheName, methodMeta);
- final CacheResolver cacheResolver = cacheResolverFactory.getCacheResolver(context);
- final Cache<Object, Object> cache = cacheResolver.resolveCache(context);
-
- final boolean afterInvocation = methodMeta.isCachePutAfter();
- if (!afterInvocation)
- {
- cache.removeAll();
- }
-
- final Object result;
- try
- {
- result = ic.proceed();
- }
- catch (final Throwable t)
- {
- if (afterInvocation)
- {
- if (helper.isIncluded(t.getClass(), methodMeta.getCacheRemoveAll().evictFor(), methodMeta.getCacheRemoveAll().noEvictFor()))
- {
- cache.removeAll();
- }
- }
- throw t;
- }
-
- if (afterInvocation)
- {
- cache.removeAll();
- }
-
- return result;
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheRemoveInterceptor.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheRemoveInterceptor.java
deleted file mode 100644
index 8835ac8..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheRemoveInterceptor.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.cdi;
-
-import java.io.Serializable;
-
-import javax.annotation.Priority;
-import javax.cache.Cache;
-import javax.cache.annotation.CacheKeyInvocationContext;
-import javax.cache.annotation.CacheRemove;
-import javax.cache.annotation.CacheResolver;
-import javax.cache.annotation.CacheResolverFactory;
-import javax.cache.annotation.GeneratedCacheKey;
-import javax.inject.Inject;
-import javax.interceptor.AroundInvoke;
-import javax.interceptor.Interceptor;
-import javax.interceptor.InvocationContext;
-
-@CacheRemove
-@Interceptor
-@Priority(/*LIBRARY_BEFORE*/1000)
-public class CacheRemoveInterceptor implements Serializable
-{
- @Inject
- private CDIJCacheHelper helper;
-
- @AroundInvoke
- public Object cache(final InvocationContext ic) throws Throwable
- {
- final CDIJCacheHelper.MethodMeta methodMeta = helper.findMeta(ic);
-
- final String cacheName = methodMeta.getCacheRemoveCacheName();
-
- final CacheResolverFactory cacheResolverFactory = methodMeta.getCacheRemoveResolverFactory();
- final CacheKeyInvocationContext<CacheRemove> context = new CacheKeyInvocationContextImpl<CacheRemove>(
- ic, methodMeta.getCacheRemove(), cacheName, methodMeta);
- final CacheResolver cacheResolver = cacheResolverFactory.getCacheResolver(context);
- final Cache<Object, Object> cache = cacheResolver.resolveCache(context);
-
- final GeneratedCacheKey cacheKey = methodMeta.getCacheRemoveKeyGenerator().generateCacheKey(context);
- final CacheRemove cacheRemove = methodMeta.getCacheRemove();
- final boolean afterInvocation = methodMeta.isCacheRemoveAfter();
-
- if (!afterInvocation)
- {
- cache.remove(cacheKey);
- }
-
- final Object result;
- try
- {
- result = ic.proceed();
- }
- catch (final Throwable t)
- {
- if (afterInvocation)
- {
- if (helper.isIncluded(t.getClass(), cacheRemove.evictFor(), cacheRemove.noEvictFor()))
- {
- cache.remove(cacheKey);
- }
- }
-
- throw t;
- }
-
- if (afterInvocation)
- {
- cache.remove(cacheKey);
- }
-
- return result;
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheResolverFactoryImpl.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheResolverFactoryImpl.java
deleted file mode 100644
index 442fba1..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheResolverFactoryImpl.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.cdi;
-
-import javax.cache.Cache;
-import javax.cache.CacheManager;
-import javax.cache.Caching;
-import javax.cache.annotation.CacheMethodDetails;
-import javax.cache.annotation.CacheResolver;
-import javax.cache.annotation.CacheResolverFactory;
-import javax.cache.annotation.CacheResult;
-import javax.cache.configuration.MutableConfiguration;
-import javax.cache.spi.CachingProvider;
-import java.lang.annotation.Annotation;
-
-public class CacheResolverFactoryImpl implements CacheResolverFactory
-{
- private final CacheManager cacheManager;
- private final CachingProvider provider;
-
- public CacheResolverFactoryImpl()
- {
- provider = Caching.getCachingProvider();
- cacheManager = provider.getCacheManager(provider.getDefaultURI(), provider.getDefaultClassLoader());
- }
-
- @Override
- public CacheResolver getCacheResolver(CacheMethodDetails<? extends Annotation> cacheMethodDetails)
- {
- return findCacheResolver(cacheMethodDetails.getCacheName());
- }
-
- @Override
- public CacheResolver getExceptionCacheResolver(final CacheMethodDetails<CacheResult> cacheMethodDetails)
- {
- final String exceptionCacheName = cacheMethodDetails.getCacheAnnotation().exceptionCacheName();
- if (exceptionCacheName == null || exceptionCacheName.isEmpty())
- {
- throw new IllegalArgumentException("CacheResult.exceptionCacheName() not specified");
- }
- return findCacheResolver(exceptionCacheName);
- }
-
- private CacheResolver findCacheResolver(String exceptionCacheName)
- {
- Cache<?, ?> cache = cacheManager.getCache(exceptionCacheName);
- if (cache == null)
- {
- cache = createCache(exceptionCacheName);
- }
- return new CacheResolverImpl(cache);
- }
-
- private Cache<?, ?> createCache(final String exceptionCacheName)
- {
- cacheManager.createCache(exceptionCacheName, new MutableConfiguration<Object, Object>().setStoreByValue(false));
- return cacheManager.getCache(exceptionCacheName);
- }
-
- public void release()
- {
- cacheManager.close();
- provider.close();
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheResolverImpl.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheResolverImpl.java
deleted file mode 100644
index 17f983c..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheResolverImpl.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.cdi;
-
-import javax.cache.Cache;
-import javax.cache.annotation.CacheInvocationContext;
-import javax.cache.annotation.CacheResolver;
-import java.lang.annotation.Annotation;
-
-public class CacheResolverImpl implements CacheResolver
-{
- private final Cache<?, ?> delegate;
-
- public CacheResolverImpl(final Cache<?, ?> cache)
- {
- delegate = cache;
- }
-
- @Override
- public <K, V> Cache<K, V> resolveCache(final CacheInvocationContext<? extends Annotation> cacheInvocationContext)
- {
- return (Cache<K, V>) delegate;
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheResultInterceptor.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheResultInterceptor.java
deleted file mode 100644
index e58ad34..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/CacheResultInterceptor.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.cdi;
-
-import java.io.Serializable;
-import java.lang.reflect.Method;
-import javax.annotation.Priority;
-import javax.cache.Cache;
-import javax.cache.annotation.CacheKeyInvocationContext;
-import javax.cache.annotation.CacheResolver;
-import javax.cache.annotation.CacheResolverFactory;
-import javax.cache.annotation.CacheResult;
-import javax.cache.annotation.GeneratedCacheKey;
-import javax.inject.Inject;
-import javax.interceptor.AroundInvoke;
-import javax.interceptor.Interceptor;
-import javax.interceptor.InvocationContext;
-
-@CacheResult
-@Interceptor
-@Priority(/*LIBRARY_BEFORE*/1000)
-public class CacheResultInterceptor implements Serializable
-{
- @Inject
- private CDIJCacheHelper helper;
-
- @AroundInvoke
- public Object cache(final InvocationContext ic) throws Throwable
- {
- final CDIJCacheHelper.MethodMeta methodMeta = helper.findMeta(ic);
-
- final String cacheName = methodMeta.getCacheResultCacheName();
-
- final CacheResult cacheResult = methodMeta.getCacheResult();
- final CacheKeyInvocationContext<CacheResult> context = new CacheKeyInvocationContextImpl<CacheResult>(
- ic, cacheResult, cacheName, methodMeta);
-
- final CacheResolverFactory cacheResolverFactory = methodMeta.getCacheResultResolverFactory();
- final CacheResolver cacheResolver = cacheResolverFactory.getCacheResolver(context);
- final Cache<Object, Object> cache = cacheResolver.resolveCache(context);
-
- final GeneratedCacheKey cacheKey = methodMeta.getCacheResultKeyGenerator().generateCacheKey(context);
-
- Cache<Object, Object> exceptionCache = null; // lazily created
-
- Object result;
- if (!cacheResult.skipGet())
- {
- result = cache.get(cacheKey);
- if (result != null)
- {
- return result;
- }
-
-
- if (!cacheResult.exceptionCacheName().isEmpty())
- {
- exceptionCache = cacheResolverFactory.getExceptionCacheResolver(context).resolveCache(context);
- final Object exception = exceptionCache.get(cacheKey);
- if (exception != null)
- {
- throw Throwable.class.cast(exception);
- }
- }
- }
-
- try
- {
- result = ic.proceed();
- if (result != null)
- {
- cache.put(cacheKey, result);
- }
-
- return result;
- }
- catch (final Throwable t)
- {
- if (helper.isIncluded(t.getClass(), cacheResult.cachedExceptions(), cacheResult.nonCachedExceptions()))
- {
- if (exceptionCache == null)
- {
- exceptionCache = cacheResolverFactory.getExceptionCacheResolver(context).resolveCache(context);
- }
- exceptionCache.put(cacheKey, t);
- }
- throw t;
- }
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/GeneratedCacheKeyImpl.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/GeneratedCacheKeyImpl.java
deleted file mode 100644
index 95c53c1..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/GeneratedCacheKeyImpl.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.cdi;
-
-import javax.cache.annotation.GeneratedCacheKey;
-import java.util.Arrays;
-
-public class GeneratedCacheKeyImpl implements GeneratedCacheKey
-{
- private final Object[] params;
- private final int hash;
-
- public GeneratedCacheKeyImpl(final Object[] parameters)
- {
- this.params = parameters;
- this.hash = Arrays.deepHashCode(parameters);
- }
-
- @Override
- public boolean equals(final Object o)
- {
- if (this == o)
- {
- return true;
- }
- if (o == null || getClass() != o.getClass())
- {
- return false;
- }
- final GeneratedCacheKeyImpl that = GeneratedCacheKeyImpl.class.cast(o);
- return Arrays.deepEquals(params, that.params);
-
- }
-
- @Override
- public int hashCode()
- {
- return hash;
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/MakeJCacheCDIInterceptorFriendly.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/MakeJCacheCDIInterceptorFriendly.java
deleted file mode 100644
index 72dc883..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/cdi/MakeJCacheCDIInterceptorFriendly.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.cdi;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import javax.cache.annotation.CachePut;
-import javax.cache.annotation.CacheRemove;
-import javax.cache.annotation.CacheRemoveAll;
-import javax.cache.annotation.CacheResult;
-import javax.enterprise.context.ApplicationScoped;
-import javax.enterprise.context.spi.CreationalContext;
-import javax.enterprise.event.Observes;
-import javax.enterprise.inject.Any;
-import javax.enterprise.inject.Default;
-import javax.enterprise.inject.spi.AfterBeanDiscovery;
-import javax.enterprise.inject.spi.AnnotatedType;
-import javax.enterprise.inject.spi.Bean;
-import javax.enterprise.inject.spi.BeanManager;
-import javax.enterprise.inject.spi.BeforeBeanDiscovery;
-import javax.enterprise.inject.spi.Extension;
-import javax.enterprise.inject.spi.InjectionPoint;
-import javax.enterprise.inject.spi.InjectionTarget;
-import javax.enterprise.inject.spi.PassivationCapable;
-import javax.enterprise.inject.spi.ProcessAnnotatedType;
-import javax.enterprise.util.AnnotationLiteral;
-
-import static java.util.Arrays.asList;
-
-// TODO: observe annotated type (or maybe sthg else) to cache data and inject this extension (used as metadata cache)
-// to get class model and this way allow to add cache annotation on the fly - == avoid java pure reflection to get metadata
-public class MakeJCacheCDIInterceptorFriendly implements Extension
-{
- private static final AtomicInteger id = new AtomicInteger();
- private static final boolean USE_ID = !Boolean.getBoolean("org.apache.commons.jcs.cdi.skip-id");
-
- private boolean needHelper = true;
-
- protected void discoverInterceptorBindings(final @Observes BeforeBeanDiscovery beforeBeanDiscoveryEvent,
- final BeanManager bm)
- {
- // CDI 1.1 will just pick createAnnotatedType(X) as beans so we'll skip our HelperBean
- // but CDI 1.0 needs our HelperBean + interceptors in beans.xml like:
- /*
- <beans xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
- http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
- <interceptors>
- <class>org.apache.commons.jcs.jcache.cdi.CacheResultInterceptor</class>
- <class>org.apache.commons.jcs.jcache.cdi.CacheRemoveAllInterceptor</class>
- <class>org.apache.commons.jcs.jcache.cdi.CacheRemoveInterceptor</class>
- <class>org.apache.commons.jcs.jcache.cdi.CachePutInterceptor</class>
- </interceptors>
- </beans>
- */
- bm.createAnnotatedType(CDIJCacheHelper.class);
- for (final Class<?> interceptor : asList(
- CachePutInterceptor.class, CacheRemoveInterceptor.class,
- CacheRemoveAllInterceptor.class, CacheResultInterceptor.class)) {
- beforeBeanDiscoveryEvent.addAnnotatedType(bm.createAnnotatedType(interceptor));
- }
- for (final Class<? extends Annotation> interceptor : asList(
- CachePut.class, CacheRemove.class,
- CacheRemoveAll.class, CacheResult.class)) {
- beforeBeanDiscoveryEvent.addInterceptorBinding(interceptor);
- }
- }
-
- protected void addHelper(final @Observes AfterBeanDiscovery afterBeanDiscovery,
- final BeanManager bm)
- {
- if (!needHelper) {
- return;
- }
- /* CDI >= 1.1 only. Actually we shouldn't go here with CDI 1.1 since we defined the annotated type for the helper
- final AnnotatedType<CDIJCacheHelper> annotatedType = bm.createAnnotatedType(CDIJCacheHelper.class);
- final BeanAttributes<CDIJCacheHelper> beanAttributes = bm.createBeanAttributes(annotatedType);
- final InjectionTarget<CDIJCacheHelper> injectionTarget = bm.createInjectionTarget(annotatedType);
- final Bean<CDIJCacheHelper> bean = bm.createBean(beanAttributes, CDIJCacheHelper.class, new InjectionTargetFactory<CDIJCacheHelper>() {
- @Override
- public InjectionTarget<CDIJCacheHelper> createInjectionTarget(Bean<CDIJCacheHelper> bean) {
- return injectionTarget;
- }
- });
- */
- final AnnotatedType<CDIJCacheHelper> annotatedType = bm.createAnnotatedType(CDIJCacheHelper.class);
- final InjectionTarget<CDIJCacheHelper> injectionTarget = bm.createInjectionTarget(annotatedType);
- final HelperBean bean = new HelperBean(annotatedType, injectionTarget, findIdSuffix());
- afterBeanDiscovery.addBean(bean);
- }
-
- protected void vetoScannedCDIJCacheHelperQualifiers(final @Observes ProcessAnnotatedType<CDIJCacheHelper> pat) {
- if (!needHelper) { // already seen, shouldn't really happen,just a protection
- pat.veto();
- }
- needHelper = false;
- }
-
- // TODO: make it better for ear+cluster case with CDI 1.0
- private String findIdSuffix() {
- // big disadvantage is all deployments of a cluster needs to be in the exact same order but it works with ears
- if (USE_ID) {
- return "lib" + id.incrementAndGet();
- }
- return "default";
- }
-
- public static class HelperBean implements Bean<CDIJCacheHelper>, PassivationCapable {
- private final AnnotatedType<CDIJCacheHelper> at;
- private final InjectionTarget<CDIJCacheHelper> it;
- private final HashSet<Annotation> qualifiers;
- private final String id;
-
- public HelperBean(final AnnotatedType<CDIJCacheHelper> annotatedType,
- final InjectionTarget<CDIJCacheHelper> injectionTarget,
- final String id) {
- this.at = annotatedType;
- this.it = injectionTarget;
- this.id = "JCS#CDIHelper#" + id;
-
- this.qualifiers = new HashSet<Annotation>();
- this.qualifiers.add(new AnnotationLiteral<Default>() {});
- this.qualifiers.add(new AnnotationLiteral<Any>() {});
- }
-
- @Override
- public Set<InjectionPoint> getInjectionPoints() {
- return it.getInjectionPoints();
- }
-
- @Override
- public Class<?> getBeanClass() {
- return at.getJavaClass();
- }
-
- @Override
- public boolean isNullable() {
- return false;
- }
-
- @Override
- public Set<Type> getTypes() {
- return at.getTypeClosure();
- }
-
- @Override
- public Set<Annotation> getQualifiers() {
- return qualifiers;
- }
-
- @Override
- public Class<? extends Annotation> getScope() {
- return ApplicationScoped.class;
- }
-
- @Override
- public String getName() {
- return null;
- }
-
- @Override
- public Set<Class<? extends Annotation>> getStereotypes() {
- return Collections.emptySet();
- }
-
- @Override
- public boolean isAlternative() {
- return false;
- }
-
- @Override
- public CDIJCacheHelper create(final CreationalContext<CDIJCacheHelper> context) {
- final CDIJCacheHelper produce = it.produce(context);
- it.inject(produce, context);
- it.postConstruct(produce);
- return produce;
- }
-
- @Override
- public void destroy(final CDIJCacheHelper instance, final CreationalContext<CDIJCacheHelper> context) {
- it.preDestroy(instance);
- it.dispose(instance);
- context.release();
- }
-
- @Override
- public String getId() {
- return id;
- }
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/jmx/ConfigurableMBeanServerIdBuilder.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/jmx/ConfigurableMBeanServerIdBuilder.java
deleted file mode 100644
index cd5746f..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/jmx/ConfigurableMBeanServerIdBuilder.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.jmx;
-
-import javax.management.ListenerNotFoundException;
-import javax.management.MBeanNotificationInfo;
-import javax.management.MBeanServer;
-import javax.management.MBeanServerBuilder;
-import javax.management.MBeanServerDelegate;
-import javax.management.Notification;
-import javax.management.NotificationFilter;
-import javax.management.NotificationListener;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-public class ConfigurableMBeanServerIdBuilder extends MBeanServerBuilder
-{
- private static ConcurrentMap<Key, MBeanServer> JVM_SINGLETONS = new ConcurrentHashMap<Key, MBeanServer>();
-
- private static class Key
- {
- private final String domain;
- private final MBeanServer outer;
-
- private Key(final String domain, final MBeanServer outer)
- {
- this.domain = domain;
- this.outer = outer;
- }
-
- @Override
- public boolean equals(final Object o)
- {
- if (this == o)
- return true;
- if (o == null || getClass() != o.getClass())
- return false;
-
- final Key key = Key.class.cast(o);
- return !(domain != null ? !domain.equals(key.domain) : key.domain != null)
- && !(outer != null ? !outer.equals(key.outer) : key.outer != null);
-
- }
-
- @Override
- public int hashCode()
- {
- int result = domain != null ? domain.hashCode() : 0;
- result = 31 * result + (outer != null ? outer.hashCode() : 0);
- return result;
- }
- }
-
- @Override
- public MBeanServer newMBeanServer(final String defaultDomain, final MBeanServer outer, final MBeanServerDelegate delegate)
- {
- final Key key = new Key(defaultDomain, outer);
- MBeanServer server = JVM_SINGLETONS.get(key);
- if (server == null)
- {
- server = super.newMBeanServer(defaultDomain, outer, new ForceIdMBeanServerDelegate(delegate));
- final MBeanServer existing = JVM_SINGLETONS.putIfAbsent(key, server);
- if (existing != null)
- {
- server = existing;
- }
- }
- return server;
- }
-
- private class ForceIdMBeanServerDelegate extends MBeanServerDelegate
- {
- private final MBeanServerDelegate delegate;
-
- public ForceIdMBeanServerDelegate(final MBeanServerDelegate delegate)
- {
- this.delegate = delegate;
- }
-
- @Override
- public String getMBeanServerId()
- {
- return System.getProperty("org.jsr107.tck.management.agentId", delegate.getMBeanServerId());
- }
-
- @Override
- public String getSpecificationName()
- {
- return delegate.getSpecificationName();
- }
-
- @Override
- public String getSpecificationVersion()
- {
- return delegate.getSpecificationVersion();
- }
-
- @Override
- public String getSpecificationVendor()
- {
- return delegate.getSpecificationVendor();
- }
-
- @Override
- public String getImplementationName()
- {
- return delegate.getImplementationName();
- }
-
- @Override
- public String getImplementationVersion()
- {
- return delegate.getImplementationVersion();
- }
-
- @Override
- public String getImplementationVendor()
- {
- return delegate.getImplementationVendor();
- }
-
- @Override
- public MBeanNotificationInfo[] getNotificationInfo()
- {
- return delegate.getNotificationInfo();
- }
-
- @Override
- public void addNotificationListener(final NotificationListener listener, final NotificationFilter filter, final Object handback)
- throws IllegalArgumentException
- {
- delegate.addNotificationListener(listener, filter, handback);
- }
-
- @Override
- public void removeNotificationListener(final NotificationListener listener, final NotificationFilter filter, final Object handback)
- throws ListenerNotFoundException
- {
- delegate.removeNotificationListener(listener, filter, handback);
- }
-
- @Override
- public void removeNotificationListener(final NotificationListener listener) throws ListenerNotFoundException
- {
- delegate.removeNotificationListener(listener);
- }
-
- @Override
- public void sendNotification(final Notification notification)
- {
- delegate.sendNotification(notification);
- }
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/jmx/JCSCacheMXBean.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/jmx/JCSCacheMXBean.java
deleted file mode 100644
index 3e352df..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/jmx/JCSCacheMXBean.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.jmx;
-
-import javax.cache.Cache;
-import javax.cache.configuration.CompleteConfiguration;
-import javax.cache.configuration.Configuration;
-import javax.cache.management.CacheMXBean;
-
-public class JCSCacheMXBean<K, V> implements CacheMXBean
-{
- private final Cache<K, V> delegate;
-
- public JCSCacheMXBean(final Cache<K, V> delegate)
- {
- this.delegate = delegate;
- }
-
- private Configuration<K, V> config()
- {
- return delegate.getConfiguration(Configuration.class);
- }
-
- private CompleteConfiguration<K, V> completeConfig()
- {
- return delegate.getConfiguration(CompleteConfiguration.class);
- }
-
- @Override
- public String getKeyType()
- {
- return config().getKeyType().getName();
- }
-
- @Override
- public String getValueType()
- {
- return config().getValueType().getName();
- }
-
- @Override
- public boolean isReadThrough()
- {
- try
- {
- return completeConfig().isReadThrough();
- }
- catch (final Exception e)
- {
- return false;
- }
- }
-
- @Override
- public boolean isWriteThrough()
- {
- try
- {
- return completeConfig().isWriteThrough();
- }
- catch (final Exception e)
- {
- return false;
- }
- }
-
- @Override
- public boolean isStoreByValue()
- {
- return config().isStoreByValue();
- }
-
- @Override
- public boolean isStatisticsEnabled()
- {
- try
- {
- return completeConfig().isStatisticsEnabled();
- }
- catch (final Exception e)
- {
- return false;
- }
- }
-
- @Override
- public boolean isManagementEnabled()
- {
- try
- {
- return completeConfig().isManagementEnabled();
- }
- catch (final Exception e)
- {
- return false;
- }
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/jmx/JCSCacheStatisticsMXBean.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/jmx/JCSCacheStatisticsMXBean.java
deleted file mode 100644
index df1273a..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/jmx/JCSCacheStatisticsMXBean.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.jmx;
-
-import org.apache.commons.jcs.jcache.Statistics;
-
-import javax.cache.management.CacheStatisticsMXBean;
-
-public class JCSCacheStatisticsMXBean implements CacheStatisticsMXBean
-{
- private final Statistics statistics;
-
- public JCSCacheStatisticsMXBean(final Statistics stats)
- {
- this.statistics = stats;
- }
-
- @Override
- public void clear()
- {
- statistics.reset();
- }
-
- @Override
- public long getCacheHits()
- {
- return statistics.getHits();
- }
-
- @Override
- public float getCacheHitPercentage()
- {
- final long hits = getCacheHits();
- if (hits == 0)
- {
- return 0;
- }
- return (float) hits / getCacheGets() * 100.0f;
- }
-
- @Override
- public long getCacheMisses()
- {
- return statistics.getMisses();
- }
-
- @Override
- public float getCacheMissPercentage()
- {
- final long misses = getCacheMisses();
- if (misses == 0)
- {
- return 0;
- }
- return (float) misses / getCacheGets() * 100.0f;
- }
-
- @Override
- public long getCacheGets()
- {
- return getCacheHits() + getCacheMisses();
- }
-
- @Override
- public long getCachePuts()
- {
- return statistics.getPuts();
- }
-
- @Override
- public long getCacheRemovals()
- {
- return statistics.getRemovals();
- }
-
- @Override
- public long getCacheEvictions()
- {
- return statistics.getEvictions();
- }
-
- @Override
- public float getAverageGetTime()
- {
- return averageTime(statistics.getTimeTakenForGets());
- }
-
- @Override
- public float getAveragePutTime()
- {
- return averageTime(statistics.getTimeTakenForPuts());
- }
-
- @Override
- public float getAverageRemoveTime()
- {
- return averageTime(statistics.getTimeTakenForRemovals());
- }
-
- private float averageTime(final long timeTaken)
- {
- final long gets = getCacheGets();
- if (timeTaken == 0 || gets == 0)
- {
- return 0;
- }
- return timeTaken / gets;
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/jmx/JMXs.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/jmx/JMXs.java
deleted file mode 100644
index c8597df..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/jmx/JMXs.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.jmx;
-
-import javax.management.MBeanServer;
-import javax.management.MBeanServerFactory;
-import javax.management.ObjectName;
-import java.lang.management.ManagementFactory;
-
-public class JMXs
-{
- private static final MBeanServer SERVER = findMBeanServer();
-
- public static MBeanServer server()
- {
- return SERVER;
- }
-
- public static void register(final ObjectName on, final Object bean)
- {
- if (!SERVER.isRegistered(on))
- {
- try
- {
- SERVER.registerMBean(bean, on);
- }
- catch (final Exception e)
- {
- throw new IllegalStateException(e.getMessage(), e);
- }
- }
- }
-
- public static void unregister(final ObjectName on)
- {
- if (SERVER.isRegistered(on))
- {
- try
- {
- SERVER.unregisterMBean(on);
- }
- catch (final Exception e)
- {
- // no-op
- }
- }
- }
-
- private static MBeanServer findMBeanServer()
- {
- if (System.getProperty("javax.management.builder.initial") != null)
- {
- return MBeanServerFactory.createMBeanServer();
- }
- return ManagementFactory.getPlatformMBeanServer();
- }
-
- private JMXs()
- {
- // no-op
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/lang/DefaultSubsitutor.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/lang/DefaultSubsitutor.java
deleted file mode 100644
index f3a0ecb..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/lang/DefaultSubsitutor.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.lang;
-
-public class DefaultSubsitutor implements Subsitutor
-{
- @Override
- public String substitute(final String value)
- {
- if (value.startsWith("${") && value.endsWith("}")) {
- return System.getProperty(value.substring("${".length(), value.length() - 1), value);
- }
- return value;
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/lang/Lang3Substitutor.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/lang/Lang3Substitutor.java
deleted file mode 100644
index bd00eff..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/lang/Lang3Substitutor.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.lang;
-
-import org.apache.commons.lang3.text.StrSubstitutor;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class Lang3Substitutor implements Subsitutor
-{
- private static final StrSubstitutor SUBSTITUTOR = new StrSubstitutor(new HashMap<String, Object>() {{
- putAll(Map.class.cast(System.getProperties()));
- putAll(System.getenv());
- }});
-
- @Override
- public String substitute(final String value)
- {
- return SUBSTITUTOR.replace(value);
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/lang/Subsitutor.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/lang/Subsitutor.java
deleted file mode 100644
index 9c049a2..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/lang/Subsitutor.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.lang;
-
-public interface Subsitutor
-{
- String substitute(String value);
-
- public static class Helper {
- public static final Subsitutor INSTANCE;
- static {
- Subsitutor value = null;
- for (final String name : new String[]
- { // ordered by features
- "org.apache.commons.jcs.jcache.lang.Lang3Substitutor",
- "org.apache.commons.jcs.jcache.lang.DefaultSubsitutor"
- })
- {
- try
- {
- value = Subsitutor.class.cast(
- Subsitutor.class.getClassLoader().loadClass(name).newInstance());
- value.substitute("${java.version}"); // ensure it works
- }
- catch (final Throwable e) // not Exception otherwise NoClassDefFoundError
- {
- // no-op: next
- }
- }
- if (value == null) {
- throw new IllegalStateException("Can't find a " + Subsitutor.class.getName());
- }
- INSTANCE = value;
- }
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/proxy/ClassLoaderAwareCache.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/proxy/ClassLoaderAwareCache.java
deleted file mode 100644
index 7a01488..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/proxy/ClassLoaderAwareCache.java
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.proxy;
-
-import org.apache.commons.jcs.jcache.JCSCache;
-
-import javax.cache.Cache;
-import javax.cache.CacheManager;
-import javax.cache.configuration.CacheEntryListenerConfiguration;
-import javax.cache.configuration.Configuration;
-import javax.cache.integration.CompletionListener;
-import javax.cache.processor.EntryProcessor;
-import javax.cache.processor.EntryProcessorException;
-import javax.cache.processor.EntryProcessorResult;
-import java.io.Serializable;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-// don't use a proxy, reflection is too slow here :(
-public class ClassLoaderAwareCache<K, V> implements Cache<K, V>
-{
- private final ClassLoader loader;
- private final JCSCache<K, V> delegate;
-
- public ClassLoaderAwareCache(final ClassLoader loader, final JCSCache<K, V> delegate)
- {
- this.loader = loader;
- this.delegate = delegate;
- }
-
- private ClassLoader before(final Thread thread)
- {
- final ClassLoader tccl = thread.getContextClassLoader();
- thread.setContextClassLoader(loader);
- return tccl;
- }
-
- public V get(final K key)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.get(key);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public Map<K, V> getAll(final Set<? extends K> keys)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.getAll(keys);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public boolean containsKey(final K key)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.containsKey(key);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public void loadAll(final Set<? extends K> keys, boolean replaceExistingValues, final CompletionListener completionListener)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- delegate.loadAll(keys, replaceExistingValues, completionListener);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public void put(final K key, final V value)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- delegate.put(key, value);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public V getAndPut(final K key, final V value)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.getAndPut(key, value);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public void putAll(final Map<? extends K, ? extends V> map)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- delegate.putAll(map);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public boolean putIfAbsent(final K key, final V value)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.putIfAbsent(key, value);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public boolean remove(final K key)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.remove(key);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public boolean remove(final K key, final V oldValue)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.remove(key, oldValue);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public V getAndRemove(final K key)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.getAndRemove(key);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public boolean replace(final K key, final V oldValue, final V newValue)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.replace(key, oldValue, newValue);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public boolean replace(final K key, final V value)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.replace(key, value);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public V getAndReplace(final K key, final V value)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.getAndReplace(key, value);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public void removeAll(final Set<? extends K> keys)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- delegate.removeAll(keys);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- @Override
- public void removeAll()
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- delegate.removeAll();
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- @Override
- public void clear()
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- delegate.clear();
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public <C extends Configuration<K, V>> C getConfiguration(final Class<C> clazz)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.getConfiguration(clazz);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public <T> T invoke(final K key, final EntryProcessor<K, V, T> entryProcessor, final Object... arguments) throws EntryProcessorException
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.invoke(key, entryProcessor, arguments);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public <T> Map<K, EntryProcessorResult<T>> invokeAll(Set<? extends K> keys, EntryProcessor<K, V, T> entryProcessor, Object... arguments)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.invokeAll(keys, entryProcessor, arguments);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- @Override
- public String getName()
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.getName();
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- @Override
- public CacheManager getCacheManager()
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.getCacheManager();
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- @Override
- public void close()
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- delegate.close();
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- @Override
- public boolean isClosed()
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.isClosed();
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- @Override
- public <T> T unwrap(final Class<T> clazz)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.unwrap(clazz);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public void registerCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- delegate.registerCacheEntryListener(cacheEntryListenerConfiguration);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- public void deregisterCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- delegate.deregisterCacheEntryListener(cacheEntryListenerConfiguration);
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- @Override
- public Iterator<Entry<K, V>> iterator()
- {
- final Thread thread = Thread.currentThread();
- final ClassLoader loader = before(thread);
- try
- {
- return delegate.iterator();
- }
- finally
- {
- thread.setContextClassLoader(loader);
- }
- }
-
- @Override
- public boolean equals(final Object obj)
- {
- if (ClassLoaderAwareCache.class.isInstance(obj))
- {
- return delegate.equals(ClassLoaderAwareCache.class.cast(obj).delegate);
- }
- return super.equals(obj);
- }
-
- @Override
- public int hashCode()
- {
- return delegate.hashCode();
- }
-
- public static <K extends Serializable, V extends Serializable> Cache<K, V> wrap(final ClassLoader loader, final JCSCache<K, V> delegate)
- {
- ClassLoader dontWrapLoader = ClassLoaderAwareCache.class.getClassLoader();
- while (dontWrapLoader != null)
- {
- if (loader == dontWrapLoader)
- {
- return delegate;
- }
- dontWrapLoader = dontWrapLoader.getParent();
- }
- return new ClassLoaderAwareCache<K, V>(loader, delegate);
- }
-
- public static <K extends Serializable, V extends Serializable> JCSCache<K, V> getDelegate(final Cache<?, ?> cache)
- {
- if (JCSCache.class.isInstance(cache))
- {
- return (JCSCache<K, V>) cache;
- }
- return ((ClassLoaderAwareCache<K, V>) cache).delegate;
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/proxy/ExceptionWrapperHandler.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/proxy/ExceptionWrapperHandler.java
deleted file mode 100644
index 9c81427..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/proxy/ExceptionWrapperHandler.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.proxy;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-
-public class ExceptionWrapperHandler<T> implements InvocationHandler
-{
- private final T delegate;
- private final Constructor<? extends RuntimeException> wrapper;
-
- public ExceptionWrapperHandler(final T delegate, final Class<? extends RuntimeException> exceptionType)
- {
- this.delegate = delegate;
- try
- {
- this.wrapper = exceptionType.getConstructor(Throwable.class);
- }
- catch (final NoSuchMethodException e)
- {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
- public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable
- {
- try
- {
- return method.invoke(delegate, args);
- }
- catch (final InvocationTargetException ite)
- {
- final Throwable e = ite.getCause();
- if (RuntimeException.class.isInstance(e))
- {
- final RuntimeException re;
- try
- {
- re = wrapper.newInstance(e);
- }
- catch (final Exception e1)
- {
- throw new IllegalArgumentException(e1);
- }
- throw re;
- }
- throw e;
- }
- }
-
- public static <T> T newProxy(final ClassLoader loader, final T delegate, final Class<? extends RuntimeException> exceptionType,
- final Class<T> apis)
- {
- return (T) Proxy.newProxyInstance(loader, new Class<?>[] { apis }, new ExceptionWrapperHandler<T>(delegate, exceptionType));
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/serialization/Serializations.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/serialization/Serializations.java
deleted file mode 100644
index b024719..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/serialization/Serializations.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.serialization;
-
-import org.apache.commons.jcs.engine.behavior.IElementSerializer;
-
-public class Serializations
-{
- public static <K> K copy(final IElementSerializer serializer, final ClassLoader loader, final K key)
- {
- try
- {
- return serializer.deSerialize(serializer.serialize(key), loader);
- }
- catch ( final Exception e)
- {
- throw new IllegalStateException(e);
- }
- }
-}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/thread/DaemonThreadFactory.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/thread/DaemonThreadFactory.java
deleted file mode 100644
index ce97d9d..0000000
--- a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs/jcache/thread/DaemonThreadFactory.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache.thread;
-
-
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.atomic.AtomicInteger;
-
-public class DaemonThreadFactory implements ThreadFactory
-{
- private final AtomicInteger index = new AtomicInteger(1);
- private final String prefix;
-
- public DaemonThreadFactory(final String prefix)
- {
- this.prefix = prefix;
- }
-
- @Override
- public Thread newThread( final Runnable runner )
- {
- final Thread t = new Thread( runner );
- t.setName(prefix + index.getAndIncrement());
- t.setDaemon(true);
- return t;
- }
-}
\ No newline at end of file
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/Asserts.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/Asserts.java
new file mode 100644
index 0000000..93c7fbd
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/Asserts.java
@@ -0,0 +1,36 @@
+package org.apache.commons.jcs3.jcache;
+
+/*
+ * 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.
+ */
+
+public class Asserts
+{
+ public static void assertNotNull(final Object value, final String name)
+ {
+ if (value == null)
+ {
+ throw new NullPointerException(name + " is null");
+ }
+ }
+
+ private Asserts()
+ {
+ // no-op
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/EvictionListener.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/EvictionListener.java
new file mode 100644
index 0000000..111b04c
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/EvictionListener.java
@@ -0,0 +1,46 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import org.apache.commons.jcs3.engine.control.event.behavior.IElementEvent;
+import org.apache.commons.jcs3.engine.control.event.behavior.IElementEventHandler;
+
+public class EvictionListener implements IElementEventHandler
+{
+ private final Statistics stats;
+
+ public EvictionListener(final Statistics statistics)
+ {
+ this.stats = statistics;
+ }
+
+ @Override
+ public void handleElementEvent(final IElementEvent event)
+ {
+ switch (event.getElementEvent())
+ {
+ case EXCEEDED_MAXLIFE_BACKGROUND:
+ case EXCEEDED_MAXLIFE_ONREQUEST:
+ case EXCEEDED_IDLETIME_ONREQUEST:
+ case EXCEEDED_IDLETIME_BACKGROUND:
+ stats.increaseEvictions(1);
+ break;
+ }
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/ExpiryAwareCache.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/ExpiryAwareCache.java
new file mode 100644
index 0000000..1b865c9
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/ExpiryAwareCache.java
@@ -0,0 +1,61 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import javax.cache.Cache;
+import javax.cache.configuration.CacheEntryListenerConfiguration;
+import javax.cache.event.CacheEntryEvent;
+import javax.cache.event.EventType;
+
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+
+// allows us to plug some lifecycle callbacks on the core cache without impacting too much the core
+public class ExpiryAwareCache<A, B> extends CompositeCache<A, B>
+{
+ private Map<CacheEntryListenerConfiguration<A, B>, JCSListener<A, B>> listeners;
+ private Cache<A, B> cacheRef;
+
+ ExpiryAwareCache(final ICompositeCacheAttributes cattr, final IElementAttributes attr)
+ {
+ super(cattr, attr);
+ }
+
+ @Override
+ protected void doExpires(final ICacheElement<A, B> element)
+ {
+ super.doExpires(element);
+ for (final JCSListener<A, B> listener : listeners.values())
+ {
+ listener.onExpired(Arrays.<CacheEntryEvent<? extends A, ? extends B>> asList(new JCSCacheEntryEvent<A, B>(
+ cacheRef, EventType.REMOVED, null, element.getKey(), element.getVal())));
+ }
+ }
+
+ void init(final Cache<A, B> cache, final Map<CacheEntryListenerConfiguration<A, B>, JCSListener<A, B>> listeners)
+ {
+ this.cacheRef = cache;
+ this.listeners = listeners;
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/ImmutableIterable.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/ImmutableIterable.java
new file mode 100644
index 0000000..ac54ee7
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/ImmutableIterable.java
@@ -0,0 +1,39 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+public class ImmutableIterable<T> implements Iterable<T>
+{
+ private final Collection<T> delegate;
+
+ public ImmutableIterable(final Collection<T> delegate)
+ {
+ this.delegate = new ArrayList<>(delegate);
+ }
+
+ @Override
+ public Iterator<T> iterator()
+ {
+ return new ImmutableIterator<>(delegate.iterator());
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/ImmutableIterator.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/ImmutableIterator.java
new file mode 100644
index 0000000..535eac7
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/ImmutableIterator.java
@@ -0,0 +1,49 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import java.util.Iterator;
+
+public class ImmutableIterator<T> implements Iterator<T>
+{
+ private final Iterator<T> delegate;
+
+ public ImmutableIterator(final Iterator<T> delegate)
+ {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return delegate.hasNext();
+ }
+
+ @Override
+ public T next()
+ {
+ return delegate.next();
+ }
+
+ @Override
+ public void remove()
+ {
+ throw new UnsupportedOperationException("this iterator is immutable");
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSCache.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSCache.java
new file mode 100644
index 0000000..61b39a1
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSCache.java
@@ -0,0 +1,994 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import static org.apache.commons.jcs3.jcache.Asserts.assertNotNull;
+import static org.apache.commons.jcs3.jcache.serialization.Serializations.copy;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.cache.Cache;
+import javax.cache.CacheException;
+import javax.cache.CacheManager;
+import javax.cache.configuration.CacheEntryListenerConfiguration;
+import javax.cache.configuration.Configuration;
+import javax.cache.configuration.Factory;
+import javax.cache.event.CacheEntryEvent;
+import javax.cache.event.EventType;
+import javax.cache.expiry.Duration;
+import javax.cache.expiry.EternalExpiryPolicy;
+import javax.cache.expiry.ExpiryPolicy;
+import javax.cache.integration.CacheLoader;
+import javax.cache.integration.CacheLoaderException;
+import javax.cache.integration.CacheWriter;
+import javax.cache.integration.CacheWriterException;
+import javax.cache.integration.CompletionListener;
+import javax.cache.processor.EntryProcessor;
+import javax.cache.processor.EntryProcessorException;
+import javax.cache.processor.EntryProcessorResult;
+import javax.management.ObjectName;
+
+import org.apache.commons.jcs3.engine.CacheElement;
+import org.apache.commons.jcs3.engine.ElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.ICacheElement;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+import org.apache.commons.jcs3.jcache.jmx.JCSCacheMXBean;
+import org.apache.commons.jcs3.jcache.jmx.JCSCacheStatisticsMXBean;
+import org.apache.commons.jcs3.jcache.jmx.JMXs;
+import org.apache.commons.jcs3.jcache.proxy.ExceptionWrapperHandler;
+import org.apache.commons.jcs3.jcache.thread.DaemonThreadFactory;
+import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
+
+// TODO: configure serializer
+public class JCSCache<K, V> implements Cache<K, V>
+{
+ private final ExpiryAwareCache<K, V> delegate;
+ private final JCSCachingManager manager;
+ private final JCSConfiguration<K, V> config;
+ private final CacheLoader<K, V> loader;
+ private final CacheWriter<? super K, ? super V> writer;
+ private final ExpiryPolicy expiryPolicy;
+ private final ObjectName cacheConfigObjectName;
+ private final ObjectName cacheStatsObjectName;
+ private final String name;
+ private volatile boolean closed = false;
+ private final Map<CacheEntryListenerConfiguration<K, V>, JCSListener<K, V>> listeners = new ConcurrentHashMap<>();
+ private final Statistics statistics = new Statistics();
+ private final ExecutorService pool;
+ private final IElementSerializer serializer; // using json/xml should work as well -> don't force Serializable
+
+
+ public JCSCache(final ClassLoader classLoader, final JCSCachingManager mgr,
+ final String cacheName, final JCSConfiguration<K, V> configuration,
+ final Properties properties, final ExpiryAwareCache<K, V> cache)
+ {
+ manager = mgr;
+
+ name = cacheName;
+
+ delegate = cache;
+ if (delegate.getElementAttributes() == null)
+ {
+ delegate.setElementAttributes(new ElementAttributes());
+ }
+ delegate.getElementAttributes().addElementEventHandler(new EvictionListener(statistics));
+
+ config = configuration;
+
+ final int poolSize = Integer.parseInt(property(properties, cacheName, "pool.size", "3"));
+ final DaemonThreadFactory threadFactory = new DaemonThreadFactory("JCS-JCache-" + cacheName + "-");
+ pool = poolSize > 0 ? Executors.newFixedThreadPool(poolSize, threadFactory) : Executors.newCachedThreadPool(threadFactory);
+
+ try
+ {
+ serializer = IElementSerializer.class.cast(classLoader.loadClass(property(properties, "serializer", cacheName, StandardSerializer.class.getName())).newInstance());
+ }
+ catch (final Exception e)
+ {
+ throw new IllegalArgumentException(e);
+ }
+
+ final Factory<CacheLoader<K, V>> cacheLoaderFactory = configuration.getCacheLoaderFactory();
+ if (cacheLoaderFactory == null)
+ {
+ loader = NoLoader.INSTANCE;
+ }
+ else
+ {
+ loader = ExceptionWrapperHandler
+ .newProxy(classLoader, cacheLoaderFactory.create(), CacheLoaderException.class, CacheLoader.class);
+ }
+
+ final Factory<CacheWriter<? super K, ? super V>> cacheWriterFactory = configuration.getCacheWriterFactory();
+ if (cacheWriterFactory == null)
+ {
+ writer = NoWriter.INSTANCE;
+ }
+ else
+ {
+ writer = ExceptionWrapperHandler
+ .newProxy(classLoader, cacheWriterFactory.create(), CacheWriterException.class, CacheWriter.class);
+ }
+
+ final Factory<ExpiryPolicy> expiryPolicyFactory = configuration.getExpiryPolicyFactory();
+ if (expiryPolicyFactory == null)
+ {
+ expiryPolicy = new EternalExpiryPolicy();
+ }
+ else
+ {
+ expiryPolicy = expiryPolicyFactory.create();
+ }
+
+ for (final CacheEntryListenerConfiguration<K, V> listener : config.getCacheEntryListenerConfigurations())
+ {
+ listeners.put(listener, new JCSListener<>(listener));
+ }
+ delegate.init(this, listeners);
+
+ statistics.setActive(config.isStatisticsEnabled());
+
+ final String mgrStr = manager.getURI().toString().replaceAll(",|:|=|\n", ".");
+ final String cacheStr = name.replaceAll(",|:|=|\n", ".");
+ try
+ {
+ cacheConfigObjectName = new ObjectName("javax.cache:type=CacheConfiguration,"
+ + "CacheManager=" + mgrStr + "," + "Cache=" + cacheStr);
+ cacheStatsObjectName = new ObjectName("javax.cache:type=CacheStatistics,"
+ + "CacheManager=" + mgrStr + "," + "Cache=" + cacheStr);
+ }
+ catch (final Exception e)
+ {
+ throw new IllegalArgumentException(e);
+ }
+ if (config.isManagementEnabled())
+ {
+ JMXs.register(cacheConfigObjectName, new JCSCacheMXBean<>(this));
+ }
+ if (config.isStatisticsEnabled())
+ {
+ JMXs.register(cacheStatsObjectName, new JCSCacheStatisticsMXBean(statistics));
+ }
+ }
+
+ private static String property(final Properties properties, final String cacheName, final String name, final String defaultValue)
+ {
+ return properties.getProperty(cacheName + "." + name, properties.getProperty(name, defaultValue));
+ }
+
+ private void assertNotClosed()
+ {
+ if (isClosed())
+ {
+ throw new IllegalStateException("cache closed");
+ }
+ }
+
+ @Override
+ public V get(final K key)
+ {
+ assertNotClosed();
+ assertNotNull(key, "key");
+ final long getStart = Times.now(false);
+ return doGetControllingExpiry(getStart, key, true, false, false, true);
+ }
+
+ private V doLoad(final K key, final boolean update, final long now, final boolean propagateLoadException)
+ {
+ V v = null;
+ try
+ {
+ v = loader.load(key);
+ }
+ catch (final CacheLoaderException e)
+ {
+ if (propagateLoadException)
+ {
+ throw e;
+ }
+ }
+ if (v != null)
+ {
+ final Duration duration = update ? expiryPolicy.getExpiryForUpdate() : expiryPolicy.getExpiryForCreation();
+ if (isNotZero(duration))
+ {
+ final IElementAttributes clone = delegate.getElementAttributes().clone();
+ if (ElementAttributes.class.isInstance(clone))
+ {
+ ElementAttributes.class.cast(clone).setCreateTime();
+ }
+ final ICacheElement<K, V> element = updateElement(key, v, duration, clone);
+ try
+ {
+ delegate.update(element);
+ }
+ catch (final IOException e)
+ {
+ throw new CacheException(e);
+ }
+ }
+ }
+ return v;
+ }
+
+ private ICacheElement<K, V> updateElement(final K key, final V v, final Duration duration, final IElementAttributes attrs)
+ {
+ final ICacheElement<K, V> element = new CacheElement<K, V>(name, key, v);
+ if (duration != null)
+ {
+ attrs.setTimeFactorForMilliseconds(1);
+ final boolean eternal = duration.isEternal();
+ attrs.setIsEternal(eternal);
+ if (!eternal)
+ {
+ attrs.setLastAccessTimeNow();
+ }
+ // MaxLife = -1 to use IdleTime excepted if jcache.ccf asked for something else
+ }
+ element.setElementAttributes(attrs);
+ return element;
+ }
+
+ private void touch(final K key, final ICacheElement<K, V> element)
+ {
+ if (config.isStoreByValue())
+ {
+ final K copy = copy(serializer, manager.getClassLoader(), key);
+ try
+ {
+ delegate.update(new CacheElement<K, V>(name, copy, element.getVal(), element.getElementAttributes()));
+ }
+ catch (final IOException e)
+ {
+ throw new CacheException(e);
+ }
+ }
+ }
+
+ @Override
+ public Map<K, V> getAll(final Set<? extends K> keys)
+ {
+ assertNotClosed();
+ for (final K k : keys)
+ {
+ assertNotNull(k, "key");
+ }
+
+ final long now = Times.now(false);
+ final Map<K, V> result = new HashMap<>();
+ for (final K key : keys) {
+ assertNotNull(key, "key");
+
+ final ICacheElement<K, V> elt = delegate.get(key);
+ V val = elt != null ? elt.getVal() : null;
+ if (val == null && config.isReadThrough())
+ {
+ val = doLoad(key, false, now, false);
+ if (val != null)
+ {
+ result.put(key, val);
+ }
+ }
+ else if (elt != null)
+ {
+ final Duration expiryForAccess = expiryPolicy.getExpiryForAccess();
+ if (isNotZero(expiryForAccess))
+ {
+ touch(key, elt);
+ result.put(key, val);
+ }
+ else
+ {
+ forceExpires(key);
+ }
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public boolean containsKey(final K key)
+ {
+ assertNotClosed();
+ assertNotNull(key, "key");
+ return delegate.get(key) != null;
+ }
+
+ @Override
+ public void put(final K key, final V rawValue)
+ {
+ assertNotClosed();
+ assertNotNull(key, "key");
+ assertNotNull(rawValue, "value");
+
+ final ICacheElement<K, V> oldElt = delegate.get(key);
+ final V old = oldElt != null ? oldElt.getVal() : null;
+
+ final boolean storeByValue = config.isStoreByValue();
+ final V value = storeByValue ? copy(serializer, manager.getClassLoader(), rawValue) : rawValue;
+
+ final boolean created = old == null;
+ final Duration duration = created ? expiryPolicy.getExpiryForCreation() : expiryPolicy.getExpiryForUpdate();
+ if (isNotZero(duration))
+ {
+ final boolean statisticsEnabled = config.isStatisticsEnabled();
+ final long start = Times.now(false);
+
+ final K jcsKey = storeByValue ? copy(serializer, manager.getClassLoader(), key) : key;
+ final ICacheElement<K, V> element = updateElement( // reuse it to create basic structure
+ jcsKey, value, created ? null : duration,
+ oldElt != null ? oldElt.getElementAttributes() : delegate.getElementAttributes().clone());
+ if (created && duration != null) { // set maxLife
+ final IElementAttributes copy = element.getElementAttributes();
+ copy.setTimeFactorForMilliseconds(1);
+ final boolean eternal = duration.isEternal();
+ copy.setIsEternal(eternal);
+ if (ElementAttributes.class.isInstance(copy)) {
+ ElementAttributes.class.cast(copy).setCreateTime();
+ }
+ if (!eternal)
+ {
+ copy.setIsEternal(false);
+ if (duration == expiryPolicy.getExpiryForAccess())
+ {
+ element.getElementAttributes().setIdleTime(duration.getTimeUnit().toMillis(duration.getDurationAmount()));
+ }
+ else
+ {
+ element.getElementAttributes().setMaxLife(duration.getTimeUnit().toMillis(duration.getDurationAmount()));
+ }
+ }
+ element.setElementAttributes(copy);
+ }
+ writer.write(new JCSEntry<>(jcsKey, value));
+ try
+ {
+ delegate.update(element);
+ }
+ catch (final IOException e)
+ {
+ throw new CacheException(e);
+ }
+ for (final JCSListener<K, V> listener : listeners.values())
+ {
+ if (created)
+ {
+ listener.onCreated(Arrays.<CacheEntryEvent<? extends K, ? extends V>> asList(new JCSCacheEntryEvent<>(this,
+ EventType.CREATED, null, key, value)));
+ }
+ else
+ {
+ listener.onUpdated(Arrays.<CacheEntryEvent<? extends K, ? extends V>> asList(new JCSCacheEntryEvent<>(this,
+ EventType.UPDATED, old, key, value)));
+ }
+ }
+
+ if (statisticsEnabled)
+ {
+ statistics.increasePuts(1);
+ statistics.addPutTime(System.currentTimeMillis() - start);
+ }
+ }
+ else
+ {
+ if (!created)
+ {
+ forceExpires(key);
+ }
+ }
+ }
+
+ private static boolean isNotZero(final Duration duration)
+ {
+ return duration == null || !duration.isZero();
+ }
+
+ private void forceExpires(final K cacheKey)
+ {
+ final ICacheElement<K, V> elt = delegate.get(cacheKey);
+ delegate.remove(cacheKey);
+ for (final JCSListener<K, V> listener : listeners.values())
+ {
+ listener.onExpired(Arrays.<CacheEntryEvent<? extends K, ? extends V>> asList(new JCSCacheEntryEvent<K, V>(this,
+ EventType.REMOVED, null, cacheKey, elt.getVal())));
+ }
+ }
+
+ @Override
+ public V getAndPut(final K key, final V value)
+ {
+ assertNotClosed();
+ assertNotNull(key, "key");
+ assertNotNull(value, "value");
+ final long getStart = Times.now(false);
+ final V v = doGetControllingExpiry(getStart, key, false, false, true, false);
+ put(key, value);
+ return v;
+ }
+
+ @Override
+ public void putAll(final Map<? extends K, ? extends V> map)
+ {
+ assertNotClosed();
+ final TempStateCacheView<K, V> view = new TempStateCacheView<>(this);
+ for (final Map.Entry<? extends K, ? extends V> e : map.entrySet())
+ {
+ view.put(e.getKey(), e.getValue());
+ }
+ view.merge();
+ }
+
+ @Override
+ public boolean putIfAbsent(final K key, final V value)
+ {
+ if (!containsKey(key))
+ {
+ put(key, value);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean remove(final K key)
+ {
+ assertNotClosed();
+ assertNotNull(key, "key");
+
+ final boolean statisticsEnabled = config.isStatisticsEnabled();
+ final long start = Times.now(!statisticsEnabled);
+
+ writer.delete(key);
+ final K cacheKey = key;
+
+ final ICacheElement<K, V> v = delegate.get(cacheKey);
+ delegate.remove(cacheKey);
+
+ final V value = v != null && v.getVal() != null ? v.getVal() : null;
+ boolean remove = v != null;
+ for (final JCSListener<K, V> listener : listeners.values())
+ {
+ listener.onRemoved(Arrays.<CacheEntryEvent<? extends K, ? extends V>> asList(new JCSCacheEntryEvent<>(this,
+ EventType.REMOVED, null, key, value)));
+ }
+ if (remove && statisticsEnabled)
+ {
+ statistics.increaseRemovals(1);
+ statistics.addRemoveTime(Times.now(false) - start);
+ }
+ return remove;
+ }
+
+ @Override
+ public boolean remove(final K key, final V oldValue)
+ {
+ assertNotClosed();
+ assertNotNull(key, "key");
+ assertNotNull(oldValue, "oldValue");
+ final long getStart = Times.now(false);
+ final V v = doGetControllingExpiry(getStart, key, false, false, false, false);
+ if (oldValue.equals(v))
+ {
+ remove(key);
+ return true;
+ }
+ else if (v != null)
+ {
+ // weird but just for stats to be right (org.jsr107.tck.expiry.CacheExpiryTest.removeSpecifiedEntryShouldNotCallExpiryPolicyMethods())
+ expiryPolicy.getExpiryForAccess();
+ }
+ return false;
+ }
+
+ @Override
+ public V getAndRemove(final K key)
+ {
+ assertNotClosed();
+ assertNotNull(key, "key");
+ final long getStart = Times.now(false);
+ final V v = doGetControllingExpiry(getStart, key, false, false, true, false);
+ remove(key);
+ return v;
+ }
+
+ private V doGetControllingExpiry(final long getStart, final K key, final boolean updateAcess, final boolean forceDoLoad, final boolean skipLoad,
+ final boolean propagateLoadException)
+ {
+ final boolean statisticsEnabled = config.isStatisticsEnabled();
+ final ICacheElement<K, V> elt = delegate.get(key);
+ V v = elt != null ? elt.getVal() : null;
+ if (v == null && (config.isReadThrough() || forceDoLoad))
+ {
+ if (!skipLoad)
+ {
+ v = doLoad(key, false, getStart, propagateLoadException);
+ }
+ }
+ else if (statisticsEnabled)
+ {
+ if (v != null)
+ {
+ statistics.increaseHits(1);
+ }
+ else
+ {
+ statistics.increaseMisses(1);
+ }
+ }
+
+ if (updateAcess && elt != null)
+ {
+ final Duration expiryForAccess = expiryPolicy.getExpiryForAccess();
+ if (!isNotZero(expiryForAccess))
+ {
+ forceExpires(key);
+ }
+ else if (expiryForAccess != null && (!elt.getElementAttributes().getIsEternal() || !expiryForAccess.isEternal()))
+ {
+ try
+ {
+ delegate.update(updateElement(key, elt.getVal(), expiryForAccess, elt.getElementAttributes()));
+ }
+ catch (final IOException e)
+ {
+ throw new CacheException(e);
+ }
+ }
+ }
+ if (statisticsEnabled && v != null)
+ {
+ statistics.addGetTime(Times.now(false) - getStart);
+ }
+ return v;
+ }
+
+ @Override
+ public boolean replace(final K key, final V oldValue, final V newValue)
+ {
+ assertNotClosed();
+ assertNotNull(key, "key");
+ assertNotNull(oldValue, "oldValue");
+ assertNotNull(newValue, "newValue");
+ final boolean statisticsEnabled = config.isStatisticsEnabled();
+ final ICacheElement<K, V> elt = delegate.get(key);
+ if (elt != null)
+ {
+ V value = elt.getVal();
+ if (value != null && statisticsEnabled)
+ {
+ statistics.increaseHits(1);
+ }
+ if (value == null && config.isReadThrough())
+ {
+ value = doLoad(key, false, Times.now(false), false);
+ }
+ if (value != null && value.equals(oldValue))
+ {
+ put(key, newValue);
+ return true;
+ }
+ else if (value != null)
+ {
+ final Duration expiryForAccess = expiryPolicy.getExpiryForAccess();
+ if (expiryForAccess != null && (!elt.getElementAttributes().getIsEternal() || !expiryForAccess.isEternal()))
+ {
+ try
+ {
+ delegate.update(updateElement(key, elt.getVal(), expiryForAccess, elt.getElementAttributes()));
+ }
+ catch (final IOException e)
+ {
+ throw new CacheException(e);
+ }
+ }
+ }
+ }
+ else if (statisticsEnabled)
+ {
+ statistics.increaseMisses(1);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean replace(final K key, final V value)
+ {
+ assertNotClosed();
+ assertNotNull(key, "key");
+ assertNotNull(value, "value");
+ boolean statisticsEnabled = config.isStatisticsEnabled();
+ if (containsKey(key))
+ {
+ if (statisticsEnabled)
+ {
+ statistics.increaseHits(1);
+ }
+ put(key, value);
+ return true;
+ }
+ else if (statisticsEnabled)
+ {
+ statistics.increaseMisses(1);
+ }
+ return false;
+ }
+
+ @Override
+ public V getAndReplace(final K key, final V value)
+ {
+ assertNotClosed();
+ assertNotNull(key, "key");
+ assertNotNull(value, "value");
+
+ final boolean statisticsEnabled = config.isStatisticsEnabled();
+
+ final ICacheElement<K, V> elt = delegate.get(key);
+ if (elt != null)
+ {
+ V oldValue = elt.getVal();
+ if (oldValue == null && config.isReadThrough())
+ {
+ oldValue = doLoad(key, false, Times.now(false), false);
+ }
+ else if (statisticsEnabled)
+ {
+ statistics.increaseHits(1);
+ }
+ put(key, value);
+ return oldValue;
+ }
+ else if (statisticsEnabled)
+ {
+ statistics.increaseMisses(1);
+ }
+ return null;
+ }
+
+ @Override
+ public void removeAll(final Set<? extends K> keys)
+ {
+ assertNotClosed();
+ assertNotNull(keys, "keys");
+ for (final K k : keys)
+ {
+ remove(k);
+ }
+ }
+
+ @Override
+ public void removeAll()
+ {
+ assertNotClosed();
+ for (final K k : delegate.getKeySet())
+ {
+ remove(k);
+ }
+ }
+
+ @Override
+ public void clear()
+ {
+ assertNotClosed();
+ try
+ {
+ delegate.removeAll();
+ }
+ catch (final IOException e)
+ {
+ throw new CacheException(e);
+ }
+ }
+
+ @Override
+ public <C2 extends Configuration<K, V>> C2 getConfiguration(final Class<C2> clazz)
+ {
+ assertNotClosed();
+ return clazz.cast(config);
+ }
+
+ @Override
+ public void loadAll(final Set<? extends K> keys, final boolean replaceExistingValues, final CompletionListener completionListener)
+ {
+ assertNotClosed();
+ assertNotNull(keys, "keys");
+ for (final K k : keys)
+ {
+ assertNotNull(k, "a key");
+ }
+ pool.submit(() -> doLoadAll(keys, replaceExistingValues, completionListener));
+ }
+
+ private void doLoadAll(final Set<? extends K> keys, final boolean replaceExistingValues, final CompletionListener completionListener)
+ {
+ try
+ {
+ final long now = Times.now(false);
+ for (final K k : keys)
+ {
+ if (replaceExistingValues)
+ {
+ doLoad(k, containsKey(k), now, completionListener != null);
+ continue;
+ }
+ else if (containsKey(k))
+ {
+ continue;
+ }
+ doGetControllingExpiry(now, k, true, true, false, completionListener != null);
+ }
+ }
+ catch (final RuntimeException e)
+ {
+ if (completionListener != null)
+ {
+ completionListener.onException(e);
+ return;
+ }
+ }
+ if (completionListener != null)
+ {
+ completionListener.onCompletion();
+ }
+ }
+
+ @Override
+ public <T> T invoke(final K key, final EntryProcessor<K, V, T> entryProcessor, final Object... arguments) throws EntryProcessorException
+ {
+ final TempStateCacheView<K, V> view = new TempStateCacheView<>(this);
+ final T t = doInvoke(view, key, entryProcessor, arguments);
+ view.merge();
+ return t;
+ }
+
+ private <T> T doInvoke(final TempStateCacheView<K, V> view, final K key, final EntryProcessor<K, V, T> entryProcessor,
+ final Object... arguments)
+ {
+ assertNotClosed();
+ assertNotNull(entryProcessor, "entryProcessor");
+ assertNotNull(key, "key");
+ try
+ {
+ if (config.isStatisticsEnabled())
+ {
+ if (containsKey(key))
+ {
+ statistics.increaseHits(1);
+ }
+ else
+ {
+ statistics.increaseMisses(1);
+ }
+ }
+ return entryProcessor.process(new JCSMutableEntry<>(view, key), arguments);
+ }
+ catch (final Exception ex)
+ {
+ return throwEntryProcessorException(ex);
+ }
+ }
+
+ private static <T> T throwEntryProcessorException(final Exception ex)
+ {
+ if (EntryProcessorException.class.isInstance(ex))
+ {
+ throw EntryProcessorException.class.cast(ex);
+ }
+ throw new EntryProcessorException(ex);
+ }
+
+ @Override
+ public <T> Map<K, EntryProcessorResult<T>> invokeAll(final Set<? extends K> keys, final EntryProcessor<K, V, T> entryProcessor,
+ final Object... arguments)
+ {
+ assertNotClosed();
+ assertNotNull(entryProcessor, "entryProcessor");
+ final Map<K, EntryProcessorResult<T>> results = new HashMap<>();
+ for (final K k : keys)
+ {
+ try
+ {
+ final T invoke = invoke(k, entryProcessor, arguments);
+ if (invoke != null)
+ {
+ results.put(k, () -> invoke);
+ }
+ }
+ catch (final Exception e)
+ {
+ results.put(k, () -> throwEntryProcessorException(e));
+ }
+ }
+ return results;
+ }
+
+ @Override
+ public void registerCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
+ {
+ assertNotClosed();
+ if (listeners.containsKey(cacheEntryListenerConfiguration))
+ {
+ throw new IllegalArgumentException(cacheEntryListenerConfiguration + " already registered");
+ }
+ listeners.put(cacheEntryListenerConfiguration, new JCSListener<>(cacheEntryListenerConfiguration));
+ config.addListener(cacheEntryListenerConfiguration);
+ }
+
+ @Override
+ public void deregisterCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
+ {
+ assertNotClosed();
+ listeners.remove(cacheEntryListenerConfiguration);
+ config.removeListener(cacheEntryListenerConfiguration);
+ }
+
+ @Override
+ public Iterator<Entry<K, V>> iterator()
+ {
+ assertNotClosed();
+ final Iterator<K> keys = new HashSet<K>(delegate.getKeySet()).iterator();
+ return new Iterator<Entry<K, V>>()
+ {
+ private K lastKey = null;
+
+ @Override
+ public boolean hasNext()
+ {
+ return keys.hasNext();
+ }
+
+ @Override
+ public Entry<K, V> next()
+ {
+ lastKey = keys.next();
+ return new JCSEntry<>(lastKey, get(lastKey));
+ }
+
+ @Override
+ public void remove()
+ {
+ if (isClosed() || lastKey == null)
+ {
+ throw new IllegalStateException(isClosed() ? "cache closed" : "call next() before remove()");
+ }
+ JCSCache.this.remove(lastKey);
+ }
+ };
+ }
+
+ @Override
+ public String getName()
+ {
+ assertNotClosed();
+ return name;
+ }
+
+ @Override
+ public CacheManager getCacheManager()
+ {
+ assertNotClosed();
+ return manager;
+ }
+
+ @Override
+ public synchronized void close()
+ {
+ if (isClosed())
+ {
+ return;
+ }
+
+ for (final Runnable task : pool.shutdownNow()) {
+ task.run();
+ }
+
+ manager.release(getName());
+ closed = true;
+ close(loader);
+ close(writer);
+ close(expiryPolicy);
+ for (final JCSListener<K, V> listener : listeners.values())
+ {
+ close(listener);
+ }
+ listeners.clear();
+ JMXs.unregister(cacheConfigObjectName);
+ JMXs.unregister(cacheStatsObjectName);
+ try
+ {
+ delegate.removeAll();
+ }
+ catch (final IOException e)
+ {
+ throw new CacheException(e);
+ }
+ }
+
+ private static void close(final Object potentiallyCloseable)
+ {
+ if (Closeable.class.isInstance(potentiallyCloseable))
+ {
+ Closeable.class.cast(potentiallyCloseable);
+ }
+ }
+
+ @Override
+ public boolean isClosed()
+ {
+ return closed;
+ }
+
+ @Override
+ public <T> T unwrap(final Class<T> clazz)
+ {
+ assertNotClosed();
+ if (clazz.isInstance(this))
+ {
+ return clazz.cast(this);
+ }
+ if (clazz.isAssignableFrom(Map.class) || clazz.isAssignableFrom(ConcurrentMap.class))
+ {
+ return clazz.cast(delegate);
+ }
+ throw new IllegalArgumentException(clazz.getName() + " not supported in unwrap");
+ }
+
+ public Statistics getStatistics()
+ {
+ return statistics;
+ }
+
+ public void enableManagement()
+ {
+ config.managementEnabled();
+ JMXs.register(cacheConfigObjectName, new JCSCacheMXBean<>(this));
+ }
+
+ public void disableManagement()
+ {
+ config.managementDisabled();
+ JMXs.unregister(cacheConfigObjectName);
+ }
+
+ public void enableStatistics()
+ {
+ config.statisticsEnabled();
+ statistics.setActive(true);
+ JMXs.register(cacheStatsObjectName, new JCSCacheStatisticsMXBean(statistics));
+ }
+
+ public void disableStatistics()
+ {
+ config.statisticsDisabled();
+ statistics.setActive(false);
+ JMXs.unregister(cacheStatsObjectName);
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSCacheEntryEvent.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSCacheEntryEvent.java
new file mode 100644
index 0000000..13ea943
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSCacheEntryEvent.java
@@ -0,0 +1,75 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import javax.cache.Cache;
+import javax.cache.event.CacheEntryEvent;
+import javax.cache.event.EventType;
+
+public class JCSCacheEntryEvent<K, V> extends CacheEntryEvent<K, V>
+{
+ /** Serial version */
+ private static final long serialVersionUID = 4761272981003897488L;
+
+ private final V old;
+ private final K key;
+ private final V value;
+
+ public JCSCacheEntryEvent(final Cache<K, V> source, final EventType eventType, final V old, final K key, final V value)
+ {
+ super(source, eventType);
+ this.old = old;
+ this.key = key;
+ this.value = value;
+ }
+
+ @Override
+ public V getOldValue()
+ {
+ return old;
+ }
+
+ @Override
+ public boolean isOldValueAvailable()
+ {
+ return old != null;
+ }
+
+ @Override
+ public K getKey()
+ {
+ return key;
+ }
+
+ @Override
+ public V getValue()
+ {
+ return value;
+ }
+
+ @Override
+ public <T> T unwrap(final Class<T> clazz)
+ {
+ if (clazz.isInstance(this))
+ {
+ return clazz.cast(this);
+ }
+ throw new IllegalArgumentException(clazz.getName() + " not supported in unwrap");
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSCachingManager.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSCachingManager.java
new file mode 100644
index 0000000..8cb5a98
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSCachingManager.java
@@ -0,0 +1,400 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import static org.apache.commons.jcs3.jcache.Asserts.assertNotNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.configuration.Configuration;
+import javax.cache.spi.CachingProvider;
+
+import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
+import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
+import org.apache.commons.jcs3.engine.control.CompositeCache;
+import org.apache.commons.jcs3.engine.control.CompositeCacheConfigurator;
+import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
+import org.apache.commons.jcs3.jcache.lang.Subsitutor;
+import org.apache.commons.jcs3.jcache.proxy.ClassLoaderAwareCache;
+
+public class JCSCachingManager implements CacheManager
+{
+ private static final Subsitutor SUBSTITUTOR = Subsitutor.Helper.INSTANCE;
+ private static final String DEFAULT_CONFIG =
+ "jcs.default=DC\n" +
+ "jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes\n" +
+ "jcs.default.cacheattributes.MaxObjects=200001\n" +
+ "jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache\n" +
+ "jcs.default.cacheattributes.UseMemoryShrinker=true\n" +
+ "jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600\n" +
+ "jcs.default.cacheattributes.ShrinkerIntervalSeconds=60\n" +
+ "jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes\n" +
+ "jcs.default.elementattributes.IsEternal=false\n" +
+ "jcs.default.elementattributes.MaxLife=700\n" +
+ "jcs.default.elementattributes.IdleTime=1800\n" +
+ "jcs.default.elementattributes.IsSpool=true\n" +
+ "jcs.default.elementattributes.IsRemote=true\n" +
+ "jcs.default.elementattributes.IsLateral=true\n";
+
+ private static class InternalManager extends CompositeCacheManager
+ {
+ protected static InternalManager create()
+ {
+ return new InternalManager();
+ }
+
+ @Override
+ protected CompositeCacheConfigurator newConfigurator()
+ {
+ return new CompositeCacheConfigurator()
+ {
+ @Override
+ protected <K, V> CompositeCache<K, V> newCache(
+ final ICompositeCacheAttributes cca, final IElementAttributes ea)
+ {
+ return new ExpiryAwareCache<K, V>( cca, ea );
+ }
+ };
+ }
+
+ @Override // needed to call it from JCSCachingManager
+ protected void initialize() {
+ super.initialize();
+ }
+ }
+
+ private final CachingProvider provider;
+ private final URI uri;
+ private final ClassLoader loader;
+ private final Properties properties;
+ private final ConcurrentMap<String, Cache<?, ?>> caches = new ConcurrentHashMap<>();
+ private final Properties configProperties;
+ private volatile boolean closed = false;
+ private final InternalManager delegate = InternalManager.create();
+
+ public JCSCachingManager(final CachingProvider provider, final URI uri, final ClassLoader loader, final Properties properties)
+ {
+ this.provider = provider;
+ this.uri = uri;
+ this.loader = loader;
+ this.properties = readConfig(uri, loader, properties);
+ this.configProperties = properties;
+
+ delegate.setJmxName(CompositeCacheManager.JMX_OBJECT_NAME
+ + ",provider=" + provider.hashCode()
+ + ",uri=" + uri.toString().replaceAll(",|:|=|\n", ".")
+ + ",classloader=" + loader.hashCode()
+ + ",properties=" + this.properties.hashCode());
+ delegate.initialize();
+ delegate.configure(this.properties);
+ }
+
+ private Properties readConfig(final URI uri, final ClassLoader loader, final Properties properties) {
+ final Properties props = new Properties();
+ try {
+ if (JCSCachingProvider.DEFAULT_URI.toString().equals(uri.toString()) || uri.toURL().getProtocol().equals("jcs"))
+ {
+
+ final Enumeration<URL> resources = loader.getResources(uri.getPath());
+ if (!resources.hasMoreElements()) // default
+ {
+ props.load(new ByteArrayInputStream(DEFAULT_CONFIG.getBytes("UTF-8")));
+ }
+ else
+ {
+ do
+ {
+ addProperties(resources.nextElement(), props);
+ }
+ while (resources.hasMoreElements());
+ }
+ }
+ else
+ {
+ props.load(uri.toURL().openStream());
+ }
+ } catch (final IOException e) {
+ throw new IllegalStateException(e);
+ }
+
+ if (properties != null)
+ {
+ props.putAll(properties);
+ }
+
+ for (final Map.Entry<Object, Object> entry : props.entrySet()) {
+ if (entry.getValue() == null)
+ {
+ continue;
+ }
+ final String substitute = SUBSTITUTOR.substitute(entry.getValue().toString());
+ if (!substitute.equals(entry.getValue()))
+ {
+ entry.setValue(substitute);
+ }
+ }
+ return props;
+ }
+
+ private void addProperties(final URL url, final Properties aggregator)
+ {
+ InputStream inStream = null;
+ try
+ {
+ inStream = url.openStream();
+ aggregator.load(inStream);
+ }
+ catch (final IOException e)
+ {
+ throw new IllegalArgumentException(e);
+ }
+ finally
+ {
+ if (inStream != null)
+ {
+ try
+ {
+ inStream.close();
+ }
+ catch (final IOException e)
+ {
+ // no-op
+ }
+ }
+ }
+ }
+
+ private void assertNotClosed()
+ {
+ if (isClosed())
+ {
+ throw new IllegalStateException("cache manager closed");
+ }
+ }
+
+ @Override
+ // TODO: use configuration + handle not serializable key/values
+ public <K, V, C extends Configuration<K, V>> Cache<K, V> createCache(final String cacheName, final C configuration)
+ throws IllegalArgumentException
+ {
+ assertNotClosed();
+ assertNotNull(cacheName, "cacheName");
+ assertNotNull(configuration, "configuration");
+ final Class<?> keyType = configuration == null ? Object.class : configuration.getKeyType();
+ final Class<?> valueType = configuration == null ? Object.class : configuration.getValueType();
+ if (!caches.containsKey(cacheName))
+ {
+ final Cache<K, V> cache = ClassLoaderAwareCache.wrap(loader,
+ new JCSCache/*<K, V>*/(
+ loader, this, cacheName,
+ new JCSConfiguration/*<K, V>*/(configuration, keyType, valueType),
+ properties,
+ ExpiryAwareCache.class.cast(delegate.getCache(cacheName))));
+ caches.putIfAbsent(cacheName, cache);
+ }
+ else
+ {
+ throw new javax.cache.CacheException("cache " + cacheName + " already exists");
+ }
+ return (Cache<K, V>) getCache(cacheName, keyType, valueType);
+ }
+
+ @Override
+ public void destroyCache(final String cacheName)
+ {
+ assertNotClosed();
+ assertNotNull(cacheName, "cacheName");
+ final Cache<?, ?> cache = caches.remove(cacheName);
+ if (cache != null && !cache.isClosed())
+ {
+ cache.clear();
+ cache.close();
+ }
+ }
+
+ @Override
+ public void enableManagement(final String cacheName, final boolean enabled)
+ {
+ assertNotClosed();
+ assertNotNull(cacheName, "cacheName");
+ final JCSCache<?, ?> cache = getJCSCache(cacheName);
+ if (cache != null)
+ {
+ if (enabled)
+ {
+ cache.enableManagement();
+ }
+ else
+ {
+ cache.disableManagement();
+ }
+ }
+ }
+
+ private JCSCache<?, ?> getJCSCache(final String cacheName)
+ {
+ final Cache<?, ?> cache = caches.get(cacheName);
+ return JCSCache.class.cast(ClassLoaderAwareCache.getDelegate(cache));
+ }
+
+ @Override
+ public void enableStatistics(final String cacheName, final boolean enabled)
+ {
+ assertNotClosed();
+ assertNotNull(cacheName, "cacheName");
+ final JCSCache<?, ?> cache = getJCSCache(cacheName);
+ if (cache != null)
+ {
+ if (enabled)
+ {
+ cache.enableStatistics();
+ }
+ else
+ {
+ cache.disableStatistics();
+ }
+ }
+ }
+
+ @Override
+ public synchronized void close()
+ {
+ if (isClosed())
+ {
+ return;
+ }
+
+ assertNotClosed();
+ for (final Cache<?, ?> c : caches.values())
+ {
+ c.close();
+ }
+ caches.clear();
+ closed = true;
+ if (JCSCachingProvider.class.isInstance(provider))
+ {
+ JCSCachingProvider.class.cast(provider).remove(this);
+ }
+ delegate.shutDown();
+ }
+
+ @Override
+ public <T> T unwrap(final Class<T> clazz)
+ {
+ if (clazz.isInstance(this))
+ {
+ return clazz.cast(this);
+ }
+ throw new IllegalArgumentException(clazz.getName() + " not supported in unwrap");
+ }
+
+ @Override
+ public boolean isClosed()
+ {
+ return closed;
+ }
+
+ @Override
+ public <K, V> Cache<K, V> getCache(final String cacheName)
+ {
+ assertNotClosed();
+ assertNotNull(cacheName, "cacheName");
+ return (Cache<K, V>) doGetCache(cacheName, Object.class, Object.class);
+ }
+
+ @Override
+ public Iterable<String> getCacheNames()
+ {
+ return new ImmutableIterable<>(caches.keySet());
+ }
+
+ @Override
+ public <K, V> Cache<K, V> getCache(final String cacheName, final Class<K> keyType, final Class<V> valueType)
+ {
+ assertNotClosed();
+ assertNotNull(cacheName, "cacheName");
+ assertNotNull(keyType, "keyType");
+ assertNotNull(valueType, "valueType");
+ try
+ {
+ return doGetCache(cacheName, keyType, valueType);
+ }
+ catch (final IllegalArgumentException iae)
+ {
+ throw new ClassCastException(iae.getMessage());
+ }
+ }
+
+ private <K, V> Cache<K, V> doGetCache(final String cacheName, final Class<K> keyType, final Class<V> valueType)
+ {
+ final Cache<K, V> cache = (Cache<K, V>) caches.get(cacheName);
+ if (cache == null)
+ {
+ return null;
+ }
+
+ final Configuration<K, V> config = cache.getConfiguration(Configuration.class);
+ if ((keyType != null && !config.getKeyType().isAssignableFrom(keyType))
+ || (valueType != null && !config.getValueType().isAssignableFrom(valueType)))
+ {
+ throw new IllegalArgumentException("this cache is <" + config.getKeyType().getName() + ", " + config.getValueType().getName()
+ + "> " + " and not <" + keyType.getName() + ", " + valueType.getName() + ">");
+ }
+ return cache;
+ }
+
+ @Override
+ public CachingProvider getCachingProvider()
+ {
+ return provider;
+ }
+
+ @Override
+ public URI getURI()
+ {
+ return uri;
+ }
+
+ @Override
+ public ClassLoader getClassLoader()
+ {
+ return loader;
+ }
+
+ @Override
+ public Properties getProperties()
+ {
+ return configProperties;
+ }
+
+ public void release(final String name) {
+ caches.remove(name);
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSCachingProvider.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSCachingProvider.java
new file mode 100644
index 0000000..52929c3
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSCachingProvider.java
@@ -0,0 +1,158 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import javax.cache.CacheManager;
+import javax.cache.configuration.OptionalFeature;
+import javax.cache.spi.CachingProvider;
+import java.net.URI;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+public class JCSCachingProvider implements CachingProvider
+{
+ public static final URI DEFAULT_URI = URI.create("jcs://jcache.ccf");
+
+ private final ConcurrentMap<ClassLoader, ConcurrentMap<URI, CacheManager>> cacheManagersByLoader = new ConcurrentHashMap<>();
+
+ @Override
+ public CacheManager getCacheManager(final URI inUri, final ClassLoader inClassLoader, final Properties properties)
+ {
+ final URI uri = inUri != null ? inUri : getDefaultURI();
+ final ClassLoader classLoader = inClassLoader != null ? inClassLoader : getDefaultClassLoader();
+
+ ConcurrentMap<URI, CacheManager> managers = cacheManagersByLoader.get(classLoader);
+ if (managers == null)
+ {
+ managers = new ConcurrentHashMap<>();
+ final ConcurrentMap<URI, CacheManager> existingManagers = cacheManagersByLoader.putIfAbsent(classLoader, managers);
+ if (existingManagers != null)
+ {
+ managers = existingManagers;
+ }
+ }
+
+ CacheManager mgr = managers.get(uri);
+ if (mgr == null)
+ {
+ mgr = new JCSCachingManager(this, uri, classLoader, properties);
+ final CacheManager existing = managers.putIfAbsent(uri, mgr);
+ if (existing != null)
+ {
+ mgr = existing;
+ }
+ }
+
+ return mgr;
+ }
+
+ @Override
+ public URI getDefaultURI()
+ {
+ return DEFAULT_URI;
+ }
+
+ @Override
+ public void close()
+ {
+ for (final Map<URI, CacheManager> v : cacheManagersByLoader.values())
+ {
+ for (final CacheManager m : v.values())
+ {
+ m.close();
+ }
+ v.clear();
+ }
+ cacheManagersByLoader.clear();
+ }
+
+ @Override
+ public void close(final ClassLoader classLoader)
+ {
+ final Map<URI, CacheManager> cacheManagers = cacheManagersByLoader.remove(classLoader);
+ if (cacheManagers != null)
+ {
+ for (final CacheManager mgr : cacheManagers.values())
+ {
+ mgr.close();
+ }
+ cacheManagers.clear();
+ }
+ }
+
+ @Override
+ public void close(final URI uri, final ClassLoader classLoader)
+ {
+ final Map<URI, CacheManager> cacheManagers = cacheManagersByLoader.remove(classLoader);
+ if (cacheManagers != null)
+ {
+ final CacheManager mgr = cacheManagers.remove(uri);
+ if (mgr != null)
+ {
+ mgr.close();
+ }
+ }
+ }
+
+ @Override
+ public CacheManager getCacheManager(final URI uri, final ClassLoader classLoader)
+ {
+ return getCacheManager(uri, classLoader, getDefaultProperties());
+ }
+
+ @Override
+ public CacheManager getCacheManager()
+ {
+ return getCacheManager(getDefaultURI(), getDefaultClassLoader());
+ }
+
+ @Override
+ public boolean isSupported(final OptionalFeature optionalFeature)
+ {
+ return optionalFeature == OptionalFeature.STORE_BY_REFERENCE;
+ }
+
+ @Override
+ public ClassLoader getDefaultClassLoader()
+ {
+ return JCSCachingProvider.class.getClassLoader();
+ }
+
+ @Override
+ public Properties getDefaultProperties()
+ {
+ return new Properties();
+ }
+
+ void remove(final CacheManager mgr)
+ {
+ final ClassLoader classLoader = mgr.getClassLoader();
+ final Map<URI, CacheManager> mgrs = cacheManagersByLoader.get(classLoader);
+ if (mgrs != null)
+ {
+ mgrs.remove(mgr.getURI());
+ if (mgrs.isEmpty())
+ {
+ cacheManagersByLoader.remove(classLoader);
+ }
+ }
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSConfiguration.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSConfiguration.java
new file mode 100644
index 0000000..ffd7195
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSConfiguration.java
@@ -0,0 +1,200 @@
+/*
+ * 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.
+ */
+/**
+ * Copyright 2003-2010 Terracotta, Inc.
+ *
+ * Licensed 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.apache.commons.jcs3.jcache;
+
+import javax.cache.configuration.CacheEntryListenerConfiguration;
+import javax.cache.configuration.CompleteConfiguration;
+import javax.cache.configuration.Configuration;
+import javax.cache.configuration.Factory;
+import javax.cache.expiry.EternalExpiryPolicy;
+import javax.cache.expiry.ExpiryPolicy;
+import javax.cache.integration.CacheLoader;
+import javax.cache.integration.CacheWriter;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+public class JCSConfiguration<K, V> implements CompleteConfiguration<K, V>
+{
+
+ private final Class<K> keyType;
+ private final Class<V> valueType;
+ private final boolean storeByValue;
+ private final boolean readThrough;
+ private final boolean writeThrough;
+ private final Factory<CacheLoader<K, V>> cacheLoaderFactory;
+ private final Factory<CacheWriter<? super K, ? super V>> cacheWristerFactory;
+ private final Factory<ExpiryPolicy> expiryPolicyFactory;
+ private final Set<CacheEntryListenerConfiguration<K, V>> cacheEntryListenerConfigurations;
+
+ private volatile boolean statisticsEnabled;
+ private volatile boolean managementEnabled;
+
+ public JCSConfiguration(final Configuration<K, V> configuration, final Class<K> keyType, final Class<V> valueType)
+ {
+ this.keyType = keyType;
+ this.valueType = valueType;
+ if (configuration instanceof CompleteConfiguration)
+ {
+ final CompleteConfiguration<K, V> cConfiguration = (CompleteConfiguration<K, V>) configuration;
+ storeByValue = configuration.isStoreByValue();
+ readThrough = cConfiguration.isReadThrough();
+ writeThrough = cConfiguration.isWriteThrough();
+ statisticsEnabled = cConfiguration.isStatisticsEnabled();
+ managementEnabled = cConfiguration.isManagementEnabled();
+ cacheLoaderFactory = cConfiguration.getCacheLoaderFactory();
+ cacheWristerFactory = cConfiguration.getCacheWriterFactory();
+ this.expiryPolicyFactory = cConfiguration.getExpiryPolicyFactory();
+ cacheEntryListenerConfigurations = new HashSet<>();
+
+ final Iterable<CacheEntryListenerConfiguration<K, V>> entryListenerConfigurations = cConfiguration
+ .getCacheEntryListenerConfigurations();
+ if (entryListenerConfigurations != null)
+ {
+ for (final CacheEntryListenerConfiguration<K, V> kvCacheEntryListenerConfiguration : entryListenerConfigurations)
+ {
+ cacheEntryListenerConfigurations.add(kvCacheEntryListenerConfiguration);
+ }
+ }
+ }
+ else
+ {
+ expiryPolicyFactory = EternalExpiryPolicy.factoryOf();
+ storeByValue = true;
+ readThrough = false;
+ writeThrough = false;
+ statisticsEnabled = false;
+ managementEnabled = false;
+ cacheLoaderFactory = null;
+ cacheWristerFactory = null;
+ cacheEntryListenerConfigurations = new HashSet<>();
+ }
+ }
+
+ @Override
+ public Class<K> getKeyType()
+ {
+ return keyType == null ? (Class<K>) Object.class : keyType;
+ }
+
+ @Override
+ public Class<V> getValueType()
+ {
+ return valueType == null ? (Class<V>) Object.class : valueType;
+ }
+
+ @Override
+ public boolean isStoreByValue()
+ {
+ return storeByValue;
+ }
+
+ @Override
+ public boolean isReadThrough()
+ {
+ return readThrough;
+ }
+
+ @Override
+ public boolean isWriteThrough()
+ {
+ return writeThrough;
+ }
+
+ @Override
+ public boolean isStatisticsEnabled()
+ {
+ return statisticsEnabled;
+ }
+
+ @Override
+ public boolean isManagementEnabled()
+ {
+ return managementEnabled;
+ }
+
+ @Override
+ public Iterable<CacheEntryListenerConfiguration<K, V>> getCacheEntryListenerConfigurations()
+ {
+ return Collections.unmodifiableSet(cacheEntryListenerConfigurations);
+ }
+
+ @Override
+ public Factory<CacheLoader<K, V>> getCacheLoaderFactory()
+ {
+ return cacheLoaderFactory;
+ }
+
+ @Override
+ public Factory<CacheWriter<? super K, ? super V>> getCacheWriterFactory()
+ {
+ return cacheWristerFactory;
+ }
+
+ @Override
+ public Factory<ExpiryPolicy> getExpiryPolicyFactory()
+ {
+ return expiryPolicyFactory;
+ }
+
+ public synchronized void addListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
+ {
+ cacheEntryListenerConfigurations.add(cacheEntryListenerConfiguration);
+ }
+
+ public synchronized void removeListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
+ {
+ cacheEntryListenerConfigurations.remove(cacheEntryListenerConfiguration);
+ }
+
+ public void statisticsEnabled()
+ {
+ statisticsEnabled = true;
+ }
+
+ public void managementEnabled()
+ {
+ managementEnabled = true;
+ }
+
+ public void statisticsDisabled()
+ {
+ statisticsEnabled = false;
+ }
+
+ public void managementDisabled()
+ {
+ managementEnabled = false;
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSEntry.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSEntry.java
new file mode 100644
index 0000000..83e9d3e
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSEntry.java
@@ -0,0 +1,55 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import javax.cache.Cache;
+
+public class JCSEntry<K, V> implements Cache.Entry<K, V>
+{
+ private final K key;
+ private final V value;
+
+ public JCSEntry(final K key, final V value)
+ {
+ this.key = key;
+ this.value = value;
+ }
+
+ @Override
+ public K getKey()
+ {
+ return key;
+ }
+
+ @Override
+ public V getValue()
+ {
+ return value;
+ }
+
+ @Override
+ public <T> T unwrap(final Class<T> clazz)
+ {
+ if (clazz.isInstance(this))
+ {
+ return clazz.cast(this);
+ }
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSListener.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSListener.java
new file mode 100644
index 0000000..b0387e4
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSListener.java
@@ -0,0 +1,127 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import javax.cache.configuration.CacheEntryListenerConfiguration;
+import javax.cache.configuration.Factory;
+import javax.cache.event.CacheEntryCreatedListener;
+import javax.cache.event.CacheEntryEvent;
+import javax.cache.event.CacheEntryEventFilter;
+import javax.cache.event.CacheEntryExpiredListener;
+import javax.cache.event.CacheEntryListener;
+import javax.cache.event.CacheEntryListenerException;
+import javax.cache.event.CacheEntryRemovedListener;
+import javax.cache.event.CacheEntryUpdatedListener;
+import java.io.Closeable;
+import java.util.ArrayList;
+import java.util.List;
+
+public class JCSListener<K, V> implements Closeable
+{
+ private final boolean oldValue;
+ private final boolean synchronous;
+ private final CacheEntryEventFilter<? super K, ? super V> filter;
+ private final CacheEntryListener<? super K, ? super V> delegate;
+ private final boolean remove;
+ private final boolean expire;
+ private final boolean update;
+ private final boolean create;
+
+ public JCSListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
+ {
+ oldValue = cacheEntryListenerConfiguration.isOldValueRequired();
+ synchronous = cacheEntryListenerConfiguration.isSynchronous();
+
+ final Factory<CacheEntryEventFilter<? super K, ? super V>> filterFactory = cacheEntryListenerConfiguration
+ .getCacheEntryEventFilterFactory();
+ if (filterFactory == null)
+ {
+ filter = NoFilter.INSTANCE;
+ }
+ else
+ {
+ filter = filterFactory.create();
+ }
+
+ delegate = cacheEntryListenerConfiguration.getCacheEntryListenerFactory().create();
+ remove = CacheEntryRemovedListener.class.isInstance(delegate);
+ expire = CacheEntryExpiredListener.class.isInstance(delegate);
+ update = CacheEntryUpdatedListener.class.isInstance(delegate);
+ create = CacheEntryCreatedListener.class.isInstance(delegate);
+ }
+
+ public void onRemoved(final List<CacheEntryEvent<? extends K, ? extends V>> events) throws CacheEntryListenerException
+ {
+ if (remove)
+ {
+ CacheEntryRemovedListener.class.cast(delegate).onRemoved(filter(events));
+ }
+ }
+
+ public void onExpired(final List<CacheEntryEvent<? extends K, ? extends V>> events) throws CacheEntryListenerException
+ {
+ if (expire)
+ {
+ CacheEntryExpiredListener.class.cast(delegate).onExpired(filter(events));
+ }
+ }
+
+ public void onUpdated(final List<CacheEntryEvent<? extends K, ? extends V>> events) throws CacheEntryListenerException
+ {
+ if (update)
+ {
+ CacheEntryUpdatedListener.class.cast(delegate).onUpdated(filter(events));
+ }
+ }
+
+ public void onCreated(final List<CacheEntryEvent<? extends K, ? extends V>> events) throws CacheEntryListenerException
+ {
+ if (create)
+ {
+ CacheEntryCreatedListener.class.cast(delegate).onCreated(filter(events));
+ }
+ }
+
+ private Iterable<CacheEntryEvent<? extends K, ? extends V>> filter(final List<CacheEntryEvent<? extends K, ? extends V>> events)
+ {
+ if (filter == NoFilter.INSTANCE)
+ {
+ return events;
+ }
+
+ final List<CacheEntryEvent<? extends K, ? extends V>> filtered = new ArrayList<>(
+ events.size());
+ for (final CacheEntryEvent<? extends K, ? extends V> event : events)
+ {
+ if (filter.evaluate(event))
+ {
+ filtered.add(event);
+ }
+ }
+ return filtered;
+ }
+
+ @Override
+ public void close()
+ {
+ if (Closeable.class.isInstance(delegate)) {
+ Closeable.class.cast(delegate);
+ }
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSMutableEntry.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSMutableEntry.java
new file mode 100644
index 0000000..38c296a
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/JCSMutableEntry.java
@@ -0,0 +1,74 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import javax.cache.Cache;
+import javax.cache.processor.MutableEntry;
+
+public class JCSMutableEntry<K, V> implements MutableEntry<K, V>
+{
+ private final Cache<K, V> cache;
+ private final K key;
+
+ public JCSMutableEntry(final Cache<K, V> cache, final K key)
+ {
+ this.cache = cache;
+ this.key = key;
+ }
+
+ @Override
+ public boolean exists()
+ {
+ return cache.containsKey(key);
+ }
+
+ @Override
+ public void remove()
+ {
+ cache.remove(key);
+ }
+
+ @Override
+ public void setValue(final V value)
+ {
+ cache.put(key, value);
+ }
+
+ @Override
+ public K getKey()
+ {
+ return key;
+ }
+
+ @Override
+ public V getValue()
+ {
+ return cache.get(key);
+ }
+
+ @Override
+ public <T> T unwrap(final Class<T> clazz)
+ {
+ if (clazz.isInstance(this))
+ {
+ return clazz.cast(this);
+ }
+ throw new IllegalArgumentException(clazz.getName() + " not supported in unwrap");
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/NoFilter.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/NoFilter.java
new file mode 100644
index 0000000..7d4a67b
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/NoFilter.java
@@ -0,0 +1,39 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import javax.cache.event.CacheEntryEvent;
+import javax.cache.event.CacheEntryEventFilter;
+import javax.cache.event.CacheEntryListenerException;
+
+public class NoFilter implements CacheEntryEventFilter<Object, Object>
+{
+ public static final CacheEntryEventFilter<Object, Object> INSTANCE = new NoFilter();
+
+ private NoFilter()
+ {
+ // no-op
+ }
+
+ @Override
+ public boolean evaluate(final CacheEntryEvent<?, ?> event) throws CacheEntryListenerException
+ {
+ return true;
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/NoLoader.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/NoLoader.java
new file mode 100644
index 0000000..e3a1bbe
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/NoLoader.java
@@ -0,0 +1,51 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import javax.cache.integration.CacheLoader;
+import javax.cache.integration.CacheLoaderException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class NoLoader<K, V> implements CacheLoader<K, V>
+{
+ public static final NoLoader INSTANCE = new NoLoader();
+
+ private NoLoader()
+ {
+ // no-op
+ }
+
+ @Override
+ public V load(K key) throws CacheLoaderException
+ {
+ return null;
+ }
+
+ @Override
+ public Map<K, V> loadAll(final Iterable<? extends K> keys) throws CacheLoaderException
+ {
+ final Map<K, V> entries = new HashMap<>();
+ for (final K k : keys)
+ {
+ entries.put(k, null);
+ }
+ return entries;
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/NoWriter.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/NoWriter.java
new file mode 100644
index 0000000..939d3a6
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/NoWriter.java
@@ -0,0 +1,59 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import javax.cache.Cache;
+import javax.cache.integration.CacheWriter;
+import javax.cache.integration.CacheWriterException;
+import java.util.Collection;
+
+public class NoWriter<K, V> implements CacheWriter<K, V>
+{
+ public static final NoWriter INSTANCE = new NoWriter();
+
+ @Override
+ public void write(final Cache.Entry<? extends K, ? extends V> entry) throws CacheWriterException
+ {
+ // no-op
+ }
+
+ @Override
+ public void delete(final Object key) throws CacheWriterException
+ {
+ // no-op
+ }
+
+ @Override
+ public void writeAll(final Collection<Cache.Entry<? extends K, ? extends V>> entries) throws CacheWriterException
+ {
+ for (final Cache.Entry<? extends K, ? extends V> entry : entries)
+ {
+ write(entry);
+ }
+ }
+
+ @Override
+ public void deleteAll(final Collection<?> keys) throws CacheWriterException
+ {
+ for (final Object k : keys)
+ {
+ delete(k);
+ }
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/Statistics.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/Statistics.java
new file mode 100644
index 0000000..91613e1
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/Statistics.java
@@ -0,0 +1,166 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+public class Statistics
+{
+ private volatile boolean active = true;
+
+ private final AtomicLong removals = new AtomicLong();
+ private final AtomicLong expiries = new AtomicLong();
+ private final AtomicLong puts = new AtomicLong();
+ private final AtomicLong hits = new AtomicLong();
+ private final AtomicLong misses = new AtomicLong();
+ private final AtomicLong evictions = new AtomicLong();
+ private final AtomicLong putTimeTaken = new AtomicLong();
+ private final AtomicLong getTimeTaken = new AtomicLong();
+ private final AtomicLong removeTimeTaken = new AtomicLong();
+
+ public long getHits()
+ {
+ return hits.get();
+ }
+
+ public long getMisses()
+ {
+ return misses.get();
+ }
+
+ public long getPuts()
+ {
+ return puts.get();
+ }
+
+ public long getRemovals()
+ {
+ return removals.get();
+ }
+
+ public long getEvictions()
+ {
+ return evictions.get();
+ }
+
+ public long getTimeTakenForGets()
+ {
+ return getTimeTaken.get();
+ }
+
+ public long getTimeTakenForPuts()
+ {
+ return putTimeTaken.get();
+ }
+
+ public long getTimeTakenForRemovals()
+ {
+ return removeTimeTaken.get();
+ }
+
+ public void increaseRemovals(final long number)
+ {
+ increment(removals, number);
+ }
+
+ public void increaseExpiries(final long number)
+ {
+ increment(expiries, number);
+ }
+
+ public void increasePuts(final long number)
+ {
+ increment(puts, number);
+ }
+
+ public void increaseHits(final long number)
+ {
+ increment(hits, number);
+ }
+
+ public void increaseMisses(final long number)
+ {
+ increment(misses, number);
+ }
+
+ public void increaseEvictions(final long number)
+ {
+ increment(evictions, number);
+ }
+
+ public void addGetTime(final long duration)
+ {
+ increment(duration, getTimeTaken);
+ }
+
+ public void addPutTime(final long duration)
+ {
+ increment(duration, putTimeTaken);
+ }
+
+ public void addRemoveTime(final long duration)
+ {
+ increment(duration, removeTimeTaken);
+ }
+
+ private void increment(final AtomicLong counter, final long number)
+ {
+ if (!active)
+ {
+ return;
+ }
+ counter.addAndGet(number);
+ }
+
+ private void increment(final long duration, final AtomicLong counter)
+ {
+ if (!active)
+ {
+ return;
+ }
+
+ if (counter.get() < Long.MAX_VALUE - duration)
+ {
+ counter.addAndGet(duration);
+ }
+ else
+ {
+ reset();
+ counter.set(duration);
+ }
+ }
+
+ public void reset()
+ {
+ puts.set(0);
+ misses.set(0);
+ removals.set(0);
+ expiries.set(0);
+ hits.set(0);
+ evictions.set(0);
+ getTimeTaken.set(0);
+ putTimeTaken.set(0);
+ removeTimeTaken.set(0);
+ }
+
+ public void setActive(final boolean active)
+ {
+ this.active = active;
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/TempStateCacheView.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/TempStateCacheView.java
new file mode 100644
index 0000000..f3436c3
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/TempStateCacheView.java
@@ -0,0 +1,352 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.configuration.CacheEntryListenerConfiguration;
+import javax.cache.configuration.CompleteConfiguration;
+import javax.cache.configuration.Configuration;
+import javax.cache.integration.CompletionListener;
+import javax.cache.processor.EntryProcessor;
+import javax.cache.processor.EntryProcessorException;
+import javax.cache.processor.EntryProcessorResult;
+
+import static org.apache.commons.jcs3.jcache.Asserts.assertNotNull;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+
+// kind of transactional view for a Cache<K, V>, to use with EntryProcessor
+public class TempStateCacheView<K, V> implements Cache<K, V>
+{
+ private final JCSCache<K, V> cache;
+ private final Map<K, V> put = new HashMap<>();
+ private final Collection<K> remove = new LinkedList<>();
+ private boolean removeAll = false;
+ private boolean clear = false;
+
+ public TempStateCacheView(final JCSCache<K, V> entries)
+ {
+ this.cache = entries;
+ }
+
+ @Override
+ public V get(final K key)
+ {
+ if (ignoreKey(key))
+ {
+ return null;
+ }
+
+ final V v = put.get(key);
+ if (v != null)
+ {
+ return v;
+ }
+
+ // for an EntryProcessor we already incremented stats - to enhance
+ // surely
+ if (cache.getConfiguration(CompleteConfiguration.class).isStatisticsEnabled())
+ {
+ final Statistics statistics = cache.getStatistics();
+ if (cache.containsKey(key))
+ {
+ statistics.increaseHits(-1);
+ }
+ else
+ {
+ statistics.increaseMisses(-1);
+ }
+ }
+ return cache.get(key);
+ }
+
+ private boolean ignoreKey(final K key)
+ {
+ return removeAll || clear || remove.contains(key);
+ }
+
+ @Override
+ public Map<K, V> getAll(final Set<? extends K> keys)
+ {
+ final Map<K, V> v = new HashMap<>(keys.size());
+ final Set<K> missing = new HashSet<>();
+ for (final K k : keys)
+ {
+ final V value = put.get(k);
+ if (value != null)
+ {
+ v.put(k, value);
+ }
+ else if (!ignoreKey(k))
+ {
+ missing.add(k);
+ }
+ }
+ if (!missing.isEmpty())
+ {
+ v.putAll(cache.getAll(missing));
+ }
+ return v;
+ }
+
+ @Override
+ public boolean containsKey(final K key)
+ {
+ return !ignoreKey(key) && (put.containsKey(key) || cache.containsKey(key));
+ }
+
+ @Override
+ public void loadAll(final Set<? extends K> keys, final boolean replaceExistingValues, final CompletionListener completionListener)
+ {
+ cache.loadAll(keys, replaceExistingValues, completionListener);
+ }
+
+ @Override
+ public void put(final K key, final V value)
+ {
+ assertNotNull(key, "key");
+ assertNotNull(value, "value");
+ put.put(key, value);
+ remove.remove(key);
+ }
+
+ @Override
+ public V getAndPut(final K key, final V value)
+ {
+ final V v = get(key);
+ put(key, value);
+ return v;
+ }
+
+ @Override
+ public void putAll(final Map<? extends K, ? extends V> map)
+ {
+ put.putAll(map);
+ for (final K k : map.keySet())
+ {
+ remove.remove(k);
+ }
+ }
+
+ @Override
+ public boolean putIfAbsent(final K key, final V value)
+ {
+ if (!put.containsKey(key))
+ {
+ put.put(key, value);
+ remove.remove(key);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean remove(final K key)
+ {
+ final boolean noop = put.containsKey(key);
+ put.remove(key);
+ if (!ignoreKey(key))
+ {
+ if (!noop)
+ {
+ remove.add(key);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean remove(final K key, final V oldValue)
+ {
+ put.remove(key);
+ if (!ignoreKey(key) && oldValue.equals(cache.get(key)))
+ {
+ remove.add(key);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public V getAndRemove(final K key)
+ {
+ final V v = get(key);
+ remove.add(key);
+ put.remove(key);
+ return v;
+ }
+
+ @Override
+ public boolean replace(final K key, final V oldValue, final V newValue)
+ {
+ if (oldValue.equals(get(key)))
+ {
+ put(key, newValue);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean replace(final K key, final V value)
+ {
+ if (containsKey(key))
+ {
+ remove(key);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public V getAndReplace(final K key, final V value)
+ {
+ if (containsKey(key))
+ {
+ final V oldValue = get(key);
+ put(key, value);
+ return oldValue;
+ }
+ return null;
+ }
+
+ @Override
+ public void removeAll(final Set<? extends K> keys)
+ {
+ remove.addAll(keys);
+ for (final K k : keys)
+ {
+ put.remove(k);
+ }
+ }
+
+ @Override
+ public void removeAll()
+ {
+ removeAll = true;
+ put.clear();
+ remove.clear();
+ }
+
+ @Override
+ public void clear()
+ {
+ clear = true;
+ put.clear();
+ remove.clear();
+ }
+
+ @Override
+ public <C extends Configuration<K, V>> C getConfiguration(final Class<C> clazz)
+ {
+ return cache.getConfiguration(clazz);
+ }
+
+ @Override
+ public <T> T invoke(final K key, final EntryProcessor<K, V, T> entryProcessor, final Object... arguments) throws EntryProcessorException
+ {
+ return cache.invoke(key, entryProcessor, arguments);
+ }
+
+ @Override
+ public <T> Map<K, EntryProcessorResult<T>> invokeAll(Set<? extends K> keys, final EntryProcessor<K, V, T> entryProcessor,
+ final Object... arguments)
+ {
+ return cache.invokeAll(keys, entryProcessor, arguments);
+ }
+
+ @Override
+ public String getName()
+ {
+ return cache.getName();
+ }
+
+ @Override
+ public CacheManager getCacheManager()
+ {
+ return cache.getCacheManager();
+ }
+
+ @Override
+ public void close()
+ {
+ cache.close();
+ }
+
+ @Override
+ public boolean isClosed()
+ {
+ return cache.isClosed();
+ }
+
+ @Override
+ public <T> T unwrap(final Class<T> clazz)
+ {
+ return cache.unwrap(clazz);
+ }
+
+ @Override
+ public void registerCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
+ {
+ cache.registerCacheEntryListener(cacheEntryListenerConfiguration);
+ }
+
+ @Override
+ public void deregisterCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
+ {
+ cache.deregisterCacheEntryListener(cacheEntryListenerConfiguration);
+ }
+
+ @Override
+ public Iterator<Entry<K, V>> iterator()
+ {
+ return cache.iterator();
+ }
+
+ public void merge()
+ {
+ if (removeAll)
+ {
+ cache.removeAll();
+ }
+ if (clear)
+ {
+ cache.clear();
+ }
+
+ for (final Map.Entry<K, V> entry : put.entrySet())
+ {
+ cache.put(entry.getKey(), entry.getValue());
+ }
+ put.clear();
+ for (final K entry : remove)
+ {
+ cache.remove(entry);
+ }
+ remove.clear();
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/Times.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/Times.java
new file mode 100644
index 0000000..26c22d1
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/Times.java
@@ -0,0 +1,37 @@
+package org.apache.commons.jcs3.jcache;
+
+/*
+ * 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.
+ */
+
+public class Times
+{
+ public static long now(final boolean ignore)
+ {
+ if (ignore)
+ {
+ return -1;
+ }
+ return System.nanoTime() / 1000;
+ }
+
+ private Times()
+ {
+ // no-op
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CDIJCacheHelper.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CDIJCacheHelper.java
new file mode 100644
index 0000000..6a5eab8
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CDIJCacheHelper.java
@@ -0,0 +1,670 @@
+/*
+ * 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.apache.commons.jcs3.jcache.cdi;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.logging.Logger;
+
+import javax.annotation.PreDestroy;
+import javax.cache.annotation.CacheDefaults;
+import javax.cache.annotation.CacheKey;
+import javax.cache.annotation.CacheKeyGenerator;
+import javax.cache.annotation.CachePut;
+import javax.cache.annotation.CacheRemove;
+import javax.cache.annotation.CacheRemoveAll;
+import javax.cache.annotation.CacheResolverFactory;
+import javax.cache.annotation.CacheResult;
+import javax.cache.annotation.CacheValue;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.inject.Inject;
+import javax.interceptor.InvocationContext;
+
+@ApplicationScoped
+public class CDIJCacheHelper
+{
+ private static final Logger LOGGER = Logger.getLogger(CDIJCacheHelper.class.getName());
+ private static final boolean CLOSE_CACHE = !Boolean.getBoolean("org.apache.commons.jcs3.jcache.cdi.skip-close");
+
+ private volatile CacheResolverFactoryImpl defaultCacheResolverFactory = null; // lazy to not create any cache if not needed
+ private final CacheKeyGeneratorImpl defaultCacheKeyGenerator = new CacheKeyGeneratorImpl();
+
+ private final Collection<CreationalContext<?>> toRelease = new ArrayList<>();
+ private final ConcurrentMap<MethodKey, MethodMeta> methods = new ConcurrentHashMap<>();
+
+ @Inject
+ private BeanManager beanManager;
+
+ @PreDestroy
+ private void release() {
+ if (CLOSE_CACHE && defaultCacheResolverFactory != null)
+ {
+ defaultCacheResolverFactory.release();
+ }
+ for (final CreationalContext<?> cc : toRelease)
+ {
+ try
+ {
+ cc.release();
+ }
+ catch (final RuntimeException re)
+ {
+ LOGGER.warning(re.getMessage());
+ }
+ }
+ }
+
+ public MethodMeta findMeta(final InvocationContext ic)
+ {
+ final Method mtd = ic.getMethod();
+ final Class<?> refType = findKeyType(ic.getTarget());
+ final MethodKey key = new MethodKey(refType, mtd);
+ MethodMeta methodMeta = methods.get(key);
+ if (methodMeta == null)
+ {
+ synchronized (this)
+ {
+ methodMeta = methods.get(key);
+ if (methodMeta == null)
+ {
+ methodMeta = createMeta(ic);
+ methods.put(key, methodMeta);
+ }
+ }
+ }
+ return methodMeta;
+ }
+
+ private Class<?> findKeyType(final Object target)
+ {
+ if (null == target)
+ {
+ return null;
+ }
+ return target.getClass();
+ }
+
+ // it is unlikely we have all annotations but for now we have a single meta model
+ private MethodMeta createMeta(final InvocationContext ic)
+ {
+ final CacheDefaults defaults = findDefaults(ic.getTarget() == null ? null : ic.getTarget()
+ .getClass(), ic.getMethod());
+
+ final Class<?>[] parameterTypes = ic.getMethod().getParameterTypes();
+ final Annotation[][] parameterAnnotations = ic.getMethod().getParameterAnnotations();
+ final List<Set<Annotation>> annotations = new ArrayList<>();
+ for (final Annotation[] parameterAnnotation : parameterAnnotations)
+ {
+ final Set<Annotation> set = new HashSet<>(parameterAnnotation.length);
+ set.addAll(Arrays.asList(parameterAnnotation));
+ annotations.add(set);
+ }
+
+ final Set<Annotation> mtdAnnotations = new HashSet<>();
+ mtdAnnotations.addAll(Arrays.asList(ic.getMethod().getAnnotations()));
+
+ final CacheResult cacheResult = ic.getMethod().getAnnotation(CacheResult.class);
+ final String cacheResultCacheResultName = cacheResult == null ? null : defaultName(ic.getMethod(), defaults, cacheResult.cacheName());
+ final CacheResolverFactory cacheResultCacheResolverFactory = cacheResult == null ?
+ null : cacheResolverFactoryFor(defaults, cacheResult.cacheResolverFactory());
+ final CacheKeyGenerator cacheResultCacheKeyGenerator = cacheResult == null ?
+ null : cacheKeyGeneratorFor(defaults, cacheResult.cacheKeyGenerator());
+
+ final CachePut cachePut = ic.getMethod().getAnnotation(CachePut.class);
+ final String cachePutCachePutName = cachePut == null ? null : defaultName(ic.getMethod(), defaults, cachePut.cacheName());
+ final CacheResolverFactory cachePutCacheResolverFactory = cachePut == null ?
+ null : cacheResolverFactoryFor(defaults, cachePut.cacheResolverFactory());
+ final CacheKeyGenerator cachePutCacheKeyGenerator = cachePut == null ?
+ null : cacheKeyGeneratorFor(defaults, cachePut.cacheKeyGenerator());
+
+ final CacheRemove cacheRemove = ic.getMethod().getAnnotation(CacheRemove.class);
+ final String cacheRemoveCacheRemoveName = cacheRemove == null ? null : defaultName(ic.getMethod(), defaults, cacheRemove.cacheName());
+ final CacheResolverFactory cacheRemoveCacheResolverFactory = cacheRemove == null ?
+ null : cacheResolverFactoryFor(defaults, cacheRemove.cacheResolverFactory());
+ final CacheKeyGenerator cacheRemoveCacheKeyGenerator = cacheRemove == null ?
+ null : cacheKeyGeneratorFor(defaults, cacheRemove.cacheKeyGenerator());
+
+ final CacheRemoveAll cacheRemoveAll = ic.getMethod().getAnnotation(CacheRemoveAll.class);
+ final String cacheRemoveAllCacheRemoveAllName = cacheRemoveAll == null ? null : defaultName(ic.getMethod(), defaults, cacheRemoveAll.cacheName());
+ final CacheResolverFactory cacheRemoveAllCacheResolverFactory = cacheRemoveAll == null ?
+ null : cacheResolverFactoryFor(defaults, cacheRemoveAll.cacheResolverFactory());
+
+ return new MethodMeta(
+ parameterTypes,
+ annotations,
+ mtdAnnotations,
+ keyParameterIndexes(ic.getMethod()),
+ getValueParameter(annotations),
+ getKeyParameters(annotations),
+ cacheResultCacheResultName,
+ cacheResultCacheResolverFactory,
+ cacheResultCacheKeyGenerator,
+ cacheResult,
+ cachePutCachePutName,
+ cachePutCacheResolverFactory,
+ cachePutCacheKeyGenerator,
+ cachePut != null && cachePut.afterInvocation(),
+ cachePut,
+ cacheRemoveCacheRemoveName,
+ cacheRemoveCacheResolverFactory,
+ cacheRemoveCacheKeyGenerator,
+ cacheRemove != null && cacheRemove.afterInvocation(),
+ cacheRemove,
+ cacheRemoveAllCacheRemoveAllName,
+ cacheRemoveAllCacheResolverFactory,
+ cacheRemoveAll != null && cacheRemoveAll.afterInvocation(),
+ cacheRemoveAll);
+ }
+
+ private Integer[] getKeyParameters(final List<Set<Annotation>> annotations)
+ {
+ final Collection<Integer> list = new ArrayList<>();
+ int idx = 0;
+ for (final Set<Annotation> set : annotations)
+ {
+ for (final Annotation a : set)
+ {
+ if (a.annotationType() == CacheKey.class)
+ {
+ list.add(idx);
+ }
+ }
+ idx++;
+ }
+ if (list.isEmpty())
+ {
+ for (int i = 0; i < annotations.size(); i++)
+ {
+ list.add(i);
+ }
+ }
+ return list.toArray(new Integer[list.size()]);
+ }
+
+ private Integer getValueParameter(final List<Set<Annotation>> annotations)
+ {
+ int idx = 0;
+ for (final Set<Annotation> set : annotations)
+ {
+ for (final Annotation a : set)
+ {
+ if (a.annotationType() == CacheValue.class)
+ {
+ return idx;
+ }
+ }
+ }
+ return -1;
+ }
+
+ private String defaultName(final Method method, final CacheDefaults defaults, final String cacheName)
+ {
+ if (!cacheName.isEmpty())
+ {
+ return cacheName;
+ }
+ if (defaults != null)
+ {
+ final String name = defaults.cacheName();
+ if (!name.isEmpty())
+ {
+ return name;
+ }
+ }
+
+ final StringBuilder name = new StringBuilder(method.getDeclaringClass().getName());
+ name.append(".");
+ name.append(method.getName());
+ name.append("(");
+ final Class<?>[] parameterTypes = method.getParameterTypes();
+ for (int pIdx = 0; pIdx < parameterTypes.length; pIdx++)
+ {
+ name.append(parameterTypes[pIdx].getName());
+ if ((pIdx + 1) < parameterTypes.length)
+ {
+ name.append(",");
+ }
+ }
+ name.append(")");
+ return name.toString();
+ }
+
+ private CacheDefaults findDefaults(final Class<?> targetType, final Method method)
+ {
+ if (Proxy.isProxyClass(targetType)) // target doesnt hold annotations
+ {
+ final Class<?> api = method.getDeclaringClass();
+ for (final Class<?> type : targetType
+ .getInterfaces())
+ {
+ if (!api.isAssignableFrom(type))
+ {
+ continue;
+ }
+ return extractDefaults(type);
+ }
+ }
+ return extractDefaults(targetType);
+ }
+
+ private CacheDefaults extractDefaults(final Class<?> type)
+ {
+ CacheDefaults annotation = null;
+ Class<?> clazz = type;
+ while (clazz != null && clazz != Object.class)
+ {
+ annotation = clazz.getAnnotation(CacheDefaults.class);
+ if (annotation != null)
+ {
+ break;
+ }
+ clazz = clazz.getSuperclass();
+ }
+ return annotation;
+ }
+
+ public boolean isIncluded(final Class<?> aClass, final Class<?>[] in, final Class<?>[] out)
+ {
+ if (in.length == 0 && out.length == 0)
+ {
+ return false;
+ }
+ for (final Class<?> potentialIn : in)
+ {
+ if (potentialIn.isAssignableFrom(aClass))
+ {
+ for (final Class<?> potentialOut : out)
+ {
+ if (potentialOut.isAssignableFrom(aClass))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private CacheKeyGenerator cacheKeyGeneratorFor(final CacheDefaults defaults, final Class<? extends CacheKeyGenerator> cacheKeyGenerator)
+ {
+ if (!CacheKeyGenerator.class.equals(cacheKeyGenerator))
+ {
+ return instance(cacheKeyGenerator);
+ }
+ if (defaults != null)
+ {
+ final Class<? extends CacheKeyGenerator> defaultCacheKeyGenerator = defaults.cacheKeyGenerator();
+ if (!CacheKeyGenerator.class.equals(defaultCacheKeyGenerator))
+ {
+ return instance(defaultCacheKeyGenerator);
+ }
+ }
+ return defaultCacheKeyGenerator;
+ }
+
+ private CacheResolverFactory cacheResolverFactoryFor(final CacheDefaults defaults, final Class<? extends CacheResolverFactory> cacheResolverFactory)
+ {
+ if (!CacheResolverFactory.class.equals(cacheResolverFactory))
+ {
+ return instance(cacheResolverFactory);
+ }
+ if (defaults != null)
+ {
+ final Class<? extends CacheResolverFactory> defaultCacheResolverFactory = defaults.cacheResolverFactory();
+ if (!CacheResolverFactory.class.equals(defaultCacheResolverFactory))
+ {
+ return instance(defaultCacheResolverFactory);
+ }
+ }
+ return defaultCacheResolverFactory();
+ }
+
+ private <T> T instance(final Class<T> type)
+ {
+ final Set<Bean<?>> beans = beanManager.getBeans(type);
+ if (beans.isEmpty())
+ {
+ if (CacheKeyGenerator.class == type) {
+ return (T) defaultCacheKeyGenerator;
+ }
+ if (CacheResolverFactory.class == type) {
+ return (T) defaultCacheResolverFactory();
+ }
+ return null;
+ }
+ final Bean<?> bean = beanManager.resolve(beans);
+ final CreationalContext<?> context = beanManager.createCreationalContext(bean);
+ final Class<? extends Annotation> scope = bean.getScope();
+ final boolean normalScope = beanManager.isNormalScope(scope);
+ try
+ {
+ final Object reference = beanManager.getReference(bean, bean.getBeanClass(), context);
+ if (!normalScope)
+ {
+ toRelease.add(context);
+ }
+ return (T) reference;
+ }
+ finally
+ {
+ if (normalScope)
+ { // TODO: release at the right moment, @PreDestroy? question is: do we assume it is thread safe?
+ context.release();
+ }
+ }
+ }
+
+ private CacheResolverFactoryImpl defaultCacheResolverFactory()
+ {
+ if (defaultCacheResolverFactory != null) {
+ return defaultCacheResolverFactory;
+ }
+ synchronized (this) {
+ if (defaultCacheResolverFactory != null) {
+ return defaultCacheResolverFactory;
+ }
+ defaultCacheResolverFactory = new CacheResolverFactoryImpl();
+ }
+ return defaultCacheResolverFactory;
+ }
+
+ private Integer[] keyParameterIndexes(final Method method)
+ {
+ final List<Integer> keys = new LinkedList<>();
+ final Annotation[][] parameterAnnotations = method.getParameterAnnotations();
+
+ // first check if keys are specified explicitely
+ for (int i = 0; i < method.getParameterTypes().length; i++)
+ {
+ final Annotation[] annotations = parameterAnnotations[i];
+ for (final Annotation a : annotations)
+ {
+ if (a.annotationType().equals(CacheKey.class))
+ {
+ keys.add(i);
+ break;
+ }
+ }
+ }
+
+ // if not then use all parameters but value ones
+ if (keys.isEmpty())
+ {
+ for (int i = 0; i < method.getParameterTypes().length; i++)
+ {
+ final Annotation[] annotations = parameterAnnotations[i];
+ boolean value = false;
+ for (final Annotation a : annotations)
+ {
+ if (a.annotationType().equals(CacheValue.class))
+ {
+ value = true;
+ break;
+ }
+ }
+ if (!value) {
+ keys.add(i);
+ }
+ }
+ }
+ return keys.toArray(new Integer[keys.size()]);
+ }
+
+ private static final class MethodKey
+ {
+ private final Class<?> base;
+ private final Method delegate;
+ private final int hash;
+
+ private MethodKey(final Class<?> base, final Method delegate)
+ {
+ this.base = base; // we need a class to ensure inheritance don't fall in the same key
+ this.delegate = delegate;
+ this.hash = 31 * delegate.hashCode() + (base == null ? 0 : base.hashCode());
+ }
+
+ @Override
+ public boolean equals(final Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass())
+ {
+ return false;
+ }
+ final MethodKey classKey = MethodKey.class.cast(o);
+ return delegate.equals(classKey.delegate) && ((base == null && classKey.base == null) || (base != null && base.equals(classKey.base)));
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return hash;
+ }
+ }
+
+ // TODO: split it in 5?
+ public static class MethodMeta
+ {
+ private final Class<?>[] parameterTypes;
+ private final List<Set<Annotation>> parameterAnnotations;
+ private final Set<Annotation> annotations;
+ private final Integer[] keysIndices;
+ private final Integer valueIndex;
+ private final Integer[] parameterIndices;
+
+ private final String cacheResultCacheName;
+ private final CacheResolverFactory cacheResultResolverFactory;
+ private final CacheKeyGenerator cacheResultKeyGenerator;
+ private final CacheResult cacheResult;
+
+ private final String cachePutCacheName;
+ private final CacheResolverFactory cachePutResolverFactory;
+ private final CacheKeyGenerator cachePutKeyGenerator;
+ private final boolean cachePutAfter;
+ private final CachePut cachePut;
+
+ private final String cacheRemoveCacheName;
+ private final CacheResolverFactory cacheRemoveResolverFactory;
+ private final CacheKeyGenerator cacheRemoveKeyGenerator;
+ private final boolean cacheRemoveAfter;
+ private final CacheRemove cacheRemove;
+
+ private final String cacheRemoveAllCacheName;
+ private final CacheResolverFactory cacheRemoveAllResolverFactory;
+ private final boolean cacheRemoveAllAfter;
+ private final CacheRemoveAll cacheRemoveAll;
+
+ public MethodMeta(Class<?>[] parameterTypes, List<Set<Annotation>> parameterAnnotations, Set<Annotation>
+ annotations, Integer[] keysIndices, Integer valueIndex, Integer[] parameterIndices, String
+ cacheResultCacheName, CacheResolverFactory cacheResultResolverFactory, CacheKeyGenerator
+ cacheResultKeyGenerator, CacheResult cacheResult, String cachePutCacheName, CacheResolverFactory
+ cachePutResolverFactory, CacheKeyGenerator cachePutKeyGenerator, boolean cachePutAfter, CachePut cachePut, String
+ cacheRemoveCacheName, CacheResolverFactory cacheRemoveResolverFactory, CacheKeyGenerator
+ cacheRemoveKeyGenerator, boolean cacheRemoveAfter, CacheRemove cacheRemove, String cacheRemoveAllCacheName,
+ CacheResolverFactory cacheRemoveAllResolverFactory, boolean
+ cacheRemoveAllAfter, CacheRemoveAll cacheRemoveAll)
+ {
+ this.parameterTypes = parameterTypes;
+ this.parameterAnnotations = parameterAnnotations;
+ this.annotations = annotations;
+ this.keysIndices = keysIndices;
+ this.valueIndex = valueIndex;
+ this.parameterIndices = parameterIndices;
+ this.cacheResultCacheName = cacheResultCacheName;
+ this.cacheResultResolverFactory = cacheResultResolverFactory;
+ this.cacheResultKeyGenerator = cacheResultKeyGenerator;
+ this.cacheResult = cacheResult;
+ this.cachePutCacheName = cachePutCacheName;
+ this.cachePutResolverFactory = cachePutResolverFactory;
+ this.cachePutKeyGenerator = cachePutKeyGenerator;
+ this.cachePutAfter = cachePutAfter;
+ this.cachePut = cachePut;
+ this.cacheRemoveCacheName = cacheRemoveCacheName;
+ this.cacheRemoveResolverFactory = cacheRemoveResolverFactory;
+ this.cacheRemoveKeyGenerator = cacheRemoveKeyGenerator;
+ this.cacheRemoveAfter = cacheRemoveAfter;
+ this.cacheRemove = cacheRemove;
+ this.cacheRemoveAllCacheName = cacheRemoveAllCacheName;
+ this.cacheRemoveAllResolverFactory = cacheRemoveAllResolverFactory;
+ this.cacheRemoveAllAfter = cacheRemoveAllAfter;
+ this.cacheRemoveAll = cacheRemoveAll;
+ }
+
+ public boolean isCacheRemoveAfter()
+ {
+ return cacheRemoveAfter;
+ }
+
+ public boolean isCachePutAfter()
+ {
+ return cachePutAfter;
+ }
+
+ public Class<?>[] getParameterTypes()
+ {
+ return parameterTypes;
+ }
+
+ public List<Set<Annotation>> getParameterAnnotations()
+ {
+ return parameterAnnotations;
+ }
+
+ public String getCacheResultCacheName()
+ {
+ return cacheResultCacheName;
+ }
+
+ public CacheResolverFactory getCacheResultResolverFactory()
+ {
+ return cacheResultResolverFactory;
+ }
+
+ public CacheKeyGenerator getCacheResultKeyGenerator()
+ {
+ return cacheResultKeyGenerator;
+ }
+
+ public CacheResult getCacheResult() {
+ return cacheResult;
+ }
+
+ public Integer[] getParameterIndices()
+ {
+ return parameterIndices;
+ }
+
+ public Set<Annotation> getAnnotations()
+ {
+ return annotations;
+ }
+
+ public Integer[] getKeysIndices()
+ {
+ return keysIndices;
+ }
+
+ public Integer getValuesIndex()
+ {
+ return valueIndex;
+ }
+
+ public Integer getValueIndex()
+ {
+ return valueIndex;
+ }
+
+ public String getCachePutCacheName()
+ {
+ return cachePutCacheName;
+ }
+
+ public CacheResolverFactory getCachePutResolverFactory()
+ {
+ return cachePutResolverFactory;
+ }
+
+ public CacheKeyGenerator getCachePutKeyGenerator()
+ {
+ return cachePutKeyGenerator;
+ }
+
+ public CachePut getCachePut()
+ {
+ return cachePut;
+ }
+
+ public String getCacheRemoveCacheName()
+ {
+ return cacheRemoveCacheName;
+ }
+
+ public CacheResolverFactory getCacheRemoveResolverFactory()
+ {
+ return cacheRemoveResolverFactory;
+ }
+
+ public CacheKeyGenerator getCacheRemoveKeyGenerator()
+ {
+ return cacheRemoveKeyGenerator;
+ }
+
+ public CacheRemove getCacheRemove()
+ {
+ return cacheRemove;
+ }
+
+ public String getCacheRemoveAllCacheName()
+ {
+ return cacheRemoveAllCacheName;
+ }
+
+ public CacheResolverFactory getCacheRemoveAllResolverFactory()
+ {
+ return cacheRemoveAllResolverFactory;
+ }
+
+ public boolean isCacheRemoveAllAfter()
+ {
+ return cacheRemoveAllAfter;
+ }
+
+ public CacheRemoveAll getCacheRemoveAll()
+ {
+ return cacheRemoveAll;
+ }
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheInvocationContextImpl.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheInvocationContextImpl.java
new file mode 100644
index 0000000..4ebcc78
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheInvocationContextImpl.java
@@ -0,0 +1,99 @@
+/*
+ * 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.apache.commons.jcs3.jcache.cdi;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+import java.util.Set;
+
+import javax.cache.annotation.CacheInvocationContext;
+import javax.cache.annotation.CacheInvocationParameter;
+import javax.interceptor.InvocationContext;
+
+public class CacheInvocationContextImpl<A extends Annotation> extends CacheMethodDetailsImpl<A> implements CacheInvocationContext<A>
+{
+ private static final Object[] EMPTY_ARGS = new Object[0];
+
+ private CacheInvocationParameter[] parameters = null;
+
+ public CacheInvocationContextImpl(final InvocationContext delegate, final A cacheAnnotation, final String cacheName,
+ final CDIJCacheHelper.MethodMeta meta)
+ {
+ super(delegate, cacheAnnotation, cacheName, meta);
+ }
+
+ @Override
+ public Object getTarget()
+ {
+ return delegate.getTarget();
+ }
+
+ @Override
+ public CacheInvocationParameter[] getAllParameters()
+ {
+ if (parameters == null)
+ {
+ parameters = doGetAllParameters(null);
+ }
+ return parameters;
+ }
+
+ @Override
+ public <T> T unwrap(final Class<T> cls)
+ {
+ if (cls.isAssignableFrom(getClass()))
+ {
+ return cls.cast(this);
+ }
+ throw new IllegalArgumentException(cls.getName());
+ }
+
+ protected CacheInvocationParameter[] doGetAllParameters(final Integer[] indexes)
+ {
+ final Object[] parameters = delegate.getParameters();
+ final Object[] args = parameters == null ? EMPTY_ARGS : parameters;
+ final Class<?>[] parameterTypes = meta.getParameterTypes();
+ final List<Set<Annotation>> parameterAnnotations = meta.getParameterAnnotations();
+
+ final CacheInvocationParameter[] parametersAsArray = new CacheInvocationParameter[indexes == null ? args.length : indexes.length];
+ if (indexes == null)
+ {
+ for (int i = 0; i < args.length; i++)
+ {
+ parametersAsArray[i] = newCacheInvocationParameterImpl(parameterTypes[i], args[i], parameterAnnotations.get(i), i);
+ }
+ }
+ else
+ {
+ int outIdx = 0;
+ for (int idx = 0; idx < indexes.length; idx++)
+ {
+ final int i = indexes[idx];
+ parametersAsArray[outIdx] = newCacheInvocationParameterImpl(parameterTypes[i], args[i], parameterAnnotations.get(i), i);
+ outIdx++;
+ }
+ }
+ return parametersAsArray;
+ }
+
+ private CacheInvocationParameterImpl newCacheInvocationParameterImpl(final Class<?> type, final Object arg,
+ final Set<Annotation> annotations, final int i) {
+ return new CacheInvocationParameterImpl(type, arg, annotations, i);
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheInvocationParameterImpl.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheInvocationParameterImpl.java
new file mode 100644
index 0000000..4d5caa5
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheInvocationParameterImpl.java
@@ -0,0 +1,63 @@
+/*
+ * 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.apache.commons.jcs3.jcache.cdi;
+
+import javax.cache.annotation.CacheInvocationParameter;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+
+public class CacheInvocationParameterImpl implements CacheInvocationParameter
+{
+ private final Class<?> type;
+ private final Object value;
+ private final Set<Annotation> annotations;
+ private final int position;
+
+ public CacheInvocationParameterImpl(final Class<?> type, final Object value, final Set<Annotation> annotations, final int position)
+ {
+ this.type = type;
+ this.value = value;
+ this.annotations = annotations;
+ this.position = position;
+ }
+
+ @Override
+ public Class<?> getRawType()
+ {
+ return type;
+ }
+
+ @Override
+ public Object getValue()
+ {
+ return value;
+ }
+
+ @Override
+ public Set<Annotation> getAnnotations()
+ {
+ return annotations;
+ }
+
+ @Override
+ public int getParameterPosition()
+ {
+ return position;
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheKeyGeneratorImpl.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheKeyGeneratorImpl.java
new file mode 100644
index 0000000..10e0a41
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheKeyGeneratorImpl.java
@@ -0,0 +1,40 @@
+/*
+ * 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.apache.commons.jcs3.jcache.cdi;
+
+import javax.cache.annotation.CacheInvocationParameter;
+import javax.cache.annotation.CacheKeyGenerator;
+import javax.cache.annotation.CacheKeyInvocationContext;
+import javax.cache.annotation.GeneratedCacheKey;
+import java.lang.annotation.Annotation;
+
+public class CacheKeyGeneratorImpl implements CacheKeyGenerator
+{
+ @Override
+ public GeneratedCacheKey generateCacheKey(final CacheKeyInvocationContext<? extends Annotation> cacheKeyInvocationContext)
+ {
+ final CacheInvocationParameter[] keyParameters = cacheKeyInvocationContext.getKeyParameters();
+ final Object[] parameters = new Object[keyParameters.length];
+ for (int index = 0; index < keyParameters.length; index++)
+ {
+ parameters[index] = keyParameters[index].getValue();
+ }
+ return new GeneratedCacheKeyImpl(parameters);
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheKeyInvocationContextImpl.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheKeyInvocationContextImpl.java
new file mode 100644
index 0000000..a0c0a52
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheKeyInvocationContextImpl.java
@@ -0,0 +1,57 @@
+/*
+ * 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.apache.commons.jcs3.jcache.cdi;
+
+import java.lang.annotation.Annotation;
+
+import javax.cache.annotation.CacheInvocationParameter;
+import javax.cache.annotation.CacheKeyInvocationContext;
+import javax.interceptor.InvocationContext;
+
+public class CacheKeyInvocationContextImpl<A extends Annotation> extends CacheInvocationContextImpl<A> implements CacheKeyInvocationContext<A>
+{
+ private CacheInvocationParameter[] keyParams = null;
+ private CacheInvocationParameter valueParam = null;
+
+ public CacheKeyInvocationContextImpl(final InvocationContext delegate, final A annotation, final String name,
+ final CDIJCacheHelper.MethodMeta methodMeta)
+ {
+ super(delegate, annotation, name, methodMeta);
+ }
+
+ @Override
+ public CacheInvocationParameter[] getKeyParameters()
+ {
+ if (keyParams == null)
+ {
+ keyParams = doGetAllParameters(meta.getKeysIndices());
+ }
+ return keyParams;
+ }
+
+ @Override
+ public CacheInvocationParameter getValueParameter()
+ {
+ if (valueParam == null)
+ {
+ valueParam = meta.getValueIndex() >= 0 ? doGetAllParameters(new Integer[]{meta.getValueIndex()})[0] : null;
+ }
+ return valueParam;
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheMethodDetailsImpl.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheMethodDetailsImpl.java
new file mode 100644
index 0000000..b9a0df1
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheMethodDetailsImpl.java
@@ -0,0 +1,68 @@
+/*
+ * 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.apache.commons.jcs3.jcache.cdi;
+
+import javax.cache.annotation.CacheMethodDetails;
+import javax.interceptor.InvocationContext;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Set;
+
+public class CacheMethodDetailsImpl<A extends Annotation> implements CacheMethodDetails<A>
+{
+ protected final InvocationContext delegate;
+ private final Set<Annotation> annotations;
+ private final A cacheAnnotation;
+ private final String cacheName;
+ protected final CDIJCacheHelper.MethodMeta meta;
+
+ public CacheMethodDetailsImpl(final InvocationContext delegate, final A cacheAnnotation, final String cacheName,
+ final CDIJCacheHelper.MethodMeta meta)
+ {
+ this.delegate = delegate;
+ this.annotations = meta.getAnnotations();
+ this.cacheAnnotation = cacheAnnotation;
+ this.cacheName = cacheName;
+ this.meta = meta;
+ }
+
+ @Override
+ public Method getMethod()
+ {
+ return delegate.getMethod();
+ }
+
+ @Override
+ public Set<Annotation> getAnnotations()
+ {
+ return annotations;
+ }
+
+ @Override
+ public A getCacheAnnotation()
+ {
+ return cacheAnnotation;
+ }
+
+ @Override
+ public String getCacheName()
+ {
+ return cacheName;
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CachePutInterceptor.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CachePutInterceptor.java
new file mode 100644
index 0000000..ec8416d
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CachePutInterceptor.java
@@ -0,0 +1,90 @@
+/*
+ * 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.apache.commons.jcs3.jcache.cdi;
+
+import java.io.Serializable;
+
+import javax.annotation.Priority;
+import javax.cache.Cache;
+import javax.cache.annotation.CacheKeyInvocationContext;
+import javax.cache.annotation.CachePut;
+import javax.cache.annotation.CacheResolver;
+import javax.cache.annotation.CacheResolverFactory;
+import javax.cache.annotation.GeneratedCacheKey;
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+
+@CachePut
+@Interceptor
+@Priority(/*LIBRARY_BEFORE*/1000)
+public class CachePutInterceptor implements Serializable
+{
+ @Inject
+ private CDIJCacheHelper helper;
+
+ @AroundInvoke
+ public Object cache(final InvocationContext ic) throws Throwable
+ {
+ final CDIJCacheHelper.MethodMeta methodMeta = helper.findMeta(ic);
+
+ final String cacheName = methodMeta.getCachePutCacheName();
+
+ final CacheResolverFactory cacheResolverFactory = methodMeta.getCachePutResolverFactory();
+ final CacheKeyInvocationContext<CachePut> context = new CacheKeyInvocationContextImpl<>(
+ ic, methodMeta.getCachePut(), cacheName, methodMeta);
+ final CacheResolver cacheResolver = cacheResolverFactory.getCacheResolver(context);
+ final Cache<Object, Object> cache = cacheResolver.resolveCache(context);
+
+ final GeneratedCacheKey cacheKey = methodMeta.getCachePutKeyGenerator().generateCacheKey(context);
+ final CachePut cachePut = methodMeta.getCachePut();
+ final boolean afterInvocation = methodMeta.isCachePutAfter();
+
+ if (!afterInvocation)
+ {
+ cache.put(cacheKey, context.getValueParameter());
+ }
+
+ final Object result;
+ try
+ {
+ result = ic.proceed();
+ }
+ catch (final Throwable t)
+ {
+ if (afterInvocation)
+ {
+ if (helper.isIncluded(t.getClass(), cachePut.cacheFor(), cachePut.noCacheFor()))
+ {
+ cache.put(cacheKey, context.getValueParameter());
+ }
+ }
+
+ throw t;
+ }
+
+ if (afterInvocation)
+ {
+ cache.put(cacheKey, context.getValueParameter());
+ }
+
+ return result;
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheRemoveAllInterceptor.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheRemoveAllInterceptor.java
new file mode 100644
index 0000000..b719852
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheRemoveAllInterceptor.java
@@ -0,0 +1,85 @@
+/*
+ * 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.apache.commons.jcs3.jcache.cdi;
+
+import java.io.Serializable;
+
+import javax.annotation.Priority;
+import javax.cache.Cache;
+import javax.cache.annotation.CacheKeyInvocationContext;
+import javax.cache.annotation.CacheRemoveAll;
+import javax.cache.annotation.CacheResolver;
+import javax.cache.annotation.CacheResolverFactory;
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+
+@CacheRemoveAll
+@Interceptor
+@Priority(/*LIBRARY_BEFORE*/1000)
+public class CacheRemoveAllInterceptor implements Serializable
+{
+ @Inject
+ private CDIJCacheHelper helper;
+
+ @AroundInvoke
+ public Object cache(final InvocationContext ic) throws Throwable
+ {
+ final CDIJCacheHelper.MethodMeta methodMeta = helper.findMeta(ic);
+
+ final String cacheName = methodMeta.getCacheRemoveAllCacheName();
+
+ final CacheResolverFactory cacheResolverFactory = methodMeta.getCacheRemoveAllResolverFactory();
+ final CacheKeyInvocationContext<CacheRemoveAll> context = new CacheKeyInvocationContextImpl<>(
+ ic, methodMeta.getCacheRemoveAll(), cacheName, methodMeta);
+ final CacheResolver cacheResolver = cacheResolverFactory.getCacheResolver(context);
+ final Cache<Object, Object> cache = cacheResolver.resolveCache(context);
+
+ final boolean afterInvocation = methodMeta.isCachePutAfter();
+ if (!afterInvocation)
+ {
+ cache.removeAll();
+ }
+
+ final Object result;
+ try
+ {
+ result = ic.proceed();
+ }
+ catch (final Throwable t)
+ {
+ if (afterInvocation)
+ {
+ if (helper.isIncluded(t.getClass(), methodMeta.getCacheRemoveAll().evictFor(), methodMeta.getCacheRemoveAll().noEvictFor()))
+ {
+ cache.removeAll();
+ }
+ }
+ throw t;
+ }
+
+ if (afterInvocation)
+ {
+ cache.removeAll();
+ }
+
+ return result;
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheRemoveInterceptor.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheRemoveInterceptor.java
new file mode 100644
index 0000000..cfd1738
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheRemoveInterceptor.java
@@ -0,0 +1,90 @@
+/*
+ * 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.apache.commons.jcs3.jcache.cdi;
+
+import java.io.Serializable;
+
+import javax.annotation.Priority;
+import javax.cache.Cache;
+import javax.cache.annotation.CacheKeyInvocationContext;
+import javax.cache.annotation.CacheRemove;
+import javax.cache.annotation.CacheResolver;
+import javax.cache.annotation.CacheResolverFactory;
+import javax.cache.annotation.GeneratedCacheKey;
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+
+@CacheRemove
+@Interceptor
+@Priority(/*LIBRARY_BEFORE*/1000)
+public class CacheRemoveInterceptor implements Serializable
+{
+ @Inject
+ private CDIJCacheHelper helper;
+
+ @AroundInvoke
+ public Object cache(final InvocationContext ic) throws Throwable
+ {
+ final CDIJCacheHelper.MethodMeta methodMeta = helper.findMeta(ic);
+
+ final String cacheName = methodMeta.getCacheRemoveCacheName();
+
+ final CacheResolverFactory cacheResolverFactory = methodMeta.getCacheRemoveResolverFactory();
+ final CacheKeyInvocationContext<CacheRemove> context = new CacheKeyInvocationContextImpl<>(
+ ic, methodMeta.getCacheRemove(), cacheName, methodMeta);
+ final CacheResolver cacheResolver = cacheResolverFactory.getCacheResolver(context);
+ final Cache<Object, Object> cache = cacheResolver.resolveCache(context);
+
+ final GeneratedCacheKey cacheKey = methodMeta.getCacheRemoveKeyGenerator().generateCacheKey(context);
+ final CacheRemove cacheRemove = methodMeta.getCacheRemove();
+ final boolean afterInvocation = methodMeta.isCacheRemoveAfter();
+
+ if (!afterInvocation)
+ {
+ cache.remove(cacheKey);
+ }
+
+ final Object result;
+ try
+ {
+ result = ic.proceed();
+ }
+ catch (final Throwable t)
+ {
+ if (afterInvocation)
+ {
+ if (helper.isIncluded(t.getClass(), cacheRemove.evictFor(), cacheRemove.noEvictFor()))
+ {
+ cache.remove(cacheKey);
+ }
+ }
+
+ throw t;
+ }
+
+ if (afterInvocation)
+ {
+ cache.remove(cacheKey);
+ }
+
+ return result;
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheResolverFactoryImpl.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheResolverFactoryImpl.java
new file mode 100644
index 0000000..7adae36
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheResolverFactoryImpl.java
@@ -0,0 +1,81 @@
+/*
+ * 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.apache.commons.jcs3.jcache.cdi;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+import javax.cache.annotation.CacheMethodDetails;
+import javax.cache.annotation.CacheResolver;
+import javax.cache.annotation.CacheResolverFactory;
+import javax.cache.annotation.CacheResult;
+import javax.cache.configuration.MutableConfiguration;
+import javax.cache.spi.CachingProvider;
+import java.lang.annotation.Annotation;
+
+public class CacheResolverFactoryImpl implements CacheResolverFactory
+{
+ private final CacheManager cacheManager;
+ private final CachingProvider provider;
+
+ public CacheResolverFactoryImpl()
+ {
+ provider = Caching.getCachingProvider();
+ cacheManager = provider.getCacheManager(provider.getDefaultURI(), provider.getDefaultClassLoader());
+ }
+
+ @Override
+ public CacheResolver getCacheResolver(CacheMethodDetails<? extends Annotation> cacheMethodDetails)
+ {
+ return findCacheResolver(cacheMethodDetails.getCacheName());
+ }
+
+ @Override
+ public CacheResolver getExceptionCacheResolver(final CacheMethodDetails<CacheResult> cacheMethodDetails)
+ {
+ final String exceptionCacheName = cacheMethodDetails.getCacheAnnotation().exceptionCacheName();
+ if (exceptionCacheName == null || exceptionCacheName.isEmpty())
+ {
+ throw new IllegalArgumentException("CacheResult.exceptionCacheName() not specified");
+ }
+ return findCacheResolver(exceptionCacheName);
+ }
+
+ private CacheResolver findCacheResolver(String exceptionCacheName)
+ {
+ Cache<?, ?> cache = cacheManager.getCache(exceptionCacheName);
+ if (cache == null)
+ {
+ cache = createCache(exceptionCacheName);
+ }
+ return new CacheResolverImpl(cache);
+ }
+
+ private Cache<?, ?> createCache(final String exceptionCacheName)
+ {
+ cacheManager.createCache(exceptionCacheName, new MutableConfiguration<>().setStoreByValue(false));
+ return cacheManager.getCache(exceptionCacheName);
+ }
+
+ public void release()
+ {
+ cacheManager.close();
+ provider.close();
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheResolverImpl.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheResolverImpl.java
new file mode 100644
index 0000000..49e1e91
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheResolverImpl.java
@@ -0,0 +1,40 @@
+/*
+ * 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.apache.commons.jcs3.jcache.cdi;
+
+import javax.cache.Cache;
+import javax.cache.annotation.CacheInvocationContext;
+import javax.cache.annotation.CacheResolver;
+import java.lang.annotation.Annotation;
+
+public class CacheResolverImpl implements CacheResolver
+{
+ private final Cache<?, ?> delegate;
+
+ public CacheResolverImpl(final Cache<?, ?> cache)
+ {
+ delegate = cache;
+ }
+
+ @Override
+ public <K, V> Cache<K, V> resolveCache(final CacheInvocationContext<? extends Annotation> cacheInvocationContext)
+ {
+ return (Cache<K, V>) delegate;
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheResultInterceptor.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheResultInterceptor.java
new file mode 100644
index 0000000..71701c3
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/CacheResultInterceptor.java
@@ -0,0 +1,105 @@
+/*
+ * 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.apache.commons.jcs3.jcache.cdi;
+
+import java.io.Serializable;
+import javax.annotation.Priority;
+import javax.cache.Cache;
+import javax.cache.annotation.CacheKeyInvocationContext;
+import javax.cache.annotation.CacheResolver;
+import javax.cache.annotation.CacheResolverFactory;
+import javax.cache.annotation.CacheResult;
+import javax.cache.annotation.GeneratedCacheKey;
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+
+@CacheResult
+@Interceptor
+@Priority(/*LIBRARY_BEFORE*/1000)
+public class CacheResultInterceptor implements Serializable
+{
+ @Inject
+ private CDIJCacheHelper helper;
+
+ @AroundInvoke
+ public Object cache(final InvocationContext ic) throws Throwable
+ {
+ final CDIJCacheHelper.MethodMeta methodMeta = helper.findMeta(ic);
+
+ final String cacheName = methodMeta.getCacheResultCacheName();
+
+ final CacheResult cacheResult = methodMeta.getCacheResult();
+ final CacheKeyInvocationContext<CacheResult> context = new CacheKeyInvocationContextImpl<>(
+ ic, cacheResult, cacheName, methodMeta);
+
+ final CacheResolverFactory cacheResolverFactory = methodMeta.getCacheResultResolverFactory();
+ final CacheResolver cacheResolver = cacheResolverFactory.getCacheResolver(context);
+ final Cache<Object, Object> cache = cacheResolver.resolveCache(context);
+
+ final GeneratedCacheKey cacheKey = methodMeta.getCacheResultKeyGenerator().generateCacheKey(context);
+
+ Cache<Object, Object> exceptionCache = null; // lazily created
+
+ Object result;
+ if (!cacheResult.skipGet())
+ {
+ result = cache.get(cacheKey);
+ if (result != null)
+ {
+ return result;
+ }
+
+
+ if (!cacheResult.exceptionCacheName().isEmpty())
+ {
+ exceptionCache = cacheResolverFactory.getExceptionCacheResolver(context).resolveCache(context);
+ final Object exception = exceptionCache.get(cacheKey);
+ if (exception != null)
+ {
+ throw Throwable.class.cast(exception);
+ }
+ }
+ }
+
+ try
+ {
+ result = ic.proceed();
+ if (result != null)
+ {
+ cache.put(cacheKey, result);
+ }
+
+ return result;
+ }
+ catch (final Throwable t)
+ {
+ if (helper.isIncluded(t.getClass(), cacheResult.cachedExceptions(), cacheResult.nonCachedExceptions()))
+ {
+ if (exceptionCache == null)
+ {
+ exceptionCache = cacheResolverFactory.getExceptionCacheResolver(context).resolveCache(context);
+ }
+ exceptionCache.put(cacheKey, t);
+ }
+ throw t;
+ }
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/GeneratedCacheKeyImpl.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/GeneratedCacheKeyImpl.java
new file mode 100644
index 0000000..1802fc0
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/GeneratedCacheKeyImpl.java
@@ -0,0 +1,56 @@
+/*
+ * 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.apache.commons.jcs3.jcache.cdi;
+
+import javax.cache.annotation.GeneratedCacheKey;
+import java.util.Arrays;
+
+public class GeneratedCacheKeyImpl implements GeneratedCacheKey
+{
+ private final Object[] params;
+ private final int hash;
+
+ public GeneratedCacheKeyImpl(final Object[] parameters)
+ {
+ this.params = parameters;
+ this.hash = Arrays.deepHashCode(parameters);
+ }
+
+ @Override
+ public boolean equals(final Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass())
+ {
+ return false;
+ }
+ final GeneratedCacheKeyImpl that = GeneratedCacheKeyImpl.class.cast(o);
+ return Arrays.deepEquals(params, that.params);
+
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return hash;
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/MakeJCacheCDIInterceptorFriendly.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/MakeJCacheCDIInterceptorFriendly.java
new file mode 100644
index 0000000..22232d0
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/cdi/MakeJCacheCDIInterceptorFriendly.java
@@ -0,0 +1,212 @@
+/*
+ * 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.apache.commons.jcs3.jcache.cdi;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.cache.annotation.CachePut;
+import javax.cache.annotation.CacheRemove;
+import javax.cache.annotation.CacheRemoveAll;
+import javax.cache.annotation.CacheResult;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Default;
+import javax.enterprise.inject.spi.AfterBeanDiscovery;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
+import javax.enterprise.inject.spi.Extension;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.enterprise.inject.spi.InjectionTarget;
+import javax.enterprise.inject.spi.PassivationCapable;
+import javax.enterprise.inject.spi.ProcessAnnotatedType;
+import javax.enterprise.util.AnnotationLiteral;
+
+import static java.util.Arrays.asList;
+
+// TODO: observe annotated type (or maybe sthg else) to cache data and inject this extension (used as metadata cache)
+// to get class model and this way allow to add cache annotation on the fly - == avoid java pure reflection to get metadata
+public class MakeJCacheCDIInterceptorFriendly implements Extension
+{
+ private static final AtomicInteger id = new AtomicInteger();
+ private static final boolean USE_ID = !Boolean.getBoolean("org.apache.commons.jcs3.cdi.skip-id");
+
+ private boolean needHelper = true;
+
+ protected void discoverInterceptorBindings(final @Observes BeforeBeanDiscovery beforeBeanDiscoveryEvent,
+ final BeanManager bm)
+ {
+ // CDI 1.1 will just pick createAnnotatedType(X) as beans so we'll skip our HelperBean
+ // but CDI 1.0 needs our HelperBean + interceptors in beans.xml like:
+ /*
+ <beans xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
+ http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
+ <interceptors>
+ <class>org.apache.commons.jcs3.jcache.cdi.CacheResultInterceptor</class>
+ <class>org.apache.commons.jcs3.jcache.cdi.CacheRemoveAllInterceptor</class>
+ <class>org.apache.commons.jcs3.jcache.cdi.CacheRemoveInterceptor</class>
+ <class>org.apache.commons.jcs3.jcache.cdi.CachePutInterceptor</class>
+ </interceptors>
+ </beans>
+ */
+ bm.createAnnotatedType(CDIJCacheHelper.class);
+ for (final Class<?> interceptor : asList(
+ CachePutInterceptor.class, CacheRemoveInterceptor.class,
+ CacheRemoveAllInterceptor.class, CacheResultInterceptor.class)) {
+ beforeBeanDiscoveryEvent.addAnnotatedType(bm.createAnnotatedType(interceptor));
+ }
+ for (final Class<? extends Annotation> interceptor : asList(
+ CachePut.class, CacheRemove.class,
+ CacheRemoveAll.class, CacheResult.class)) {
+ beforeBeanDiscoveryEvent.addInterceptorBinding(interceptor);
+ }
+ }
+
+ protected void addHelper(final @Observes AfterBeanDiscovery afterBeanDiscovery,
+ final BeanManager bm)
+ {
+ if (!needHelper) {
+ return;
+ }
+ /* CDI >= 1.1 only. Actually we shouldn't go here with CDI 1.1 since we defined the annotated type for the helper
+ final AnnotatedType<CDIJCacheHelper> annotatedType = bm.createAnnotatedType(CDIJCacheHelper.class);
+ final BeanAttributes<CDIJCacheHelper> beanAttributes = bm.createBeanAttributes(annotatedType);
+ final InjectionTarget<CDIJCacheHelper> injectionTarget = bm.createInjectionTarget(annotatedType);
+ final Bean<CDIJCacheHelper> bean = bm.createBean(beanAttributes, CDIJCacheHelper.class, new InjectionTargetFactory<CDIJCacheHelper>() {
+ @Override
+ public InjectionTarget<CDIJCacheHelper> createInjectionTarget(Bean<CDIJCacheHelper> bean) {
+ return injectionTarget;
+ }
+ });
+ */
+ final AnnotatedType<CDIJCacheHelper> annotatedType = bm.createAnnotatedType(CDIJCacheHelper.class);
+ final InjectionTarget<CDIJCacheHelper> injectionTarget = bm.createInjectionTarget(annotatedType);
+ final HelperBean bean = new HelperBean(annotatedType, injectionTarget, findIdSuffix());
+ afterBeanDiscovery.addBean(bean);
+ }
+
+ protected void vetoScannedCDIJCacheHelperQualifiers(final @Observes ProcessAnnotatedType<CDIJCacheHelper> pat) {
+ if (!needHelper) { // already seen, shouldn't really happen,just a protection
+ pat.veto();
+ }
+ needHelper = false;
+ }
+
+ // TODO: make it better for ear+cluster case with CDI 1.0
+ private String findIdSuffix() {
+ // big disadvantage is all deployments of a cluster needs to be in the exact same order but it works with ears
+ if (USE_ID) {
+ return "lib" + id.incrementAndGet();
+ }
+ return "default";
+ }
+
+ public static class HelperBean implements Bean<CDIJCacheHelper>, PassivationCapable {
+ private final AnnotatedType<CDIJCacheHelper> at;
+ private final InjectionTarget<CDIJCacheHelper> it;
+ private final HashSet<Annotation> qualifiers;
+ private final String id;
+
+ public HelperBean(final AnnotatedType<CDIJCacheHelper> annotatedType,
+ final InjectionTarget<CDIJCacheHelper> injectionTarget,
+ final String id) {
+ this.at = annotatedType;
+ this.it = injectionTarget;
+ this.id = "JCS#CDIHelper#" + id;
+
+ this.qualifiers = new HashSet<>();
+ this.qualifiers.add(new AnnotationLiteral<Default>() {});
+ this.qualifiers.add(new AnnotationLiteral<Any>() {});
+ }
+
+ @Override
+ public Set<InjectionPoint> getInjectionPoints() {
+ return it.getInjectionPoints();
+ }
+
+ @Override
+ public Class<?> getBeanClass() {
+ return at.getJavaClass();
+ }
+
+ @Override
+ public boolean isNullable() {
+ return false;
+ }
+
+ @Override
+ public Set<Type> getTypes() {
+ return at.getTypeClosure();
+ }
+
+ @Override
+ public Set<Annotation> getQualifiers() {
+ return qualifiers;
+ }
+
+ @Override
+ public Class<? extends Annotation> getScope() {
+ return ApplicationScoped.class;
+ }
+
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public Set<Class<? extends Annotation>> getStereotypes() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public boolean isAlternative() {
+ return false;
+ }
+
+ @Override
+ public CDIJCacheHelper create(final CreationalContext<CDIJCacheHelper> context) {
+ final CDIJCacheHelper produce = it.produce(context);
+ it.inject(produce, context);
+ it.postConstruct(produce);
+ return produce;
+ }
+
+ @Override
+ public void destroy(final CDIJCacheHelper instance, final CreationalContext<CDIJCacheHelper> context) {
+ it.preDestroy(instance);
+ it.dispose(instance);
+ context.release();
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/jmx/ConfigurableMBeanServerIdBuilder.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/jmx/ConfigurableMBeanServerIdBuilder.java
new file mode 100644
index 0000000..3b4acde
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/jmx/ConfigurableMBeanServerIdBuilder.java
@@ -0,0 +1,170 @@
+/*
+ * 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.apache.commons.jcs3.jcache.jmx;
+
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerBuilder;
+import javax.management.MBeanServerDelegate;
+import javax.management.Notification;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+public class ConfigurableMBeanServerIdBuilder extends MBeanServerBuilder
+{
+ private static ConcurrentMap<Key, MBeanServer> JVM_SINGLETONS = new ConcurrentHashMap<>();
+
+ private static class Key
+ {
+ private final String domain;
+ private final MBeanServer outer;
+
+ private Key(final String domain, final MBeanServer outer)
+ {
+ this.domain = domain;
+ this.outer = outer;
+ }
+
+ @Override
+ public boolean equals(final Object o)
+ {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ final Key key = Key.class.cast(o);
+ return !(domain != null ? !domain.equals(key.domain) : key.domain != null)
+ && !(outer != null ? !outer.equals(key.outer) : key.outer != null);
+
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int result = domain != null ? domain.hashCode() : 0;
+ result = 31 * result + (outer != null ? outer.hashCode() : 0);
+ return result;
+ }
+ }
+
+ @Override
+ public MBeanServer newMBeanServer(final String defaultDomain, final MBeanServer outer, final MBeanServerDelegate delegate)
+ {
+ final Key key = new Key(defaultDomain, outer);
+ MBeanServer server = JVM_SINGLETONS.get(key);
+ if (server == null)
+ {
+ server = super.newMBeanServer(defaultDomain, outer, new ForceIdMBeanServerDelegate(delegate));
+ final MBeanServer existing = JVM_SINGLETONS.putIfAbsent(key, server);
+ if (existing != null)
+ {
+ server = existing;
+ }
+ }
+ return server;
+ }
+
+ private class ForceIdMBeanServerDelegate extends MBeanServerDelegate
+ {
+ private final MBeanServerDelegate delegate;
+
+ public ForceIdMBeanServerDelegate(final MBeanServerDelegate delegate)
+ {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public String getMBeanServerId()
+ {
+ return System.getProperty("org.jsr107.tck.management.agentId", delegate.getMBeanServerId());
+ }
+
+ @Override
+ public String getSpecificationName()
+ {
+ return delegate.getSpecificationName();
+ }
+
+ @Override
+ public String getSpecificationVersion()
+ {
+ return delegate.getSpecificationVersion();
+ }
+
+ @Override
+ public String getSpecificationVendor()
+ {
+ return delegate.getSpecificationVendor();
+ }
+
+ @Override
+ public String getImplementationName()
+ {
+ return delegate.getImplementationName();
+ }
+
+ @Override
+ public String getImplementationVersion()
+ {
+ return delegate.getImplementationVersion();
+ }
+
+ @Override
+ public String getImplementationVendor()
+ {
+ return delegate.getImplementationVendor();
+ }
+
+ @Override
+ public MBeanNotificationInfo[] getNotificationInfo()
+ {
+ return delegate.getNotificationInfo();
+ }
+
+ @Override
+ public void addNotificationListener(final NotificationListener listener, final NotificationFilter filter, final Object handback)
+ throws IllegalArgumentException
+ {
+ delegate.addNotificationListener(listener, filter, handback);
+ }
+
+ @Override
+ public void removeNotificationListener(final NotificationListener listener, final NotificationFilter filter, final Object handback)
+ throws ListenerNotFoundException
+ {
+ delegate.removeNotificationListener(listener, filter, handback);
+ }
+
+ @Override
+ public void removeNotificationListener(final NotificationListener listener) throws ListenerNotFoundException
+ {
+ delegate.removeNotificationListener(listener);
+ }
+
+ @Override
+ public void sendNotification(final Notification notification)
+ {
+ delegate.sendNotification(notification);
+ }
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/jmx/JCSCacheMXBean.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/jmx/JCSCacheMXBean.java
new file mode 100644
index 0000000..d397e77
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/jmx/JCSCacheMXBean.java
@@ -0,0 +1,114 @@
+/*
+ * 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.apache.commons.jcs3.jcache.jmx;
+
+import javax.cache.Cache;
+import javax.cache.configuration.CompleteConfiguration;
+import javax.cache.configuration.Configuration;
+import javax.cache.management.CacheMXBean;
+
+public class JCSCacheMXBean<K, V> implements CacheMXBean
+{
+ private final Cache<K, V> delegate;
+
+ public JCSCacheMXBean(final Cache<K, V> delegate)
+ {
+ this.delegate = delegate;
+ }
+
+ private Configuration<K, V> config()
+ {
+ return delegate.getConfiguration(Configuration.class);
+ }
+
+ private CompleteConfiguration<K, V> completeConfig()
+ {
+ return delegate.getConfiguration(CompleteConfiguration.class);
+ }
+
+ @Override
+ public String getKeyType()
+ {
+ return config().getKeyType().getName();
+ }
+
+ @Override
+ public String getValueType()
+ {
+ return config().getValueType().getName();
+ }
+
+ @Override
+ public boolean isReadThrough()
+ {
+ try
+ {
+ return completeConfig().isReadThrough();
+ }
+ catch (final Exception e)
+ {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean isWriteThrough()
+ {
+ try
+ {
+ return completeConfig().isWriteThrough();
+ }
+ catch (final Exception e)
+ {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean isStoreByValue()
+ {
+ return config().isStoreByValue();
+ }
+
+ @Override
+ public boolean isStatisticsEnabled()
+ {
+ try
+ {
+ return completeConfig().isStatisticsEnabled();
+ }
+ catch (final Exception e)
+ {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean isManagementEnabled()
+ {
+ try
+ {
+ return completeConfig().isManagementEnabled();
+ }
+ catch (final Exception e)
+ {
+ return false;
+ }
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/jmx/JCSCacheStatisticsMXBean.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/jmx/JCSCacheStatisticsMXBean.java
new file mode 100644
index 0000000..37db76e
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/jmx/JCSCacheStatisticsMXBean.java
@@ -0,0 +1,125 @@
+/*
+ * 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.apache.commons.jcs3.jcache.jmx;
+
+import javax.cache.management.CacheStatisticsMXBean;
+
+import org.apache.commons.jcs3.jcache.Statistics;
+
+public class JCSCacheStatisticsMXBean implements CacheStatisticsMXBean
+{
+ private final Statistics statistics;
+
+ public JCSCacheStatisticsMXBean(final Statistics stats)
+ {
+ this.statistics = stats;
+ }
+
+ @Override
+ public void clear()
+ {
+ statistics.reset();
+ }
+
+ @Override
+ public long getCacheHits()
+ {
+ return statistics.getHits();
+ }
+
+ @Override
+ public float getCacheHitPercentage()
+ {
+ final long hits = getCacheHits();
+ if (hits == 0)
+ {
+ return 0;
+ }
+ return (float) hits / getCacheGets() * 100.0f;
+ }
+
+ @Override
+ public long getCacheMisses()
+ {
+ return statistics.getMisses();
+ }
+
+ @Override
+ public float getCacheMissPercentage()
+ {
+ final long misses = getCacheMisses();
+ if (misses == 0)
+ {
+ return 0;
+ }
+ return (float) misses / getCacheGets() * 100.0f;
+ }
+
+ @Override
+ public long getCacheGets()
+ {
+ return getCacheHits() + getCacheMisses();
+ }
+
+ @Override
+ public long getCachePuts()
+ {
+ return statistics.getPuts();
+ }
+
+ @Override
+ public long getCacheRemovals()
+ {
+ return statistics.getRemovals();
+ }
+
+ @Override
+ public long getCacheEvictions()
+ {
+ return statistics.getEvictions();
+ }
+
+ @Override
+ public float getAverageGetTime()
+ {
+ return averageTime(statistics.getTimeTakenForGets());
+ }
+
+ @Override
+ public float getAveragePutTime()
+ {
+ return averageTime(statistics.getTimeTakenForPuts());
+ }
+
+ @Override
+ public float getAverageRemoveTime()
+ {
+ return averageTime(statistics.getTimeTakenForRemovals());
+ }
+
+ private float averageTime(final long timeTaken)
+ {
+ final long gets = getCacheGets();
+ if (timeTaken == 0 || gets == 0)
+ {
+ return 0;
+ }
+ return timeTaken / gets;
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/jmx/JMXs.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/jmx/JMXs.java
new file mode 100644
index 0000000..31d1f60
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/jmx/JMXs.java
@@ -0,0 +1,78 @@
+/*
+ * 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.apache.commons.jcs3.jcache.jmx;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
+import java.lang.management.ManagementFactory;
+
+public class JMXs
+{
+ private static final MBeanServer SERVER = findMBeanServer();
+
+ public static MBeanServer server()
+ {
+ return SERVER;
+ }
+
+ public static void register(final ObjectName on, final Object bean)
+ {
+ if (!SERVER.isRegistered(on))
+ {
+ try
+ {
+ SERVER.registerMBean(bean, on);
+ }
+ catch (final Exception e)
+ {
+ throw new IllegalStateException(e.getMessage(), e);
+ }
+ }
+ }
+
+ public static void unregister(final ObjectName on)
+ {
+ if (SERVER.isRegistered(on))
+ {
+ try
+ {
+ SERVER.unregisterMBean(on);
+ }
+ catch (final Exception e)
+ {
+ // no-op
+ }
+ }
+ }
+
+ private static MBeanServer findMBeanServer()
+ {
+ if (System.getProperty("javax.management.builder.initial") != null)
+ {
+ return MBeanServerFactory.createMBeanServer();
+ }
+ return ManagementFactory.getPlatformMBeanServer();
+ }
+
+ private JMXs()
+ {
+ // no-op
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/lang/DefaultSubsitutor.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/lang/DefaultSubsitutor.java
new file mode 100644
index 0000000..0fa9cad
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/lang/DefaultSubsitutor.java
@@ -0,0 +1,32 @@
+/*
+ * 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.apache.commons.jcs3.jcache.lang;
+
+public class DefaultSubsitutor implements Subsitutor
+{
+ @Override
+ public String substitute(final String value)
+ {
+ if (value.startsWith("${") && value.endsWith("}")) {
+ return System.getProperty(value.substring("${".length(), value.length() - 1), value);
+ }
+ return value;
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/lang/Lang3Substitutor.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/lang/Lang3Substitutor.java
new file mode 100644
index 0000000..88be6b4
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/lang/Lang3Substitutor.java
@@ -0,0 +1,39 @@
+/*
+ * 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.apache.commons.jcs3.jcache.lang;
+
+import org.apache.commons.lang3.text.StrSubstitutor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Lang3Substitutor implements Subsitutor
+{
+ private static final StrSubstitutor SUBSTITUTOR = new StrSubstitutor(new HashMap<String, Object>() {{
+ putAll(Map.class.cast(System.getProperties()));
+ putAll(System.getenv());
+ }});
+
+ @Override
+ public String substitute(final String value)
+ {
+ return SUBSTITUTOR.replace(value);
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/lang/Subsitutor.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/lang/Subsitutor.java
new file mode 100644
index 0000000..3e07545
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/lang/Subsitutor.java
@@ -0,0 +1,53 @@
+/*
+ * 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.apache.commons.jcs3.jcache.lang;
+
+public interface Subsitutor
+{
+ String substitute(String value);
+
+ public static class Helper {
+ public static final Subsitutor INSTANCE;
+ static {
+ Subsitutor value = null;
+ for (final String name : new String[]
+ { // ordered by features
+ "org.apache.commons.jcs3.jcache.lang.Lang3Substitutor",
+ "org.apache.commons.jcs3.jcache.lang.DefaultSubsitutor"
+ })
+ {
+ try
+ {
+ value = Subsitutor.class.cast(
+ Subsitutor.class.getClassLoader().loadClass(name).newInstance());
+ value.substitute("${java.version}"); // ensure it works
+ }
+ catch (final Throwable e) // not Exception otherwise NoClassDefFoundError
+ {
+ // no-op: next
+ }
+ }
+ if (value == null) {
+ throw new IllegalStateException("Can't find a " + Subsitutor.class.getName());
+ }
+ INSTANCE = value;
+ }
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/proxy/ClassLoaderAwareCache.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/proxy/ClassLoaderAwareCache.java
new file mode 100644
index 0000000..1522c4d
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/proxy/ClassLoaderAwareCache.java
@@ -0,0 +1,514 @@
+/*
+ * 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.apache.commons.jcs3.jcache.proxy;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.configuration.CacheEntryListenerConfiguration;
+import javax.cache.configuration.Configuration;
+import javax.cache.integration.CompletionListener;
+import javax.cache.processor.EntryProcessor;
+import javax.cache.processor.EntryProcessorException;
+import javax.cache.processor.EntryProcessorResult;
+
+import org.apache.commons.jcs3.jcache.JCSCache;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+// don't use a proxy, reflection is too slow here :(
+public class ClassLoaderAwareCache<K, V> implements Cache<K, V>
+{
+ private final ClassLoader loader;
+ private final JCSCache<K, V> delegate;
+
+ public ClassLoaderAwareCache(final ClassLoader loader, final JCSCache<K, V> delegate)
+ {
+ this.loader = loader;
+ this.delegate = delegate;
+ }
+
+ private ClassLoader before(final Thread thread)
+ {
+ final ClassLoader tccl = thread.getContextClassLoader();
+ thread.setContextClassLoader(loader);
+ return tccl;
+ }
+
+ @Override
+ public V get(final K key)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.get(key);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public Map<K, V> getAll(final Set<? extends K> keys)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.getAll(keys);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public boolean containsKey(final K key)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.containsKey(key);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public void loadAll(final Set<? extends K> keys, boolean replaceExistingValues, final CompletionListener completionListener)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ delegate.loadAll(keys, replaceExistingValues, completionListener);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public void put(final K key, final V value)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ delegate.put(key, value);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public V getAndPut(final K key, final V value)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.getAndPut(key, value);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public void putAll(final Map<? extends K, ? extends V> map)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ delegate.putAll(map);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public boolean putIfAbsent(final K key, final V value)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.putIfAbsent(key, value);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public boolean remove(final K key)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.remove(key);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public boolean remove(final K key, final V oldValue)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.remove(key, oldValue);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public V getAndRemove(final K key)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.getAndRemove(key);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public boolean replace(final K key, final V oldValue, final V newValue)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.replace(key, oldValue, newValue);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public boolean replace(final K key, final V value)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.replace(key, value);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public V getAndReplace(final K key, final V value)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.getAndReplace(key, value);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public void removeAll(final Set<? extends K> keys)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ delegate.removeAll(keys);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public void removeAll()
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ delegate.removeAll();
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public void clear()
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ delegate.clear();
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public <C extends Configuration<K, V>> C getConfiguration(final Class<C> clazz)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.getConfiguration(clazz);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public <T> T invoke(final K key, final EntryProcessor<K, V, T> entryProcessor, final Object... arguments) throws EntryProcessorException
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.invoke(key, entryProcessor, arguments);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public <T> Map<K, EntryProcessorResult<T>> invokeAll(Set<? extends K> keys, EntryProcessor<K, V, T> entryProcessor, Object... arguments)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.invokeAll(keys, entryProcessor, arguments);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public String getName()
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.getName();
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public CacheManager getCacheManager()
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.getCacheManager();
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public void close()
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ delegate.close();
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public boolean isClosed()
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.isClosed();
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public <T> T unwrap(final Class<T> clazz)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.unwrap(clazz);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public void registerCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ delegate.registerCacheEntryListener(cacheEntryListenerConfiguration);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public void deregisterCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ delegate.deregisterCacheEntryListener(cacheEntryListenerConfiguration);
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public Iterator<Entry<K, V>> iterator()
+ {
+ final Thread thread = Thread.currentThread();
+ final ClassLoader loader = before(thread);
+ try
+ {
+ return delegate.iterator();
+ }
+ finally
+ {
+ thread.setContextClassLoader(loader);
+ }
+ }
+
+ @Override
+ public boolean equals(final Object obj)
+ {
+ if (ClassLoaderAwareCache.class.isInstance(obj))
+ {
+ return delegate.equals(ClassLoaderAwareCache.class.cast(obj).delegate);
+ }
+ return super.equals(obj);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return delegate.hashCode();
+ }
+
+ public static <K extends Serializable, V extends Serializable> Cache<K, V> wrap(final ClassLoader loader, final JCSCache<K, V> delegate)
+ {
+ ClassLoader dontWrapLoader = ClassLoaderAwareCache.class.getClassLoader();
+ while (dontWrapLoader != null)
+ {
+ if (loader == dontWrapLoader)
+ {
+ return delegate;
+ }
+ dontWrapLoader = dontWrapLoader.getParent();
+ }
+ return new ClassLoaderAwareCache<>(loader, delegate);
+ }
+
+ public static <K extends Serializable, V extends Serializable> JCSCache<K, V> getDelegate(final Cache<?, ?> cache)
+ {
+ if (JCSCache.class.isInstance(cache))
+ {
+ return (JCSCache<K, V>) cache;
+ }
+ return ((ClassLoaderAwareCache<K, V>) cache).delegate;
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/proxy/ExceptionWrapperHandler.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/proxy/ExceptionWrapperHandler.java
new file mode 100644
index 0000000..056cc93
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/proxy/ExceptionWrapperHandler.java
@@ -0,0 +1,77 @@
+/*
+ * 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.apache.commons.jcs3.jcache.proxy;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+public class ExceptionWrapperHandler<T> implements InvocationHandler
+{
+ private final T delegate;
+ private final Constructor<? extends RuntimeException> wrapper;
+
+ public ExceptionWrapperHandler(final T delegate, final Class<? extends RuntimeException> exceptionType)
+ {
+ this.delegate = delegate;
+ try
+ {
+ this.wrapper = exceptionType.getConstructor(Throwable.class);
+ }
+ catch (final NoSuchMethodException e)
+ {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable
+ {
+ try
+ {
+ return method.invoke(delegate, args);
+ }
+ catch (final InvocationTargetException ite)
+ {
+ final Throwable e = ite.getCause();
+ if (RuntimeException.class.isInstance(e))
+ {
+ final RuntimeException re;
+ try
+ {
+ re = wrapper.newInstance(e);
+ }
+ catch (final Exception e1)
+ {
+ throw new IllegalArgumentException(e1);
+ }
+ throw re;
+ }
+ throw e;
+ }
+ }
+
+ public static <T> T newProxy(final ClassLoader loader, final T delegate, final Class<? extends RuntimeException> exceptionType,
+ final Class<T> apis)
+ {
+ return (T) Proxy.newProxyInstance(loader, new Class<?>[] { apis }, new ExceptionWrapperHandler<>(delegate, exceptionType));
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/serialization/Serializations.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/serialization/Serializations.java
new file mode 100644
index 0000000..618738b
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/serialization/Serializations.java
@@ -0,0 +1,36 @@
+/*
+ * 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.apache.commons.jcs3.jcache.serialization;
+
+import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
+
+public class Serializations
+{
+ public static <K> K copy(final IElementSerializer serializer, final ClassLoader loader, final K key)
+ {
+ try
+ {
+ return serializer.deSerialize(serializer.serialize(key), loader);
+ }
+ catch ( final Exception e)
+ {
+ throw new IllegalStateException(e);
+ }
+ }
+}
diff --git a/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/thread/DaemonThreadFactory.java b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/thread/DaemonThreadFactory.java
new file mode 100644
index 0000000..b24f846
--- /dev/null
+++ b/commons-jcs-jcache/src/main/java/org/apache/commons/jcs3/jcache/thread/DaemonThreadFactory.java
@@ -0,0 +1,43 @@
+/*
+ * 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.apache.commons.jcs3.jcache.thread;
+
+
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class DaemonThreadFactory implements ThreadFactory
+{
+ private final AtomicInteger index = new AtomicInteger(1);
+ private final String prefix;
+
+ public DaemonThreadFactory(final String prefix)
+ {
+ this.prefix = prefix;
+ }
+
+ @Override
+ public Thread newThread( final Runnable runner )
+ {
+ final Thread t = new Thread( runner );
+ t.setName(prefix + index.getAndIncrement());
+ t.setDaemon(true);
+ return t;
+ }
+}
\ No newline at end of file
diff --git a/commons-jcs-jcache/src/main/resources/META-INF/services/javax.cache.spi.CachingProvider b/commons-jcs-jcache/src/main/resources/META-INF/services/javax.cache.spi.CachingProvider
index c3eaf99..72078cf 100644
--- a/commons-jcs-jcache/src/main/resources/META-INF/services/javax.cache.spi.CachingProvider
+++ b/commons-jcs-jcache/src/main/resources/META-INF/services/javax.cache.spi.CachingProvider
@@ -15,4 +15,4 @@
# specific language governing permissions and limitations
# under the License.
-org.apache.commons.jcs.jcache.JCSCachingProvider
+org.apache.commons.jcs3.jcache.JCSCachingProvider
diff --git a/commons-jcs-jcache/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/commons-jcs-jcache/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
index a47b35b..164b57e 100644
--- a/commons-jcs-jcache/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
+++ b/commons-jcs-jcache/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
@@ -14,4 +14,4 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-org.apache.commons.jcs.jcache.cdi.MakeJCacheCDIInterceptorFriendly
+org.apache.commons.jcs3.jcache.cdi.MakeJCacheCDIInterceptorFriendly
diff --git a/commons-jcs-jcache/src/test/java/org/apache/commons/jcs/jcache/CacheTest.java b/commons-jcs-jcache/src/test/java/org/apache/commons/jcs/jcache/CacheTest.java
deleted file mode 100644
index 045f41d..0000000
--- a/commons-jcs-jcache/src/test/java/org/apache/commons/jcs/jcache/CacheTest.java
+++ /dev/null
@@ -1,350 +0,0 @@
-package org.apache.commons.jcs.jcache;
-
-/*
- * 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.
- */
-
-import org.junit.Test;
-
-import javax.cache.Cache;
-import javax.cache.CacheManager;
-import javax.cache.Caching;
-import javax.cache.configuration.CacheEntryListenerConfiguration;
-import javax.cache.configuration.CompleteConfiguration;
-import javax.cache.configuration.Factory;
-import javax.cache.configuration.MutableConfiguration;
-import javax.cache.event.CacheEntryCreatedListener;
-import javax.cache.event.CacheEntryEvent;
-import javax.cache.event.CacheEntryEventFilter;
-import javax.cache.event.CacheEntryListener;
-import javax.cache.event.CacheEntryListenerException;
-import javax.cache.event.CacheEntryRemovedListener;
-import javax.cache.event.CacheEntryUpdatedListener;
-import javax.cache.expiry.AccessedExpiryPolicy;
-import javax.cache.expiry.Duration;
-import javax.cache.expiry.ExpiryPolicy;
-import javax.cache.integration.CacheLoader;
-import javax.cache.integration.CacheLoaderException;
-import javax.cache.integration.CacheWriter;
-import javax.cache.spi.CachingProvider;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class CacheTest
-{
- @Test
- public void accessExpiry() throws InterruptedException
- {
- final CachingProvider cachingProvider = Caching.getCachingProvider();
- final CacheManager cacheManager = cachingProvider.getCacheManager(cachingProvider.getDefaultURI(),
- Thread.currentThread().getContextClassLoader(),
- cachingProvider.getDefaultProperties());
- final Cache<Integer, Integer> cache = cacheManager.createCache(
- "test",
- new MutableConfiguration<Integer, Integer>()
- .setStoreByValue(false)
- .setStatisticsEnabled(true)
- .setManagementEnabled(true)
- .setTypes(Integer.class, Integer.class)
- .setExpiryPolicyFactory(AccessedExpiryPolicy.factoryOf(new Duration(TimeUnit.MILLISECONDS, 500))));
-
- try {
- cache.put(1, 2);
- cache.get(1);
- Thread.sleep(650);
- assertFalse(cache.containsKey(1));
- cache.put(1, 2);
- for (int i = 0; i < 3; i++) { // we update the last access to force the idle time and lastaccess to be synced
- Thread.sleep(250);
- assertTrue("iteration: " + Integer.toString(i), cache.containsKey(1));
- }
- assertTrue(cache.containsKey(1));
- Thread.sleep(650);
- assertFalse(cache.containsKey(1));
- } finally {
- cacheManager.close();
- cachingProvider.close();
- }
- }
-
- @Test
- public void getPut()
- {
- final CachingProvider cachingProvider = Caching.getCachingProvider();
- final CacheManager cacheManager = cachingProvider.getCacheManager();
- final Cache<String, String> cache = cacheManager.createCache("default", new MutableConfiguration<String, String>());
- assertFalse(cache.containsKey("foo"));
- cache.put("foo", "bar");
- assertTrue(cache.containsKey("foo"));
- assertEquals("bar", cache.get("foo"));
- cache.remove("foo");
- assertFalse(cache.containsKey("foo"));
- cachingProvider.close();
- }
-
- @Test
- public void listeners()
- {
- final CachingProvider cachingProvider = Caching.getCachingProvider();
- final CacheManager cacheManager = cachingProvider.getCacheManager();
- cacheManager.createCache("default", new MutableConfiguration<Object, Object>());
- final Cache<String, String> cache = cacheManager.getCache("default");
- final Set<String> event = new HashSet<String>();
- cache.registerCacheEntryListener(new CacheEntryListenerConfiguration<String, String>()
- {
- @Override
- public Factory<CacheEntryListener<? super String, ? super String>> getCacheEntryListenerFactory()
- {
- return new Factory<CacheEntryListener<? super String, ? super String>>()
- {
- @Override
- public CacheEntryListener<? super String, ? super String> create()
- {
- return new CacheEntryCreatedListener<String, String>()
- {
- @Override
- public void onCreated(Iterable<CacheEntryEvent<? extends String, ? extends String>> cacheEntryEvents)
- throws CacheEntryListenerException
- {
- event.add(cacheEntryEvents.iterator().next().getKey());
- }
- };
- }
- };
- }
-
- @Override
- public boolean isOldValueRequired()
- {
- return false;
- }
-
- @Override
- public Factory<CacheEntryEventFilter<? super String, ? super String>> getCacheEntryEventFilterFactory()
- {
- return null;
- }
-
- @Override
- public boolean isSynchronous()
- {
- return false;
- }
- });
- cache.registerCacheEntryListener(new CacheEntryListenerConfiguration<String, String>()
- {
- @Override
- public Factory<CacheEntryListener<? super String, ? super String>> getCacheEntryListenerFactory()
- {
- return new Factory<CacheEntryListener<? super String, ? super String>>()
- {
- @Override
- public CacheEntryListener<? super String, ? super String> create()
- {
- return new CacheEntryUpdatedListener<String, String>()
- {
- @Override
- public void onUpdated(Iterable<CacheEntryEvent<? extends String, ? extends String>> cacheEntryEvents)
- throws CacheEntryListenerException
- {
- event.add(cacheEntryEvents.iterator().next().getKey());
- }
- };
- }
- };
- }
-
- @Override
- public boolean isOldValueRequired()
- {
- return false;
- }
-
- @Override
- public Factory<CacheEntryEventFilter<? super String, ? super String>> getCacheEntryEventFilterFactory()
- {
- return null;
- }
-
- @Override
- public boolean isSynchronous()
- {
- return false;
- }
- });
- cache.registerCacheEntryListener(new CacheEntryListenerConfiguration<String, String>()
- {
- @Override
- public Factory<CacheEntryListener<? super String, ? super String>> getCacheEntryListenerFactory()
- {
- return new Factory<CacheEntryListener<? super String, ? super String>>()
- {
- @Override
- public CacheEntryListener<? super String, ? super String> create()
- {
- return new CacheEntryRemovedListener<String, String>()
- {
- @Override
- public void onRemoved(Iterable<CacheEntryEvent<? extends String, ? extends String>> cacheEntryEvents)
- throws CacheEntryListenerException
- {
- event.add(cacheEntryEvents.iterator().next().getKey());
- }
- };
- }
- };
- }
-
- @Override
- public boolean isOldValueRequired()
- {
- return false;
- }
-
- @Override
- public Factory<CacheEntryEventFilter<? super String, ? super String>> getCacheEntryEventFilterFactory()
- {
- return null;
- }
-
- @Override
- public boolean isSynchronous()
- {
- return false;
- }
- });
-
- cache.put("foo", "bar");
- assertEquals(1, event.size());
- assertEquals("foo", event.iterator().next());
- event.clear();
- cache.put("foo", "new");
- assertEquals(1, event.size());
- assertEquals("foo", event.iterator().next());
- event.clear();
- cache.remove("foo");
- assertEquals(1, event.size());
- assertEquals("foo", event.iterator().next());
-
- cachingProvider.close();
- }
-
- @Test
- public void loader()
- {
- final CachingProvider cachingProvider = Caching.getCachingProvider();
- final CacheManager cacheManager = cachingProvider.getCacheManager();
- cacheManager.createCache("default", new CompleteConfiguration<Object, Object>()
- {
- @Override
- public boolean isReadThrough()
- {
- return true;
- }
-
- @Override
- public boolean isWriteThrough()
- {
- return false;
- }
-
- @Override
- public boolean isStatisticsEnabled()
- {
- return false;
- }
-
- @Override
- public boolean isManagementEnabled()
- {
- return false;
- }
-
- @Override
- public Iterable<CacheEntryListenerConfiguration<Object, Object>> getCacheEntryListenerConfigurations()
- {
- return null;
- }
-
- @Override
- public Factory<CacheLoader<Object, Object>> getCacheLoaderFactory()
- {
- return new Factory<CacheLoader<Object, Object>>()
- {
- @Override
- public CacheLoader<Object, Object> create()
- {
- return new CacheLoader<Object, Object>()
- {
- @Override
- public Object load(Object key) throws CacheLoaderException
- {
- return "super";
- }
-
- @Override
- public Map<Object, Object> loadAll(Iterable<?> keys) throws CacheLoaderException
- {
- return null;
- }
- };
- }
- };
- }
-
- @Override
- public Factory<CacheWriter<? super Object, ? super Object>> getCacheWriterFactory()
- {
- return null;
- }
-
- @Override
- public Factory<ExpiryPolicy> getExpiryPolicyFactory()
- {
- return null;
- }
-
- @Override
- public Class<Object> getKeyType()
- {
- return Object.class;
- }
-
- @Override
- public Class<Object> getValueType()
- {
- return Object.class;
- }
-
- @Override
- public boolean isStoreByValue()
- {
- return false;
- }
- });
- final Cache<String, String> cache = cacheManager.getCache("default");
- assertEquals("super", cache.get("lazilyLoaded"));
- cachingProvider.close();
- }
-}
diff --git a/commons-jcs-jcache/src/test/java/org/apache/commons/jcs/jcache/CachingProviderTest.java b/commons-jcs-jcache/src/test/java/org/apache/commons/jcs/jcache/CachingProviderTest.java
deleted file mode 100644
index 24234e8..0000000
--- a/commons-jcs-jcache/src/test/java/org/apache/commons/jcs/jcache/CachingProviderTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.apache.commons.jcs.jcache;
-
-/*
- * 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.
- */
-
-import org.junit.Test;
-
-import javax.cache.Caching;
-import javax.cache.spi.CachingProvider;
-
-import static org.junit.Assert.assertNotNull;
-
-public class CachingProviderTest
-{
- @Test
- public void findProvider()
- {
- assertNotNull(Caching.getCachingProvider());
- }
-
- @Test
- public void createCacheMgr()
- {
- final CachingProvider cachingProvider = Caching.getCachingProvider();
- assertNotNull(cachingProvider.getCacheManager());
- cachingProvider.close();
- }
-}
diff --git a/commons-jcs-jcache/src/test/java/org/apache/commons/jcs/jcache/ExpiryListenerTest.java b/commons-jcs-jcache/src/test/java/org/apache/commons/jcs/jcache/ExpiryListenerTest.java
deleted file mode 100644
index 1ac2cc1..0000000
--- a/commons-jcs-jcache/src/test/java/org/apache/commons/jcs/jcache/ExpiryListenerTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.concurrent.TimeUnit;
-
-import javax.cache.Cache;
-import javax.cache.CacheManager;
-import javax.cache.Caching;
-import javax.cache.configuration.FactoryBuilder;
-import javax.cache.configuration.MutableCacheEntryListenerConfiguration;
-import javax.cache.configuration.MutableConfiguration;
-import javax.cache.event.CacheEntryEvent;
-import javax.cache.event.CacheEntryExpiredListener;
-import javax.cache.event.CacheEntryListenerException;
-import javax.cache.expiry.CreatedExpiryPolicy;
-import javax.cache.expiry.Duration;
-import javax.cache.expiry.ExpiryPolicy;
-import javax.cache.spi.CachingProvider;
-
-import org.junit.Test;
-
-public class ExpiryListenerTest {
-
- @Test
- public void listener() throws InterruptedException {
- final CachingProvider cachingProvider = Caching.getCachingProvider();
- final CacheManager cacheManager = cachingProvider.getCacheManager();
- final CacheEntryExpiredListenerImpl listener = new CacheEntryExpiredListenerImpl();
- cacheManager.createCache("default", new MutableConfiguration<String, String>()
- .setExpiryPolicyFactory(new FactoryBuilder.SingletonFactory<ExpiryPolicy>(
- new CreatedExpiryPolicy(new Duration(TimeUnit.MILLISECONDS, 1))))
- .addCacheEntryListenerConfiguration(new MutableCacheEntryListenerConfiguration<String, String>(
- FactoryBuilder.factoryOf(listener),
- null, false, false
- )));
- final Cache<String, String> cache = cacheManager.getCache("default");
- assertFalse(cache.containsKey("foo"));
- cache.put("foo", "bar");
- Thread.sleep(10);
- assertFalse(cache.containsKey("foo"));
- cachingProvider.close();
- assertEquals(1, listener.events.size());
- }
-
- private static class CacheEntryExpiredListenerImpl implements CacheEntryExpiredListener<String, String>, Serializable {
- private final Collection<CacheEntryEvent<? extends String, ? extends String>> events =
- new ArrayList<CacheEntryEvent<? extends String, ? extends String>>();
-
- @Override
- public void onExpired(final Iterable<CacheEntryEvent<? extends String, ? extends String>> cacheEntryEvents)
- throws CacheEntryListenerException {
- for (final CacheEntryEvent<? extends String, ? extends String> cacheEntryEvent : cacheEntryEvents) {
- events.add(cacheEntryEvent);
- }
- }
- }
-}
diff --git a/commons-jcs-jcache/src/test/java/org/apache/commons/jcs/jcache/ImmediateExpiryTest.java b/commons-jcs-jcache/src/test/java/org/apache/commons/jcs/jcache/ImmediateExpiryTest.java
deleted file mode 100644
index bd4d445..0000000
--- a/commons-jcs-jcache/src/test/java/org/apache/commons/jcs/jcache/ImmediateExpiryTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import org.junit.Test;
-
-import javax.cache.Cache;
-import javax.cache.CacheManager;
-import javax.cache.Caching;
-import javax.cache.configuration.FactoryBuilder;
-import javax.cache.configuration.MutableConfiguration;
-import javax.cache.expiry.CreatedExpiryPolicy;
-import javax.cache.expiry.Duration;
-import javax.cache.expiry.ExpiryPolicy;
-import javax.cache.spi.CachingProvider;
-
-import static org.junit.Assert.assertFalse;
-
-public class ImmediateExpiryTest
-{
- @Test
- public void immediate()
- {
- final CachingProvider cachingProvider = Caching.getCachingProvider();
- final CacheManager cacheManager = cachingProvider.getCacheManager();
- cacheManager.createCache("default",
- new MutableConfiguration<Object, Object>()
- .setExpiryPolicyFactory(
- new FactoryBuilder.SingletonFactory<ExpiryPolicy>(new CreatedExpiryPolicy(Duration.ZERO))));
- final Cache<String, String> cache = cacheManager.getCache("default");
- assertFalse(cache.containsKey("foo"));
- cache.put("foo", "bar");
- assertFalse(cache.containsKey("foo"));
- cachingProvider.close();
- }
-}
diff --git a/commons-jcs-jcache/src/test/java/org/apache/commons/jcs/jcache/NotSerializableTest.java b/commons-jcs-jcache/src/test/java/org/apache/commons/jcs/jcache/NotSerializableTest.java
deleted file mode 100644
index dc9e729..0000000
--- a/commons-jcs-jcache/src/test/java/org/apache/commons/jcs/jcache/NotSerializableTest.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import org.junit.Test;
-
-import javax.cache.Cache;
-import javax.cache.CacheManager;
-import javax.cache.Caching;
-import javax.cache.configuration.MutableConfiguration;
-import javax.cache.spi.CachingProvider;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class NotSerializableTest
-{
- @Test
- public void run()
- {
- final CachingProvider cachingProvider = Caching.getCachingProvider();
- final CacheManager cacheManager = cachingProvider.getCacheManager();
- cacheManager.createCache("default", new MutableConfiguration<String, NotSerializableAndImHappyWithIt>().setStoreByValue(false));
- final Cache<String, NotSerializableAndImHappyWithIt> cache = cacheManager.getCache("default");
- assertFalse(cache.containsKey("foo"));
- cache.put("foo", new NotSerializableAndImHappyWithIt("bar"));
- assertTrue(cache.containsKey("foo"));
- assertEquals("bar", cache.get("foo").name);
- cache.remove("foo");
- assertFalse(cache.containsKey("foo"));
- cache.close();
- cacheManager.close();
- cachingProvider.close();
- }
-
- public static class NotSerializableAndImHappyWithIt {
- private final String name;
-
- public NotSerializableAndImHappyWithIt(final String name)
- {
- this.name = name;
- }
- }
-}
diff --git a/commons-jcs-jcache/src/test/java/org/apache/commons/jcs/jcache/cdi/CDIJCacheHelperTest.java b/commons-jcs-jcache/src/test/java/org/apache/commons/jcs/jcache/cdi/CDIJCacheHelperTest.java
deleted file mode 100644
index bf5a014..0000000
--- a/commons-jcs-jcache/src/test/java/org/apache/commons/jcs/jcache/cdi/CDIJCacheHelperTest.java
+++ /dev/null
@@ -1,140 +0,0 @@
-package org.apache.commons.jcs.jcache.cdi;
-
-/*
- * 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.
- */
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.util.Map;
-import javax.cache.annotation.CacheDefaults;
-import javax.cache.annotation.CacheResult;
-import javax.interceptor.InvocationContext;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import org.junit.Test;
-
-public class CDIJCacheHelperTest
-{
- @Test
- public void proxyCacheDefaults()
- {
- final CDIJCacheHelper helper = new CDIJCacheHelper();
-
- final MyParent child1 = MyParent.class.cast(Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
- new Class<?>[]{MyChild1.class}, new InvocationHandler()
- {
- @Override
- public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable
- {
- return null;
- }
- }));
- final CDIJCacheHelper.MethodMeta meta1 = helper.findMeta(newContext(child1));
- assertEquals("child", meta1.getCacheResultCacheName());
-
- final MyParent child2 = MyParent.class.cast(Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
- new Class<?>[]{MyChild2.class}, new InvocationHandler()
- {
- @Override
- public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable
- {
- return null;
- }
- }));
- final CDIJCacheHelper.MethodMeta meta2 = helper.findMeta(newContext(child2));
- assertEquals("child2", meta2.getCacheResultCacheName());
- }
-
- private InvocationContext newContext(final MyParent child1) {
- return new InvocationContext()
- {
- @Override
- public Object getTarget()
- {
- return child1;
- }
-
- @Override
- public Method getMethod()
- {
- try {
- return MyParent.class.getMethod("foo");
- } catch (NoSuchMethodException e) {
- fail(e.getMessage());
- return null;
- }
- }
-
- @Override
- public Constructor<?> getConstructor()
- {
- return null;
- }
-
- @Override
- public Object[] getParameters()
- {
- return new Object[0];
- }
-
- @Override
- public void setParameters(final Object[] objects)
- {
-
- }
-
- @Override
- public Map<String, Object> getContextData()
- {
- return null;
- }
-
- @Override
- public Object proceed() throws Exception
- {
- return null;
- }
-
- @Override
- public Object getTimer()
- {
- return null;
- }
- };
- }
-
- public interface MyParent
- {
- @CacheResult
- String foo();
- }
-
- @CacheDefaults(cacheName = "child")
- public interface MyChild1 extends MyParent
- {
- }
-
- @CacheDefaults(cacheName = "child2")
- public interface MyChild2 extends MyParent
- {
- }
-}
diff --git a/commons-jcs-jcache/src/test/java/org/apache/commons/jcs3/jcache/CacheTest.java b/commons-jcs-jcache/src/test/java/org/apache/commons/jcs3/jcache/CacheTest.java
new file mode 100644
index 0000000..dfb5f70
--- /dev/null
+++ b/commons-jcs-jcache/src/test/java/org/apache/commons/jcs3/jcache/CacheTest.java
@@ -0,0 +1,298 @@
+package org.apache.commons.jcs3.jcache;
+
+/*
+ * 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.
+ */
+
+import org.junit.Test;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+import javax.cache.configuration.CacheEntryListenerConfiguration;
+import javax.cache.configuration.CompleteConfiguration;
+import javax.cache.configuration.Factory;
+import javax.cache.configuration.MutableConfiguration;
+import javax.cache.event.CacheEntryCreatedListener;
+import javax.cache.event.CacheEntryEvent;
+import javax.cache.event.CacheEntryEventFilter;
+import javax.cache.event.CacheEntryListener;
+import javax.cache.event.CacheEntryListenerException;
+import javax.cache.event.CacheEntryRemovedListener;
+import javax.cache.event.CacheEntryUpdatedListener;
+import javax.cache.expiry.AccessedExpiryPolicy;
+import javax.cache.expiry.Duration;
+import javax.cache.expiry.ExpiryPolicy;
+import javax.cache.integration.CacheLoader;
+import javax.cache.integration.CacheLoaderException;
+import javax.cache.integration.CacheWriter;
+import javax.cache.spi.CachingProvider;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class CacheTest
+{
+ @Test
+ public void accessExpiry() throws InterruptedException
+ {
+ final CachingProvider cachingProvider = Caching.getCachingProvider();
+ final CacheManager cacheManager = cachingProvider.getCacheManager(cachingProvider.getDefaultURI(),
+ Thread.currentThread().getContextClassLoader(),
+ cachingProvider.getDefaultProperties());
+ final Cache<Integer, Integer> cache = cacheManager.createCache(
+ "test",
+ new MutableConfiguration<Integer, Integer>()
+ .setStoreByValue(false)
+ .setStatisticsEnabled(true)
+ .setManagementEnabled(true)
+ .setTypes(Integer.class, Integer.class)
+ .setExpiryPolicyFactory(AccessedExpiryPolicy.factoryOf(new Duration(TimeUnit.MILLISECONDS, 500))));
+
+ try {
+ cache.put(1, 2);
+ cache.get(1);
+ Thread.sleep(650);
+ assertFalse(cache.containsKey(1));
+ cache.put(1, 2);
+ for (int i = 0; i < 3; i++) { // we update the last access to force the idle time and lastaccess to be synced
+ Thread.sleep(250);
+ assertTrue("iteration: " + Integer.toString(i), cache.containsKey(1));
+ }
+ assertTrue(cache.containsKey(1));
+ Thread.sleep(650);
+ assertFalse(cache.containsKey(1));
+ } finally {
+ cacheManager.close();
+ cachingProvider.close();
+ }
+ }
+
+ @Test
+ public void getPut()
+ {
+ final CachingProvider cachingProvider = Caching.getCachingProvider();
+ final CacheManager cacheManager = cachingProvider.getCacheManager();
+ final Cache<String, String> cache = cacheManager.createCache("default", new MutableConfiguration<String, String>());
+ assertFalse(cache.containsKey("foo"));
+ cache.put("foo", "bar");
+ assertTrue(cache.containsKey("foo"));
+ assertEquals("bar", cache.get("foo"));
+ cache.remove("foo");
+ assertFalse(cache.containsKey("foo"));
+ cachingProvider.close();
+ }
+
+ @Test
+ public void listeners()
+ {
+ final CachingProvider cachingProvider = Caching.getCachingProvider();
+ final CacheManager cacheManager = cachingProvider.getCacheManager();
+ cacheManager.createCache("default", new MutableConfiguration<>());
+ final Cache<String, String> cache = cacheManager.getCache("default");
+ final Set<String> event = new HashSet<>();
+ cache.registerCacheEntryListener(new CacheEntryListenerConfiguration<String, String>()
+ {
+ @Override
+ public Factory<CacheEntryListener<? super String, ? super String>> getCacheEntryListenerFactory()
+ {
+ return () -> (CacheEntryCreatedListener<String, String>) cacheEntryEvents -> event.add(cacheEntryEvents.iterator().next().getKey());
+ }
+
+ @Override
+ public boolean isOldValueRequired()
+ {
+ return false;
+ }
+
+ @Override
+ public Factory<CacheEntryEventFilter<? super String, ? super String>> getCacheEntryEventFilterFactory()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isSynchronous()
+ {
+ return false;
+ }
+ });
+ cache.registerCacheEntryListener(new CacheEntryListenerConfiguration<String, String>()
+ {
+ @Override
+ public Factory<CacheEntryListener<? super String, ? super String>> getCacheEntryListenerFactory()
+ {
+ return () -> (CacheEntryUpdatedListener<String, String>) cacheEntryEvents -> event.add(cacheEntryEvents.iterator().next().getKey());
+ }
+
+ @Override
+ public boolean isOldValueRequired()
+ {
+ return false;
+ }
+
+ @Override
+ public Factory<CacheEntryEventFilter<? super String, ? super String>> getCacheEntryEventFilterFactory()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isSynchronous()
+ {
+ return false;
+ }
+ });
+ cache.registerCacheEntryListener(new CacheEntryListenerConfiguration<String, String>()
+ {
+ @Override
+ public Factory<CacheEntryListener<? super String, ? super String>> getCacheEntryListenerFactory()
+ {
+ return () -> (CacheEntryRemovedListener<String, String>) cacheEntryEvents -> event.add(cacheEntryEvents.iterator().next().getKey());
+ }
+
+ @Override
+ public boolean isOldValueRequired()
+ {
+ return false;
+ }
+
+ @Override
+ public Factory<CacheEntryEventFilter<? super String, ? super String>> getCacheEntryEventFilterFactory()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isSynchronous()
+ {
+ return false;
+ }
+ });
+
+ cache.put("foo", "bar");
+ assertEquals(1, event.size());
+ assertEquals("foo", event.iterator().next());
+ event.clear();
+ cache.put("foo", "new");
+ assertEquals(1, event.size());
+ assertEquals("foo", event.iterator().next());
+ event.clear();
+ cache.remove("foo");
+ assertEquals(1, event.size());
+ assertEquals("foo", event.iterator().next());
+
+ cachingProvider.close();
+ }
+
+ @Test
+ public void loader()
+ {
+ final CachingProvider cachingProvider = Caching.getCachingProvider();
+ final CacheManager cacheManager = cachingProvider.getCacheManager();
+ cacheManager.createCache("default", new CompleteConfiguration<Object, Object>()
+ {
+ @Override
+ public boolean isReadThrough()
+ {
+ return true;
+ }
+
+ @Override
+ public boolean isWriteThrough()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isStatisticsEnabled()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isManagementEnabled()
+ {
+ return false;
+ }
+
+ @Override
+ public Iterable<CacheEntryListenerConfiguration<Object, Object>> getCacheEntryListenerConfigurations()
+ {
+ return null;
+ }
+
+ @Override
+ public Factory<CacheLoader<Object, Object>> getCacheLoaderFactory()
+ {
+ return () -> new CacheLoader<Object, Object>()
+ {
+ @Override
+ public Object load(Object key) throws CacheLoaderException
+ {
+ return "super";
+ }
+
+ @Override
+ public Map<Object, Object> loadAll(Iterable<?> keys) throws CacheLoaderException
+ {
+ return null;
+ }
+ };
+ }
+
+ @Override
+ public Factory<CacheWriter<? super Object, ? super Object>> getCacheWriterFactory()
+ {
+ return null;
+ }
+
+ @Override
+ public Factory<ExpiryPolicy> getExpiryPolicyFactory()
+ {
+ return null;
+ }
+
+ @Override
+ public Class<Object> getKeyType()
+ {
+ return Object.class;
+ }
+
+ @Override
+ public Class<Object> getValueType()
+ {
+ return Object.class;
+ }
+
+ @Override
+ public boolean isStoreByValue()
+ {
+ return false;
+ }
+ });
+ final Cache<String, String> cache = cacheManager.getCache("default");
+ assertEquals("super", cache.get("lazilyLoaded"));
+ cachingProvider.close();
+ }
+}
diff --git a/commons-jcs-jcache/src/test/java/org/apache/commons/jcs3/jcache/CachingProviderTest.java b/commons-jcs-jcache/src/test/java/org/apache/commons/jcs3/jcache/CachingProviderTest.java
new file mode 100644
index 0000000..5e28cf4
--- /dev/null
+++ b/commons-jcs-jcache/src/test/java/org/apache/commons/jcs3/jcache/CachingProviderTest.java
@@ -0,0 +1,44 @@
+package org.apache.commons.jcs3.jcache;
+
+/*
+ * 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.
+ */
+
+import org.junit.Test;
+
+import javax.cache.Caching;
+import javax.cache.spi.CachingProvider;
+
+import static org.junit.Assert.assertNotNull;
+
+public class CachingProviderTest
+{
+ @Test
+ public void findProvider()
+ {
+ assertNotNull(Caching.getCachingProvider());
+ }
+
+ @Test
+ public void createCacheMgr()
+ {
+ final CachingProvider cachingProvider = Caching.getCachingProvider();
+ assertNotNull(cachingProvider.getCacheManager());
+ cachingProvider.close();
+ }
+}
diff --git a/commons-jcs-jcache/src/test/java/org/apache/commons/jcs3/jcache/ExpiryListenerTest.java b/commons-jcs-jcache/src/test/java/org/apache/commons/jcs3/jcache/ExpiryListenerTest.java
new file mode 100644
index 0000000..2dd6e6f
--- /dev/null
+++ b/commons-jcs-jcache/src/test/java/org/apache/commons/jcs3/jcache/ExpiryListenerTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.concurrent.TimeUnit;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+import javax.cache.configuration.FactoryBuilder;
+import javax.cache.configuration.MutableCacheEntryListenerConfiguration;
+import javax.cache.configuration.MutableConfiguration;
+import javax.cache.event.CacheEntryEvent;
+import javax.cache.event.CacheEntryExpiredListener;
+import javax.cache.event.CacheEntryListenerException;
+import javax.cache.expiry.CreatedExpiryPolicy;
+import javax.cache.expiry.Duration;
+import javax.cache.expiry.ExpiryPolicy;
+import javax.cache.spi.CachingProvider;
+
+import org.junit.Test;
+
+public class ExpiryListenerTest {
+
+ @Test
+ public void listener() throws InterruptedException {
+ final CachingProvider cachingProvider = Caching.getCachingProvider();
+ final CacheManager cacheManager = cachingProvider.getCacheManager();
+ final CacheEntryExpiredListenerImpl listener = new CacheEntryExpiredListenerImpl();
+ cacheManager.createCache("default", new MutableConfiguration<String, String>()
+ .setExpiryPolicyFactory(new FactoryBuilder.SingletonFactory<ExpiryPolicy>(
+ new CreatedExpiryPolicy(new Duration(TimeUnit.MILLISECONDS, 1))))
+ .addCacheEntryListenerConfiguration(new MutableCacheEntryListenerConfiguration<>(
+ FactoryBuilder.factoryOf(listener),
+ null, false, false
+ )));
+ final Cache<String, String> cache = cacheManager.getCache("default");
+ assertFalse(cache.containsKey("foo"));
+ cache.put("foo", "bar");
+ Thread.sleep(10);
+ assertFalse(cache.containsKey("foo"));
+ cachingProvider.close();
+ assertEquals(1, listener.events.size());
+ }
+
+ private static class CacheEntryExpiredListenerImpl implements CacheEntryExpiredListener<String, String>, Serializable {
+ private final Collection<CacheEntryEvent<? extends String, ? extends String>> events =
+ new ArrayList<>();
+
+ @Override
+ public void onExpired(final Iterable<CacheEntryEvent<? extends String, ? extends String>> cacheEntryEvents)
+ throws CacheEntryListenerException {
+ for (final CacheEntryEvent<? extends String, ? extends String> cacheEntryEvent : cacheEntryEvents) {
+ events.add(cacheEntryEvent);
+ }
+ }
+ }
+}
diff --git a/commons-jcs-jcache/src/test/java/org/apache/commons/jcs3/jcache/ImmediateExpiryTest.java b/commons-jcs-jcache/src/test/java/org/apache/commons/jcs3/jcache/ImmediateExpiryTest.java
new file mode 100644
index 0000000..a3b372b
--- /dev/null
+++ b/commons-jcs-jcache/src/test/java/org/apache/commons/jcs3/jcache/ImmediateExpiryTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import org.junit.Test;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+import javax.cache.configuration.FactoryBuilder;
+import javax.cache.configuration.MutableConfiguration;
+import javax.cache.expiry.CreatedExpiryPolicy;
+import javax.cache.expiry.Duration;
+import javax.cache.expiry.ExpiryPolicy;
+import javax.cache.spi.CachingProvider;
+
+import static org.junit.Assert.assertFalse;
+
+public class ImmediateExpiryTest
+{
+ @Test
+ public void immediate()
+ {
+ final CachingProvider cachingProvider = Caching.getCachingProvider();
+ final CacheManager cacheManager = cachingProvider.getCacheManager();
+ cacheManager.createCache("default",
+ new MutableConfiguration<>()
+ .setExpiryPolicyFactory(
+ new FactoryBuilder.SingletonFactory<ExpiryPolicy>(new CreatedExpiryPolicy(Duration.ZERO))));
+ final Cache<String, String> cache = cacheManager.getCache("default");
+ assertFalse(cache.containsKey("foo"));
+ cache.put("foo", "bar");
+ assertFalse(cache.containsKey("foo"));
+ cachingProvider.close();
+ }
+}
diff --git a/commons-jcs-jcache/src/test/java/org/apache/commons/jcs3/jcache/NotSerializableTest.java b/commons-jcs-jcache/src/test/java/org/apache/commons/jcs3/jcache/NotSerializableTest.java
new file mode 100644
index 0000000..7ce2526
--- /dev/null
+++ b/commons-jcs-jcache/src/test/java/org/apache/commons/jcs3/jcache/NotSerializableTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import org.junit.Test;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+import javax.cache.configuration.MutableConfiguration;
+import javax.cache.spi.CachingProvider;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class NotSerializableTest
+{
+ @Test
+ public void run()
+ {
+ final CachingProvider cachingProvider = Caching.getCachingProvider();
+ final CacheManager cacheManager = cachingProvider.getCacheManager();
+ cacheManager.createCache("default", new MutableConfiguration<String, NotSerializableAndImHappyWithIt>().setStoreByValue(false));
+ final Cache<String, NotSerializableAndImHappyWithIt> cache = cacheManager.getCache("default");
+ assertFalse(cache.containsKey("foo"));
+ cache.put("foo", new NotSerializableAndImHappyWithIt("bar"));
+ assertTrue(cache.containsKey("foo"));
+ assertEquals("bar", cache.get("foo").name);
+ cache.remove("foo");
+ assertFalse(cache.containsKey("foo"));
+ cache.close();
+ cacheManager.close();
+ cachingProvider.close();
+ }
+
+ public static class NotSerializableAndImHappyWithIt {
+ private final String name;
+
+ public NotSerializableAndImHappyWithIt(final String name)
+ {
+ this.name = name;
+ }
+ }
+}
diff --git a/commons-jcs-jcache/src/test/java/org/apache/commons/jcs3/jcache/cdi/CDIJCacheHelperTest.java b/commons-jcs-jcache/src/test/java/org/apache/commons/jcs3/jcache/cdi/CDIJCacheHelperTest.java
new file mode 100644
index 0000000..bf67273
--- /dev/null
+++ b/commons-jcs-jcache/src/test/java/org/apache/commons/jcs3/jcache/cdi/CDIJCacheHelperTest.java
@@ -0,0 +1,127 @@
+package org.apache.commons.jcs3.jcache.cdi;
+
+/*
+ * 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.
+ */
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Map;
+import javax.cache.annotation.CacheDefaults;
+import javax.cache.annotation.CacheResult;
+import javax.interceptor.InvocationContext;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.apache.commons.jcs3.jcache.cdi.CDIJCacheHelper;
+import org.junit.Test;
+
+public class CDIJCacheHelperTest
+{
+ @Test
+ public void proxyCacheDefaults()
+ {
+ final CDIJCacheHelper helper = new CDIJCacheHelper();
+
+ final MyParent child1 = MyParent.class.cast(Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
+ new Class<?>[]{MyChild1.class}, (proxy, method, args) -> null));
+ final CDIJCacheHelper.MethodMeta meta1 = helper.findMeta(newContext(child1));
+ assertEquals("child", meta1.getCacheResultCacheName());
+
+ final MyParent child2 = MyParent.class.cast(Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
+ new Class<?>[]{MyChild2.class}, (proxy, method, args) -> null));
+ final CDIJCacheHelper.MethodMeta meta2 = helper.findMeta(newContext(child2));
+ assertEquals("child2", meta2.getCacheResultCacheName());
+ }
+
+ private InvocationContext newContext(final MyParent child1) {
+ return new InvocationContext()
+ {
+ @Override
+ public Object getTarget()
+ {
+ return child1;
+ }
+
+ @Override
+ public Method getMethod()
+ {
+ try {
+ return MyParent.class.getMethod("foo");
+ } catch (NoSuchMethodException e) {
+ fail(e.getMessage());
+ return null;
+ }
+ }
+
+ @Override
+ public Constructor<?> getConstructor()
+ {
+ return null;
+ }
+
+ @Override
+ public Object[] getParameters()
+ {
+ return new Object[0];
+ }
+
+ @Override
+ public void setParameters(final Object[] objects)
+ {
+
+ }
+
+ @Override
+ public Map<String, Object> getContextData()
+ {
+ return null;
+ }
+
+ @Override
+ public Object proceed() throws Exception
+ {
+ return null;
+ }
+
+ @Override
+ public Object getTimer()
+ {
+ return null;
+ }
+ };
+ }
+
+ public interface MyParent
+ {
+ @CacheResult
+ String foo();
+ }
+
+ @CacheDefaults(cacheName = "child")
+ public interface MyChild1 extends MyParent
+ {
+ }
+
+ @CacheDefaults(cacheName = "child2")
+ public interface MyChild2 extends MyParent
+ {
+ }
+}
diff --git a/commons-jcs-sandbox/pom.xml b/commons-jcs-sandbox/pom.xml
index a302cfb..d76dd5f 100644
--- a/commons-jcs-sandbox/pom.xml
+++ b/commons-jcs-sandbox/pom.xml
@@ -23,7 +23,7 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.commons</groupId>
- <artifactId>commons-jcs</artifactId>
+ <artifactId>commons-jcs3</artifactId>
<version>3.0-SNAPSHOT</version>
</parent>
diff --git a/commons-jcs-tck-tests/pom.xml b/commons-jcs-tck-tests/pom.xml
index 6d2dade..88123f9 100644
--- a/commons-jcs-tck-tests/pom.xml
+++ b/commons-jcs-tck-tests/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.commons</groupId>
- <artifactId>commons-jcs</artifactId>
+ <artifactId>commons-jcs3</artifactId>
<version>3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@@ -30,10 +30,10 @@
<!--
to run from an IDE a JMX test add:
- -Dorg.jsr107.tck.management.agentId=MBeanServerJCS -Djavax.management.builder.initial=org.apache.commons.jcs.jcache.jmx.ConfigurableMBeanServerIdBuilder
+ -Dorg.jsr107.tck.management.agentId=MBeanServerJCS -Djavax.management.builder.initial=org.apache.commons.jcs3.jcache.jmx.ConfigurableMBeanServerIdBuilder
-->
- <artifactId>commons-jcs-jcache-tck</artifactId>
+ <artifactId>commons-jcs3-jcache-tck</artifactId>
<version>3.0-SNAPSHOT</version>
<name>Apache Commons JCS :: JCache TCK</name>
@@ -47,14 +47,14 @@
<properties>
<implementation-groupId>${project.groupId}</implementation-groupId>
- <implementation-artifactId>commons-jcs</implementation-artifactId>
+ <implementation-artifactId>commons-jcs3</implementation-artifactId>
<implementation-version>${project.version}</implementation-version>
- <CacheManagerImpl>org.apache.commons.jcs.jcache.JCSCachingManager</CacheManagerImpl>
- <CacheImpl>org.apache.commons.jcs.jcache.JCSCache</CacheImpl>
- <CacheEntryImpl>org.apache.commons.jcs.jcache.JCSEntry</CacheEntryImpl>
+ <CacheManagerImpl>org.apache.commons.jcs3.jcache.JCSCachingManager</CacheManagerImpl>
+ <CacheImpl>org.apache.commons.jcs3.jcache.JCSCache</CacheImpl>
+ <CacheEntryImpl>org.apache.commons.jcs3.jcache.JCSEntry</CacheEntryImpl>
- <javax.management.builder.initial>org.apache.commons.jcs.jcache.jmx.ConfigurableMBeanServerIdBuilder</javax.management.builder.initial>
+ <javax.management.builder.initial>org.apache.commons.jcs3.jcache.jmx.ConfigurableMBeanServerIdBuilder</javax.management.builder.initial>
<org.jsr107.tck.management.agentId>MBeanServerJCS</org.jsr107.tck.management.agentId>
<domain-lib-dir>${project.build.directory}/domainlib</domain-lib-dir>
@@ -64,12 +64,12 @@
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>commons-jcs-core</artifactId>
+ <artifactId>commons-jcs3-core</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>commons-jcs-jcache</artifactId>
+ <artifactId>commons-jcs3-jcache</artifactId>
</dependency>
<dependency>
diff --git a/commons-jcs-tck-tests/src/test/java/org/apache/commons/jcs/jcache/EnsureCDIIsTestedWhenTCKsRunTest.java b/commons-jcs-tck-tests/src/test/java/org/apache/commons/jcs/jcache/EnsureCDIIsTestedWhenTCKsRunTest.java
deleted file mode 100644
index fdcab32..0000000
--- a/commons-jcs-tck-tests/src/test/java/org/apache/commons/jcs/jcache/EnsureCDIIsTestedWhenTCKsRunTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import org.junit.Test;
-
-import javax.cache.annotation.BeanProvider;
-import java.util.Iterator;
-import java.util.ServiceLoader;
-
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-// useless test but without it we are not sure
-// CDI TCKs passed
-public class EnsureCDIIsTestedWhenTCKsRunTest
-{
- @Test
- public void checkOWBProvider()
- {
- try {
- final Iterator<BeanProvider> iterator = ServiceLoader.load(BeanProvider.class).iterator();
- assertTrue(iterator.hasNext());
- assertThat(iterator.next(), instanceOf(OWBBeanProvider.class));
- } catch (java.lang.UnsupportedClassVersionError e) {
- System.err.println("Ignoring checkOWBProvider test failure on " + System.getProperty("java.version"));
- }
- }
-}
diff --git a/commons-jcs-tck-tests/src/test/java/org/apache/commons/jcs/jcache/OWBBeanProvider.java b/commons-jcs-tck-tests/src/test/java/org/apache/commons/jcs/jcache/OWBBeanProvider.java
deleted file mode 100644
index 3863106..0000000
--- a/commons-jcs-tck-tests/src/test/java/org/apache/commons/jcs/jcache/OWBBeanProvider.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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.apache.commons.jcs.jcache;
-
-import org.apache.webbeans.config.WebBeansContext;
-import org.apache.webbeans.container.BeanManagerImpl;
-import org.apache.webbeans.spi.ContainerLifecycle;
-
-import java.util.Set;
-import javax.cache.annotation.BeanProvider;
-import javax.enterprise.inject.spi.Bean;
-
-public class OWBBeanProvider implements BeanProvider
-{
- private final BeanManagerImpl bm;
-
- public OWBBeanProvider()
- {
- final WebBeansContext webBeansContext = WebBeansContext.currentInstance();
- final ContainerLifecycle lifecycle = webBeansContext.getService(ContainerLifecycle.class);
- lifecycle.startApplication(null);
- Runtime.getRuntime().addShutdownHook(new Thread()
- {
- @Override
- public void run()
- {
- lifecycle.stopApplication(null);
- }
- });
- bm = webBeansContext.getBeanManagerImpl();
- }
-
- @Override
- public <T> T getBeanByType(final Class<T> tClass)
- {
- if (tClass == null)
- {
- throw new IllegalArgumentException("no bean class specified");
- }
-
- final Set<Bean<?>> beans = bm.getBeans(tClass);
- if (beans.isEmpty())
- {
- throw new IllegalStateException("no bean of type " + tClass.getName());
- }
- final Bean<?> bean = bm.resolve(beans);
- return (T) bm.getReference(bean, bean.getBeanClass(), bm.createCreationalContext(bean));
- }
-}
diff --git a/commons-jcs-tck-tests/src/test/java/org/apache/commons/jcs3/jcache/EnsureCDIIsTestedWhenTCKsRunTest.java b/commons-jcs-tck-tests/src/test/java/org/apache/commons/jcs3/jcache/EnsureCDIIsTestedWhenTCKsRunTest.java
new file mode 100644
index 0000000..ef1f621
--- /dev/null
+++ b/commons-jcs-tck-tests/src/test/java/org/apache/commons/jcs3/jcache/EnsureCDIIsTestedWhenTCKsRunTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import org.junit.Test;
+
+import javax.cache.annotation.BeanProvider;
+import java.util.Iterator;
+import java.util.ServiceLoader;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+// useless test but without it we are not sure
+// CDI TCKs passed
+public class EnsureCDIIsTestedWhenTCKsRunTest
+{
+ @Test
+ public void checkOWBProvider()
+ {
+ try {
+ final Iterator<BeanProvider> iterator = ServiceLoader.load(BeanProvider.class).iterator();
+ assertTrue(iterator.hasNext());
+ assertThat(iterator.next(), instanceOf(OWBBeanProvider.class));
+ } catch (java.lang.UnsupportedClassVersionError e) {
+ System.err.println("Ignoring checkOWBProvider test failure on " + System.getProperty("java.version"));
+ }
+ }
+}
diff --git a/commons-jcs-tck-tests/src/test/java/org/apache/commons/jcs3/jcache/OWBBeanProvider.java b/commons-jcs-tck-tests/src/test/java/org/apache/commons/jcs3/jcache/OWBBeanProvider.java
new file mode 100644
index 0000000..2f0d006
--- /dev/null
+++ b/commons-jcs-tck-tests/src/test/java/org/apache/commons/jcs3/jcache/OWBBeanProvider.java
@@ -0,0 +1,65 @@
+/*
+ * 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.apache.commons.jcs3.jcache;
+
+import org.apache.webbeans.config.WebBeansContext;
+import org.apache.webbeans.container.BeanManagerImpl;
+import org.apache.webbeans.spi.ContainerLifecycle;
+
+import java.util.Set;
+import javax.cache.annotation.BeanProvider;
+import javax.enterprise.inject.spi.Bean;
+
+public class OWBBeanProvider implements BeanProvider
+{
+ private final BeanManagerImpl bm;
+
+ public OWBBeanProvider()
+ {
+ final WebBeansContext webBeansContext = WebBeansContext.currentInstance();
+ final ContainerLifecycle lifecycle = webBeansContext.getService(ContainerLifecycle.class);
+ lifecycle.startApplication(null);
+ Runtime.getRuntime().addShutdownHook(new Thread()
+ {
+ @Override
+ public void run()
+ {
+ lifecycle.stopApplication(null);
+ }
+ });
+ bm = webBeansContext.getBeanManagerImpl();
+ }
+
+ @Override
+ public <T> T getBeanByType(final Class<T> tClass)
+ {
+ if (tClass == null)
+ {
+ throw new IllegalArgumentException("no bean class specified");
+ }
+
+ final Set<Bean<?>> beans = bm.getBeans(tClass);
+ if (beans.isEmpty())
+ {
+ throw new IllegalStateException("no bean of type " + tClass.getName());
+ }
+ final Bean<?> bean = bm.resolve(beans);
+ return (T) bm.getReference(bean, bean.getBeanClass(), bm.createCreationalContext(bean));
+ }
+}
diff --git a/commons-jcs-tck-tests/src/test/resources/META-INF/services/javax.cache.annotation.BeanProvider b/commons-jcs-tck-tests/src/test/resources/META-INF/services/javax.cache.annotation.BeanProvider
index ee527d8..3af617c 100644
--- a/commons-jcs-tck-tests/src/test/resources/META-INF/services/javax.cache.annotation.BeanProvider
+++ b/commons-jcs-tck-tests/src/test/resources/META-INF/services/javax.cache.annotation.BeanProvider
@@ -15,4 +15,4 @@
# specific language governing permissions and limitations
# under the License.
-org.apache.commons.jcs.jcache.OWBBeanProvider
+org.apache.commons.jcs3.jcache.OWBBeanProvider
diff --git a/commons-jcs-tck-tests/src/test/resources/log4j.properties b/commons-jcs-tck-tests/src/test/resources/log4j.properties
deleted file mode 100644
index 18c5889..0000000
--- a/commons-jcs-tck-tests/src/test/resources/log4j.properties
+++ /dev/null
@@ -1,19 +0,0 @@
-# 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.
-log4j.rootCategory=INFO, stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
diff --git a/pom.xml b/pom.xml
index 3a4bfa6..7768c50 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
<version>50</version>
</parent>
- <artifactId>commons-jcs</artifactId>
+ <artifactId>commons-jcs3</artifactId>
<packaging>pom</packaging>
<version>3.0-SNAPSHOT</version>
@@ -290,13 +290,13 @@
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>commons-jcs-core</artifactId>
+ <artifactId>commons-jcs3-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>commons-jcs-core</artifactId>
+ <artifactId>commons-jcs3-core</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
@@ -304,17 +304,10 @@
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>commons-jcs-jcache</artifactId>
+ <artifactId>commons-jcs3-jcache</artifactId>
<version>${project.version}</version>
</dependency>
- <!-- REQUIRED FOR JCS CORE -->
- <dependency>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- <version>1.2</version>
- </dependency>
-
<!-- JDBC DISK CACHE -->
<dependency>
<groupId>org.apache.commons</groupId>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index e578112..ce7c0a3 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -66,6 +66,14 @@
Finally require Java 8
</action>
</release>
+ <release version="2.2.1" date="2018-08-21">
+ <action dev="kinow" type="fix" due-to="athun">
+ Unexpected dispose() in CompositeCacheManager.release()
+ </action>
+ <action issue="JCS-183" dev="rmannibucau" type="fix">
+ JCache CDI Integration is slow
+ </action>
+ </release>
<release version="2.2" date="2017-08-02">
<action issue="JCS-180" dev="rmannibucau" type="fix">
CacheInvocationContextImpl NPE if method doesnt have any argument
diff --git a/src/site/site.xml b/src/site/site.xml
index 83832db..edd1123 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -32,6 +32,7 @@
<menu name="Development">
<item name="Release Notes" href="/changes-report.html"/>
<item name="Upgrading from 1.3 to 2.0" href="/UpgradingFrom13.html"/>
+ <item name="Upgrading from 2.x to 3.0" href="/UpgradingFrom2x.html"/>
<item name="Mailing Lists" href="/mail-lists.html"/>
<item name="Issue Tracking" href="/issue-tracking.html"/>
<item name="Source Repository" href="/source-repository.html"/>
diff --git a/xdocs/UpgradingFrom2x.xml b/xdocs/UpgradingFrom2x.xml
index 70611e5..409fbae 100644
--- a/xdocs/UpgradingFrom2x.xml
+++ b/xdocs/UpgradingFrom2x.xml
@@ -45,9 +45,9 @@
The Maven coordinates change from
<source><![CDATA[
<dependency>
- <groupId>org.apache.jcs</groupId>
- <artifactId>jcs</artifactId>
- <version>1.3</version>
+ <groupId>org.apache.commons.jcs</groupId>
+ <artifactId>commons-jcs-core</artifactId>
+ <version>2.2.1</version>
</dependency>
]]></source>
to