You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by do...@apache.org on 2002/04/26 07:01:07 UTC

cvs commit: jakarta-avalon-excalibur/threadcontext/src/scratchpad LayeredThreadContext.java Layer.java

donaldp     02/04/25 22:01:07

  Added:       threadcontext/src/scratchpad LayeredThreadContext.java
                        Layer.java
  Log:
  Move the layered stuff to a scratchpad area as it has never really worked anyway and ThreadContext needs to be stabilized and released soon.
  
  Revision  Changes    Path
  1.1                  jakarta-avalon-excalibur/threadcontext/src/scratchpad/LayeredThreadContext.java
  
  Index: LayeredThreadContext.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.excalibur.threadcontext;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  
  /**
   * The <code>LayeredThreadContext</code> defines a set of data
   * that is associated with a particular thread. This is a useful
   * feature for many of the same reasons as <code>ThreadContext</code>
   * is useful.
   *
   * <p>The difference between <code>LayeredThreadContext</code> and
   * <code>ThreadContext</code> is the presence of Layers. When accessing
   * a variable from the context the system will check the top layer. If
   * the variable is not in the top layer it will check the layer underneath
   * and so on until the variable is found or there are no more layers or
   * a "divider" layer occurs.</p>
   *
   * <p>These variables are managed by the LayeredThreadContext. However as it
   * is not possible to inject code to be executed at the start of a
   * thread, new threads may not be activated and the variables may not
   * be set appropriately. In such cases it is recomended that the developer
   * use <code>InheritableThreadLocal</code> as the underlying representation
   * of the variable. By doing this the <code>InheritableThreadLocal</code>
   * will maintain the appropriate state in newly created Thread.</p>
   *
   * <p>The policy chosend to manage such state is pluggable by the user.
   * It is expected developers will provide a policy object that will manage
   * thread local variables. For instance an application server may choose to
   * keep the name of the application, the Subject it is running as and perhaps
   * other state in such variables.</p>
   *
   * <p>Note that the idea for this code was derived from the HPs CSF framework.</p>
   *
   * @author <a href="mailto:peter@apache.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2002/04/26 05:01:07 $
   */
  public final class LayeredThreadContext
  {
      ///Permission used to guard setThreadContext method.
      private static final RuntimePermission c_setThreadContextPermission =
          new RuntimePermission( "LayeredThreadContext.setThreadContext" );
  
      ///Permission used to guard push method.
      private static final RuntimePermission c_pushPermission =
          new RuntimePermission( "LayeredThreadContext.push" );
  
      private static final InheritableThreadLocal c_context = new CloningInheritableThreadLocal();
  
      ///Accessor object used to provide policy with access to variables in context
      private final ThreadContextAccessor m_accessor = new InnerThreadContextAccessor();
  
      ///The policy for ThreadContext
      private final ThreadContextPolicy m_policy;
  
      ///The list of Layers
      private final ArrayList m_layers = new ArrayList();
  
      /**
       * This variable is set to the thread that the ThreadContext
       * is currently active on. A ThreadContext can not be active
       * on multiple threads at the same time.
       */
      private Thread m_activeThread;
  
      /**
       * Retrieve the LayeredThreadContext associated with the current thread.
       *
       * @return the LayeredThreadContext associated with the current thread.
       */
      public static LayeredThreadContext getThreadContext()
      {
          return (LayeredThreadContext)c_context.get();
      }
  
      /**
       * Set the LayeredThreadContext associated with the current thread.
       * This code will also call <code>deactivate()</code> on the old
       * <code>LayeredThreadContext</code> if present and <code>activate()</code>
       * on new <code>LayeredThreadContext</code> (if not null).
       *
       * @param threadContext the new LayeredThreadContext
       * @throws SecurityException if the caller does not have permission to set thread pool
       * @throws IllegalArgumentException if the specified context is already bound to a thread
       */
      public static void setThreadContext( final LayeredThreadContext threadContext )
          throws SecurityException
      {
          final SecurityManager securityManager = System.getSecurityManager();
          if( null != securityManager )
          {
              securityManager.checkPermission( c_setThreadContextPermission );
          }
  
          if( threadContext.isActive() )
          {
              throw new IllegalArgumentException( "Specified ThreadContext is already " +
                                                  "bound to a thread" );
          }
  
          final LayeredThreadContext oldThreadContext = (LayeredThreadContext)c_context.get();
          if( null != oldThreadContext )
          {
              oldThreadContext.deactivate();
          }
  
          c_context.set( threadContext );
          if( null != threadContext )
          {
              threadContext.activate();
          }
      }
  
      /**
       * Default constructor to create an empty <code>LayeredThreadContext</code>
       * with specified policy.
       */
      public LayeredThreadContext( final ThreadContextPolicy policy )
      {
          if( null == policy )
          {
              throw new NullPointerException( "policy property is null" );
          }
  
          m_policy = policy;
      }
  
      /**
       * Pop layers off the top of context stack until you
       * find a layer that has a key that matches specified key.
       *
       * <p>Note that no security check is performed because it is expected
       * that anyone with the correct key is allowed to call pop() for the
       * matching layer.</p>
       *
       * @param key the layer key
       * @exception IllegalArgumentException if no layer matches key
       */
      public synchronized void pop( final Object key )
          throws IllegalArgumentException
      {
          final int size = m_layers.size();
          final int top = size - 1;
          for( int i = top; i >= 0; i-- )
          {
              final Layer layer = (Layer)m_layers.get( i );
              if( layer.matchesKey( key ) )
              {
                  for( int j = top; j >= i; j-- )
                  {
                      m_layers.remove( j );
                  }
                  return;
              }
          }
  
          throw new IllegalArgumentException( "Unknown key " + key );
      }
  
      /**
       * Push a layer onto context stack with specified key.
       * Add entries to layer as specified in map and make the layer
       * a "divider" layer if isDivider == true.
       *
       * @param key the layer key
       * @param map the map of values to place in layer
       * @param isDivider true if the layer is to be a divider layer
       * @exception IllegalArgumentException if the map contains invalid entries
       */
      public synchronized void push( final Object key, final Map map, final boolean isDivider )
          throws SecurityException, IllegalArgumentException
      {
          final SecurityManager securityManager = System.getSecurityManager();
          if( null != securityManager )
          {
              securityManager.checkPermission( c_pushPermission );
          }
  
          final Map data = new HashMap();
  
          final Iterator keys = map.keySet().iterator();
          while( keys.hasNext() )
          {
              final Object keyValue = keys.next();
              final Object value = map.get( keyValue );
              final String keyString = keyValue.toString();
  
              m_policy.verifyKeyValue( keyString, value );
              data.put( keyString, value );
          }
  
          m_layers.add( new Layer( key, data, isDivider ) );
      }
  
      /**
       * Utility method to search layers to retrieve value for key.
       *
       * @param key the key to look for
       * @return the Object found or null
       */
      synchronized Object contextGet( final String key )
      {
          final int size = m_layers.size();
          final int top = size - 1;
          for( int i = top; i >= 0; i-- )
          {
              final Layer layer = (Layer)m_layers.get( i );
              if( layer.containsKey( key ) )
              {
                  return layer.get( key );
              }
  
              //Failed to locate key before divider so return null
              if( layer.isDivider() ) break;
          }
  
          return null;
      }
  
      /**
       * Utility method to search layers to see if key is found.
       *
       * @param key the key to look for
       * @return true if key found, false otherwise
       */
      synchronized boolean contextContainsKey( final String key )
      {
          final int size = m_layers.size();
          final int top = size - 1;
          for( int i = top; i >= 0; i-- )
          {
              final Layer layer = (Layer)m_layers.get( i );
              if( layer.containsKey( key ) )
              {
                  return true;
              }
  
              //Failed to locate key before divider so return false
              if( layer.isDivider() ) break;
          }
  
          return false;
      }
  
      /**
       * Method to allow duplication of ThreadContext for new threads.
       *
       * @return the duplicated context
       */
      synchronized LayeredThreadContext duplicate()
      {
          final LayeredThreadContext context = new LayeredThreadContext( m_policy );
  
          final int size = m_layers.size();
          for( int i = 0; i < size; i++ )
          {
              final Layer layer = (Layer)m_layers.get( i );
  
              //Layers can be shared because they are immutable
              context.m_layers.add( layer );
          }
  
          return context;
      }
  
      /**
       * Determine if ThreadContext is active (ie bound to a thread).
       */
      private boolean isActive()
      {
          return ( null != m_activeThread );
      }
  
      /**
       * Utility method to call activate on policy object.
       */
      private void activate()
      {
          m_policy.activate( m_accessor );
          m_activeThread = Thread.currentThread();
      }
  
      /**
       * Utility method to call deactivate on policy object.
       */
      private void deactivate()
      {
          m_activeThread = null;
          m_policy.deactivate( m_accessor );
      }
  
      /**
       * Class that manages inheritance of ThreadContext between threads.
       */
      private static class CloningInheritableThreadLocal
          extends InheritableThreadLocal
      {
          protected Object childValue( final Object parentValue )
          {
              final LayeredThreadContext context = (LayeredThreadContext)parentValue;
              return context.duplicate();
          }
      }
  
      /**
       * Inner class to offer accessor interface to policy object.
       */
      private class InnerThreadContextAccessor
          implements ThreadContextAccessor
      {
          public boolean containsKey( final String key )
          {
              return contextContainsKey( key );
          }
  
          public Object get( final String key )
          {
              return contextGet( key );
          }
      }
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/threadcontext/src/scratchpad/Layer.java
  
  Index: Layer.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.excalibur.threadcontext;
  
  import java.util.Map;
  
  /**
   * This object represents a Layer in the <code>LayeredThreadContext</code>.
   *
   * Note: LayeredThreadContext assumes Layers are immutable in duplicate() method.
   *
   * @author <a href="mailto:peter@apache.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2002/04/26 05:01:07 $
   */
  final class Layer
  {
      private Object m_key;
      private Map m_map;
      private boolean m_isDivider;
  
      public Layer( final Object key, final Map map, final boolean isDivider )
      {
          m_key = key;
          m_map = map;
          m_isDivider = isDivider;
      }
  
      protected boolean matchesKey( final Object other )
      {
          return m_key.equals( other );
      }
  
      protected boolean isDivider()
      {
          return m_isDivider;
      }
  
      protected boolean containsKey( final String key )
      {
          return m_map.containsKey( key );
      }
  
      protected Object get( final String key )
      {
          return m_map.get( key );
      }
  }
  
  
  
  

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