Author: asmuts Date: Wed Aug 12 21:41:44 2009 New Revision: 803719 URL: http://svn.apache.org/viewvc?rev=803719&view=rev Log: Added a rough sketch of a partitioned cache access. I changed the get multiple to return a Map and not a HashMap. Unfortunately, this may break some client. I hate to do this, but it's a trivial fix.
Added: jakarta/jcs/trunk/src/java/org/apache/jcs/access/PartitionedCacheAccess.java jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/ConfigurationException.java jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/AbstractPropertyContainer.java jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactory.java jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactoryFileImpl.java Modified: jakarta/jcs/trunk/src/java/org/apache/jcs/access/CacheAccess.java jakarta/jcs/trunk/src/java/org/apache/jcs/access/behavior/ICacheAccess.java jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/CacheException.java jakarta/jcs/trunk/src/java/org/apache/jcs/engine/match/KeyMatcherPatternImpl.java Modified: jakarta/jcs/trunk/src/java/org/apache/jcs/access/CacheAccess.java URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/access/CacheAccess.java?rev=803719&r1=803718&r2=803719&view=diff ============================================================================== --- jakarta/jcs/trunk/src/java/org/apache/jcs/access/CacheAccess.java (original) +++ jakarta/jcs/trunk/src/java/org/apache/jcs/access/CacheAccess.java Wed Aug 12 21:41:44 2009 @@ -200,7 +200,7 @@ * @param pattern - a key pattern for the objects stored * @return A map of key to values. These are stripped from the wrapper. */ - public HashMap getMatching( String pattern ) + public Map getMatching( String pattern ) { HashMap unwrappedResults = new HashMap(); Added: jakarta/jcs/trunk/src/java/org/apache/jcs/access/PartitionedCacheAccess.java URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/access/PartitionedCacheAccess.java?rev=803719&view=auto ============================================================================== --- jakarta/jcs/trunk/src/java/org/apache/jcs/access/PartitionedCacheAccess.java (added) +++ jakarta/jcs/trunk/src/java/org/apache/jcs/access/PartitionedCacheAccess.java Wed Aug 12 21:41:44 2009 @@ -0,0 +1,737 @@ +package org.apache.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.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jcs.JCS; +import org.apache.jcs.access.behavior.ICacheAccess; +import org.apache.jcs.access.exception.CacheException; +import org.apache.jcs.access.exception.ConfigurationException; +import org.apache.jcs.engine.behavior.ICacheElement; +import org.apache.jcs.engine.behavior.ICompositeCacheAttributes; +import org.apache.jcs.engine.behavior.IElementAttributes; +import org.apache.jcs.utils.props.AbstractPropertyContainer; + +/** + * TODO: Add new methods that will allow you to provide a partition indicator for all major calls. Add an interface as well. + * <p> + * This handles dividing puts and gets. + * <p> + * There are two required properties. + * <p> + * <ol> + * <li>.numberOfPartitions</li> + * <li>.partitionRegionNamePrefix</li> + * </ol> + * System properties will override values in the properties file. + * <p> + * We use a JCS region name for each partition that looks like this: partitionRegionNamePrefix + "_" + * + patitionNuber. The number is ) indexed based. + * <p> + * @author Aaron Smuts + */ +public class PartitionedCacheAccess + extends AbstractPropertyContainer + implements ICacheAccess +{ + /** the logger. */ + private static final Log log = LogFactory.getLog( PartitionedCacheAccess.class ); + + /** The number of partitions. */ + private int numberOfPartitions = 1; + + /** + * We use a JCS region name for each partition that looks like this: partitionRegionNamePrefix + + * "_" + partitionNumber + */ + private String partitionRegionNamePrefix; + + /** An array of partitions built during initialization. */ + private ICacheAccess[] partitions; + + /** Is the class initialized. */ + private boolean initialized = false; + + /** Sets default properties heading and group. */ + public PartitionedCacheAccess() + { + setPropertiesHeading( "PartitionedCacheAccess" ); + setPropertiesGroup( "cache" ); + } + + /** + * Puts the value into the appropriate cache partition. + * <p> + * @param key key + * @param object object + * @throws CacheException on configuration problem + */ + public void put( Object key, Object object ) + throws CacheException + { + if ( key == null || object == null ) + { + log.warn( "Bad input key [" + key + "]. Cannot put null into the cache." ); + return; + } + ensureInit(); + + int partition = getPartitionNumberForKey( key ); + try + { + partitions[partition].put( key, object ); + } + catch ( CacheException e ) + { + log.error( "Problem putting value for key [" + key + "] in cache [" + partitions[partition] + "]" ); + throw ( e ); + } + } + + /** + * Puts in cache if an item does not exist with the name in that region. + * <p> + * @param key + * @param object + * @throws CacheException + */ + public void putSafe( Object key, Object object ) + throws CacheException + { + if ( key == null || object == null ) + { + log.warn( "Bad input key [" + key + "]. Cannot putSafe null into the cache." ); + } + ensureInit(); + + int partition = getPartitionNumberForKey( key ); + partitions[partition].putSafe( key, object ); + } + + /** + * Puts the value into the appropriate cache partition. + * <p> + * @param key key + * @param object object + * @param attr + * @throws CacheException on configuration problem + */ + public void put( Object key, Object object, IElementAttributes attr ) + throws CacheException + { + if ( key == null || object == null ) + { + log.warn( "Bad input key [" + key + "]. Cannot put null into the cache." ); + return; + } + ensureInit(); + + int partition = getPartitionNumberForKey( key ); + try + { + partitions[partition].put( key, object, attr ); + } + catch ( CacheException e ) + { + log.error( "Problem putting value for key [" + key + "] in cache [" + partitions[partition] + "]" ); + throw ( e ); + } + } + + /** + * Gets the object for the key from the desired partition. + * <p> + * @param key key + * @return result, null if not found. + */ + public Object get( Object key ) + { + if ( key == null ) + { + log.warn( "Bad input key [" + key + "]." ); + return null; + } + try + { + ensureInit(); + } + catch ( ConfigurationException e ) + { + // TODO add exception to interface method. + log.error( "Couldn't configure partioned access.", e ); + return null; + } + + int partition = getPartitionNumberForKey( key ); + + return partitions[partition].get( key ); + } + + /** + * Gets the ICacheElement (the wrapped object) for the key from the desired partition. + * <p> + * @param key key + * @return result, null if not found. + */ + public ICacheElement getCacheElement( Object key ) + { + if ( key == null ) + { + log.warn( "Bad input key [" + key + "]." ); + return null; + } + try + { + ensureInit(); + } + catch ( ConfigurationException e ) + { + // TODO add exception to interface method. + log.error( "Couldn't configure partioned access.", e ); + return null; + } + + int partition = getPartitionNumberForKey( key ); + + return partitions[partition].getCacheElement( key ); + } + + /** + * This is a getMultiple. We try to group the keys so that we make as few calls as needed. + * <p> + * @param names + * @return Map of keys to ICacheElement + */ + public Map getCacheElements( Set names ) + { + if ( names == null ) + { + log.warn( "Bad input names cannot be null." ); + return Collections.EMPTY_MAP; + } + + Set[] dividedNames = new Set[this.getNumberOfPartitions()]; + + Iterator it = names.iterator(); + while ( it.hasNext() ) + { + Object key = it.next(); + int partition = getPartitionNumberForKey( key ); + if ( dividedNames[partition] == null ) + { + dividedNames[partition] = new HashSet(); + } + dividedNames[partition].add( key ); + } + + Map result = new HashMap(); + for ( int i = 0; i < partitions.length; i++ ) + { + if ( dividedNames[i] != null && !dividedNames[i].isEmpty() ) + { + result.putAll( partitions[i].getCacheElements( dividedNames[i] ) ); + } + } + return result; + } + + /** + * This is tricky. Do we need to get from all the partitions? + * <p> + * If this interface took an object, we could use the hashcode to determine the partition. Then + * we could user the toString for the pattern. + * <p> + * @param pattern + * @return HashMap key to value + */ + public Map getMatching( String pattern ) + { + if ( pattern == null ) + { + log.warn( "Bad input keypattern [" + pattern + "]." ); + return null; + } + try + { + ensureInit(); + } + catch ( ConfigurationException e ) + { + // TODO add exception to interface method. + log.error( "Couldn't configure partioned access.", e ); + return null; + } + + Map result = new HashMap(); + for ( int i = 0; i < partitions.length; i++ ) + { + result.putAll( partitions[i].getMatching( pattern ) ); + } + return result; + } + + /** + * This is tricky. Do we need to get from all the partitions? + * <p> + * @param pattern + * @return HashMap key to ICacheElement + */ + public Map getMatchingCacheElements( String pattern ) + { + if ( pattern == null ) + { + log.warn( "Bad input keypattern [" + pattern + "]." ); + return null; + } + try + { + ensureInit(); + } + catch ( ConfigurationException e ) + { + // TODO add exception to interface method. + log.error( "Couldn't configure partioned access.", e ); + return null; + } + + Map result = new HashMap(); + for ( int i = 0; i < partitions.length; i++ ) + { + result.putAll( partitions[i].getMatchingCacheElements( pattern ) ); + } + return result; + } + + /** + * Calls remove on all partitions. This gets translated into a removeAll call. + * <p> + * @throws CacheException + */ + public void remove() + throws CacheException + { + ensureInit(); + + for ( int i = 0; i < partitions.length; i++ ) + { + partitions[i].remove(); + } + } + + /** + * Removes the item from the appropriate partition. + * <p> + * @param key + * @throws CacheException + */ + public void remove( Object key ) + throws CacheException + { + if ( key == null ) + { + log.warn( "Bad input key [" + key + "]. Cannot remove null from the cache." ); + return; + } + ensureInit(); + + int partition = getPartitionNumberForKey( key ); + try + { + partitions[partition].remove( key ); + } + catch ( CacheException e ) + { + log.error( "Problem removing value for key [" + key + "] in cache [" + partitions[partition] + "]" ); + throw ( e ); + } + } + + /** + * Calls free on each partition. + * <p> + * @param numberToFree + * @return number removed + * @throws CacheException + */ + public int freeMemoryElements( int numberToFree ) + throws CacheException + { + ensureInit(); + + int count = 0; + for ( int i = 0; i < partitions.length; i++ ) + { + count += partitions[i].freeMemoryElements( numberToFree ); + } + return count; + } + + /** + * @return ICompositeCacheAttributes from the first partition. + */ + public ICompositeCacheAttributes getCacheAttributes() + { + try + { + ensureInit(); + } + catch ( ConfigurationException e ) + { + // TODO add exception to interface method. + log.error( "Couldn't configure partioned access.", e ); + return null; + } + + if ( partitions.length == 0 ) + { + return null; + } + + return partitions[0].getCacheAttributes(); + } + + /** + * @return IElementAttributes from the first partition. + * @throws CacheException + */ + public IElementAttributes getElementAttributes() + throws CacheException + { + ensureInit(); + + if ( partitions.length == 0 ) + { + return null; + } + + return partitions[0].getElementAttributes(); + } + + /** + * This is no more efficient than simply getting the cache element. + * <p> + * @param key + * @return IElementAttributes + * @throws CacheException + */ + public IElementAttributes getElementAttributes( Object key ) + throws CacheException + { + if ( key == null ) + { + log.warn( "Bad input key [" + key + "]. Cannot getElementAttributes for null from the cache." ); + return null; + } + ensureInit(); + + int partition = getPartitionNumberForKey( key ); + + return partitions[partition].getElementAttributes( key ); + } + + /** + * Resets the default element attributes on all partitions. This does not change items that are + * already in the cache. + * <p> + * @param attributes + * @throws CacheException + */ + public void resetElementAttributes( IElementAttributes attributes ) + throws CacheException + { + ensureInit(); + + for ( int i = 0; i < partitions.length; i++ ) + { + partitions[i].resetElementAttributes( attributes ); + } + } + + /** + * Resets the attributes for this item. This has the same effect as an update, in most cases. + * None of the auxiliaries are optimized to do this more efficiently than a simply update. + * <p> + * @param key + * @param attributes + * @throws CacheException + */ + public void resetElementAttributes( Object key, IElementAttributes attributes ) + throws CacheException + { + if ( key == null ) + { + log.warn( "Bad input key [" + key + "]. Cannot resetElementAttributes for null." ); + return; + } + ensureInit(); + + int partition = getPartitionNumberForKey( key ); + + partitions[partition].resetElementAttributes( key, attributes ); + } + + /** + * Sets the attributes on all the partitions. + * <p> + * @param cattr + */ + public void setCacheAttributes( ICompositeCacheAttributes cattr ) + { + try + { + ensureInit(); + } + catch ( ConfigurationException e ) + { + // TODO add exception to interface method. + log.error( "Couldn't configure partioned access.", e ); + return; + } + + for ( int i = 0; i < partitions.length; i++ ) + { + partitions[i].setCacheAttributes( cattr ); + } + } + + /** + * This expects a numeric key. If the key cannot be converted into a number, we wil return 0. + * TODO we could md5 it or get the hashcode. + * <p> + * We determine the partition by taking the mod of the number of partions. + * <p> + * @param key key + * @return the partition number. + */ + protected int getPartitionNumberForKey( Object key ) + { + if ( key == null ) + { + return 0; + } + + long keyNum = getNumericValueForKey( key ); + + int partition = (int) ( keyNum % getNumberOfPartitions() ); + + if ( log.isDebugEnabled() ) + { + log.debug( "Using partition [" + partition + "] for key [" + key + "]" ); + } + + return partition; + } + + /** + * This can be overridden for special purposes. + * <p> + * @param key key + * @return long + */ + public long getNumericValueForKey( Object key ) + { + String keyString = key.toString(); + long keyNum = -1; + try + { + keyNum = Long.parseLong( keyString ); + } + catch ( NumberFormatException e ) + { + // THIS IS UGLY, but I can't think of a better failsafe right now. + keyNum = key.hashCode(); + log.warn( "Counldn't convert [" + key + "] into a number. Will use hashcode [" + keyNum + "]" ); + } + return keyNum; + } + + /** + * Initialize if we haven't already. + * <p> + * @throws ConfigurationException on configuration problem + */ + protected synchronized void ensureInit() + throws ConfigurationException + { + if ( !initialized ) + { + initialize(); + } + } + + /** + * Use the partion prefix and the number of partions to get JCS regions. + * <p> + * @throws ConfigurationException on configuration problem + */ + protected synchronized void initialize() + throws ConfigurationException + { + ensureProperties(); + + ICacheAccess[] tempPartitions = new ICacheAccess[this.getNumberOfPartitions()]; + for ( int i = 0; i < this.getNumberOfPartitions(); i++ ) + { + String regionName = this.getPartitionRegionNamePrefix() + "_" + i; + try + { + tempPartitions[i] = CacheAccess.getAccess( regionName ); + } + catch ( CacheException e ) + { + log.error( "Problem getting cache for region [" + regionName + "]" ); + } + } + partitions = tempPartitions; + initialized = true; + } + + /** + * Loads in the needed configuration settings. System properties are checked first. A system + * property will override local property value. + * <p> + * Loads the following JCS Cache specific properties: + * <ul> + * <li>heading.numberOfPartitions</li> + * <li>heading.partitionRegionNamePrefix</li> + * </ul> + * @throws ConfigurationException on configuration problem + */ + protected void handleProperties() + throws ConfigurationException + { + // Number of Partitions. + String numberOfPartitionsPropertyName = this.getPropertiesHeading() + ".numberOfPartitions"; + String numberOfPartitionsPropertyValue = getPropertyForName( numberOfPartitionsPropertyName, true ); + try + { + this.setNumberOfPartitions( Integer.parseInt( numberOfPartitionsPropertyValue ) ); + } + catch ( NumberFormatException e ) + { + String message = "Could not convert [" + numberOfPartitionsPropertyValue + "] into a number for [" + + numberOfPartitionsPropertyName + "]"; + log.error( message ); + throw new ConfigurationException( message ); + } + + // Partition Name Prefix. + String prefixPropertyName = this.getPropertiesHeading() + ".partitionRegionNamePrefix"; + String prefix = getPropertyForName( prefixPropertyName, true ); + this.setPartitionRegionNamePrefix( prefix ); + } + + /** + * Checks the system properties before the properties. + * <p> + * @param propertyName name + * @param required is it required? + * @return the property value if one is found + * @throws ConfigurationException thrown if it is required and not found. + */ + protected String getPropertyForName( String propertyName, boolean required ) + throws ConfigurationException + { + String propertyValue = null; + propertyValue = System.getProperty( propertyName ); + if ( propertyValue != null ) + { + if ( log.isInfoEnabled() ) + { + log.info( "Found system property override: Name [" + propertyName + "] Value [" + propertyValue + "]" ); + } + } + else + { + propertyValue = this.getProperties().getProperty( propertyName ); + if ( required && propertyValue == null ) + { + String message = "Could not find required property [" + propertyName + "] in propertiesGroup [" + + this.getPropertiesGroup() + "]"; + log.error( message ); + throw new ConfigurationException( message ); + } + else + { + if ( log.isInfoEnabled() ) + { + log.info( "Name [" + propertyName + "] Value [" + propertyValue + "]" ); + } + } + } + return propertyValue; + } + + /** + * @param numberOfPartitions The numberOfPartitions to set. + */ + protected void setNumberOfPartitions( int numberOfPartitions ) + { + this.numberOfPartitions = numberOfPartitions; + } + + /** + * @return Returns the numberOfPartitions. + */ + protected int getNumberOfPartitions() + { + return numberOfPartitions; + } + + /** + * @param partitionRegionNamePrefix The partitionRegionNamePrefix to set. + */ + protected void setPartitionRegionNamePrefix( String partitionRegionNamePrefix ) + { + this.partitionRegionNamePrefix = partitionRegionNamePrefix; + } + + /** + * @return Returns the partitionRegionNamePrefix. + */ + protected String getPartitionRegionNamePrefix() + { + return partitionRegionNamePrefix; + } + + /** + * @param partitions The partitions to set. + */ + protected void setPartitions( JCS[] partitions ) + { + this.partitions = partitions; + } + + /** + * @return Returns the partitions. + */ + protected ICacheAccess[] getPartitions() + { + return partitions; + } +} Modified: jakarta/jcs/trunk/src/java/org/apache/jcs/access/behavior/ICacheAccess.java URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/access/behavior/ICacheAccess.java?rev=803719&r1=803718&r2=803719&view=diff ============================================================================== --- jakarta/jcs/trunk/src/java/org/apache/jcs/access/behavior/ICacheAccess.java (original) +++ jakarta/jcs/trunk/src/java/org/apache/jcs/access/behavior/ICacheAccess.java Wed Aug 12 21:41:44 2009 @@ -19,7 +19,6 @@ * under the License. */ -import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -45,10 +44,10 @@ * 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. + * @return A map of key to values. These are stripped from the wrapper. */ - HashMap getMatching( String pattern ); - + Map getMatching( String pattern ); + /** * Puts in cache if an item does not exist with the name in that region. * <p> @@ -112,7 +111,8 @@ * 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 element, or empty map if none of the keys are present + * @return a map of Object key to ICacheElement element, or empty map if none of the keys are + * present */ Map getCacheElements( Set names ); @@ -131,19 +131,10 @@ * The last access time in the ElementAttributes should be current. * <p> * @param pattern key search patern - * @return a map of Object key to ICacheElement element, or empty map if no keys match the pattern + * @return a map of Object key to ICacheElement element, or empty map if no keys match the + * pattern */ Map getMatchingCacheElements( String pattern ); - - /** - * Removes an item or all items. Should be called remove. - * <p> - * @throws CacheException - * @deprecated - * @see #remove() - */ - void destroy() - throws CacheException; /** * Old remove all method. @@ -153,17 +144,6 @@ throws CacheException; /** - * The older removeall method. - * <p> - * @param name - * @throws CacheException - * @deprecated - * @see #remove(Object) - */ - void destroy( Object name ) - throws CacheException; - - /** * Remove an object for this key if one exists, else do nothing. * <p> * @param name @@ -173,14 +153,13 @@ throws CacheException; /** - * ResetAttributes allows for some of the attributes of a region to be reset - * in particular expiration time attriubtes, time to live, default time to - * live and idle time, and event handlers. The cacheloader object and - * attributes set as flags can't be reset with resetAttributes, the object - * must be destroyed and redefined to cache those parameters. Changing - * default settings on groups and regions will not affect existing objects. - * Only object loaded after the reset will use the new defaults. If no name - * argument is provided, the reset is applied to the region. + * ResetAttributes allows for some of the attributes of a region to be reset in particular + * expiration time attriubtes, time to live, default time to live and idle time, and event + * handlers. The cacheloader object and attributes set as flags can't be reset with + * resetAttributes, the object must be destroyed and redefined to cache those parameters. + * Changing default settings on groups and regions will not affect existing objects. Only object + * loaded after the reset will use the new defaults. If no name argument is provided, the reset + * is applied to the region. * <p> * @param attributes * @throws CacheException @@ -199,10 +178,10 @@ 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. + * 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 @@ -230,20 +209,18 @@ /** * Sets the ICompositeCacheAttributes of the cache region * <p> - * @param cattr - * The new ICompositeCacheAttribute value + * @param cattr The new ICompositeCacheAttribute value */ public 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. + * 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. + * @return the number that were removed. if you ask to free 5, but there are only 3, you will + * get 3. * @throws CacheException */ public int freeMemoryElements( int numberToFree ) Modified: jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/CacheException.java URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/CacheException.java?rev=803719&r1=803718&r2=803719&view=diff ============================================================================== --- jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/CacheException.java (original) +++ jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/CacheException.java Wed Aug 12 21:41:44 2009 @@ -57,5 +57,4 @@ { super( message ); } - } Added: jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/ConfigurationException.java URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/ConfigurationException.java?rev=803719&view=auto ============================================================================== --- jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/ConfigurationException.java (added) +++ jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/ConfigurationException.java Wed Aug 12 21:41:44 2009 @@ -0,0 +1,25 @@ +package org.apache.jcs.access.exception; + +/** 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 ); + } +} Modified: jakarta/jcs/trunk/src/java/org/apache/jcs/engine/match/KeyMatcherPatternImpl.java URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/engine/match/KeyMatcherPatternImpl.java?rev=803719&r1=803718&r2=803719&view=diff ============================================================================== --- jakarta/jcs/trunk/src/java/org/apache/jcs/engine/match/KeyMatcherPatternImpl.java (original) +++ jakarta/jcs/trunk/src/java/org/apache/jcs/engine/match/KeyMatcherPatternImpl.java Wed Aug 12 21:41:44 2009 @@ -28,6 +28,7 @@ for ( int i = 0; i < keyArray.length; i++ ) { Object key = keyArray[i]; + // TODO we might want to match on the toString. if ( key instanceof String ) { Matcher matcher = compiledPattern.matcher( (String) key ); Added: jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/AbstractPropertyContainer.java URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/AbstractPropertyContainer.java?rev=803719&view=auto ============================================================================== --- jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/AbstractPropertyContainer.java (added) +++ jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/AbstractPropertyContainer.java Wed Aug 12 21:41:44 2009 @@ -0,0 +1,190 @@ +package org.apache.jcs.utils.props; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR 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.jcs.access.exception.ConfigurationException; + +/** + * Provides a mechanism to load properties into objects. + * <p> + * Functions that depend on properties should call ensureProperties() before it uses any properties. + */ +public abstract class AbstractPropertyContainer +{ + /** File, db, etc */ + private static final PropertiesFactory DEFAULT_PROPERTIES_FACTORY = new PropertiesFactoryFileImpl(); + + /** + * A property group is a subsection of properties. It's sent to the properties factory to + * specify which group of properties to pull back. This will probably mean different things to + * different property factories. For PropertiesFactoryFileImpl, the propertiesGroup maps to a + * filename. + */ + private String propertiesGroup; + + /** + * The property heading is used to specify a starting point in the properties object. This is + * used so that settings can be relative to this propertiesHeading, as opposed to being + * statically coded. There's no enforcement of this, but users are encouraged to call + * getProperties().get( getPropertiesHeading() + ".foo" ); + */ + private String propertiesHeading; + + /** The factory to use. */ + private PropertiesFactory propertiesFactory; + + /** The loaded properties. */ + private Properties properties; + + /** + * Makes sure an AbstractPropertyClass has all the properties it needs. + * <p> + * Synchronized mutators so multiple threads cannot cause problems. We wouldn't want the + * properties heading to get changed as we were processing the properties. + * <p> + * @throws ConfigurationException on configuration failure + */ + public synchronized void ensureProperties() + throws ConfigurationException + { + if ( getProperties() == null ) + { + initializeProperties(); + } + } + + /** + * Loads the properties and then calls handleProperties. Typically, you don't need to call this. + * This is primarily intended for reinitialization. + * <p> + * If the properties object is null, when you call ensureProperties initialize will be called. + * <p> + * @throws ConfigurationException on configuration failure + */ + public synchronized void initializeProperties() + throws ConfigurationException + { + loadProperties(); + + handleProperties(); + } + + /** + * This loads the properties regardless of whether or not they have already been loaded. + * <p> + * @throws ConfigurationException on configuration failure + */ + private void loadProperties() + throws ConfigurationException + { + if ( getPropertiesGroup() == null ) + { + throw new ConfigurationException( "Properties group is null and it shouldn't be" ); + } + + if ( getPropertiesHeading() == null ) + { + throw new ConfigurationException( "Properties heading is null and it shouldn't be" ); + } + + if ( getPropertiesFactory() == null ) + { + setProperties( DEFAULT_PROPERTIES_FACTORY.getProperties( getPropertiesGroup() ) ); + } + else + { + setProperties( getPropertiesFactory().getProperties( getPropertiesGroup() ) ); + } + } + + /** + * Sets fields for properties, and verifies that all necessary properties are there. + * <p> + * @throws ConfigurationException on configuration failure + */ + protected abstract void handleProperties() + throws ConfigurationException; + + /** + * @return Returns the properties. + */ + public Properties getProperties() + { + return properties; + } + + /** + * @param properties The properties to set. + */ + public synchronized void setProperties( Properties properties ) + { + this.properties = properties; + } + + /** + * @return Returns the propertiesHeading. + */ + public String getPropertiesHeading() + { + return propertiesHeading; + } + + /** + * @param propertiesHeading The propertiesHeading to set. + */ + public synchronized void setPropertiesHeading( String propertiesHeading ) + { + this.propertiesHeading = propertiesHeading; + } + + /** + * @return Returns the propertiesFactory. + */ + public PropertiesFactory getPropertiesFactory() + { + return propertiesFactory; + } + + /** + * @param propertiesFactory The propertiesFactory to set. + */ + public void setPropertiesFactory( PropertiesFactory propertiesFactory ) + { + this.propertiesFactory = propertiesFactory; + } + + /** + * @return Returns the propertiesGroup. + */ + public String getPropertiesGroup() + { + return propertiesGroup; + } + + /** + * @param propertiesGroup The propertiesGroup to set. + */ + public void setPropertiesGroup( String propertiesGroup ) + { + this.propertiesGroup = propertiesGroup; + } +} Added: jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactory.java URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactory.java?rev=803719&view=auto ============================================================================== --- jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactory.java (added) +++ jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactory.java Wed Aug 12 21:41:44 2009 @@ -0,0 +1,36 @@ +package org.apache.jcs.utils.props; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR 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; + +/** + * Retrieves properties from a configurable source. + */ +public interface PropertiesFactory +{ + /** + * Fetches a set of properties for the specified group. + * <p> + * @param groupName the group to pull properties from. + * @return a properties object. + */ + Properties getProperties( String groupName ); +} Added: jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactoryFileImpl.java URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactoryFileImpl.java?rev=803719&view=auto ============================================================================== --- jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactoryFileImpl.java (added) +++ jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactoryFileImpl.java Wed Aug 12 21:41:44 2009 @@ -0,0 +1,39 @@ +package org.apache.jcs.utils.props; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR 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; + +/** + * Goes to the file system to load a properties file. + */ +public class PropertiesFactoryFileImpl + implements PropertiesFactory +{ + /** + * Loads the properties using the property loader. + * @param groupName property group name + * @return Properties + */ + public Properties getProperties( String groupName ) + { + return PropertyLoader.loadProperties( groupName ); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: jcs-dev-unsubscr...@jakarta.apache.org For additional commands, e-mail: jcs-dev-h...@jakarta.apache.org