[jboss-cvs] JBossCache/src/org/jboss/cache/pojo ...
Ben Wang
bwang at jboss.com
Sat Jan 13 10:55:01 EST 2007
User: bwang
Date: 07/01/13 10:55:01
Added: src/org/jboss/cache/pojo
InvocationContext.java PojoCache.java
CachedType.java PojoCacheMBean.java
PojoCacheAlreadyDetachedException.java
PojoTxSynchronizationHandler.java PojoUtil.java
PojoInstance.java Option.java PojoCacheFactory.java
InternalConstant.java MethodDeclarations.java
PojoCacheListener.java PojoTreeCache.java
PojoReference.java PojoCacheException.java
Log:
JBCACHE-922 Merged src-50 and tests-50 into src and tests, respectively.
Revision Changes Path
1.1 date: 2007/01/13 15:55:01; author: bwang; state: Exp;JBossCache/src/org/jboss/cache/pojo/InvocationContext.java
Index: InvocationContext.java
===================================================================
/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo;
/**
* This context holds information specific to a method invocation.
*
* @author Ben Wang
* @deprecated since 2.0. Has no use for now.
* @version $Id: InvocationContext.java,v 1.1 2007/01/13 15:55:01 bwang Exp $
*/
public class InvocationContext
{
private static ThreadLocal<InvocationContext> container = new ThreadLocal<InvocationContext>();
private String region_ = null;
/**
* @return the current invocation context associated with the current thread.
*/
private static InvocationContext getCurrent()
{
InvocationContext i = container.get();
if (i == null)
{
i = new InvocationContext();
container.set(i);
}
return i;
}
private InvocationContext()
{
}
private void setRegion(String region)
{
region_ = region;
}
private String getRegion()
{
return region_;
}
}
1.1 date: 2007/01/13 15:55:01; author: bwang; state: Exp;JBossCache/src/org/jboss/cache/pojo/PojoCache.java
Index: PojoCache.java
===================================================================
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo;
import org.jboss.cache.Cache;
import java.util.Collection;
import java.util.Map;
/**
* <p>Main PojoCache APIs. PojoCache is an in-memory, transactional, fine-grained, and
* object-oriented POJO (plain old Java object) distributed cache system. It
* differs from the traditional generic distributed cache library by operating on the
* POJO level directly without requiring that object to be serializable. It can preserve
* object graph relationship during replication or persistency. It also track the
* replication via fine-grained maner, i.e., only modified fields are replicated.</p>
*
* @author Ben Wang
* @since 2.0
*/
public interface PojoCache
{
/**
* <p>Attach a POJO into PojoCache. It will also recursively put any
* sub-POJO into the cache system. A POJO can be the following and have the
* consqeuences when attached:</p> <p/> <li>it is Replicable, that is, it
* has been annotated with {@see
* org.jboss.cache.aop.annotation.Replicable} annotation (or via XML),
* and has
* been "instrumented" either compile- or load-time. The POJO will be mapped
* recursively to the system and fine-grained replication will be
* performed.</li> <li>It is Serializable. The POJO will still be stored in
* the cache system. However, it is treated as an "opaque" object per se.
* That is, the POJO will neither be intercepted
* (for fine-grained operation) or object relantionship will be
* maintained.</li>
* <li>Neither of above. In this case, a user can specify whether it wants
* this POJO to be stored (e.g., replicated or persistent). If not, a
* PojoCacheException will be thrown.</li>
*
* @param id An id String to identify the object in the cache. To promote
* concurrency, we recommend the use of hierarchical String separating by a
* designated separator. Default is "/" but it can be set differently via a
* System property, jbosscache.separator in the future release. E.g., "ben",
* or "student/joe", etc.
* @param pojo object to be inerted into the cache. If null, it will nullify
* the fqn node.
* @return Existing POJO or null if there is none.
* @throws PojoCacheException Throws if there is an error related to the cache operation.
*/
Object attach(String id, Object pojo) throws PojoCacheException;
/**
* Remove POJO object from the cache.
*
* @param id Is string that associates with this node.
* @return Original value object from this node.
* @throws PojoCacheException Throws if there is an error related to the cache operation.
*/
Object detach(String id) throws PojoCacheException;
/**
* Return the POJO id that is associated with PojoCache. Note that if a POJO has not yet
* attached to the cache system, it will simply return null.
*
* @param pojo The POJO that is attached to PojoCache.
* @return String ID. Null if not existed.
*/
String getPojoID(Object pojo);
/**
* Retrieve POJO from the cache system. Return null if object does not exist in the cache.
* Note that this operation is fast if there is already a POJO instance attached to the cache.
*
* @param id that associates with this node.
* @return Current content value. Null if does not exist.
* @throws PojoCacheException Throws if there is an error related to the cache operation.
*/
Object find(String id) throws PojoCacheException;
/**
* Query all managed POJO objects under the id recursively. Note that this will not return
* the sub-object POJOs, e.g., if <em>Person</em> has a sub-object of <em>Address</em>, it
* won't return <em>Address</em> pojo. Also note also that this operation is not thread-safe
* now. In addition, it assumes that once a POJO is found with a id, no more POJO is stored
* under the children of the id. That is, we don't mix the id with different POJOs.
*
* @param id The starting place to find all POJOs.
* @return Map of all POJOs found with (id, POJO) pair. Return size of 0, if not found.
* @throws PojoCacheException Throws if there is an error related to the cache operation.
*/
Map findAll(String id) throws PojoCacheException;
/**
* Lifecycle method to start PojoCache.
*
* @throws PojoCacheException
*/
void create() throws PojoCacheException;
/**
* Lifecycle method to start PojoCache.
*
* @throws PojoCacheException
*/
void start() throws PojoCacheException;
/**
* Lifecycle method to stop PojoCache. Note that PojoCache can be stopped and started
* repeatedly.
*
* @throws PojoCacheException
*/
void stop() throws PojoCacheException;
/**
* Lifecycle method to destroy PojoCache.
*
* @throws PojoCacheException
*/
void destroy() throws PojoCacheException;
/**
* Add a PojoCacheListener
*
* @param listener
*/
void addListener(PojoCacheListener listener);
/**
* Retrieve a list of listeners.
*/
Collection getListeners();
/**
* Remove the specific listener.
*
* @param listener
*/
void removeListener(PojoCacheListener listener);
/**
* Obtain the underlying generic cache system. Use this for non-POJO cache operation, e.g.
*/
Cache getCache();
}
1.1 date: 2007/01/13 15:55:01; author: bwang; state: Exp;JBossCache/src/org/jboss/cache/pojo/CachedType.java
Index: CachedType.java
===================================================================
package org.jboss.cache.pojo;
import org.jboss.aop.Advisor;
import org.jboss.aop.joinpoint.FieldInvocation;
import org.jboss.cache.pojo.interceptors.PojoBeginInterceptor;
import org.jboss.cache.pojo.memory.FieldPersistentReference;
import org.jboss.cache.pojo.memory.PersistentReference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
/**
* Represent a cached object type, e.g., whether it is <b>primitive</b> or not.
* Note: need to pay special attention not to leak classloader.
*
* @author <a href="mailto:harald at gliebe.de">Harald Gliebe</a>
* @author Ben Wang
*/
public class CachedType
{
// Types that are considered "primitive".
private static final Set immediates =
new HashSet(Arrays.asList(new Object[]{
String.class,
Boolean.class,
Double.class,
Float.class,
Integer.class,
Long.class,
Short.class,
Character.class,
Byte.class,
Boolean.TYPE,
Double.TYPE,
Float.TYPE,
Integer.TYPE,
Long.TYPE,
Short.TYPE,
Character.TYPE,
Byte.TYPE,
Class.class}));
private WeakReference<Class> type;
private boolean immutable;
private boolean immediate;
// This map caches the class that contains no annotation.
private static Map CachedClassWithNoAnnotation_ = new WeakHashMap();
private static Map CachedClassWithAnnotation_ = new WeakHashMap();
// Java fields . Will use special FieldPersistentReference to prevent classloader leakage.
private List fields = new ArrayList();
private Map fieldMap = new HashMap();// Name -> CachedAttribute
public CachedType()
{
}
public CachedType(Class type)
{
this.type = new WeakReference<Class>(type);
analyze();
}
public Class getType()
{
return type.get();
}
// determines if the object should be stored in the Nodes map or as a subnode
public boolean isImmediate()
{
return immediate;
}
private static boolean isImmediate(Class clazz)
{
return immediates.contains(clazz);
}
public boolean isImmutable()
{
return immutable;
}
public List getFields()
{
return fields;
}
public Field getField(String name)
{
FieldPersistentReference ref = (FieldPersistentReference) fieldMap.get(name);
if (ref == null) return null;
return (Field) ref.get();
}
/*
public List getAttributes()
{
return attributes;
}
public CachedAttribute getAttribute(Method m)
{
return (CachedAttribute) attributeMap.get(m);
}
protected void setAttributes(List attributes)
{
this.attributes = attributes;
attributeMap.clear();
// TODO: is a class with no set methods immutable ?
this.immutable = true;
for (Iterator i = attributes.iterator(); i.hasNext();) {
CachedAttribute attribute = (CachedAttribute) i.next();
if (attribute.getGet() != null) {
attributeMap.put(attribute.getGet(), attribute);
}
if (attribute.getSet() != null) {
attributeMap.put(attribute.getSet(), attribute);
immutable = false;
}
}
}
*/
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append(getType().getName()).append(" {\n");
/*
for (Iterator i = attributes.iterator(); i.hasNext();) {
CachedAttribute attr = (CachedAttribute) i.next();
sb
.append("\t")
.append(attr.getType().getLastElementAsString())
.append(" ")
.append(attr.getLastElementAsString())
.append(" [")
.append(attr.getGet() == null
? "<no get>"
: attr.getGet().getLastElementAsString())
.append(", ")
.append(attr.getSet() == null
? "<no set>"
: attr.getSet().getLastElementAsString())
.append("]\n");
}
*/
sb.append("}, immutable =").append(immutable);
return sb.toString();
}
/* ---------------------------------------- */
private void analyze()
{
/*
// We intercept all fields now (instead of setter methods) so there is no need to
// track the individual fields.
HashMap attributes = new HashMap();
Method[] methods = type.getMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if (isGet(method)) {
CachedAttribute attribute =
getAttribute(method, attributes, true);
attribute.setGet(method);
attribute.setType(method.getReturnType());
} else if (isSet(method)) {
CachedAttribute attribute =
getAttribute(method, attributes, true);
attribute.setSet(method);
attribute.setType(method.getParameterTypes()[0]);
}
}
this.setAttributes(new ArrayList(attributes.values()));
*/
analyzeFields(getType());
immediate = isImmediate(getType());
}
private void analyzeFields(Class clazz)
{
if (clazz == null)
{
return;
}
analyzeFields(clazz.getSuperclass());
Field[] classFields = clazz.getDeclaredFields();
for (int i = 0; i < classFields.length; i++)
{
Field f = classFields[i];
if (isPrimitiveNonReplicatable(f)) continue;
f.setAccessible(true);
FieldPersistentReference persistentRef = new FieldPersistentReference(f, PersistentReference.REFERENCE_SOFT);
fields.add(persistentRef);
fieldMap.put(f.getName(), persistentRef);
}
}
/**
* We check whether this class has any field annotation declaration. We assume that there is only
* one such declaring class per vm and it is static.
*/
public static boolean hasAnnotation(Class clazz, Advisor advisor, CachedType type)
{
// It is ok that we don't synchronize it here.
if (CachedClassWithNoAnnotation_.get(clazz) != null)
{
return false;
}
else if (CachedClassWithAnnotation_.get(clazz) != null)
{
return true;
}
for (Iterator i = type.getFields().iterator(); i.hasNext();)
{
Field field = (Field) (((FieldPersistentReference) i.next())).get();
// check for non-replicatable types
if (CachedType.hasFieldAnnotation(field, advisor))
{
synchronized (CachedClassWithAnnotation_)
{
CachedClassWithAnnotation_.put(clazz, clazz.getName());
}
return true;
}
}
// This obj class doesn't have field annotation. It is ok that multiple threads
// put it repeatedly actually.
synchronized (CachedClassWithNoAnnotation_)
{
CachedClassWithNoAnnotation_.put(clazz, clazz.getName());
}
return false;
}
public static boolean isPrimitiveNonReplicatable(Field f)
{
int mods = f.getModifiers();
/**
* The following modifiers are ignored in the cache, i.e., they will not be stored in the cache.
* Whenever, user trying to access these fields, it will be accessed from the in-memory version.
*/
if (Modifier.isStatic(mods)
|| Modifier.isTransient(mods))
{
return true;
}
if (!PojoBeginInterceptor.getReplicateFinalField() && Modifier.isFinal(mods))
{
return true;
}
return false;
}
/**
* Check if we have @Transient annotation.
*
* @param invocation
* @return true if @Transient is present.
*/
private static boolean hasTransientAnnotation(FieldInvocation invocation)
{
Object obj = invocation.resolveAnnotation(org.jboss.cache.pojo.annotation.Transient.class);
if (obj != null)
{
return true;
}
return false;
}
private static boolean hasFieldAnnotation(Field field, Advisor advisor)
{
return hasTransientAnnotation(field, advisor) || hasSerializableAnnotation(field, advisor);
}
public static boolean hasTransientAnnotation(Field field, Advisor advisor)
{
Object obj = advisor.resolveAnnotation(field, org.jboss.cache.pojo.annotation.Transient.class);
if (obj != null)
{
return true;
}
return false;
}
public static boolean hasSerializableAnnotation(Field field, Advisor advisor)
{
Object obj = advisor.resolveAnnotation(field, org.jboss.cache.pojo.annotation.Serializable.class);
if (obj != null)
{
return true;
}
return false;
}
public static boolean hasSerializableAnnotation(FieldInvocation invocation)
{
Object obj = invocation.resolveAnnotation(org.jboss.cache.pojo.annotation.Serializable.class);
if (obj != null)
{
return true;
}
return false;
}
/*
* converts a get/set method to an attribute name
*/
protected static String attributeName(String methodName)
{
return methodName.substring(3, 4).toLowerCase()
+ methodName.substring(4);
}
protected static boolean isGet(Method method)
{
return method.getName().startsWith("get")
&& method.getParameterTypes().length == 0
&& method.getReturnType() != Void.TYPE;
}
protected static boolean isSet(Method method)
{
return method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& method.getReturnType() == Void.TYPE;
}
}// CachedType
1.1 date: 2007/01/13 15:55:01; author: bwang; state: Exp;JBossCache/src/org/jboss/cache/pojo/PojoCacheMBean.java
Index: PojoCacheMBean.java
===================================================================
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo;
import org.w3c.dom.Element;
/**
* MBean interface for PojoCache. Note that it also inherits from {@link org.jboss.cache.TreeCacheMBean}.
*
* @author Ben Wang
* @since 1.4
*/
public interface PojoCacheMBean extends PojoCache
{
/**
* Inject the config element that is specific to PojoCache.
*
* @param config
*/
public void setPojoCacheConfig(Element config);
public Element getPojoCacheConfig();
}
1.1 date: 2007/01/13 15:55:01; author: bwang; state: Exp;JBossCache/src/org/jboss/cache/pojo/PojoCacheAlreadyDetachedException.java
Index: PojoCacheAlreadyDetachedException.java
===================================================================
/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo;
/**
* Thrown when the POJO has already detached from the cache store by the remote side, but user
* is still trying to access it via the cache interceptor.
*
* @author Ben Wang
* @version $Id: PojoCacheAlreadyDetachedException.java,v 1.1 2007/01/13 15:55:01 bwang Exp $
*/
public class PojoCacheAlreadyDetachedException extends PojoCacheException
{
public PojoCacheAlreadyDetachedException()
{
super();
}
public PojoCacheAlreadyDetachedException(String err, Throwable e)
{
super(err, e);
}
public PojoCacheAlreadyDetachedException(String err)
{
super(err);
}
public PojoCacheAlreadyDetachedException(Throwable e)
{
super(e);
}
}
1.1 date: 2007/01/13 15:55:01; author: bwang; state: Exp;JBossCache/src/org/jboss/cache/pojo/PojoTxSynchronizationHandler.java
Index: PojoTxSynchronizationHandler.java
===================================================================
/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.aop.InstanceAdvisor;
import org.jboss.cache.pojo.interceptors.PojoTxUndoSynchronizationInterceptor;
import org.jboss.cache.pojo.util.MethodCall;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.Transaction;
import java.lang.reflect.Field;
import java.util.List;
import java.util.ArrayList;
/**
* Handling the rollback operation for PojoCache level, specifically interceptor add/remove, etc.
*
* @author Ben Wang
* @version $Id: PojoTxSynchronizationHandler.java,v 1.1 2007/01/13 15:55:01 bwang Exp $
*/
public class PojoTxSynchronizationHandler implements Synchronization
{
private static Log log = LogFactory.getLog(PojoTxSynchronizationHandler.class.getName());
private List undoList_ = new ArrayList();
public PojoTxSynchronizationHandler()
{
}
public void beforeCompletion()
{
// Not interested
}
public void afterCompletion(int status)
{
try
{
switch (status)
{
case Status.STATUS_COMMITTED:
break;
case Status.STATUS_MARKED_ROLLBACK:
case Status.STATUS_ROLLEDBACK:
log.debug("Running Pojo rollback phase");
runRollbackPhase();
log.debug("Finished rollback phase");
break;
default:
throw new IllegalStateException("illegal status: " + status);
}
}
finally
{
resetUndoOp();
}
}
private void runRollbackPhase()
{
// Rollback the pojo interceptor add/remove
for (int i = (undoList_.size() - 1); i >= 0; i--)
{
MethodCall mc = (MethodCall) undoList_.get(i);
try
{
mc.invoke();
} catch (Throwable throwable)
{
throwable.printStackTrace();
throw new PojoCacheException(
"PojoTxSynchronizationHandler.runRollbackPhase(): error: " +throwable.toString());
}
}
}
public void addToList(MethodCall mc)
{
undoList_.add(mc);
}
public void resetUndoOp()
{
undoList_.clear();
PojoTxUndoSynchronizationInterceptor.reset();
}
}
1.1 date: 2007/01/13 15:55:01; author: bwang; state: Exp;JBossCache/src/org/jboss/cache/pojo/PojoUtil.java
Index: PojoUtil.java
===================================================================
/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo;
import org.jboss.aop.Advised;
import org.jboss.aop.Domain;
import org.jboss.aop.InstanceAdvisor;
import org.jboss.aop.advice.AdviceBinding;
import org.jboss.aop.advice.Interceptor;
import org.jboss.aop.pointcut.ast.ParseException;
import org.jboss.cache.Fqn;
import org.jboss.cache.pojo.annotation.TxUndo;
import org.jboss.cache.pojo.interceptors.dynamic.CacheFieldInterceptor;
import org.jboss.cache.pojo.interceptors.dynamic.ReentrancyStopperInterceptor;
import org.jboss.cache.pojo.observable.Observer;
import org.jboss.cache.pojo.observable.Subject;
import java.lang.reflect.Field;
import java.util.List;
/**
* Utility class for method wrappers that we are interested to rollback (i.e., rollback).
*
* @author Ben Wang
* @version $Id: PojoUtil.java,v 1.1 2007/01/13 15:55:01 bwang Exp $
*/
public class PojoUtil
{
private static final String BindingName = "ReentrancyStopperInterceptor.";
private boolean checkRecursive = false;
@TxUndo
public void attachInterceptor(Object pojo, InstanceAdvisor advisor, Interceptor interceptor,
Observer observer)
{
_attachInterceptor(pojo, advisor, interceptor, observer);
}
@TxUndo
public void detachInterceptor(InstanceAdvisor advisor, Interceptor interceptor, Observer observer)
{
_detachInterceptor(advisor, interceptor, observer);
}
public void undoAttachInterceptor(Object pojo, InstanceAdvisor advisor, Interceptor interceptor,
Observer observer)
{
_detachInterceptor(advisor, interceptor, observer);
}
public void undoDetachInterceptor(InstanceAdvisor advisor, Interceptor interceptor, Observer observer)
{
Object pojo = ((CacheFieldInterceptor) interceptor).getAopInstance().get();
if (pojo == null)
{
throw new PojoCacheException("PojoUtil.detachInterceptor(): null pojo");
}
_attachInterceptor(pojo, advisor, interceptor, observer);
}
@TxUndo
public void inMemorySubstitution(Object obj, Field field, Object newValue)
{
_inMemorySubstitution(obj, field, newValue);
}
public void undoInMemorySubstitution(Object obj, Field field, Object oldValue)
{
_inMemorySubstitution(obj, field, oldValue);
}
private void _attachInterceptor(Object pojo, InstanceAdvisor advisor, Interceptor interceptor,
Observer observer)
{
// add the observer
((Subject) pojo).addObserver(observer);
// Note that subject interceptor should come before the cache interceptor.
advisor.appendInterceptor(interceptor);
if (checkRecursive)
{
// Insert interceptor to detect recursive call
Class clazz = pojo.getClass();
Field[] fields = clazz.getDeclaredFields();
String clazzName = clazz.getName();
for (Field field : fields)
{
String name = field.getName();
if (name.contains("$aop")) continue; // this is aop declared field.
StringBuffer buf = new StringBuffer().append("set(* ").append(clazzName).append("->").
append(name).append(")");
AdviceBinding binding = null;
try
{
binding = new AdviceBinding(BindingName + name, buf.toString(), null);
}
catch (ParseException e)
{
e.printStackTrace();
throw new PojoCacheException("PojoUtil._attachInterceptor(): can't parse the field binding: "
+ e);
}
binding.addInterceptor(ReentrancyStopperInterceptor.class);
getInstanceDomain(pojo).addBinding(binding);
}
}
}
private Domain getInstanceDomain(Object obj)
{
Advised advised = ((Advised) obj);
InstanceAdvisor advisor = advised._getInstanceAdvisor();
return advisor.getDomain();
}
private void _inMemorySubstitution(Object obj, Field field, Object newValue)
{
try
{
field.set(obj, newValue);
}
catch (IllegalAccessException e)
{
throw new PojoCacheException(
"PojoUtil.inMemorySubstitution(): Can't swap out the class of field \" " +
"+field.getLastElementAsString()," + e);
}
}
private void _detachInterceptor(InstanceAdvisor advisor, Interceptor interceptor, Observer observer)
{
advisor.removeInterceptor(interceptor.getName());
// retrieve pojo
Object pojo = ((CacheFieldInterceptor) interceptor).getAopInstance().get();
if (pojo == null)
{
throw new PojoCacheException("PojoUtil.detachInterceptor(): null pojo");
}
((Subject) pojo).removeObserver(observer);
if (checkRecursive)
{
// Insert interceptor to detect recursive call
Class clazz = pojo.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields)
{
String name = field.getName();
if (name.contains("$aop")) continue; // this is aop declared field.
getInstanceDomain(pojo).removeBinding(BindingName + name);
}
}
}
@TxUndo
public int incrementReferenceCount(Fqn sourceFqn, int count, List refList)
{
return _incrementReferenceCount(sourceFqn, count, refList);
}
public int undoIncrementReferenceCount(Fqn sourceFqn, int count, List refList)
{
return _decrementReferenceCount(sourceFqn, count, refList);
}
private int _incrementReferenceCount(Fqn sourceFqn, int count, List refList)
{
refList.add(sourceFqn);
return count + 1;
}
@TxUndo
public int decrementReferenceCount(Fqn sourceFqn, int count, List refList)
{
return _decrementReferenceCount(sourceFqn, count, refList);
}
public int undoDecrementReferenceCount(Fqn sourceFqn, int count, List refList)
{
return _incrementReferenceCount(sourceFqn, count, refList);
}
private int _decrementReferenceCount(Fqn sourceFqn, int count, List refList)
{
refList.remove(sourceFqn);
return count - 1;
}
}
1.1 date: 2007/01/13 15:55:01; author: bwang; state: Exp;JBossCache/src/org/jboss/cache/pojo/PojoInstance.java
Index: PojoInstance.java
===================================================================
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo;
import org.jboss.cache.Fqn;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* POJO class metadata information.
* When an object is looked up or put in PojoCache, this object will be advised with a CacheFieldInterceptor.
* The underlying cache stores a reference to this object (for example to update the instance variables, etc.).
* Since this reference need to be transactional but never replicated (the reference is only valid
* within the VM this reference is thus stored into an PojoReference (as a transient field).
* In addition, this instance also serves as a metadata for PojoCache. E.g., it has a reference counting for
* multiple references and reference FQN.
*
* @author Ben Wang
*/
public class PojoInstance implements Serializable // Externalizable is no more efficient
{
// protected static Log log=LogFactory.getLog(PojoReference.class.getLastElementAsString());
public static final Object KEY = "PojoInstance";
public static final int INITIAL_COUNTER_VALUE = -1;
static final long serialVersionUID = 6492134565825613209L;
// The instance is transient to avoid replication outside the VM
private transient Object instance_;
// If not null, it signifies that this is a reference that points to this fqn.
// Note that this will get replicated.
private String internalFqn_ = null;
// Reference counting. THis will get replicated as well. This keep track of number of
// other instances that referenced this fqn.
private int refCount_ = INITIAL_COUNTER_VALUE;
// List of fqns that reference this fqn. Assume list size is not big since it may not be efficient.
private List referencedBy_ = null;
private Class clazz_ = null;
private transient PojoUtil util_ = new PojoUtil();
public PojoInstance()
{
}
public PojoInstance(Object instance)
{
set(instance);
}
public void setPojoClass(Class clazz)
{
clazz_ = clazz;
}
public Class getPojoClass()
{
return clazz_;
}
public Object get()
{
return instance_;
}
public void set(Object instance)
{
instance_ = instance;
}
public String getInternalFqn()
{
return internalFqn_;
}
public void setInternalFqn(String refFqn)
{
internalFqn_ = refFqn;
}
public void removeInternalFqn()
{
internalFqn_ = null;
}
synchronized public int incrementRefCount(Fqn sourceFqn)
{
if (sourceFqn == null)
{
throw new IllegalStateException("PojoInstance.incrementRefCount(): null sourceFqn");
}
if (referencedBy_ == null)
{
referencedBy_ = new ArrayList();
}
if (referencedBy_.contains(sourceFqn))
throw new IllegalStateException("PojoReference.incrementRefCount(): source fqn: " +
sourceFqn + " is already present.");
if (util_ == null) util_ = new PojoUtil();
refCount_ = util_.incrementReferenceCount(sourceFqn, refCount_, referencedBy_);
// referencedBy_.add(sourceFqn);
// refCount_ += 1;
//logger_.info("incrementRefCount(): current ref count " +refCount_);
return refCount_;
}
synchronized public int decrementRefCount(Fqn sourceFqn)
{
if (sourceFqn == null)
{
throw new IllegalStateException("PojoInstance.incrementRefCount(): null sourceFqn");
}
if (!referencedBy_.contains(sourceFqn))
throw new IllegalStateException("PojoReference.decrementRefCount(): source fqn: " +
sourceFqn + " is not present.");
if (util_ == null) util_ = new PojoUtil();
refCount_ = util_.decrementReferenceCount(sourceFqn, refCount_, referencedBy_);
// referencedBy_.remove(sourceFqn);
// refCount_ -= 1;
//logger_.info("decrementRefCount(): current ref count " +refCount_);
return refCount_;
}
synchronized public int getRefCount()
{
return refCount_;
}
synchronized public Fqn getAndRemoveFirstFqnInList()
{
return (Fqn) referencedBy_.remove(0);
}
synchronized public void addXFqnIntoList(Fqn fqn)
{
referencedBy_.add(0, fqn);
}
public String toString()
{
return "PI[fqn=" + internalFqn_ + " ref=" + refCount_ + " class=" + clazz_.getName() + "]";
}
}
1.1 date: 2007/01/13 15:55:01; author: bwang; state: Exp;JBossCache/src/org/jboss/cache/pojo/Option.java
Index: Option.java
===================================================================
/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo;
/** Option class to hold configuration for PojoCache APIs.
*
* @author Ben Wang
* @version $Id: Option.java,v 1.1 2007/01/13 15:55:01 bwang Exp $
*/
public class Option
{
private String region_ = null;
/** Set the region namespace for PojoCache IDs. When this is not null, the ID will be denoted
* with this region name. E.g., it will be something like "region/ID". Furthermore, the
* internal storage region will have this concept of region.
*
*/
public void setRegion(String region)
{
region_ = region;
}
public String getRegion()
{
return region_;
}
}
1.1 date: 2007/01/13 15:55:01; author: bwang; state: Exp;JBossCache/src/org/jboss/cache/pojo/PojoCacheFactory.java
Index: PojoCacheFactory.java
===================================================================
/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo;
import org.jboss.cache.pojo.impl.PojoCacheImpl;
import org.jboss.cache.config.Configuration;
/**
* Factory method to create a PojoCache instance.
*
* @version $Id: PojoCacheFactory.java,v 1.1 2007/01/13 15:55:01 bwang Exp $
*/
public class PojoCacheFactory
{
/**
* Create a PojoCache instance. Note that this will start the cache life cycle automatically.
* @param config A configuration string that represents the file name that is used to
* configure the underlying Cache instance.
* @return PojoCache
*/
public static PojoCache createCache(String config)
{
return new PojoCacheImpl(config, true);
}
/**
* Create a PojoCache instance.
* @param config A configuration string that represents the file name that is used to
* configure the underlying Cache instance.
* @param start If true, it will start the cache life cycle.
* @return PojoCache
*/
public static PojoCache createCache(String config, boolean start)
{
return new PojoCacheImpl(config, start);
}
/**
* Create a PojoCache instance.
* @param config A configuration object that is used to configure the underlying Cache instance.
* @param start If true, it will start the cache life cycle.
* @return PojoCache
*/
public static PojoCache createCache(Configuration config, boolean start)
{
return new PojoCacheImpl(config, start);
}
}
1.1 date: 2007/01/13 15:55:01; author: bwang; state: Exp;JBossCache/src/org/jboss/cache/pojo/InternalConstant.java
Index: InternalConstant.java
===================================================================
/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo;
import org.jboss.cache.Fqn;
/**
* Internal helper class to handle internal cache sotre, that is, the portion that is not part of
* user's data.
*
* @author Ben Wang
*/
public class InternalConstant
{
public static final String CLASS_INTERNAL = "__jboss:internal:class__";
public static final String SERIALIZED = "__SERIALIZED__";
public static final String JBOSS_INTERNAL_STRING = "__JBossInternal__";
public static final Fqn JBOSS_INTERNAL = new Fqn(JBOSS_INTERNAL_STRING);
public static final Fqn JBOSS_INTERNAL_MAP = new Fqn(InternalConstant.JBOSS_INTERNAL, "__RefMap__");
public static final String JBOSS_INTERNAL_STATIC = "__jboss:static__";
public static final String ENUM_KEY = "name";
}
1.1 date: 2007/01/13 15:55:01; author: bwang; state: Exp;JBossCache/src/org/jboss/cache/pojo/MethodDeclarations.java
Index: MethodDeclarations.java
===================================================================
/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo;
import org.jboss.aop.InstanceAdvisor;
import org.jboss.aop.advice.Interceptor;
import org.jboss.cache.pojo.observable.Observer;
import org.jboss.cache.Fqn;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.util.List;
/**
* Method declarations for rollback method mostly.
*
* @author Ben Wang
* @version $Revision: 1.1 $
*/
public class MethodDeclarations
{
public static final Method attachInterceptor;
public static final Method detachInterceptor;
public static final Method undoAttachInterceptor;
public static final Method undoDetachInterceptor;;
public static final Method inMemorySubstitution;;
public static final Method undoInMemorySubstitution;;
public static final Method incrementReferenceCount;
public static final Method decrementReferenceCount;
public static final Method undoIncrementReferenceCount;
public static final Method undoDecrementReferenceCount;
static
{
try
{
attachInterceptor = PojoUtil.class.getDeclaredMethod("attachInterceptor",
new Class[] {Object.class, InstanceAdvisor.class, Interceptor.class, Observer.class});
detachInterceptor = PojoUtil.class.getDeclaredMethod("detachInterceptor",
new Class[] {InstanceAdvisor.class, Interceptor.class, Observer.class});
undoAttachInterceptor = PojoUtil.class.getDeclaredMethod("undoAttachInterceptor",
new Class[] {Object.class, InstanceAdvisor.class, Interceptor.class, Observer.class});
undoDetachInterceptor = PojoUtil.class.getDeclaredMethod("undoDetachInterceptor",
new Class[] {InstanceAdvisor.class, Interceptor.class, Observer.class});
inMemorySubstitution = PojoUtil.class.getDeclaredMethod("inMemorySubstitution",
new Class[] {Object.class, Field.class, Object.class});
undoInMemorySubstitution = PojoUtil.class.getDeclaredMethod("undoInMemorySubstitution",
new Class[] {Object.class, Field.class, Object.class});
incrementReferenceCount = PojoUtil.class.getDeclaredMethod("incrementReferenceCount",
new Class[] {Fqn.class, int.class, List.class});
decrementReferenceCount = PojoUtil.class.getDeclaredMethod("decrementReferenceCount",
new Class[] {Fqn.class, int.class, List.class});
undoIncrementReferenceCount = PojoUtil.class.getDeclaredMethod("undoIncrementReferenceCount",
new Class[] {Fqn.class, int.class, List.class});
undoDecrementReferenceCount = PojoUtil.class.getDeclaredMethod("undoDecrementReferenceCount",
new Class[] {Fqn.class, int.class, List.class});
}
catch (NoSuchMethodException ex)
{
ex.printStackTrace();
throw new ExceptionInInitializerError(ex.toString());
}
}
}
1.1 date: 2007/01/13 15:55:01; author: bwang; state: Exp;JBossCache/src/org/jboss/cache/pojo/PojoCacheListener.java
Index: PojoCacheListener.java
===================================================================
/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo;
import java.lang.reflect.Field;
/**
* Listener interface for PojoCache events
*
* @author Ben Wang
* @version $Id: PojoCacheListener.java,v 1.1 2007/01/13 15:55:01 bwang Exp $
* @since 2.0
*/
public interface PojoCacheListener
{
/**
* Event when a POJO is attaching.
*
* @param pojo The POJO that is attaching.
* @param pre True if this the callback before it is attached.
* @param isLocal True if this is the local event, e.g., I am the active node.
*/
void attach(Object pojo, boolean pre, boolean isLocal);
/**
* Event when a POJO is detaching.
*
* @param pojo The POJO that is detaching.
* @param pre True if this the callback before it is detached.
* @param isLocal True if this is the local event, e.g., I am the active node.
*/
void detach(Object pojo, boolean pre, boolean isLocal);
/**
* Event when a POJO is modifying.
*
* @param pojo The POJO that is modifying.
* @param pre True if this the callback before it is modified.
* @param isLocal True if this is the local event, e.g., I am the active node.
*/
void modify(Object pojo, Field field, boolean pre, boolean isLocal);
}
1.1 date: 2007/01/13 15:55:01; author: bwang; state: Exp;JBossCache/src/org/jboss/cache/pojo/PojoTreeCache.java
Index: PojoTreeCache.java
===================================================================
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo;
import org.jboss.cache.CacheException;
import org.jboss.cache.CacheImpl;
import org.jboss.cache.Fqn;
import org.jboss.cache.NodeSPI;
import org.w3c.dom.Element;
import javax.transaction.Transaction;
public class PojoTreeCache extends CacheImpl
{
private Element config_ = null;
// boolean detachPojoWhenEvicted_ = false;
public PojoTreeCache(String cluster_name,
String props,
long state_fetch_timeout)
throws Exception
{
//super(cluster_name, props, state_fetch_timeout);
// TODO: Use a cache factory and delegation
}
public PojoTreeCache() throws Exception
{
}
@Override
public void start() throws Exception
{
// Replace the default state transfer manager. TODO
// setStateTransferManager(new PojoStateTransferManager(this));
super.start();
parseConfig();
}
@Override
public void stop()
{
super.stop();
}
private void parseConfig()
{
if (config_ == null)
{
log.info("parseConfig(): PojoCacheConfig is empty");
return;
}
// detachPojoWhenEvicted_ = XmlHelper.readBooleanContents(config_, "DetachPojoWhenEvicted");
}
private boolean isAopNode(Fqn fqn)
{
// Use this API so it doesn't go thru the interceptor.
NodeSPI node = peek(fqn);
if (node == null) return false;
return node.getDirect(PojoInstance.KEY) != null;
}
/**
* Overrides the {@link CacheImpl#activateRegion(String) superclass method} by
* ensuring that the internal region where information on shared object is stored
* has been activated.
*/
/*
@Override
public void activateRegion(String subtreeFqn) throws RegionNotEmptyException, RegionNameConflictException, CacheException
{
if (!getConfiguration().isUseRegionBasedMarshalling())
throw new IllegalStateException("CacheImpl.activateRegion(). useRegionBasedMarshalling flag is not set!");
if ("/".equals(subtreeFqn))
{
// Just pass it through, as we'll get the internal area
// with the normal state transfer
super.activateRegion(subtreeFqn);
} else
{
// If the internal region is not activated yet, activate it first
Region region = regionManager_.getRegion(InternalConstant.JBOSS_INTERNAL);
if ((region == null && getConfiguration().isInactiveOnStartup())
|| (region != null && region.isInactive()))
{
super.activateRegion(InternalConstant.JBOSS_INTERNAL.toString());
}
// If we don't have an internal map node yet, create one.
// Doing this ensures the code that integrates map references for
// the region will have a node to integrate into
if (get(InternalConstant.JBOSS_INTERNAL_MAP) == null)
createSubtreeRootNode(InternalConstant.JBOSS_INTERNAL_MAP);
// Now activate the requested region
super.activateRegion(subtreeFqn);
}
}
*/
public Object getLockOwner()
{
return getOwnerForLock();
}
/**
* Inject the config element that is specific to PojoCache.
*
* @param config
* @throws CacheException
*/
public void setPojoCacheConfig(Element config) throws CacheException
{
config_ = config;
}
public Element getPojoCacheConfig()
{
return config_;
}
public Transaction getTransaction()
{
return getLocalTransaction();
}
}
1.1 date: 2007/01/13 15:55:01; author: bwang; state: Exp;JBossCache/src/org/jboss/cache/pojo/PojoReference.java
Index: PojoReference.java
===================================================================
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo;
import org.jboss.cache.Fqn;
import java.io.Serializable;
/**
* POJO reference that contains the information to point to the real POJO storage.
*
* @author Ben Wang
*/
public class PojoReference implements Serializable // Externalizable is no more efficient
{
// protected static Log log=LogFactory.getLog(PojoReference.class.getLastElementAsString());
public static final Object KEY = "PojoReference";
static final long serialVersionUID = 6492134565825613209L;
// If not null, it signifies that this is a reference that points to this fqn.
// Note that this will get replicated.
private Fqn internalFqn_ = null;
private Class clazz_ = null;
public PojoReference()
{
}
public void setFqn(Fqn fqn)
{
internalFqn_ = fqn;
}
public Fqn getFqn()
{
return internalFqn_;
}
public void setPojoClass(Class clazz)
{
clazz_ = clazz;
}
public Class getPojoClass()
{
return clazz_;
}
public String toString()
{
StringBuffer buf = new StringBuffer();
buf.append("Internal Fqn --> ").append(internalFqn_);
return buf.toString();
}
}
1.1 date: 2007/01/13 15:55:01; author: bwang; state: Exp;JBossCache/src/org/jboss/cache/pojo/PojoCacheException.java
Index: PojoCacheException.java
===================================================================
/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo;
/**
* Generic PojoCacheException.
*
* @author Ben Wang
* @version $Id: PojoCacheException.java,v 1.1 2007/01/13 15:55:01 bwang Exp $
*/
public class PojoCacheException extends RuntimeException
{
public PojoCacheException()
{
super();
}
public PojoCacheException(String err, Throwable e)
{
super(err, e);
}
public PojoCacheException(String err)
{
super(err);
}
public PojoCacheException(Throwable e)
{
super(e);
}
}
More information about the jboss-cvs-commits
mailing list