KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javolution > realtime > ObjectFactory


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 javolution.Configuration;
12 import javolution.JavolutionError;
13 import j2me.lang.UnsupportedOperationException;
14
15 /**
16  * <p> This class represents an object factory; it provides control upon how
17  * and when objects are allocated (or pre-allocated). Object factories
18  * should be used preferably to class constructors (ref. "new" keyword)
19  * to allow for {@link PoolContext stack} allocations and objects
20  * {@link AllocationProfile pre-allocations}. For example:<pre>
21  * static ObjectFactory&lt;int[][]&gt; CHESSBOARD_FACTORY = new ObjectFactory&lt;int[][]&gt;() {
22  * protected int[][] create() {
23  * return new int[8][8];
24  * }
25  * };
26  * ...
27  * int[][] chessboard = CHESSBOARD_FACTORY.object(); // On the stack if current thread executes
28  * ... // in a {@link PoolContext}; heap otherwise.
29  * </pre>
30  * <p> {@link ObjectFactory} instances are uniquely identified by their class
31  * (one instance per sub-class). The number of instances is voluntarely
32  * limited (see <a HREF="{@docRoot}/overview-summary.html#configuration">
33  * Javolution Configuration</a> for details).</p>
34  *
35  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
36  * @version 3.3, May 10, 2005
37  */

38 public abstract class ObjectFactory/*<T>*/{
39
40     /**
41      * Holds the maximum number of {@link ObjectFactory}.
42      */

43     static final int MAX = Configuration.factories();
44
45     /**
46      * Holds the factory instances.
47      */

48     static ObjectFactory[] INSTANCES = new ObjectFactory[MAX];
49
50     /**
51      * Holds the current number of instances.
52      */

53     static volatile int Count;
54
55     /**
56      * Indicates if allocation profiling has been enabled.
57      */

58     static volatile boolean IsAllocationProfileEnabled;
59
60     /**
61      * Holds the number of object allocated since last preallocation.
62      */

63     volatile int _allocatedCount;
64
65     /**
66      * Holds the total number of preallocated object at last preallocation.
67      */

68     volatile int _preallocatedCount;
69
70     /**
71      * Holds the class product of this factory (for logging only)
72      */

73     volatile Class _productClass;
74
75     /**
76      * Holds pre-allocated objects.
77      */

78     Node/*<T>*/_preallocated;
79
80     /**
81      * Holds the factory index (range [0..MAX[).
82      */

83     private final int _index;
84
85     /**
86      * Holds the current pool when executing in a heap context.
87      */

88     private final HeapPool _heapPool = new HeapPool();
89
90     /**
91      * Default constructor.
92      *
93      * @throws UnsupportedOperationException if more than one instance per
94      * factory sub-class or if the {@link #MAX} number of factories
95      * has been reached.
96      */

97     protected ObjectFactory() {
98         _index = ObjectFactory.add(this);
99     }
100
101     private static synchronized int add(ObjectFactory factory) {
102         final int count = ObjectFactory.Count;
103         if (count >= MAX) {
104             throw new UnsupportedOperationException(
105                     "Maximum number of factories (system property "
106                             + "\"javolution.factories\", value " + MAX
107                             + ") has been reached");
108         }
109         Class factoryClass = factory.getClass();
110         for (int i = 0; i < count; i++) {
111             if (factoryClass == INSTANCES[i].getClass()) {
112                 throw new UnsupportedOperationException(factoryClass
113                         + " cannot have more than one instance");
114             }
115         }
116         INSTANCES[count] = factory;
117         return ObjectFactory.Count++;
118     }
119
120     /**
121      * Creates a new factory object on the heap (using the <code>new</code>
122      * keyword).
123      *
124      * @return a new factory object.
125      */

126     protected abstract Object/*T*/create();
127
128     /**
129      * Returns a {@link #create new}, potentially pre-allocated factory object.
130      *
131      * @return a pre-allocated or new factory object.
132      */

133     public final Object/*T*/newObject() {
134         if (!IsAllocationProfileEnabled)
135             return create();
136         Node/*<T>*/node = preallocatedNode();
137         Object/*T*/obj = (node != null) ? node._object : create();
138         if (_productClass == null) {
139             _productClass = obj.getClass();
140         }
141         return obj;
142     }
143
144     /**
145      * Returns a factory object allocated on the stack when executing in a
146      * {@link PoolContext}.
147      *
148      * @return a recycled, pre-allocated or new factory object.
149      */

150     public Object/*T*/object() {
151         PoolContext poolContext = Context.currentContext().poolContext();
152         return (poolContext != null) ? (Object/*T*/) poolContext.getLocalPool(
153                 _index).next() : newObject();
154     }
155
156     /**
157      * Returns the local pool for the current thread or the {@link #heapPool}
158      * when the current thread executes in a {@link HeapContext}.
159      *
160      * @return the local pool or a pool representing the heap.
161      */

162     public final ObjectPool/*<T>*/currentPool() {
163         PoolContext poolContext = Context.currentContext().poolContext();
164         return (poolContext != null) ? (ObjectPool/*<T>*/) poolContext
165                 .getLocalPool(_index) : _heapPool;
166     }
167
168     /**
169      * Returns the pool representing the heap; this pool always returns
170      * {@link #newObject} (potentially pre-allocated).
171      *
172      * @return the heap pool for this factory.
173      */

174     public final ObjectPool/*<T>*/heapPool() {
175         return _heapPool;
176     }
177
178     /**
179      * Cleans-up this factory's objects for future reuse.
180      * When overriden, this method is called on objects being recycled to
181      * dispose of system resources or to clear references to external
182      * objects potentially on the heap (it allows these external objects to
183      * be garbage collected immediately and therefore reduces the memory
184      * footprint).
185      *
186      * @param obj the object product of this factory being recycled.
187      * @throws UnsupportedOperationException if this factory does not
188      * support object clean-up (default).
189      */

190     protected void cleanup(Object/*T*/obj) {
191         throw new UnsupportedOperationException();
192     }
193
194     /**
195      * Returns a new local pool for this object factory.
196      * Sub-classes may override this method in order to use specialized pools.
197      *
198      * @return a new pool for stack allocation.
199      */

200     protected ObjectPool/*<T>*/newPool() {
201         return new LocalPool();
202     }
203
204     /**
205      * Pre-allocates (replenish the pool).
206      */

207     synchronized void preallocate() {
208         for (int i = 0; i < _allocatedCount; i++) {
209             Node/*<T>*/ node = new Node/*<T>*/();
210             node._object = this.create();
211             node._next = _preallocated;
212             _preallocated = node;
213         }
214         if (_allocatedCount > _preallocatedCount) {
215             _preallocatedCount = _allocatedCount;
216         }
217         _allocatedCount = 0;
218     }
219
220     /**
221      * Clears preallocated pool and resets counters.
222      */

223     final synchronized void reset() {
224         _allocatedCount = 0;
225         _preallocatedCount = 0;
226         _preallocated = null;
227     }
228
229     /**
230      * Returns a preallocated node or <code>null</code> if none.
231      * Should only be called when (IsAllocationProfileEnabled == true)
232      */

233     private synchronized Node/*<T>*/ preallocatedNode() {
234         if ((_allocatedCount++ == _preallocatedCount)
235                 && AllocationProfile.OverflowHandler != null) { // Notifies.
236
AllocationProfile.OverflowHandler.run();
237         }
238         if (_preallocated != null) {
239             Node/*<T>*/ node = _preallocated;
240             _preallocated = _preallocated._next;
241             return node;
242         } else {
243             return null;
244         }
245     }
246
247     /**
248      * This class represents the heap pool.
249      */

250     private final class HeapPool extends ObjectPool/*<T>*/{
251
252         // Implements ObjectPool abstract method.
253
public Object/*T*/next() {
254             return newObject();
255         }
256
257         // Implements ObjectPool abstract method.
258
public void recycle(Object/*T*/obj) {
259             // No effect for heap pool.
260
}
261
262         // Implements ObjectPool abstract method.
263
protected void recycleAll() {
264             // No effect for heap pool.
265
}
266
267         // Implements ObjectPool abstract method.
268
protected void clearAll() {
269             // No effect for heap pool.
270
}
271     }
272
273     /**
274      * This class represents the default local pool implementation.
275      */

276     private final class LocalPool extends ObjectPool/*<T>*/{
277
278         /**
279          * Indicates if clean-up has to be performed (switches to false if
280          * UnsupportedOperationException raised during clean-up).
281          */

282         private boolean _doCleanup = true;
283
284         /**
285          * Holds used objects.
286          */

287         private Node/*<T>*/_usedNodes;
288
289         /**
290          * Holds available objects.
291          */

292         private Node/*<T>*/_availNodes;
293
294         /**
295          * Holds the tail node of the used list.
296          */

297         private Node/*<T>*/_usedNodesTail;
298
299         // Implements ObjectPool abstract method.
300
public Object/*T*/next() {
301             Node/*<T>*/node;
302             if (_availNodes != null) { // Gets node from recycled.
303
node = _availNodes;
304                 _availNodes = node._next;
305             } else { // Gets preallocated node or create a new node.
306
if (IsAllocationProfileEnabled) {
307                     node = preallocatedNode();
308                     if (node == null) {
309                         node = new Node/*<T>*/();
310                         node._object = create();
311                     }
312                 } else {
313                     node = new Node/*<T>*/();
314                     node._object = create();
315                 }
316             }
317             if (_usedNodes == null) { // Marks tail node.
318
_usedNodesTail = node;
319             }
320             node._next = _usedNodes;
321             _usedNodes = node;
322             return node._object;
323         }
324
325         // Implements ObjectPool abstract method.
326
public void recycle(Object/*T*/obj) {
327             // Cleanups object.
328
if (_doCleanup) {
329                 try {
330                     cleanup(obj);
331                 } catch (UnsupportedOperationException ex) {
332                     _doCleanup = false;
333                 }
334             }
335             // Moves associated node from used to available list.
336
if (_usedNodes._object == obj) { // Last one allocated.
337
Node/*<T>*/node = _usedNodes;
338                 if (node == _usedNodesTail) { // Only one node used.
339
_usedNodesTail = null;
340                     if (node._next != null) // Sanity check.
341
throw new JavolutionError("Pool Corrupted");
342                 }
343                 _usedNodes = node._next;
344                 node._next = _availNodes;
345                 _availNodes = node;
346             } else { // Search
347
Node/*<T>*/previous = _usedNodes;
348                 for (Node/*<T>*/node = previous._next; node != null;) {
349                     if (node._object == obj) { // Found it.
350
if (node == _usedNodesTail) { // Tail node being removed.
351
_usedNodesTail = previous;
352                         }
353                         previous._next = node._next;
354                         node._next = _availNodes;
355                         _availNodes = node;
356                         return;
357                     }
358                     previous = node;
359                     node = node._next;
360                 }
361                 throw new JavolutionError("Object not in the pool");
362             }
363         }
364
365         // Implements ObjectPool abstract method.
366
protected void recycleAll() {
367             // Cleanups objects.
368
if (_doCleanup) {
369                 try {
370                     for (Node/*<T>*/node = _usedNodes; node != null;) {
371                         cleanup(node._object);
372                         node = node._next;
373                     }
374                 } catch (UnsupportedOperationException ex) {
375                     _doCleanup = false;
376                 }
377             }
378
379             if (_usedNodes != null) {
380                 _usedNodesTail._next = _availNodes;
381                 _availNodes = _usedNodes;
382                 _usedNodes = null;
383                 _usedNodesTail = null;
384             }
385         }
386
387         // Implements ObjectPool abstract method.
388
protected void clearAll() {
389             _availNodes = null;
390             _usedNodes = null;
391             _usedNodesTail = null;
392         }
393
394     }
395
396     /**
397      * This inner class represents a simple pool node.
398      */

399     static final class Node/*<T>*/{
400
401         Object/*T*/_object;
402
403         Node/*<T>*/_next;
404     }
405 }
406
Popular Tags