[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