KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javolution > realtime > Context


1 /*
2  * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
3  * Copyright (C) 2005 - Javolution (http://javolution.org/)
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software is
7  * freely granted, provided that this notice is preserved.
8  */

9 package javolution.realtime;
10
11 import java.util.EmptyStackException;
12 import javolution.util.FastMap;
13
14 /**
15  * <p> This class represents a real-time context (thread-based).
16  * Applications do not have direct access to instances of this class.
17  * {@link Context} methods are always static and typically affect
18  * the first outer context of appropriate type (as defined by the method's
19  * class). In some cases (e.g. <code>LogContext</code> below), context
20  * static methods may affect more than one context instance.</p>
21  *
22  * <p> The scope of a {@link Context} is defined by a <code>try, finally</code>
23  * block statement which starts with a static <code>enter</code> call and
24  * ends with a static <code>exit</code> call. For example:<pre>
25  * LocalContext.enter();
26  * try { // Current thread executes in a local context.
27  * ...
28  * } finally {
29  * LocalContext.exit();
30  * }</pre>
31  * The class of the enter/exit methods identifies the context type.</p>
32  *
33  * <p> Because contexts are thread local, entering/exiting a context is
34  * fast and does not involve any form of synchronization. Nonetheless,
35  * upon thread termination, it is recommended to {@link #clear}
36  * the top-level context to ensure that all the associated resources
37  * are immediately released. For example:<pre>
38  * public class MyThread extends Thread {
39  * public void run() {
40  * try {
41  * ...
42  * } finally {
43  * Context.clear(); // Finalizes all contexts associated
44  * } // to this thread.
45  * }
46  * }</pre></p>
47  *
48  * <p> Context-aware applications may extend this base class to address
49  * system-wide concerns, such as logging, security, performance,
50  * and so forth. For example:<pre>
51  * public class LogContext extends Context {
52  * public static enter(Logger logger) { ... }
53  * public static void log(String msg) { ... }
54  * public static void exit() { ... }
55  * ...
56  * }
57  * ...
58  * LogContext.enter(logger_A);
59  * try {
60  * foo(); // Logs foo with logger_A
61  * LogContext.enter(logger_B);
62  * try {
63  * foo(); // Logs foo with logger_A and logger_B
64  * } finally {
65  * LogContext.exit();
66  * }
67  * } finally (
68  * LogContext.exit();
69  * }
70  * ...
71  * void foo() {
72  * LogContext.log("blah, blah, blah");
73  * }
74  * </pre></p>
75  *
76  * <p> Note: Javolution context programming is somewhat complementary to <a HREF=
77  * "http://www.javaworld.com/javaworld/jw-01-2002/jw-0118-aspect.html">
78  * aspect-oriented programming</a>. Whereas context programming is dynamic
79  * by nature (thread based); AOP is typically code based (ref.
80  * <a HREF="http://eclipse.org/aspectj/">AspectJ</a> tool/compiler).
81  * Both can be used in conjunction to insert custom context code
82  * automatically.</p>
83  *
84  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
85  * @version 1.0, October 4, 2004
86  */

87 public abstract class Context {
88
89     /**
90      * Holds the thread to current context look-up table.
91      * Because look-up tables (with no synchronized read) do not allow
92      * key removal (ref. FastMap documentation). The whole collection
93      * is replaced when dead threads are removed.
94      */

95     private static FastMap ThreadToContext = new FastMap();
96
97     /**
98      * Holds class lock (used when thread-context mapping is changed).
99      */

100     private static final Object LOCK = new Object();
101
102     /**
103      * Holds the thread owner of this context.
104      */

105     private final Thread _owner;
106
107     /**
108      * Holds a shortcut to the pool context for this context or
109      * <code>null</code> if none (heap context).
110      */

111     private PoolContext _poolContext;
112
113     /**
114      * Holds the outer context of this context or <code>null</code>
115      * if none (root context).
116      */

117     private Context _outer;
118
119     /**
120      * Holds the last inner context used by the thread owner of this context.
121      */

122     private Context _inner;
123
124     /**
125      * Default constructor.
126      * This constructor should be called from the thread owner of the context.
127      */

128     protected Context() {
129         _owner = Thread.currentThread();
130         if (this instanceof PoolContext) {
131             _poolContext = (PoolContext) this;
132         }
133     }
134
135     /**
136      * Clears the current contexts and all its inner contexts. This method
137      * call {@link #dispose} on this context and its inner contexts.
138      */

139     public static void clear() {
140         Context current = Context.currentContext();
141         if (current._outer == null) { // Root context is being cleared.
142
synchronized (Context.LOCK) { // Remove mapping.
143
Context.ThreadToContext.put(current._owner, null);
144             }
145         } else if (current._outer._inner == current) {
146             current._outer._inner = null;
147         }
148         for (Context ctx = current; ctx != null; ctx = ctx._inner) {
149             ctx.dispose();
150         }
151     }
152
153     /**
154      * Returns the context for the current thread. The default context
155      * is a {@link HeapContext} for normal threads and a {@link PoolContext}
156      * for {@link ConcurrentThread concurrent threads}.
157      *
158      * @return the current context (always different from <code>null</code>).
159      */

160     protected static Context currentContext() {
161         Context ctx = (Context) Context.ThreadToContext.get(Thread
162                 .currentThread());
163         return (ctx != null) ? ctx : newContext();
164     }
165
166     private static Context newContext() {
167         Context ctx = (Thread.currentThread() instanceof ConcurrentThread) ? (Context) new PoolContext()
168                 : new HeapContext();
169         synchronized (Context.LOCK) {
170             cleanupDeadThreads();
171             Context.ThreadToContext.put(ctx._owner, ctx);
172             return ctx;
173         }
174     }
175
176     /**
177      * Returns the thread owner of this {@link Context}. The owner of a
178      * context is the thread which entered the context.
179      * The owner of the {@link #currentContext current} context is always the
180      * current thread but the owner of the current outer context might
181      * be another thread due to concurrency.
182      *
183      * @return the thread owner of this context.
184      */

185     protected final Thread getOwner() {
186         return _owner;
187     }
188
189     /**
190      * Holds the outer context of this {@link Context} or <code>null</code>
191      * if none (root context).
192      *
193      * @return the outer context or <code>null</code> if none (root context).
194      */

195     protected final Context getOuter() {
196         return _outer;
197     }
198
199     /**
200      * Returns the last inner context used by the owner of this context.
201      * This method allows for traversing of the contexts which have
202      * been used by this context's owner.
203      *
204      * @return the outer context or <code>null</code> if none (deepest context).
205      */

206     protected final Context getInner() {
207         return _inner;
208     }
209
210     /**
211      * Pushes a context of specified type as the current context.
212      * This method tries to reuse contexts from the context stack.
213      *
214      * @param contextClass the class of the context to be pushed.
215      * @return the context pushed or <code>null</code> if none found.
216      */

217     protected static Context push(Class contextClass) {
218         Context current = Context.currentContext();
219         Context ctx = current._inner;
220         if (contextClass.isInstance(ctx)) {
221             // All fields members are correctly set.
222
synchronized (Context.LOCK) {
223                 Context.ThreadToContext.put(ctx._owner, ctx);
224                 return ctx;
225             }
226         }
227         // Searches inner stack.
228
while (ctx != null) {
229             ctx = ctx._inner;
230             if (contextClass.isInstance(ctx)) { // Found one.
231
// Detaches.
232
Context next = ctx._inner;
233                 ctx._outer._inner = next;
234                 if (next != null) {
235                     next._outer = ctx._outer;
236                 }
237                 // Reuses.
238
push(ctx);
239                 return ctx;
240             }
241         }
242         return null;
243     }
244
245     /**
246      * Pushes the specified context as the current context. The previous
247      * context becomes the {@link #getOuter} of the specified context.
248      *
249      * @param ctx the new current context.
250      */

251     protected static void push(Context ctx) {
252         Context current = Context.currentContext();
253         ctx._outer = current;
254         ctx._inner = ctx._outer._inner;
255         ctx._outer._inner = ctx;
256         if (ctx._inner != null) {
257             ctx._inner._outer = ctx;
258         }
259         synchronized (Context.LOCK) {
260             Context.ThreadToContext.put(ctx._owner, ctx);
261         }
262         if (!(ctx instanceof PoolContext) && !(ctx instanceof HeapContext)) {
263             // Inherits pool context.
264
ctx._poolContext = ctx._outer._poolContext;
265         }
266     }
267
268     /**
269      * Pops the current context from the context stack. The {@link #getOuter}
270      * of the current context becomes the current context.
271      *
272      * @return the previous {@link #currentContext}.
273      * @throws EmptyStackException if the current thread is not the owner
274      * of the current context.
275      * @see #getOwner
276      */

277     protected static Context pop() {
278         Context ctx = Context.currentContext();
279         if ((ctx._outer != null) && (ctx._outer._owner == ctx._owner)) {
280             synchronized (Context.LOCK) {
281                 Context.ThreadToContext.put(ctx._owner, ctx._outer);
282             }
283             return ctx;
284         } else {
285             throw new EmptyStackException();
286         }
287     }
288
289     /**
290      * Disposes of this context resources. This method is called by the
291      * {@link #clear} method.
292      */

293     protected abstract void dispose();
294
295     /**
296      * Returns the pool context for this context.
297      *
298      * @return the pool context for this context or <code>null</code> if
299      * none (heap context).
300      */

301     final PoolContext poolContext() {
302         return _poolContext;
303     }
304
305     /**
306      * Sets the outer of this context (used by concurrent threads only).
307      *
308      * @param outer the new outer context.
309      */

310     final void setOuter(Context outer) {
311         _outer = outer;
312     }
313
314     /**
315      * Dissociates contexts from dead threads (for GC) and removes
316      * the threads objects themselves when more than 256 of them.
317      */

318     private static void cleanupDeadThreads() {
319         int deadThreadCount = 0;
320         for (FastMap.Entry e = Context.ThreadToContext.headEntry(), end = Context.ThreadToContext
321                 .tailEntry(); (e = e.getNextEntry()) != end;) {
322             Thread thread = (Thread) e.getKey();
323             if (!thread.isAlive()) {
324                 Context.ThreadToContext.put(thread, null);
325                 deadThreadCount++;
326             }
327         }
328         if (deadThreadCount > 256) { // Remove thread objects themselves.
329
// Replaces the whole map to keep read access unsynchronized.
330
FastMap tmp = new FastMap(Context.ThreadToContext.size());
331             for (FastMap.Entry e = Context.ThreadToContext.headEntry(), end = Context.ThreadToContext
332                     .tailEntry(); (e = e.getNextEntry()) != end;) {
333                 Thread thread = (Thread) e.getKey();
334                 if (thread.isAlive()) {
335                     tmp.put(thread, e.getValue());
336                 }
337             }
338             Context.ThreadToContext = tmp;
339         }
340     }
341 }
Popular Tags