/*
* Javolution - Java(TM) Solution for Real-Time and Embedded Systems
* Copyright (C) 2005 - Javolution (http://javolution.org/)
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software is
* freely granted, provided that this notice is preserved.
*/
package javolution37.javolution.realtime;
import java.lang.IllegalStateException;
import java.lang.ThreadLocal;
import javax.realtime.MemoryArea;
import java.util.EmptyStackException;
import javolution37.javolution.JavolutionError;
/**
* This class represents a real-time context; they are typically
* thread-local but they can also be associated to particular objects.
*
* This package provides few predefined contexts:
* - {@link LocalContext} - To define locally
* scoped setting held by {@link LocalReference}
* - {@link PoolContext} - To transparently reuse objects created using
* an {@link ObjectFactory} instead of a constructor.
* - {@link ConcurrentContext} - To take advantage of concurrent
* algorithms on multi-processors systems.
* - {@link LogContext} - For thread-based or object-based logging
* capability.
* Note:
java.util.logging provides class-based
* logging (based upon class hierarchy).
*
* Context-aware applications may extend the context base class or any
* predefined contexts in order to facilitate separation of concern
* (e.g. logging, security, performance and so forth).
*
* The scope of a {@link Context} should be surrounded by a try,
* finally block statement to ensure correct behavior in case
* of exceptions being raised. For example:[code]
* LocalContext.enter();
* try
* Length.showAs(Unit.FOOT); // Thread-Local setting (no impact on other threads)
* ...
* } finally {
* LocalContext.exit();
* }
*
* public class Calculator {
* private PoolContext _pool = new PoolContext();
* public void execute(Runnable logic) {
* PoolContext.enter(_pool);
* try {
* logic.run(); // Executes the logic using this calculator pool.
* } finally {
* PoolContext.exit(_pool); // Recycles used objects all at once.
* }
* }
* }[/code]
*
* Finally, context instances can be serialized/deserialized in
* {@link javolution37.javolution.xml.XmlFormat xml format}. For example,
* applications may want to load pool contexts at start-up to limit
* the number of object creation at run-time (and therefore reducing
* the worst-case execution time).
*
* @author Jean-Marie Dautelle
* @version 3.7, January 1, 2006
*/
public abstract class Context {
/**
* Holds the context for the current thread.
*/
private static final ThreadLocal CURRENT = new ThreadLocal() {
protected Object initialValue() {
Thread thread = Thread.currentThread();
Context ctx = new HeapContext();
ctx._owner = thread;
return ctx;
}
};
/**
* Holds a shortcut to the pool context or
* null if none (heap context).
*/
transient PoolContext inheritedPoolContext;
/**
* Holds a shortcut to the local context or
* null if none (global context).
*/
transient LocalContext inheritedLocalContext;
/**
* Holds the current thread owner of this context.
*/
private transient Thread _owner;
/**
* Holds the current outer context of this context or null
* if none (root context).
*/
private transient Context _outer;
/**
* Holds contexts available for reuse.
*
* @see #enter(Class)
*/
private Context _inner;
/**
* Default constructor.
*/
protected Context() {
}
/**
* Returns the current context for the current thread. The default context
* is a {@link HeapContext} for normal threads and a {@link PoolContext}
* for {@link ConcurrentThread concurrent threads}.
*
* @return the current context (always different from null).
*/
public static Context current() {
Context ctx = Context.Cache;
return ctx._owner == Thread.currentThread() ?
ctx : (Context.Cache = (Context) Context.CURRENT.get());
}
// Holds the latest context accessed and set (hopefully in cache memory).
private static Context Cache = (Context) Context.CURRENT.get();
/**
* Returns the current owner of this context. The owner of a
* context is the thread which entered the context.
*
* @return the thread owner of this context.
*/
public final Thread getOwner() {
return _owner;
}
/**
* Holds the outer context of this context or null
* if none (root context).
*
* @return the outer context or null if none (root context).
*/
public final Context getOuter() {
return _outer;
}
/**
* Clears this context and releases any associated resource. Dead threads
* contexts are automatically cleared before finalization.
*/
public void clear() {
if (_inner != null)
_inner.clear();
_inner = null;
}
/**
* The action to be performed after this context becomes the current
* context.
*/
protected abstract void enterAction();
/**
* The action to be performed before this context is no more the current
* context.
*/
protected abstract void exitAction();
/**
* Enters the specified context.
*
* @param context the context being entered.
* @throws IllegalStateException if this context is currently in use.
*/
public static void enter(Context context) {
if (context._owner != null)
throw new IllegalStateException("Context is currently in use");
Context current = Context.current();
context._outer = current;
context._owner = current._owner;
Context.CURRENT.set(context);
Context.Cache = context;
context.inheritedPoolContext = current.inheritedPoolContext;
context.inheritedLocalContext = current.inheritedLocalContext;
context.enterAction();
}
/**
* Exits the specified context. The {@link #getOuter outer} context
* becomes the current context.
*
* @param context the context being entered.
* @throws IllegalStateException if this context is not the current context.
*/
public static void exit(Context context) {
if (context._owner != Thread.currentThread())
throw new IllegalStateException(
"Context is not used by the current thread");
if ((context._outer == null) || (context._outer._owner != context._owner))
throw new EmptyStackException();
try {
context.exitAction();
} finally {
Context.CURRENT.set(context._outer);
Context.Cache = context._outer;
context._outer = null;
context._owner = null;
}
}
/**
* Enters a context of specified class. This method searches the current
* context for a matching context to reuse (previously used context of
* same class); if none found a new instance is created using the specified
* class no-arg constructor from the same memory area as the current
* context.
*
* @param contextClass the type of context to be entered.
* @return the context being entered.
*/
protected static Context enter(Class contextClass) {
Context current = Context.current();
// Searches inner contexts.
Context outer = current;
Context context = current._inner;
while (context != null) {
if (contextClass.equals(context.getClass())) { // Found one.
outer._inner = context._inner; // Detaches.
break;
}
outer = context;
context = context._inner;
}
if (context == null) { // None found.
try {
context = (Context) MemoryArea.getMemoryArea(outer).newInstance(contextClass);
} catch (InstantiationException e) {
throw new JavolutionError(e);
} catch (IllegalAccessException e) {
throw new JavolutionError(e);
}
}
// Attaches as inner of current.
context._inner = current._inner;
current._inner = context;
// Sets outer and owner.
context._outer = current;
context._owner = current._owner;
context.inheritedPoolContext = current.inheritedPoolContext;
context.inheritedLocalContext = current.inheritedLocalContext;
// Sets as current.
Context.CURRENT.set(context);
Context.Cache = context;
context.enterAction();
return context;
}
/**
* Exits the current context which must be of specified type.
*
* @param contextClass the type of context to be exited.
* @return the context being exited.
* @throws java.lang.IllegalStateException if the current context
* is not an instance of the specified class.
*/
protected static Context exit(Class contextClass) {
Context current = Context.current();
if (!contextClass.isInstance(current))
throw new IllegalStateException(
"Current context is not an instance of " + contextClass);
Context outer = current._outer;
if ((outer == null) || (outer._owner != current._owner))
throw new EmptyStackException();
try {
current.exitAction();
return current;
} finally {
Context.CURRENT.set(outer);
Context.Cache = outer;
current._outer = null;
current._owner = null;
}
}
/**
* Sets the current context, used by {@link ConcurrentThread}
* exclusively.
*/
static void setCurrent(PoolContext context, ConcurrentContext outer) {
((Context)context)._outer = outer;
((Context)context)._owner = Thread.currentThread();
Context.CURRENT.set(context);
Context.Cache = context;
context.inheritedPoolContext = context;
context.inheritedLocalContext = outer.inheritedLocalContext;
}
/**
* Returns the current pool context.
*
* @param currentThread the current thread.
* @return the current pool context or null if the current
* thread allocates on the heap.
*/
static PoolContext poolContext(Thread currentThread) {
Context ctx = Context.Cache;
return ctx._owner == currentThread ?
ctx.inheritedPoolContext :
(Context.Cache = (Context) Context.CURRENT.get()).inheritedPoolContext;
}
/**
* Returns the current local context.
*
* @param currentThread the current thread.
* @return the current local context or null if the current
* thread does not run in a local context.
*/
static LocalContext localContext(Thread currentThread) {
Context ctx = Context.Cache;
return ctx._owner == currentThread ?
ctx.inheritedLocalContext :
(Context.Cache = (Context) Context.CURRENT.get()).inheritedLocalContext;
}
}
Ads help maintain this website.