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>