KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javolution > context > RealtimeObject


1 /*
2  * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
3  * Copyright (C) 2006 - 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.context;
10
11 import j2mex.realtime.MemoryArea;
12 import javolution.JavolutionError;
13 import javolution.text.Text;
14 import javolution.text.TextBuilder;
15
16 /**
17  * <p> This class provides a default implementation of the {@link Realtime}
18  * interface.</p>
19  *
20  * <p> Instances of this class should be created using the inner
21  * {@link Factory Factory} class. For example:[code]
22  * public class Foo extends RealtimeObject {
23  * static final Factory<Foo> FACTORY = new Factory<Foo>() {
24  * protected Foo create() {
25  * return new Foo();
26  * }
27  * };
28  * protected Foo() {} // Default constructor for sub-classes.
29  * public static Foo newInstance() { // Static factory method.
30  * return FACTORY.object();
31  * }
32  *
33  * // Optional (see Realtime interface).
34  * public boolean move(ObjectSpace os) { ... }
35  * }[/code]</p>
36  *
37  * <p> Instances of this class can be immutable. Instances allocated in a
38  * {@link PoolContext pool context} must be {@link #export exported}
39  * (e.g. return value) or {@link #preserve preserved} (e.g. static instance)
40  * if referenced after exiting the pool context.</p>
41  *
42  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
43  * @version 3.7, January 1, 2006
44  */

45 public abstract class RealtimeObject implements Realtime {
46
47     /**
48      * Holds the next object in the pool (or null if object not in the pool).
49      */

50     private transient RealtimeObject _next;
51
52     /**
53      * The pool this object belongs to or <code>null</code> if this object
54      * has been created using a constructor (new keyword).
55      */

56     private transient Factory.Pool _pool;
57
58     /**
59      * Holds the previous object in the pool (or null if object not in the pool).
60      */

61     private transient RealtimeObject _previous;
62
63     /**
64      * Holds the preserve counter.
65      */

66     private transient int _preserved;
67
68     /**
69      * Default constructor.
70      */

71     protected RealtimeObject() {
72     }
73
74     /**
75      * Indicates if this real-time object is a local object (belongs
76      * to the current stack). Local object can safely be recycled or
77      * exported.
78      *
79      * @return <code>true</code> if this object belongs to the current
80      * thread stack; <code>false</code> otherwise (e.g. heap object).
81      */

82     public final boolean isLocal() {
83         if (_pool == null)
84             return false;
85         if (!_pool._inUse)
86             throw new JavolutionError("Reference to inner pool object detected");
87         if (!_pool._isStack) // Heap.
88
return false;
89         return (_pool._user == Thread.currentThread());
90     }
91
92     /**
93      * Returns the <code>String</code> representation of this object.
94      * This method is final to ensure consistency with {@link #toText()}
95      * (which is the method to override).
96      *
97      * @return <code>toText().stringValue()</code>
98      */

99     public final String JavaDoc toString() {
100         return (this instanceof TextBuilder) ? // Shortcut.
101
((TextBuilder) this).stringValue()
102                 : toText().stringValue();
103     }
104
105     /**
106      * Returns the default textual representation of this realtime object.
107      *
108      * @return the textual representation of this object.
109      */

110     public Text toText() {
111         return Text.valueOf(getClass().getName()).concat(Text.valueOf('@'))
112                 .concat(Text.valueOf(System.identityHashCode(this), 16));
113     }
114
115     /**
116      * Exports this object and its <b>local</b> real-time associations out of
117      * the current pool context (equivalent to <code>{@link #move move}
118      * (ObjectSpace.OUTER)</code>).
119      * This method affects only local objects allocated on the stack
120      * and has no effect on heap objects or objects allocated outside of
121      * the current pool context.
122      *
123      * <p>Note: To avoid pool depletion when exporting to outer pool,
124      * the object is actually exchanged with an outer pool object.</p>
125      *
126      * @return <code>this</code>
127      */

128     public final/*<T>*/Object JavaDoc/*{T}*/export() {
129         move(ObjectSpace.OUTER);
130         return (Object JavaDoc/*{T}*/) this;
131     }
132
133     /**
134      * Moves this object and its real-time associations to the heap
135      * (equivalent to <code>{@link #move move}(ObjectSpace.HEAP)</code>).
136      *
137      * @return <code>this</code>
138      */

139     public final/*<T>*/Object JavaDoc/*{T}*/moveHeap() {
140         move(ObjectSpace.HEAP);
141         return (Object JavaDoc/*{T}*/) this;
142     }
143
144     /**
145      * Prevents this object and its real-time associations to be recycled
146      * (equivalent to <code>{@link #move move}(ObjectSpace.HOLD)</code>).
147      * This method increments this object preserved counter.
148      *
149      * @return <code>this</code>
150      * @see #unpreserve
151      */

152     public final/*<T>*/Object JavaDoc/*{T}*/preserve() {
153         move(ObjectSpace.HOLD);
154         return (Object JavaDoc/*{T}*/) this;
155     }
156
157     /**
158      * Allows this object and its real-time associations to
159      * be immediatly recycled if not preserved any more (equivalent to
160      * <code>{@link #move move}(ObjectSpace.STACK)</code>).
161      * This method decrements this object preserved counter.
162      *
163      * @return <code>this</code>
164      * @see #preserve
165      */

166     public final/*<T>*/Object JavaDoc/*{T}*/unpreserve() {
167         move(ObjectSpace.STACK);
168         return (Object JavaDoc/*{T}*/) this;
169     }
170
171     // Implements Realtime interface.
172
public boolean move(ObjectSpace os) {
173         if (_pool == null)
174             return false; // Heap object do not move.
175
if (!_pool._inUse)
176             throw new JavolutionError("Reference to inner pool object detected");
177         if (os == ObjectSpace.OUTER) { // export()
178
if (!_pool._isStack)
179                 return false; // Heap object.
180
if (_pool._user == null)
181                 return false; // Outer object.
182
if (_pool._user != Thread.currentThread()) // Different stack.
183
throw new JavolutionError(
184                         "Cannot export objects from another thread stack");
185             LocalPools outerPools = PoolContext.current().getOuter()
186                     .getLocalPools();
187             Factory.Pool outer = (Factory.Pool) outerPools.getPool(_pool
188                     .getFactory(), false);
189             // Exchanges with outer pool.
190
detach();
191             RealtimeObject outerObj = (RealtimeObject) outer.next();
192             if (outerObj._pool != null) {
193                 outerObj.detach();
194             }
195             outerObj.insertBefore(_pool._activeTail); // Marks unused.
196
outerObj._pool = _pool;
197             insertBefore(outer._next); // Marks used.
198
_pool = outer;
199             return true;
200
201         } else if (os == ObjectSpace.HEAP) { // moveHeap()
202
if (!_pool._isStack)
203                 return false; // Heap object.
204
if ((_pool._user != null)
205                     && (_pool._user != Thread.currentThread())) // Different stack.
206
throw new JavolutionError(
207                         "Cannot move to the heap objects form another thread stack");
208             detach();
209             _pool._size--; // Object removed from pool.
210
_pool = null;
211             _next = null;
212             _previous = null;
213             return true;
214
215         } else if (os == ObjectSpace.HOLD) { // preserve()
216
if (!_pool._isStack)
217                 return false; // Heap object.
218
if ((_pool._user != null)
219                     && (_pool._user != Thread.currentThread())) // Different stack.
220
throw new JavolutionError(
221                         "Cannot preserve objects from another thread stack");
222             if (_preserved++ == 0) {
223                 detach();
224                 insertBefore(_pool._holdTail);
225                 return true;
226             } else {
227                 return false;
228             }
229
230         } else if (os == ObjectSpace.STACK) { // unpreserve()
231
if ((_preserved != 0) && (--_preserved == 0)) {
232                 detach();
233                 insertBefore(_pool._next);
234                 _pool._next = this;
235                 return true;
236             } else {
237                 return false;
238             }
239
240             // Ignores others context space (possible extensions).
241
} else {
242             return true; // Propagates by default.
243
}
244     }
245
246     /**
247      * Inserts this object before the one specified.
248      *
249      * @param the next object after insertion.
250      */

251     final void insertBefore(RealtimeObject next) {
252         _previous = next._previous;
253         _next = next;
254         _next._previous = this;
255         _previous._next = this;
256     }
257
258     /**
259      * Detaches this object from its linked list (but does not reset the
260      * objects variable members).
261      * Note: pool._next should never be detached.
262      */

263     final void detach() {
264         _next._previous = _previous;
265         _previous._next = _next;
266     }
267
268     /**
269      * This abstract class represents the factory responsible for the
270      * creation of {@link RealtimeObject} instances.
271      */

272     public static abstract class Factory/*<T extends RealtimeObject>*/extends
273             ObjectFactory/*<T>*/{
274
275         /**
276          * Default constructor.
277          */

278         protected Factory() {
279         }
280
281         // Overrides.
282
public final Object JavaDoc/*{T}*/object() {
283             // Sligthly faster for the last pool activated
284
// (most likely in the cpu cache or from high priority thread).
285
final Pool pool = _lastActivated;
286             return (pool._user == Thread.currentThread()) ? pool.next()
287                     : currentPool().next();
288         }
289
290         // Overrides.
291
public final void recycle(Object JavaDoc/*{T}*/obj) {
292             Pool pool = ((RealtimeObject) obj)._pool;
293             if (pool == null) {
294                 currentPool().recycle(obj);
295             } else {
296                 pool.recycle(obj);
297             }
298         }
299
300         // Overrides.
301
public final ObjectPool/*Pool*/currentPool() {
302             final Pool pool = (Pool) _currentPool.get();
303             return (pool._user != null) ? pool : activatePool();
304         }
305
306         private final Pool activatePool() {
307             LocalPools pools = Context.current().getLocalPools();
308             Pool pool = (Pool) pools.getPool(this, true);
309             _currentPool.set(pool);
310             _lastActivated = pool;
311             return pool;
312         }
313
314         private Pool _lastActivated = (Pool) newHeapPool(); // Dummy to avoid null.
315

316         // Overrides.
317
protected ObjectPool/*Pool*/newStackPool() {
318             return new Pool(true);
319         }
320
321         // Overrides.
322
protected ObjectPool/*Pool*/newHeapPool() {
323             return new Pool(false);
324         }
325
326         /**
327          * This class holds the specialized pool for {@link RealtimeObject}
328          * instances.
329          */

330         public final class Pool extends ObjectPool/*<T>*/{
331
332             /**
333              * Holds the next object to return.
334              */

335             private RealtimeObject _next;
336
337             /**
338              * Indicates if stack pool.
339              */

340             private final boolean _isStack;
341
342             /**
343              * Holds the memory area of this pool.
344              */

345             private final MemoryArea _memoryArea;
346
347             /**
348              * Holds number of objects held by this pool.
349              */

350             private int _size;
351
352             /**
353              * Holds the head object.
354              */

355             private final RealtimeObject _activeHead;
356
357             /**
358              * Holds the tail object.
359              */

360             private final RealtimeObject _activeTail;
361
362             /**
363              * Holds the objects on hold
364              */

365             private final RealtimeObject _holdHead;
366
367             /**
368              * Holds the objects on hold
369              */

370             private final RealtimeObject _holdTail;
371
372             /**
373              * Creates a stack of heap pool.
374              *
375              * @param isStack indicates if this is a stack.
376              */

377             private Pool(boolean isStack) {
378                 _isStack = isStack;
379                 _memoryArea = MemoryArea.getMemoryArea(this);
380
381                 _activeHead = new Bound();
382                 _activeTail = new Bound();
383                 _activeHead._next = _activeTail;
384                 _activeTail._previous = _activeHead;
385
386                 _holdHead = new Bound();
387                 _holdTail = new Bound();
388                 _holdHead._next = _holdTail;
389                 _holdTail._previous = _holdHead;
390
391                 _next = _activeTail;
392             }
393
394             ObjectFactory getFactory() {
395                 return Factory.this;
396             }
397
398             // Implements ObjectPool abstract method.
399
public int getSize() {
400                 return _size;
401             }
402
403             // Implements ObjectPool abstract method.
404
public void setSize(int size) {
405                 for (; _size < size; _size++) {
406                     RealtimeObject obj = (RealtimeObject) create();
407                     obj.insertBefore(_next); // Available immediately.
408
_next = _next._previous;
409                     obj._pool = Pool.this;
410                 }
411             }
412
413             // Implements ObjectPool abstract method.
414
public Object JavaDoc/*{T}*/next() {
415                 final RealtimeObject next = _next;
416                 return ((_next = next._next) != null) ? (Object JavaDoc/*{T}*/) next
417                         : allocate();
418             }
419
420             private Object JavaDoc/*{T}*/allocate() {
421                 _next = _activeTail; // Avoids null for _next.
422
if (_isStack)
423                     return stackAllocate();
424                 // Heap.
425
if (_size != 0)
426                     removeUse(); // Avoids keeping reference to used objects.
427
return create();
428             }
429
430             private Object JavaDoc/*{T}*/stackAllocate() {
431                 _memoryArea.executeInArea(_allocate);
432                 return (Object JavaDoc/*{T}*/) _activeTail._previous;
433             }
434
435             private final Runnable JavaDoc _allocate = new Runnable JavaDoc() {
436                 public void run() {
437                     RealtimeObject obj = (RealtimeObject) create();
438                     _size++;
439                     obj.insertBefore(_activeTail);
440                     obj._pool = Pool.this;
441                 }
442             };
443
444             // Removes the oldest heap pool object used and never recycled.
445
private void removeUse() {
446                 RealtimeObject rtObj = _activeHead._next;
447                 if (rtObj == _activeTail)
448                     throw new JavolutionError("Empty pool with non-zero size");
449                 rtObj.detach();
450                 rtObj._next = null;
451                 rtObj._previous = null;
452                 rtObj._pool = null;
453                 _size--;
454             }
455
456             // Implements ObjectPool abstract method.
457
public void recycle(Object JavaDoc/*{T}*/obj) {
458                 if (doCleanup()) {
459                     cleanup(obj);
460                 }
461                 RealtimeObject rtObj = (RealtimeObject) obj;
462                 Pool pool = rtObj._pool;
463                 if (pool == this) {
464                     rtObj.detach();
465                     rtObj.insertBefore(_next);
466                     _next = _next._previous;
467                     return;
468                 }
469                 if (pool == null) { // Heap object.
470
if (MemoryArea.getMemoryArea(rtObj) != _memoryArea)
471                         return; // Do not recycle accross memory areas.
472
rtObj.insertBefore(_next);
473                     rtObj._pool = this;
474                     _next = _next._previous;
475                     _size++;
476                     return;
477                 }
478                 throw new IllegalArgumentException JavaDoc(
479                         "Cannot recycle object belonging to a different context");
480             }
481
482             // Implements ObjectPool abstract method.
483
protected void recycleAll() {
484                 // Cleanups objects.
485
for (RealtimeObject rt = _activeHead._next; rt != _next;) {
486                     if (!doCleanup())
487                         break;
488                     cleanup((Object JavaDoc/*{T}*/) rt);
489                     rt = rt._next;
490                 }
491                 _next = _activeHead._next;
492             }
493
494             // Implements ObjectPool abstract method.
495
protected void clearAll() {
496                 _activeHead._next = _activeTail;
497                 _activeTail._previous = _activeHead;
498                 _holdHead._next = _holdTail;
499                 _holdTail._previous = _holdHead;
500             }
501
502             // For debugging.
503
public String JavaDoc toString() {
504                 String JavaDoc str = _isStack ? "Stack Pool for " : "Heap Pool for ";
505                 return str + Factory.this.getClass() + " (Size: " + _size + ")";
506             }
507
508         }
509
510         /**
511          * This inner class represents internal linked list bounds
512          * (to avoid testing for null when inserting/removing).
513          */

514         private static final class Bound extends RealtimeObject {
515         }
516     }
517 }
Popular Tags