You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@turbine.apache.org by as...@apache.org on 2002/02/18 03:34:54 UTC

cvs commit: jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/engine/control/group GroupRWLockManager.java GroupId.java GroupCacheManagerFactory.java GroupCacheManager.java GroupCache.java GroupAttrName.java

asmuts      02/02/17 18:34:54

  Added:       src/java/org/apache/stratum/jcs/engine/control/group
                        GroupRWLockManager.java GroupId.java
                        GroupCacheManagerFactory.java
                        GroupCacheManager.java GroupCache.java
                        GroupAttrName.java
  Log:
  moved group to control.group
  
  Revision  Changes    Path
  1.1                  jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/engine/control/group/GroupRWLockManager.java
  
  Index: GroupRWLockManager.java
  ===================================================================
  package org.apache.stratum.jcs.engine.control.group;
  
  import java.util.Hashtable;
  
  import org.apache.stratum.jcs.utils.locking.ReadWriteLockManager;
  
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogSource;
  
  /**
   * The ReadWriteLock Manager for distributed group list management.
   *
   * @author asmuts
   * @created January 15, 2002
   */
  class GroupRWLockManager extends ReadWriteLockManager
  {
      private final static Log log =
          LogSource.getInstance( GroupRWLockManager.class );
  
      /** Description of the Field */
      private static GroupRWLockManager instance;
      private final Hashtable ht = new Hashtable();
  
      /**
       * Returns the lock table of all the resources managed by this manager.
       *
       * @return The locks value
       */
      protected Hashtable getLocks()
      {
          return ht;
      }
  
  
      /** Constructor for the GroupRWLockManager object */
      private GroupRWLockManager() { }
  
  
      /**
       * Gets the instance attribute of the GroupRWLockManager class
       *
       * @return The instance value
       */
      static GroupRWLockManager getInstance()
      {
          if ( instance == null )
          {
              synchronized ( GroupRWLockManager.class )
              {
                  if ( instance == null )
                  {
                      instance = new GroupRWLockManager();
                      if ( log.isDebugEnabled() )
                      {
                          log.debug( "   >> GroupRWLockManager instanciated." );
                      }
                  }
              }
          }
          return instance;
      }
  }
  
  
  
  1.1                  jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/engine/control/group/GroupId.java
  
  Index: GroupId.java
  ===================================================================
  package org.apache.stratum.jcs.engine.control.group;
  
  import java.io.Serializable;
  
  /**
   * Used to avoid name conflict when group cache items are mixed with non-group
   * cache items in the same cache.
   *
   * @author asmuts
   * @created January 15, 2002
   */
  public class GroupId implements Serializable
  {
  
      /** Description of the Field */
      public final String key;
  
  
      /**
       * Constructor for the GroupId object
       *
       * @param cacheName
       * @param key
       */
      public GroupId( String cacheName, String key )
      {
          this.key = cacheName + key;
  
          if ( key == null )
          {
              throw new IllegalArgumentException( "key must not be null." );
          }
      }
  
  
      /** Description of the Method */
      public boolean equals( Object obj )
      {
          if ( obj == null || !( obj instanceof GroupId ) )
          {
              return false;
          }
          GroupId to = ( GroupId ) obj;
          return key.equals( to.key );
      }
  
  
      /** Description of the Method */
      public int hashCode()
      {
          return key.hashCode();
      }
  
  
      /** Description of the Method */
      public String toString()
      {
          return "[grouId=" + key + "]";
      }
  }
  
  
  
  1.1                  jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/engine/control/group/GroupCacheManagerFactory.java
  
  Index: GroupCacheManagerFactory.java
  ===================================================================
  package org.apache.stratum.jcs.engine.control.group;
  
  import org.apache.stratum.jcs.engine.control.group.GroupCacheManager;
  
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogSource;
  
  /** */
  public abstract class GroupCacheManagerFactory
  {
      private final static Log log =
          LogSource.getInstance( GroupCacheManagerFactory.class );
  
      private static GroupCacheManager instance;
  
      /** */
      public static GroupCacheManager getInstance()
      {
          return getInstance( null );
      }
  
      /** */
      public static GroupCacheManager getInstance( String propFile )
      {
          if ( instance == null )
          {
              synchronized ( GroupCacheManager.class )
              {
                  if ( instance == null )
                  {
                      log.debug( "Instance is null, creating" );
  
                      if ( propFile == null )
                      {
                          instance = new GroupCacheManager();
                      }
                      else
                      {
                          instance = new GroupCacheManager( propFile );
                      }
                  }
              }
          }
  
          instance.incrementClients();
          return instance;
      }
  }
  
  
  
  1.1                  jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/engine/control/group/GroupCacheManager.java
  
  Index: GroupCacheManager.java
  ===================================================================
  package org.apache.stratum.jcs.engine.control.group;
  
  import java.io.Serializable;
  
  import org.apache.stratum.jcs.engine.Attributes;
  
  import org.apache.stratum.jcs.engine.behavior.ICache;
  import org.apache.stratum.jcs.engine.behavior.ICompositeCache;
  import org.apache.stratum.jcs.engine.behavior.ICompositeCacheAttributes;
  
  import org.apache.stratum.jcs.engine.control.Cache;
  import org.apache.stratum.jcs.engine.control.CompositeCacheManager;
  
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogSource;
  
  /** */
  public class GroupCacheManager
       extends CompositeCacheManager
       implements Serializable
  {
      private final static Log log =
          LogSource.getInstance( CompositeCacheManager.class );
  
      private static GroupCacheManager instance;
  
      /** Constructor for the GroupCacheManager object */
      protected GroupCacheManager()
      {
          super();
      }
  
      /**
       * Constructor for the GroupCacheManager object
       *
       * @param propFile
       */
      protected GroupCacheManager( String propFile )
      {
          super( propFile );
      }
  
      /** Factory method to create the actual GroupCache instance. */
      protected Cache createSystemCache( String cacheName,
                                         ICache[] auxCaches,
                                         ICompositeCacheAttributes cattr,
                                         Attributes attr )
      {
          ICompositeCache systemGroupIdCache =
              ( ICompositeCache ) systemCaches.get( "groupIdCache" );
  
          return new GroupCache( cacheName, auxCaches, cattr, attr,
              systemGroupIdCache );
      }
  
      /** */
      protected Cache createCache( String cacheName,
                                   ICache[] auxCaches,
                                   ICompositeCacheAttributes cattr,
                                   Attributes attr )
      {
          ICompositeCache systemGroupIdCache =
              ( ICompositeCache ) systemCaches.get( "groupIdCache" );
  
          return new GroupCache( cacheName, auxCaches, cattr, attr,
              systemGroupIdCache );
      }
  
      /** */
      protected void incrementClients()
      {
          super.incrementClients();
      }
  }
  
  
  
  1.1                  jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/engine/control/group/GroupCache.java
  
  Index: GroupCache.java
  ===================================================================
  package org.apache.stratum.jcs.engine.control.group;
  
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Velocity", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  import java.io.IOException;
  import java.io.Serializable;
  
  import java.util.HashSet;
  
  import org.apache.stratum.jcs.access.exception.CacheException;
  import org.apache.stratum.jcs.access.exception.ObjectNotFoundException;
  
  import org.apache.stratum.jcs.engine.Attributes;
  import org.apache.stratum.jcs.engine.CacheElement;
  
  import org.apache.stratum.jcs.engine.behavior.ICache;
  import org.apache.stratum.jcs.engine.behavior.ICacheElement;
  import org.apache.stratum.jcs.engine.behavior.ICompositeCache;
  import org.apache.stratum.jcs.engine.behavior.ICompositeCacheAttributes;
  
  import org.apache.stratum.jcs.engine.control.Cache;
  
  import org.apache.stratum.jcs.engine.control.group.GroupAttrName;
  import org.apache.stratum.jcs.engine.control.group.GroupId;
  import org.apache.stratum.jcs.engine.control.group.GroupRWLockManager;
  
  import org.apache.stratum.jcs.utils.locking.ReadWriteLockManager;
  
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogSource;
  
  /**
   * Group cache is basically a composite cache with the additional capability of
   * providing automatic and safe attribute name list update for each
   * GroupAttrName cache item. TODO: WORKING ON THIS NOW -- reduce the number of
   * methods or describe them better. The complexity of this points to group
   * design problems. I need to fix the locking and the maintenance of the remote
   * list. The list can be infered fromt he contents of the cache. Iterating
   * through the hashtable could be problematic but easier.
   *
   * @author asmuts
   */
  public class GroupCache extends Cache implements ICompositeCache
  {
      private final static Log log = LogSource.getInstance( GroupCache.class );
  
      /** Manages locking for group item manipulation. */
      private ReadWriteLockManager locker = GroupRWLockManager.getInstance();
  
      /**
       * Declare a group_id cache here, so ids and elements don't compete for
       * first with the list. The systemGroupIdCache will have different remote
       * behavior. Local removal of the list will propagate to the remote, but the
       * list will not move back and forth. The list can be maintained locally but
       * the elements themselves need not be.
       */
      ICompositeCache systemGroupIdCache;
  
      /**
       * Constructor for the GroupCache object
       *
       * @param cacheName The name of the region
       * @param auxCaches The auxiliary caches to be used by this region
       * @param cattr The cache attribute
       * @param attr The default element attributes
       */
      public GroupCache( String cacheName, ICache[] auxCaches, ICompositeCacheAttributes cattr, Attributes attr )
      {
          super( cacheName, auxCaches, cattr, attr );
  
          if ( log.isDebugEnabled() )
          {
              log.debug( "constructed groupcache " + cacheName + " from super" );
          }
          //ICompositeCache systemGroupIdCache = (ICompositeCache)systemCaches.get( "groupIdCache" );
      }
  
  
      /**
       * Constructor for the GroupCache object
       *
       * @param cacheName The name of the region
       * @param auxCaches The auxiliary caches to be used by this region
       * @param cattr The cache attribute
       * @param attr The default element attributes
       * @param systemGroupIdCache The systemGroupIdCache
       */
      public GroupCache( String cacheName, ICache[] auxCaches, ICompositeCacheAttributes cattr, Attributes attr, ICompositeCache systemGroupIdCache )
      {
          super( cacheName, auxCaches, cattr, attr );
          if ( log.isDebugEnabled() )
          {
              log.debug( "constructed (2) groupcache " + cacheName + " from super" );
          }
          this.systemGroupIdCache = systemGroupIdCache;
      }
  
  
      /**
       * Overrides to provide read lock on both GroupAttrName read-operation and
       * String read-operation.
       *
       * @param key The key for the element
       * @return Returns element from the cache if found, else null
       */
      public Serializable get( Serializable key )
      {
          return get( key, false, this.LOCAL_INVOKATION );
      }
  
  
      /**
       * Gets an element fromt he cache
       *
       * @param key The key for the element
       * @param container Should it return the CacheElement wrapper
       * @return Returns element from the cache if found, else null
       */
      public Serializable get( Serializable key, boolean container )
      {
          return get( key, false, this.LOCAL_INVOKATION );
      }
  
  
      /**
       * Gets an element fromt he cache
       *
       * @param key The key for the element
       * @param container Should it return the CacheElement wrapper
       * @param invocation Is the originating method call from a local source
       * @return Returns element from the cache if found, else null
       */
      public Serializable get( Serializable key, boolean container, boolean invocation )
      {
  
          // GETTING GROUP ELEMENT
          if ( key instanceof GroupAttrName )
          {
              return getGAN( ( GroupAttrName ) key, container );
          }
  
          // GROUP ID
          if ( key instanceof GroupId )
          {
              return getGI( ( GroupId ) key, container );
          }
          if ( log.isDebugEnabled() )
          {
              log.debug( this.getCacheName() + " getting " + key + " from super " );
              if ( invocation == ICache.LOCAL_INVOKATION )
              {
                  log.debug( "invokation is LOCAL" );
              }
              else
              {
                  log.debug( "invokation is NOT Local" );
              }
          }
  
          // GETTING NON GROUP RELATED ITEM
          return super.get( key, container, invocation );
      }
  
  
      /**
       * Places a read lock on the group id for a GroupAttrName get-operation.
       *
       * @param key The key for the element
       * @param container Should it return the CacheElement wrapper
       * @return The gAN value
       */
      public Serializable getGAN( GroupAttrName key, boolean container )
      {
          return getGAN( key, container, this.LOCAL_INVOKATION );
      }
  
  
      /**
       * Gets the gAN attribute of the GroupCache object
       *
       * @param key The key for the element
       * @param container Should it return the CacheElement wrapper
       * @param invocation Is the originating method call from a local source
       * @return The gAN value
       */
      public Serializable getGAN( GroupAttrName key, boolean container, boolean invocation )
      {
          if ( log.isDebugEnabled() )
          {
              if ( invocation == ICache.LOCAL_INVOKATION )
              {
                  log.debug( "invokation is LOCAL" );
              }
              else
              {
                  log.debug( "invokation is NOT Local" );
              }
          }
  
          Object obj = null;
          // not necessary?, stops at getaux
          readLock( key.groupId );
          try
          {
              obj = super.get( key, container, invocation );
              //p( "got obj" );
          }
          finally
          {
              locker.done( key.groupId );
          }
          return ( Serializable ) obj;
      }
  
  
      /**
       * Places a read lock on the key for a GroupId get-operation.
       *
       * @param gid The group id
       * @param container Should the cache element wrapper be returned
       * @return The gI value
       */
      // get list from remote if it isn't present
      public Serializable getGI( GroupId gid, boolean container )
      {
          return getGI( gid, container, this.LOCAL_INVOKATION );
      }
  
  
      /**
       * removal of a group element will call this to get the list to edit.
       *
       * @param invocation Is the originating method call from a local source
       * @return The gI value
       */
      public Serializable getGI( GroupId gid, boolean container, boolean invocation )
      {
          if ( log.isDebugEnabled() )
          {
              log.debug( "getGi(gid,container,invocation)" );
              if ( invocation == ICache.LOCAL_INVOKATION )
              {
                  log.debug( "invocation is LOCAL" );
              }
              else
              {
                  log.debug( "invocation is NOT Local" );
              }
          }
          Object obj = null;
          readLock( gid.key );
          try
          {
              //obj = super.get(gid.key, container);
              obj = systemGroupIdCache.get( gid.key, container, invocation );
              if ( log.isDebugEnabled() )
              {
                  log.debug( "getGi(gid,container,invocation) > got obj in getGi " + obj );
              }
          }
          catch ( IOException ioeg )
          {
          }
          finally
          {
              locker.done( gid.key );
          }
          return ( Serializable ) obj;
      }
  
  
      /**
       * Internally used read lock for group modification.
       *
       * @param id What name to lock on.
       */
      private void readLock( String id )
      {
          try
          {
              locker.readLock( id );
          }
          catch ( InterruptedException e )
          {
              // This previously would wait for console input before
              // continuing if the debug flag was set. I consider this
              // a BAD IDEA since it could introduce signifigant
              // confusion. ( There are other ways to accomplish this,
              // introduction or using a debugger (breakpoints) come to
              // mind. [james@jamestaylor.org]
  
              log.error( "Was interrupted while acquiring read lock", e );
          }
      }
  
  
      /**
       * Internally used write lock for group modification.
       *
       * @param id What name to lock on.
       */
      private void writeLock( String id )
      {
          try
          {
              locker.writeLock( id );
          }
          catch ( InterruptedException e )
          {
              // See note in readLock()
  
              log.error( "Was interrupted while acquiring read lock", e );
          }
      }
  
  
      /**
       * Overrides to special handling for GroupAttrName put-operation.
       *
       * @param key Retrieval key for the element to cache
       * @param val The Object to cache
       * @param attr The element attributes
       */
      public void put( Serializable key, Serializable val, Attributes attr )
          throws IOException
      {
          if ( key instanceof GroupAttrName )
          {
              try
              {
                  if ( log.isDebugEnabled() )
                  {
                      log.debug( "putting via putGAN((GroupAttrName)key, val, attr) method" );
                  }
                  putGAN( ( GroupAttrName ) key, val, attr );
              }
              catch ( IOException ioe )
              {
              }
              return;
          }
          if ( log.isDebugEnabled() )
          {
              log.debug( "put(key,val,attr) > updating " + key + " via super method, attr.IS_REMOTE = " + attr.IS_REMOTE );
          }
  
          // NOT GROUP RELATED
          try
          {
              //updateCaches( key, val, attr );
              CacheElement ce = new CacheElement( this.getCacheName(), key, val );
              ce.setAttributes( attr );
              super.update( ce, ICache.INCLUDE_REMOTE_CACHE );
  
          }
          catch ( IOException ioe )
          {
          }
          return;
      }
  
  
      /** Description of the Method */
      public void put( Serializable key, Serializable val )
          throws IOException
      {
          //public void put (Object key, Object val) throws IOException {
  
          if ( key instanceof GroupAttrName )
          {
              try
              {
                  if ( log.isDebugEnabled() )
                  {
                      log.debug( "putting via putGAN((GroupAttrName)key, val) method" );
                  }
                  putGAN( ( GroupAttrName ) key, val );
              }
              catch ( IOException ioe )
              {
              }
              return;
          }
  
          if ( log.isDebugEnabled() )
          {
              log.debug( "put(key,value) -- updating " + key + " via super method" );
          }
  
          //super.put(key, val);
          Attributes attrE = ( Attributes ) this.attr.copy();
          try
          {
              // must make sure you call the sure here
              // updateCaches( key, val, attrE, ICache.INCLUDE_REMOTE_CACHE );
              // problem super calls back up and the last instruction gets confused
              CacheElement ce = new CacheElement( this.getCacheName(), key, val );
              ce.setAttributes( attrE );
              super.update( ce, ICache.INCLUDE_REMOTE_CACHE );
          }
          catch ( IOException ioe )
          {
          }
          return;
      }
  
  
      /** Description of the Method */
      public synchronized void update( ICacheElement ce )
          throws IOException
      {
          //update( ce, ICache.LATERAL_INVOKATION );
          if ( ce.getKey() instanceof GroupAttrName )
          {
              try
              {
                  if ( log.isDebugEnabled() )
                  {
                      log.debug( "update(ce) > putting via putGAN((GroupAttrName)key, val) method" );
                  }
                  putGAN( ( GroupAttrName ) ce.getKey(), ce.getVal() );
              }
              catch ( IOException ioe )
              {
              }
              return;
          }
          if ( log.isDebugEnabled() )
          {
              log.debug( "update(ce) > updating " + ce.getKey() + " via super method" );
          }
  
          try
          {
              // must make sure you call the sure here
              // updateCaches( key, val, attrE, ICache.INCLUDE_REMOTE_CACHE );
              // problem super calls back up and the last instruction gets confused
              super.update( ce, ICache.INCLUDE_REMOTE_CACHE );
          }
          catch ( IOException ioe )
          {
          }
          return;
      }
  
  
      /**
       * Description of the Method
       *
       * @param invocation Is the originating method call from a local source
       */
      // PROBLEM CACHE HAS THE SAME METHOD AND THE 2nd arg is updateRemote
      public synchronized void update( ICacheElement ce, boolean invocation )
          throws IOException
      {
  
          Object key = ce.getKey();
          if ( key instanceof GroupAttrName )
          {
              try
              {
                  if ( log.isDebugEnabled() )
                  {
                      log.debug( "update(ce,invocation) >putting via ga method" );
                      if ( invocation == ICache.LOCAL_INVOKATION )
                      {
                          log.debug( "invocation is LOCAL" );
                      }
                      else
                      {
                          log.debug( "invocation is NOT Local" );
                      }
                  }
                  Attributes attrE = ( Attributes ) this.attr.copy();
                  putGAN( ( GroupAttrName ) key, ce.getVal(), attrE, invocation );
              }
              catch ( IOException ioe )
              {
              }
              return;
          }
          if ( log.isDebugEnabled() )
          {
              log.debug( "update(ce,invocation) > updating " + key + " via super method" );
          }
  
          // TODO: what about id? not possible here?
          // GROUP ID
          //if ( key instanceof GroupId )
          //{
          //}
  
  
          Attributes attrE = ( Attributes ) this.attr.copy();
          try
          {
              // update should go remote if locally invoked
              boolean updateRemote = false;
              // DECIDE WHAT TO DO WITH THE LIST
              if ( invocation == ICache.LOCAL_INVOKATION )
              {
                  updateRemote = ICache.INCLUDE_REMOTE_CACHE;
              }
              else
              {
                  updateRemote = ICache.EXCLUDE_REMOTE_CACHE;
              }
              super.update( ce, updateRemote );
          }
          catch ( IOException ioe )
          {
          }
          return;
      }
      // end update
  
      /** GroupAttrName specific put-operation. */
      public void putGAN( GroupAttrName key, Serializable val )
          throws IOException
      {
          if ( log.isDebugEnabled() )
          {
              log.debug( "in putGAN(GroupAttrName key, Serializable val) method" );
          }
          if ( key == null || val == null )
          {
              NullPointerException ex = new NullPointerException( "key=" + key + " and val="
                   + val + " must not be null." );
              log.error( ex );
              throw ex;
          }
  
          Attributes attrE = ( Attributes ) this.attr.copy();
          putGAN( key, val, attrE );
          return;
      }
  
  
      /**
       * Special handling for GroupAttrName put-operation. Provides write lock and
       * automatic attribute name set update.
       */
      // TODO: DistCacheMulticaster,etc. currently only supports key of String type
      // Needs to support GroupAttrName type, or do we ?
      private void putGAN( GroupAttrName key, Serializable val, Attributes attrE )
          throws IOException
      {
          log.debug( "in putGAN( gan,val,attr) " );
  
          putGAN( key, val, attrE, ICache.LOCAL_INVOKATION );
      }
  
  
      /**
       * Put an element into a group.
       *
       * @param invocation Is the originating method call from a local source
       */
      //public void putGAN( GroupAttrName key, Serializable val, Attributes attrE, boolean updateRemote )
      public void putGAN( GroupAttrName key, Serializable val, Attributes attrE, boolean invocation )
          throws IOException
      {
  
          if ( log.isDebugEnabled() )
          {
              //p( "in putGAN( gan,val,attr,boolean updateRemote) " );
              log.debug( "in putGAN( gan,val,attr,boolean invocation) " );
              if ( invocation == ICache.LOCAL_INVOKATION )
              {
                  log.debug( "invocation is LOCAL" );
              }
              else
              {
                  log.debug( "invocation is NOT Local" );
              }
          }
  
          writeLock( key.groupId );
          try
          {
  
              // update the attribute.
              //updateCaches(key, val, attrE, INCLUDE_REMOTE_CACHE);
              CacheElement ce = new CacheElement( this.getCacheName(), key, val );
              ce.setAttributes( attrE );
  
              if ( log.isDebugEnabled() )
              {
                  log.debug( "putGAN( gan,val,attr,boolean invocation) > updating group attribute via super" );
              }
  
              // SEND THE ELEMENT IF THE INVOCATION WAS LOCAL
              // decide what to do with this item
              boolean updateRemote = false;
              if ( invocation == ICache.LOCAL_INVOKATION )
              {
                  updateRemote = ICache.INCLUDE_REMOTE_CACHE;
              }
              else
              {
                  updateRemote = ICache.EXCLUDE_REMOTE_CACHE;
              }
              super.update( ce, updateRemote );
  
              // UPDATE THE ATTRIBUTENAME LIST, get it first
              GroupId groupId = new GroupId( this.getCacheName(), key.groupId );
              HashSet attrNameSet = null;
              attrNameSet = ( HashSet ) systemGroupIdCache.get( groupId.key, false );
  
              if ( attrNameSet == null )
              {
                  attrNameSet = new HashSet();
              }
              attrNameSet.add( key.attrName );
  
              if ( log.isDebugEnabled() )
              {
                  log.debug( "putGAN( gan,val,attr,boolean invocation) > attrNameSet.size()  = " + attrNameSet.size() );
              }
  
              CacheElement ceID = new CacheElement( this.getCacheName(), groupId.key, attrNameSet );
              ceID.setAttributes( attrE );
  
              // DO NOT SEND THE UPDATE LIST REMOTELY
              // THE ELEMENT WILL BE SENT AND THE LIST MAINTAINED REMOTELY
              systemGroupIdCache.updateExclude( ceID, EXCLUDE_REMOTE_CACHE );
              // could use the updateGroupAttr method?
  
          }
          finally
          {
              locker.done( key.groupId );
          }
      }
  
  
      /** Description of the Method */
      protected void createGroup( String group )
          throws CacheException
      {
          createGroup( group, this.attr );
      }
  
  
      /** Description of the Method */
      protected void createGroup( String group, Attributes attrE )
          throws CacheException
      {
          // update the attribute name set.
          GroupId groupId = new GroupId( this.getCacheName(), group );
          HashSet attrNameSet = null;
  
          //attrNameSet = (HashSet)super.get(groupId.key);
          try
          {
              attrNameSet = ( HashSet ) systemGroupIdCache.get( groupId.key );
          }
          catch ( IOException ioe )
          {
          }
  
          if ( attrNameSet == null )
          {
              attrNameSet = new HashSet();
          }
          else
          {
              throw new CacheException( "createGroup(group,attr) > group " + group + " already exists " );
          }
          try
          {
              CacheElement ceID = new CacheElement( this.getCacheName(), groupId.key, attrNameSet );
              ceID.setAttributes( attrE );
              //updateCaches(groupId.key, attrNameSet, attrE );
              //super.update( ceID, EXCLUDE_REMOTE_CACHE );
              systemGroupIdCache.update( ceID, EXCLUDE_REMOTE_CACHE );
  
          }
          catch ( IOException ioe )
          {
          }
      }
  
  
      /**
       * Overrides to provide special handling for GroupAttrName remove-operation.
       */
      public boolean remove( Serializable key )
      {
          log.debug( "in basic remove" );
  
          // if expired super will call remove and we can't have a lock
          // need a third method
          return remove( key, ICache.LOCAL_INVOKATION );
      }// rmove
  
  
      /**
       * Easier to classify and send to other methods than relying on type
       * overriding. removeGAN could be called remove
       *
       * @param invocation Is the originating method call from a local source
       */
      public boolean remove( Serializable key, boolean invocation )
      {
  
          // THIS IS A GROUP ELEMENT
          if ( key instanceof GroupAttrName )
          {
              if ( log.isDebugEnabled() )
              {
                  log.debug( "calling removeGAN" );
                  if ( invocation == ICache.LOCAL_INVOKATION )
                  {
                      log.debug( "invokation is LOCAL" );
                  }
                  else
                  {
                      log.debug( "invokation is NOT Local" );
                  }
              }
              return removeGAN( ( GroupAttrName ) key, invocation );
          }
  
          // THIS IS A GROUP ID
          if ( key instanceof GroupId )
          {
              if ( log.isDebugEnabled() )
              {
                  log.debug( "call removeGI" );
                  if ( invocation == ICache.LOCAL_INVOKATION )
                  {
                      log.debug( "invokation is LOCAL" );
                  }
                  else
                  {
                      log.debug( "invokation is NOT Local" );
                  }
              }
              return removeGI( ( GroupId ) key, invocation );
          }
  
          // NOT GROUP RELATED
          if ( log.isDebugEnabled() )
          {
              log.debug( "call super.remove, " + invocation + " for " + key );
              if ( invocation == ICache.LOCAL_INVOKATION )
              {
                  log.debug( "invokation is LOCAL" );
              }
              else
              {
                  log.debug( "invokation is NOT Local" );
              }
          }
          return super.remove( key, invocation );
      }// end remove
  
  
      /**
       * Special handling for GroupAttrName remove-operation. Provides write lock
       * and automatic attribute name set update. <br>
       * <br>
       * Note: there is the possibility that all the remove-cache-events for all
       * group attribute names are queued and pending to be processed. Meanwhile,
       * the get-opeation for the attrbute name set will return with a size > 0.
       * Hence, when a groupn is invalidated, it's necessary to queue a
       * remove-attribute-name-set request to clean up garbage due to this race
       * condition.
       *
       * @param invocation Is the originating method call from a local source
       */
      public boolean removeGAN( GroupAttrName key, boolean invocation )
      {
  
          boolean ret;
          if ( log.isDebugEnabled() )
          {
              log.debug( "in removeGAN" );
              if ( invocation == ICache.LOCAL_INVOKATION )
              {
                  log.debug( "invocation is LOCAL" );
              }
              else
              {
                  log.debug( "invocation is NOT Local" );
              }
  
          }
  
          // TODO: fix locking, got too nested and confusing
          //writeLock(key.groupId);
          try
          {
  
              // REMOVE THE ELEMENT
              ret = super.remove( key, invocation );
  
              // UPDATE THE LIST, remove item -- 3rd arg
              updateGroupAttrNameSet( key, invocation, true );
  
          }
          finally
          {
              //locker.done(key.groupId);
          }
          return ret;
      }
  
  
      /**
       * Handles removal, update, and insertion of items into the attrNameSet for
       * a group cache region. The Group Cache listener called the add when it
       * gets a put though it may remove the item it referes to, depending ont he
       * configuration. This saves on local cache space and keeps the list up to
       * date.
       *
       * @param key The key for the group element
       * @param invocation The source of the call
       * @param remove Is this a remove request
       */
      public void updateGroupAttrNameSet( GroupAttrName key, boolean invocation, boolean remove )
      {
  
          // update the attribute name set.
          // Note: necessary to use super.get to avoid read lock within the current write lock.
          GroupId groupId = new GroupId( this.getCacheName(), key.groupId );
          HashSet attrNameSet = null;
          CacheElement ce = null;
  
          try
          {
              ce = ( CacheElement ) systemGroupIdCache.get( groupId.key, true, invocation );
          }
          catch ( IOException ioe )
          {
          }
  
          // IF THE NAME SET IS FOUND
          // TODO: move -- INITIAL INSERTION IS CURRENTLY DONE BY THE PUT
          if ( ce != null )
          {
              attrNameSet = ( HashSet ) ce.val;
  
              // HANDLE NON REMOVAL SCENARIOS
              if ( attrNameSet != null || !remove )
              {
                  // THE GROUP HAS BEEN CREATED BUT NOTHING IS IN IT
                  if ( attrNameSet == null )
                  {
                      attrNameSet = new HashSet();
                  }
  
                  if ( remove )
                  {
                      attrNameSet.remove( key.attrName );
                  }
                  else
                  {
                      attrNameSet.add( key.attrName );
                  }
  
                  if ( attrNameSet.size() > 0 )
                  {
                      // update the changed name set.
                      try
                      {
  
                          CacheElement ceID = new CacheElement( this.getCacheName(), groupId.key, attrNameSet );
                          ceID.setAttributes( ce.attr );
                          if ( log.isDebugEnabled() )
                          {
                              log.debug( "updateGroupAttrNameSet((groupAttrname)key,invocation,remove) > calling systemGroupIdCache.update( ceID, EXCLUDE_REMOTE_CACHE )" );
                          }
                          // ALWAYS EXCLUDE THE REMOTE CACHE
                          // TODO: should this be configurable? no
                          systemGroupIdCache.updateExclude( ceID, EXCLUDE_REMOTE_CACHE );
  
                      }
                      catch ( IOException ioe )
                      {
                      }
                  }
  
                  // HANDLE REMOVAL SCENARIOS
                  else if ( remove )
                  {
                      // no more attribute, so remove the name set all together, skipLock = true.
                      //super.remove(groupId, invokation );
                      //removeGI(groupId, invokation, true );
                      try
                      {
                          if ( log.isDebugEnabled() )
                          {
                              log.debug( "calling systemGroupIdCache.remove( groupId.key, EXCLUDE_REMOTE_CACHE )" );
                          }
                          // unlike insertion, removal should go remote if locally invoked
                          boolean updateRemote = false;
                          // DECIDE WHAT TO DO WITH THE LIST
                          if ( invocation == ICache.LOCAL_INVOKATION )
                          {
                              updateRemote = ICache.INCLUDE_REMOTE_CACHE;
                          }
                          else
                          {
                              updateRemote = ICache.EXCLUDE_REMOTE_CACHE;
                          }
                          systemGroupIdCache.remove( groupId.key, updateRemote );
                      }
                      catch ( IOException ioe )
                      {
                      }
                  }
              }
          }
      }
      // end updateGroupAttrNameSet
  
      /**
       * Special handling for GroupId remove-operation. Removes the attribute name
       * set of the session.
       */
      public void removeGI( GroupId groupId )
      {
          log.debug( "removeGI" );
  
          removeGI( groupId, ICache.LOCAL_INVOKATION );
      }
  
  
      /**
       * Skip the lock from the normal remove that is called from the super when
       * an element expires. Keep the read lock method for calls from groupaccess.
       */
      protected boolean removeGI( GroupId groupId, boolean invocation )
      {
          return removeGI( groupId, invocation, false );
      }
  
  
      /**
       * Removes the group id. Low level method. We need a higher level for
       * invalidating the group.
       */
      protected boolean removeGI( GroupId groupId, boolean invocation, boolean skipLock )
      {
  
          boolean ok = false;
  
          // problem with removing expired while getting!
          skipLock = false;
  
          log.debug( "in removeGI" );
  
          if ( !skipLock )
          {
              writeLock( groupId.key );
          }
          try
          {
  
              // unlike insertion, removal should go remote if locally invoked
              boolean updateRemote = false;
              // DECIDE WHAT TO DO WITH THE LIST
              if ( invocation == ICache.LOCAL_INVOKATION )
              {
                  updateRemote = ICache.INCLUDE_REMOTE_CACHE;
              }
              else
              {
                  updateRemote = ICache.EXCLUDE_REMOTE_CACHE;
              }
              ok = systemGroupIdCache.remove( groupId.key, updateRemote );
  
          }
          catch ( IOException ioeg )
          {
          }
          finally
          {
              if ( !skipLock )
              {
                  locker.done( groupId.key );
              }
          }
          return ok;
      }
  
  
      /**
       * Gets the elementAttributes attribute of the GroupCache object
       *
       * @param key Retrieval value for item.
       * @return The elementAttributes value
       */
      public Attributes getElementAttributes( Serializable key )
          throws CacheException, IOException
      {
          CacheElement ce = ( CacheElement ) getCacheElement( key );
          if ( ce == null )
          {
              throw new ObjectNotFoundException( "key " + key + " is not found" );
          }
          return ce.getAttributes();
      }
  }
  
  
  
  
  1.1                  jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/engine/control/group/GroupAttrName.java
  
  Index: GroupAttrName.java
  ===================================================================
  package org.apache.stratum.jcs.engine.control.group;
  
  import java.io.Serializable;
  
  /**
   * Description of the Class
   *
   * @author asmuts
   * @created January 15, 2002
   */
  public class GroupAttrName implements Serializable
  {
      //final GroupId groupId;
      /** Description of the Field */
      public final String groupId;
      final String attrName;
  
  
      /**
       * Constructor for the GroupAttrName object
       *
       * @param groupId
       * @param attrName
       */
      public GroupAttrName( String groupId, String attrName )
      {
          //this.groupId = new GroupId(groupId);
          this.groupId = groupId;
          this.attrName = attrName;
  
          if ( groupId == null || attrName == null )
          {
              throw new IllegalArgumentException( "groupId " + groupId + " and attrName " + attrName + ", must not be null." );
          }
      }
  
  
      /** Description of the Method */
      public boolean equals( Object obj )
      {
          if ( obj == null || !( obj instanceof GroupAttrName ) )
          {
              return false;
          }
          GroupAttrName to = ( GroupAttrName ) obj;
          return groupId.equals( to.groupId ) && attrName.equals( to.attrName );
      }
  
  
      /** Description of the Method */
      public int hashCode()
      {
          return groupId.hashCode() ^ attrName.hashCode();
      }
  
  
      /** Description of the Method */
      public String toString()
      {
          return "[groupId=" + groupId + ", attrName=" + attrName + "]";
      }
  
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>