001: /*
002: * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
003: * Copyright (C) 2007 - Javolution (http://javolution.org/)
004: * All rights reserved.
005: *
006: * Permission to use, copy, modify, and distribute this software is
007: * freely granted, provided that this notice is preserved.
008: */
009: package javolution.context;
010:
011: import javolution.xml.XMLSerializable;
012: import j2me.lang.IllegalStateException;
013: import j2me.lang.UnsupportedOperationException;
014: import j2me.lang.ThreadLocal;
015:
016: /**
017: * <p> This class represents an execution context; they can be associated to
018: * particular threads or objects.</p>
019: *
020: * <p> Context-aware applications may extend the context base class or any
021: * predefined contexts in order to facilitate <a
022: * href="package-summary.html#package_description">
023: * separation of concerns</a>.</p>
024: *
025: * <p> The scope of a {@link Context} should be surrounded by a <code>try,
026: * finally</code> block statement to ensure correct behavior in case
027: * of exceptions being raised. For example:[code]
028: * LocalContext.enter(); // Current thread enter a local context.
029: * try
030: * ModuloInteger.setModulus(m); // No impact on other threads!
031: * z = x.times(y); // Multiplication modulo m.
032: * } finally {
033: * LocalContext.exit();
034: * }[/code]</p>
035: *
036: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
037: * @version 5.0, April 15, 2007
038: */
039: public abstract class Context implements XMLSerializable {
040:
041: /**
042: * Holds the root context (top context of all threads).
043: */
044: public static final Context ROOT = new Root();
045:
046: /**
047: * Holds the current context (thread-local).
048: */
049: private static final ThreadLocal CURRENT = new ThreadLocal() {
050: protected Object initialValue() {
051: return ROOT;
052: }
053: };
054:
055: /**
056: * Holds the current owner of this context or <code>null</code> if global
057: * context.
058: */
059: private Thread _owner;
060:
061: /**
062: * Holds the outer context or <code>null</code> if none (root context).
063: */
064: private Context _outer;
065:
066: /**
067: * Holds the factory having produced this context if any (for recycling
068: * purpose upon exit).
069: */
070: private ObjectFactory _factory;
071:
072: /**
073: * Holds the inherited allocator context or <code>null</code>
074: */
075: private AllocatorContext _allocator;
076:
077: /**
078: * Default constructor.
079: */
080: protected Context() {
081: }
082:
083: /**
084: * Returns the current context for the current thread.
085: *
086: * @return the current context.
087: */
088: public static Context getCurrent() {
089: return (Context) Context.CURRENT.get();
090: }
091:
092: /**
093: * Returns the current owner of this context. The owner of a
094: * context is the thread which {@link #enter(Context) entered}
095: * the context and has not yet {@link #exit(Context) exited}.
096: * A context can only have one owner at any given time, although
097: * contexts can be shared by {@link ConcurrentContext concurrent} threads.
098: *
099: * @return the thread owner of this context or <code>null</code>.
100: */
101: public final Thread getOwner() {
102: return _owner;
103: }
104:
105: /**
106: * Returns the outer context of this context or <code>null</code>
107: * if {@link #ROOT}.
108: *
109: * @return the outer context or <code>null</code>.
110: */
111: public final Context getOuter() {
112: return _outer;
113: }
114:
115: /**
116: * Returns the string representation of this context (default
117: * <code>"Instance of " + this.getClass().getName()</code>).
118: *
119: * @return the string representation of this context.
120: */
121: public String toString() {
122: return "Instance of " + this .getClass().getName();
123: }
124:
125: /**
126: * The action to be performed after this context becomes the current
127: * context.
128: */
129: protected abstract void enterAction();
130:
131: /**
132: * The action to be performed before this context is no more the current
133: * context.
134: */
135: protected abstract void exitAction();
136:
137: /**
138: * Enters the specified context.
139: *
140: * @param context the context being entered.
141: * @return the specified context.
142: * @throws IllegalStateException if this context is currently in use.
143: */
144: public static final/*<T extends Context>*//*T*/Context enter(
145: /*T*/Context context) {
146: if (context._owner != null)
147: throw new IllegalStateException(
148: "Context is currently in use");
149: Context current = Context.getCurrent();
150: context._outer = current;
151: context._owner = Thread.currentThread();
152: context._allocator = context instanceof AllocatorContext ? (AllocatorContext) context
153: : current._allocator;
154: Context.CURRENT.set(context);
155: context.enterAction();
156: return (/*T*/Context) context;
157: }
158:
159: /**
160: * Enters a factory produced context of specified type to be recycled
161: * after {@link #exit exiting}.
162: * This method is called by the static <code>enter()</code> method
163: * of specialized contexts. If the context class has no public
164: * no-arg constructor accessible, then the factory for the class should
165: * be {@link ObjectFactory#setInstance explicitely set} (typically
166: * in a static initializer).
167: *
168: * @param contextType the type of context being entered.
169: * @return the context being entered.
170: * @see ObjectFactory#getInstance(Class)
171: */
172: public static final/*<T extends Context>*//*T*/Context enter(
173: Class/*<T>*/contextType) {
174: ObjectFactory factory = ObjectFactory.getInstance(contextType);
175: Context context = (Context) factory.object();
176: context._factory = factory;
177: Context.enter(context);
178: return (/*T*/Context) context;
179: }
180:
181: /**
182: * Exits the current context (the {@link #getOuter outer} context
183: * becomes the current context).
184: *
185: * @return the context which has been exited.
186: * @throws IllegalStateException if this context is the {@link #ROOT}
187: * context.
188: */
189: public static Context exit() {
190: Context context = Context.getCurrent();
191: Context outer = context._outer;
192: if (outer == null)
193: throw new IllegalStateException(Thread.currentThread()
194: + " Cannot exit instance of " + context.getClass());
195: try {
196: context.exitAction();
197: } finally {
198: Context.CURRENT.set(outer);
199: context._outer = null;
200: context._owner = null;
201: context._allocator = null;
202: if (context._factory != null) { // Factory produced.
203: context._factory.recycle(context);
204: context._factory = null;
205: }
206: }
207: return context;
208: }
209:
210: /**
211: * Sets the current context, used by {@link ConcurrentContext}
212: * exclusively.
213: *
214: * @param context the concurrent context.
215: */
216: protected static void setCurrent(ConcurrentContext context) {
217: Context.CURRENT.set(context);
218: }
219:
220: /**
221: * Returns the allocator context used while in this context (shortcut).
222: *
223: * @return the allocator context for this context.
224: */
225: final AllocatorContext getAllocatorContext() {
226: return (_allocator == null) ? AllocatorContext.getDefault()
227: : _allocator;
228: }
229:
230: // Holds the root context definition.
231: private static final class Root extends Context {
232:
233: protected void enterAction() {
234: throw new UnsupportedOperationException(
235: "Cannot enter the root context");
236: }
237:
238: protected void exitAction() {
239: throw new UnsupportedOperationException(
240: "Cannot enter the root context");
241: }
242:
243: };
244:
245: /**
246: * @deprecated {@link #exit()} should be used.
247: */
248: public static final void exit(Context ctx) {
249: Context.exit();
250: }
251:
252: }
|