| RegionManager.java |
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
* Created on March 25 2003
*/
package org.jboss.cache.eviction;
import org.jboss.cache.TreeCache;
import org.jboss.logging.Logger;
import java.util.HashMap;
import java.util.Map;
/**
* Factory to create region from configuration, to track region,
* and to resolve naming conflict for regions. Note that in addition to
* user-specified regions, there is also a global cache <code>_default_</code>
* region that covers everything else.
*
* @author Ben Wang 02-2004
* @version $Id: RegionManager.java,v 1.5.2.2 2005/04/04 05:44:17 bwang00 Exp $
*/
public class RegionManager
{
private Logger log_ = Logger.getLogger(RegionManager.class);
public final static int CAPACITY = 200000;
private Map regionMap_ = new HashMap();
// optimization
private Region[] regions_;
private EvictionPolicy policy_;
// There is global cache wide default values if no region is found.
final static String DEFAULT_REGION = "/_default_/";
public RegionManager(EvictionPolicy policy)
{
policy_ = policy;
regions_ = null;
}
/**
* Create a region based on fqn.
*
* @param fqn The region identifier.
* @param algorithm EvictionAlgorithm that associates with this region.
* @throws RegionNameConflictException
*/
public Region createRegion(String fqn, EvictionAlgorithm algorithm)
throws RegionNameConflictException
{
if (log_.isDebugEnabled())
{
log_.debug("createRegion(): creating region for fqn- " + fqn);
}
String newFqn = appendFqn(fqn);
checkConflict(newFqn);
Region region = new Region(newFqn, policy_, algorithm);
regionMap_.put(newFqn, region);
return region;
}
public void removeRegion(String fqn)
{
regionMap_.remove(fqn);
}
/**
* Append the fqn with "/" if necessary
*
* @param fqn
* @return
*/
private String appendFqn(String fqn)
{
if (!fqn.endsWith(TreeCache.SEPARATOR))
return fqn + TreeCache.SEPARATOR;
else
return fqn;
}
public boolean hasRegion(String myFqn)
{
String newFqn = appendFqn(myFqn);
return regionMap_.containsKey(newFqn);
}
public Region getRegion(String myFqn)
{
Region[] regions = getRegions();
// TODO. Is not needed if fqn.toString is appended with SEPARATOR.
String myRFqn = appendFqn(myFqn);
// TODO need further optimization in regex matching
// Do it in reverse order such that children fqn gets matched first.
for (int i = (regions.length - 1); i >= 0; i--)
{
String fqn = regions[i].getFqn();
if (myRFqn.startsWith(fqn)) return regions[i];
}
if (log_.isTraceEnabled())
{
log_.trace("getRegion(): not user-specified region found for this fqn- " + myFqn
+ " will use the global default region");
}
return (Region) regionMap_.get(DEFAULT_REGION);
}
public Region[] getRegions()
{
// optimization
if (regions_ != null && regions_.length == regionMap_.size())
return regions_;
Object[] objs = regionMap_.values().toArray();
Region[] regions = new Region[objs.length];
for (int i = 0; i < objs.length; i++)
{
regions[i] = (Region) objs[i];
}
if (log_.isDebugEnabled())
{
log_.debug("getRegions(): size of region " + regions.length);
}
regions_ = regions;
return regions;
}
/**
* Check for conflict in the current regions. There is a conflict
* <p/>
* if fqn is any parent fqn of the current regions.
*
* @param myFqn Current fqn for potential new region.
* @throws RegionNameConflictException to indicate a region name conflict has ocurred.
*/
public void checkConflict(String myFqn) throws RegionNameConflictException
{
// Step x. Loop thru the region map and compare the fqn. Order is important.
// Not very efficient if there is a lot of regions.
// First comer wins. E.g., /a/b/c and then /a/b/c will have /a/b in different
// region than /a/b. But if /a/b and /a/b/c, then we will /a/b/c will be
// the same region as /a/b. That is, we check if a fqn is within a region
// by looping thru regions and then check if my fqn is a child of region
// fqn. It it is, viola, and take this and exit.
Region[] regions = getRegions();
for (int i = 0; i < regions.length; i++)
{
String fqn = regions[i].getFqn();
if (myFqn.equals(fqn) || myFqn.startsWith(fqn))
{ // fqn is a child of myFqn.
throw new RegionNameConflictException("RegionManager.checkConflict(): new region fqn "
+ myFqn + " is in conflict with current region fqn- " + fqn);
}
}
// We are clear then.
}
}
| RegionManager.java |