/* Open Source Java Caching Service
* Copyright (C) 2002 Frank Karlstr�m
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* The author can be contacted by email: fjankk@users.sourceforge.net
*/
package org.fjank.jcache;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.fjank.jcache.collection.CollectionProxy;
import org.fjank.jcache.collection.SetProxy;
import EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;
/**
* Class for representin grouops in the cache. Groups can contain CacheObjects
* and other groups.
*
* @author Frank Karlstr�m
*/
public class CacheGroup implements Serializable {
/** the name of this group. */
protected String name;
/** the attributes for this group */
private AttributesImpl attributes = new AttributesImpl();
/** the current number of objects in this group. */
private int currentSize;
/** The number of objects in this group*/
private int objectCount;
/** the WeakReference objects in this group. */
protected transient Map weakReferenceObjects = new ConcurrentHashMap();
private transient final Map groups = new HashMap();
/** the actual objects in this group. These objects are here until they expire
* when they have expired, this map is cleared,
* then the weakReference is also cleared, if and only if no other
* code references the objects. */
final transient Map objects = new ConcurrentHashMap();
Map getGroups() {
return groups;
}
/**
* Creates a new CacheGroup object.
*
* @param name the name of the CacheGroup to create
*/
public CacheGroup(final String name) {
this(name, null);
}
/**
* Creates a new CacheGroup object.
*
* @param name the name of the CacheGroup to create
* @param attributes the attributes of the group to create
*/
public CacheGroup(final String name, final AttributesImpl attributes) {
setName(name);
setAttributes(attributes);
}
/**
* sets the attribute for this group
*
* @param attributes the attributes to set.
*/
private void setAttributes(final AttributesImpl attributes) {
if (attributes == null) {
return;
}
this.attributes = attributes;
}
/**
* sets the name of this group.
*
* @param name the name to set.
*/
private void setName(final String name) {
this.name = name;
}
/**
* gets an object from this group.
*
* @param name the name of the object to retrieve.
*
* @return the named object, or null if it is not found.
*
*/
public Object get(final Object aName) {
// 2004/09-FB
if ((aName != null) && aName.equals(name)) {
return this;
}
Object obj = weakReferenceObjects.get(aName);
if (obj == null) {
// 2004/09-FB
for (Iterator iter = groups.keySet().iterator(); iter.hasNext();) {
Object groupName = iter.next();
CacheGroup group = (CacheGroup) groups.get(groupName);
obj = group.get(aName);
if (obj != null) {
return obj;
}
}
}
return obj;
}
/**
* puts the named object into this group.
*
* @param name the name of the object
* @param object the object to insert.
*
*/
public void put(final Object name, final CacheObject object, final Object realObject) {
currentSize += object.getAttributes().getSize();
increaseObjectCount();
weakReferenceObjects.put(name, object);
objects.put(name, realObject);
}
/**
* puts the group into this group
*
* @param object the group to put.
*
*/
public void put(final CacheGroup group) {
currentSize += group.getAttributes().getSize();
groups.put(group.getName(), group);
}
/**
* returns the attributes for this group.
*
* @return the attributes for this group.
*/
AttributesImpl getAttributes() {
return this.attributes;
}
/**
* Will create a new version of the object indentified by the name,
* replacing the current version with the object specified. If the object
* doesn't exist in the cache, replace is equivalent to a put. The
* attributes will be inherited from the existing object or if no object
* exists, from the group or region the object associated with. Names are
* in the scope of a region so they must be unique within the region they
* are placed. This method is not valid on a disk, StreamAccess or Group
* Object.
*
* @param name the name of the object to replace.
* @param object The new object to be put in the cache.
*
* @return a reference to the newly replaced object.
*/
public CacheObject replace(final Object name, final CacheObject object) {
CacheObject oldObj = (CacheObject) weakReferenceObjects.get(name);
if (oldObj != null) {
if (oldObj.getAttributes() != null) {
object.setAttributes(oldObj.getAttributes());
}
weakReferenceObjects.remove(name);
objects.remove(name);
} else {
increaseObjectCount();
}
weakReferenceObjects.put(name, object);
objects.put(name, object.get());
return object;
}
/**
* Setter for property valid.
*/
public void invalidate() {
Iterator iter = weakReferenceObjects.keySet().iterator();
while (iter.hasNext()) {
Object key = iter.next();
CacheObject obj = (CacheObject) weakReferenceObjects.get(key);
obj.invalidate();
}
objects.clear();
iter = groups.keySet().iterator();
while (iter.hasNext()) {
Object key = iter.next();
CacheGroup obj = (CacheGroup) groups.get(key);
obj.invalidate();
}
this.objectCount = 0;
}
/**
* Destroys this group and all its children.
*
*/
public void destroy() {
this.attributes = null;
this.currentSize = 0;
this.name = null;
for (Iterator iter = weakReferenceObjects.keySet().iterator(); iter.hasNext();) {
((CacheObject) weakReferenceObjects.get(iter.next())).destroy();
}
for (Iterator iter = groups.keySet().iterator(); iter.hasNext();) {
((CacheGroup) groups.get(iter.next())).destroy();
}
weakReferenceObjects.clear();
objects.clear();
groups.clear();
weakReferenceObjects = null;
}
/**
* Checks wether this group contains the specified objects
* @param aName the name of the object to check
*
* @return a boolean indicating wether the object was present or not in
* this group.
*/
public boolean contains(final Object aName) {
if ((aName != null) && aName.equals(name)) {
return true;
}
//check the real objects instead.
if (objects.containsKey(aName))
return true;
// for(Iterator iter = weakReferenceObjects.keySet().iterator();iter.hasNext();) {
// CacheObject obj = (CacheObject)weakReferenceObjects.get(iter.next());
// if ((obj.getKey() != null)
// && obj.getKey().equals(aName)) {
// return true;
// }
// }
for (Iterator iter = groups.keySet().iterator(); iter.hasNext();) {
Object groupName = iter.next();
CacheGroup group = (CacheGroup) groups.get(groupName);
if (group.contains(aName)) {
return true;
}
}
return false;
}
/**
* removes the object from this group.
*
* @param object the object to remove.
*/
public void removeMe(final CacheObject object) {
Iterator iter = weakReferenceObjects.keySet().iterator();
while (iter.hasNext()) {
if (((CacheObject) weakReferenceObjects.get(iter.next())) == object) {
iter.remove();
objects.remove(object.getKey());
decreaseObjectCount();
currentSize -= object.getAttributes().getSize();
break;
}
}
}
private void decreaseObjectCount() {
this.objectCount = objectCount - 1;
}
private void increaseObjectCount() {
this.objectCount = objectCount + 1;
}
/**
* gets the current size (in bytes) of th3e objects in this group.
*
* @return the current size (in bytes) of th3e objects in this group.
*/
int getCurrentSize() {
return currentSize;
}
/**
* gets the named group from this group.
* If no group with the specified name is found, <code>null</code> is returned.
* @param group the group to get.
*
* @return the named group.
*
*/
public CacheGroup getGroup(final String group) {
return (CacheGroup) groups.get(group);
}
/**
* gets the name of this group.
*
* @return the name of this group.
*/
public String getName() {
return name;
}
/** Return the current number of objects in this group.
* @return the current number of objects in this group.
*/
public int getObjectCount() {
if (groups.isEmpty()) {
return objectCount;
}
int count = objectCount;
for (Iterator iter = groups.keySet().iterator(); iter.hasNext();) {
Object key = iter.next();
CacheGroup gr = (CacheGroup) groups.get(key);
count += gr.getObjectCount();
}
return count;
}
/**returns a boolean indicating wether this value is present
* in the cache root.
* @param value the value to check
* @return <code>true</code> if the value is present, <code>false</code> otherwise.
*/
public boolean containsValue(Object value) {
return objects.containsValue(value);
}
public Set keySet() {
return new SetProxy(weakReferenceObjects.keySet(), this);
}
public Collection values() {
return new CollectionProxy(weakReferenceObjects.values(), this);
}
public Set entrySet() {
return new SetProxy(weakReferenceObjects.entrySet(), this);
}
void removeObjectReference(Object key) {
//if(objects.containsKey(key)) {
objects.remove(key);
//decreaseObjectCount();
//}
}
Map getObjectReferences() {
return objects;
}
}