ix.util.context
Class Context

java.lang.Object
  extended by ix.util.context.Context

public final class Context
extends java.lang.Object

A Context is an object that is used as an additional, often implicit, parameter when accessing values, such as in a "get"-method. Instead of a value being stored directly in a field, the field contains a list of associations from contexts to values, arranged so that they can be searched efficiently. The conventions used in this implementation of contexts are that the associations are held in a chain of ContextLinks, and the relevant context is obtained from an implementation of ContextHolder. So instead of writing something like this in a class definition:

   ValClass field = new FieldValue();

   ValClass getField() {
       return field;
   }

   void setField(ValClass value) {
       field = value;
   }
 
you would write something like this:
   ContextLink field = new ContextLink(new FieldValue());

   // Here one holder used with all fields, and the holder
   // is obtained when this object is created.
   ContextHolder contextHolder = Context.getContextHolder();

   ValClass getField() {
       Context c = contextHolder.getContext();
       return (ValClass)Context.getInContext(field, c);
   }

   void setField(ValClass value) {
       Context c = contextHolder.getContext();
       Context.setInContext(field, c, value);
   }
 

An alternative is to use objects that hide some of the details. Here is the same example using a ContextValue:

   // Here one holder used with all fields, and the holder
   // is obtained when this object is created.
   ContextHolder contextHolder = Context.getContextHolder();

   ContextValue field = new ContextValue(contextHolder, new FieldValue());

   ValClass getField() {
       return (ValClass)field.get();
   }

   void setField(ValClass value) {
       field.set(value);
   }
 
Since the defaut holder used when a ContextValue is constructed is the one returned by Context.getContextHolder(), which is what ContextValue uses by default, the example can be simplified further to:
   ContextValue field = new ContextValue(new FieldValue());

   ValClass getField() {
       return (ValClass)field.get();
   }

   void setField(ValClass value) {
       field.set(value);
   }
 

A context has few properties of its own. It is simply an object with which the values obtained by context-relative accessors may be associated. Contexts are arranged in a tree: each context has a single parent and a list of children. When there is no value directly associated with a context, a value is inherited from the nearest ancestor context that does have a directly associated value. However, when a value is assigned in a context, it is always associated directly with that context, and the associations between ancestor contexts and values are not changed. This makes it possible to protect the values associated with a context, while still being able to access them, by moving to a descendent context.

An efficient search for the value associated with a context, or inherited from an ancestor, is accomplished by exploiting context numbers. Every context has a number which is assigned when it is created, and newer contexts have higher numbers than older ones. In particular, a context has a higher number than any of its ancestors. The chain of ContextLinks for a given field has links for higher-numbered (newer) contexts first. The algorithm for finding the right value is therefore as follows:

  1. Initialize target to the desired context and chain to the relevant chain of ContextLinks.
  2. Discard entries for contexts newer than target from the front of chain. If chain becomes null, then there is no value for the current context.
  3. At this point, the first of the remaining entries in chain should be for target or for a context older than target. If it's for target, then we're done: return the associated value. Otherwise, set target to the parent of target and return to step 2.
The getInContext method implements that algorithm.

Context-holders are used for two reasons. First, they make it unnecessary to pass contexts as parameters to "get"- and "set"-methods. This makes "context-layered" objects look much more like ordinary objects. Second, a context-holder may be shared by many objects, so that they all change context at once.

However, there is no single way of managing context-holders that is right for every case. In some applications, a single, global context-holder can be used. In others, a number of more local context-holders will be needed.

These problems are partly addressed by context-holding "strategies". A holding strategy provides a method that returns a context-holder, and the Context class holds a current (global) strategy. The static method Context.getContextHolder() asks the current strategy for a holder.

When using contexts, it is typical to fix the holder used by an object when the object is created (as in the examples above). Otherwise, every access to a context-dependent value would involve asking a strategy for a holder and then asking the holder for its current context, rather than just asking a holder for its current context.

See Also:
ContextLink, ContextHolder, ContextHoldingStrategy, GlobalHoldingStrategy, ThreadLocalHoldingStrategy, ContextValue

Field Summary
(package private)  java.util.List<Context> children
          A collection of this context's children.
(package private) static ContextHoldingStrategy contextHoldingStrategy
          The current context-holding strategy.
(package private) static long count
          The number of contexts that have been created.
(package private)  long number
          A number, unique to this context and larger than the number of any context created earlier.
(package private) static java.util.HashMap numberToContextTable
          A mapping from context numbers to (weak references to) contexts.
(package private)  Context parent
          This context's parent context.
static Context rootContext
          A context that is an ancestor of all others.
 
Constructor Summary
Context()
          Create a context with the root context as its parent.
Context(Context parent)
          Create a context with a given parent.
 
Method Summary
static void clearContexts()
          Removes all contexts except the root context.
 void discard()
          Remove this context and all of its descendents from the context tree and the number-to-context table.
 java.util.List<Context> getAncestors()
          Returns a list containing the path from this context back to the root.
 java.util.List<Context> getChildren()
          Returns an unmodifiable view of this context's children.
static Context getContext()
          Returns the current context from the ContextHolder returned by the current ContextHoldingStrategy.
static Context getContext(long n)
          Returns the context that has the indicated number, or null if that context has been discarded or has ceased to exist.
static ContextHolder getContextHolder()
          Returns the context-holder provided by the current context-holding strategy.
static ContextHoldingStrategy getContextHoldingStrategy()
          Returns the current context-holding strategy.
static
<T> T
getInContext(ContextLink<T> cl, Context c)
          Searches a chain of ContextLinks to find the value associated with a given context.
static
<T> T
getInContext(ContextLink<T> cl, Context c, T defaultValue)
          Searches a chain of ContextLinks to find the value associated with a given context and returns a default value if no value can be found.
 long getNumber()
          Returns this context's number.
 Context getParent()
          Returns this context's parent context.
static
<T> ContextLink<T>
getValueLinkInContext(ContextLink<T> cl, Context c)
          Searches a chain of ContextLinks to find the link that contains the value associated with a given context.
static void inContext(ContextHolder h, Context c, java.lang.Runnable r)
          Temporarily changes a context-holder's current context around a call to a Runnable's run() method.
static void inContext(Context c, java.lang.Runnable r)
          Calls inContext(ContextHolder, Context, Runnable) on the ContextHolder returned by the current ContextHoldingStrategy.
static Context popContext()
          Calls popContext(ContextHolder) on the ContextHolder returned by the current ContextHoldingStrategy
static Context popContext(ContextHolder h)
          Moves the specified context-holder to the parent of its current context.
static void printContextTree()
          Prints a description of the current context tree on Debug.out.
static Context pushContext()
          Calls pushContext(ContextHolder) on the ContextHolder returned by the current ContextHoldingStrategy.
static Context pushContext(ContextHolder h)
          Moves the specified context-holder to a new child of its current context and returns that new context.
static void setContext(Context c)
          Sets the context in the ContextHolder returned by the current ContextHoldingStrategy.
static void setContextHoldingStrategy(ContextHoldingStrategy s)
          Sets the current context-holding strategy.
static
<T> void
setInContext(ContextLink<T> cl, Context c, T value)
          Modifies a chain of ContextLinks to associate a value directly with a given context.
 java.lang.String toString()
           
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

count

static long count
The number of contexts that have been created.


numberToContextTable

static java.util.HashMap numberToContextTable
A mapping from context numbers to (weak references to) contexts.


rootContext

public static final Context rootContext
A context that is an ancestor of all others. The root context is often used for default values.

Unlike any other context, the root context's parent is null.


contextHoldingStrategy

static ContextHoldingStrategy contextHoldingStrategy
The current context-holding strategy.

See Also:
getContextHoldingStrategy(), setContextHoldingStrategy(ContextHoldingStrategy s), getContextHolder()

number

final long number
A number, unique to this context and larger than the number of any context created earlier.


parent

final Context parent
This context's parent context.


children

final java.util.List<Context> children
A collection of this context's children.

Constructor Detail

Context

public Context()
Create a context with the root context as its parent.

The constructor is also used once to create the root context itself, and then it's arranged for the root context's parent to be null.


Context

public Context(Context parent)
Create a context with a given parent. If the parent is null, the root context will be used.

Method Detail

getNumber

public long getNumber()
Returns this context's number.


getParent

public Context getParent()
Returns this context's parent context.


getAncestors

public java.util.List<Context> getAncestors()
Returns a list containing the path from this context back to the root. This method is used primarily for debugging output.


getChildren

public java.util.List<Context> getChildren()
Returns an unmodifiable view of this context's children.


discard

public void discard()
Remove this context and all of its descendents from the context tree and the number-to-context table.


toString

public java.lang.String toString()
Overrides:
toString in class java.lang.Object

getContext

public static Context getContext()
Returns the current context from the ContextHolder returned by the current ContextHoldingStrategy.

See Also:
ContextHolder.getContext()

getContext

public static Context getContext(long n)
Returns the context that has the indicated number, or null if that context has been discarded or has ceased to exist.


setContext

public static void setContext(Context c)
Sets the context in the ContextHolder returned by the current ContextHoldingStrategy.

See Also:
ContextHolder.setContext(Context)

clearContexts

public static void clearContexts()
Removes all contexts except the root context. After this, the root context will have no children, and the only context accessible from its number will be the root context. Finally, it calls the ContextHoldingStrategy.clearContexts() method of the current ContextHoldingStrategy. The strategy should set the current context of any holders it knows about to the root context.


getContextHoldingStrategy

public static ContextHoldingStrategy getContextHoldingStrategy()
Returns the current context-holding strategy.

Initially, the strategy is one that provides a single, global context holder.

See Also:
GlobalHoldingStrategy, ThreadLocalHoldingStrategy

setContextHoldingStrategy

public static void setContextHoldingStrategy(ContextHoldingStrategy s)
Sets the current context-holding strategy.


getContextHolder

public static ContextHolder getContextHolder()
Returns the context-holder provided by the current context-holding strategy.

See Also:
getContextHoldingStrategy()

getInContext

public static <T> T getInContext(ContextLink<T> cl,
                                 Context c)
Searches a chain of ContextLinks to find the value associated with a given context.

Returns:
an Object or null

getInContext

public static <T> T getInContext(ContextLink<T> cl,
                                 Context c,
                                 T defaultValue)
Searches a chain of ContextLinks to find the value associated with a given context and returns a default value if no value can be found.


getValueLinkInContext

public static <T> ContextLink<T> getValueLinkInContext(ContextLink<T> cl,
                                                       Context c)
Searches a chain of ContextLinks to find the link that contains the value associated with a given context. Note that the link may be for an ancestor of the specified context.

Returns:
a ContextLink or null

setInContext

public static <T> void setInContext(ContextLink<T> cl,
                                    Context c,
                                    T value)
Modifies a chain of ContextLinks to associate a value directly with a given context.


inContext

public static void inContext(ContextHolder h,
                             Context c,
                             java.lang.Runnable r)
Temporarily changes a context-holder's current context around a call to a Runnable's run() method.


pushContext

public static Context pushContext(ContextHolder h)
Moves the specified context-holder to a new child of its current context and returns that new context.


popContext

public static Context popContext(ContextHolder h)
Moves the specified context-holder to the parent of its current context.


pushContext

public static Context pushContext()
Calls pushContext(ContextHolder) on the ContextHolder returned by the current ContextHoldingStrategy.


popContext

public static Context popContext()
Calls popContext(ContextHolder) on the ContextHolder returned by the current ContextHoldingStrategy


inContext

public static void inContext(Context c,
                             java.lang.Runnable r)
Calls inContext(ContextHolder, Context, Runnable) on the ContextHolder returned by the current ContextHoldingStrategy.


printContextTree

public static void printContextTree()
Prints a description of the current context tree on Debug.out. Children appear after their parent, indented one more level.