KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javolution > context > ObjectFactory


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 javolution.lang.ClassInitializer;
12 import javolution.lang.Configurable;
13 import javolution.util.FastTable;
14 import j2me.lang.ThreadLocal;
15 import j2me.lang.UnsupportedOperationException;
16 import j2mex.realtime.MemoryArea;
17
18 /**
19  * <p> This class represents an object factory; it allows for object
20  * recycling and pre-allocation.
21  *
22  * <p> Object factories are recommended over class constructors (ref. "new"
23  * keyword) in order to facilitate start-up pre-allocation and/or
24  * object reuse. For example:[code]
25  * static ObjectFactory<int[][]> BOARD_FACTORY = new ObjectFactory<int[][]>() {
26  * protected int[][] create() {
27  * return new int[8][8];
28  * }
29  * };
30  * ...
31  * int[][] board = BOARD_FACTORY.object();
32  * // The board object might have been preallocated at start-up,
33  * // it might also be on the thread "stack/pool" for threads
34  * // executing in a pool context.
35  * ...
36  * BOARD_FACTORY.recycle(board); // Immediate recycling of the board object (optional).
37  * [/code]</p>
38  *
39  * <p> {@link ObjectFactory} instances are uniquely identified by their class
40  * (one instance per sub-class). The number of instances is voluntarely
41  * limited (see <a HREF="{@docRoot}/overview-summary.html#configuration">
42  * Javolution Configuration</a> for details).</p>
43  *
44  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
45  * @version 3.8, May 14, 2006
46  */

47 public abstract class ObjectFactory/*<T>*/{
48
49     /**
50      * Holds the maximum number of {@link ObjectFactory}
51      * (see <a HREF="{@docRoot}/overview-summary.html#configuration">
52      * Javolution Configuration</a> for details).
53      */

54     public static final Configurable/*<Integer>*/ MAX_COUNT = new Configurable(
55             new Integer JavaDoc(256)) {
56         protected void notifyChange() {
57             synchronized (LOCK) {
58                 final int newCount = ((Integer JavaDoc)MAX_COUNT.get()).intValue();
59                 if (_Count >= newCount)
60                     throw new j2me.lang.UnsupportedOperationException(
61                             "Already " + _Count
62                                     + " factories, cannot reduce to "
63                                     + newCount);
64                 MemoryArea.getMemoryArea(_Instances).executeInArea(
65                         new Runnable JavaDoc() {
66                             public void run() {
67                                 ObjectFactory[] tmp = new ObjectFactory[newCount];
68                                 System.arraycopy(_Instances, 0, tmp, 0, _Count);
69                                 _Instances = tmp;
70                             }
71                         });
72             }
73         }
74     };
75
76     private static final Object JavaDoc LOCK = new Object JavaDoc();
77
78     /**
79      * Holds the factory instances.
80      */

81     static ObjectFactory[] _Instances = new ObjectFactory[((Integer JavaDoc)MAX_COUNT.get()).intValue()];
82
83     /**
84      * Holds the current number of instances.
85      */

86     static int _Count;
87
88     /**
89      * Holds the factory index (range [0..MAX_COUNT[).
90      */

91     final int _index;
92
93     /**
94      * Indicates if the objects products of this factory require
95      * {@link #cleanup(Object) cleanup} when recycled.
96      */

97     private boolean _doCleanup = true;
98
99     /**
100      * Default constructor.
101      */

102     protected ObjectFactory() {
103         synchronized (LOCK) {
104             if (_Count >= _Instances.length)
105                 throw new UnsupportedOperationException JavaDoc(
106                         "Configuration setting of a maximum " + _Instances.length
107                                 + " factories has been reached");
108             Class JavaDoc factoryClass = this.getClass();
109             for (int i = 0; i < _Count; i++) {
110                 if (factoryClass == _Instances[i].getClass()) {
111                     throw new UnsupportedOperationException JavaDoc(factoryClass
112                             + " cannot have more than one instance");
113                 }
114             }
115             _index = _Count++;
116             _Instances[_index] = this;
117         }
118     }
119
120     /**
121      * Constructs a new object for this factory (using the <code>new</code>
122      * keyword).
123      *
124      * @return a new factory object.
125      */

126     protected abstract Object JavaDoc/*{T}*/create();
127
128     /**
129      * Returns a factory object possibly recycled or preallocated.
130      * This method is equivalent to <code>currentPool().next()</code>.
131      *
132      * @return a recycled, pre-allocated or new factory object.
133      */

134     public Object JavaDoc/*{T}*/object() {
135         return currentPool().next();
136     }
137
138     /**
139      * Recycles the specified object in the current pool of this factory.
140      * This method is equivalent to <code>currentPool().recycle(obj)</code>.
141      *
142      * @param obj the object to be recycled.
143      */

144     public void recycle(Object JavaDoc/*{T}*/obj) {
145         currentPool().recycle(obj);
146     }
147
148     /**
149      * Returns this factory pool for the current thread.
150      * The pool is also activated (user is the current thread).
151      *
152      * @return a context-local pool for this factory.
153      */

154     public ObjectPool/*<T>*/currentPool() {
155         ObjectPool/*<T>*/ pool = (ObjectPool/*<T>*/) _currentPool.get();
156         return (pool._user != null) ? pool : activatePool();
157     }
158     
159     private final ObjectPool/*<T>*/ activatePool() {
160         LocalPools pools = Context.current().getLocalPools();
161         ObjectPool pool = pools.getPool(this, true);
162         _currentPool.set(pool);
163         return pool;
164     }
165
166     final ThreadLocal JavaDoc _currentPool = new ThreadLocal JavaDoc() {
167         protected Object JavaDoc initialValue() {
168             return newHeapPool();
169         }
170     };
171
172     /**
173      * Cleans-up this factory's objects for future reuse.
174      * When overriden, this method is called on objects being recycled to
175      * dispose of system resources or to clear references to external
176      * objects potentially on the heap (it allows these external objects to
177      * be garbage collected immediately and therefore reduces the memory
178      * footprint). For example:[code]
179      * static ObjectFactory<ArrayList> ARRAY_LIST_FACTORY = new ObjectFactory<ArrayList>() {
180      * protected ArrayList create() {
181      * return new ArrayList();
182      * }
183      * protected void cleanup(ArrayList obj) {
184      * obj.clear(); // Clears external references.
185      * }
186      * };[/code]
187      *
188      * @param obj the factory object being recycled.
189      */

190     protected void cleanup(Object JavaDoc/*{T}*/obj) {
191         _doCleanup = false;
192     }
193
194     /**
195      * Indicates if this factory requires cleanup.
196      *
197      * @return <code>true</code> if {@link #cleanup} is overriden and
198      * {@link #cleanup} has been called at least once;
199      * <code>false</code> otherwise.
200      */

201     final boolean doCleanup() {
202         return _doCleanup;
203     }
204
205     /**
206      * Returns a new stack pool for this object factory.
207      * Sub-classes may override this method in order to use specialized pools.
208      *
209      * @return a new stack pool for this factory.
210      */

211     protected ObjectPool newStackPool() {
212         return new StackPool();
213     }
214
215     /**
216      * Returns a new heap pool for this object factory.
217      * Sub-classes may override this method in order to use specialized pools.
218      *
219      * @return a new heap pool for this factory.
220      */

221     protected ObjectPool newHeapPool() {
222         return new HeapPool();
223     }
224
225     /**
226      * Returns the factory object of specified class.
227      *
228      * @return the corresponding factory.
229      * @throws IllegalArgumentException if not found.
230      */

231     static ObjectFactory getInstance(Class JavaDoc factoryClass) {
232         // Ensures that enclosing class if any is initialized.
233
String JavaDoc className = factoryClass.getName();
234         int sep = className.lastIndexOf('$');
235         if (sep > 0) {
236             ClassInitializer.initialize(className.substring(0, sep));
237         }
238         ClassInitializer.initialize(factoryClass);
239         for (int i = 0; i < ObjectFactory._Count; i++) {
240             if (_Instances[i].getClass().equals(factoryClass))
241                 return _Instances[i];
242         }
243         throw new IllegalArgumentException JavaDoc("Factory class: " + factoryClass + " not found"
244                 + ", possibly container class not initialized");
245     }
246
247     /**
248      * This class represents the default heap pool.
249      */

250     private final class HeapPool extends ObjectPool {
251
252         /**
253          * Holds the objects in this pool.
254          */

255         private final FastTable _objects = new FastTable();
256
257         /**
258          * Default constructor.
259          */

260         private HeapPool() {
261         }
262
263         // Implements ObjectPool abstract method.
264
public int getSize() {
265             return _objects.size();
266         }
267
268         // Implements ObjectPool abstract method.
269
public void setSize(int size) {
270             for (int i=getSize(); i < size; i++) {
271                 _objects.addLast(create());
272             }
273         }
274         
275         // Implements ObjectPool abstract method.
276
public Object JavaDoc next() {
277             return _objects.isEmpty() ? create() : _objects
278                     .removeLast();
279         }
280
281         // Implements ObjectPool abstract method.
282
public void recycle(Object JavaDoc obj) {
283             cleanup((Object JavaDoc/*{T}*/)obj);
284             if (MemoryArea.getMemoryArea(obj) != MemoryArea.getMemoryArea(this))
285                  return; // Do not recycle accross memory areas.
286
_objects.addLast(obj);
287         }
288
289         // Implements ObjectPool abstract method.
290
protected void recycleAll() {
291             // No effect for heap pool.
292
}
293
294         // Implements ObjectPool abstract method.
295
protected void clearAll() {
296             _objects.clear();
297         }
298
299     }
300
301     /**
302      * This class represents the default stack pool implementation.
303      *
304      * It implements Runnable to facilitate object creation in memory area.
305      */

306     private final class StackPool extends ObjectPool implements Runnable JavaDoc {
307
308         /**
309          * Holds the objects in this pool.
310          */

311         private final FastTable _objects = new FastTable();
312
313         /**
314          * Holds the current index.
315          */

316         private int _index;
317
318         /**
319          * Default constructor.
320          */

321         private StackPool() {
322         }
323
324         // Implements ObjectPool abstract method.
325
public int getSize() {
326             return _objects.size();
327         }
328
329         // Implements ObjectPool abstract method.
330
public void setSize(int size) {
331             for (int i=getSize(); i < size; i++) {
332                 _objects.addLast(create());
333             }
334         }
335
336         // Implements ObjectPool abstract method.
337
public Object JavaDoc next() {
338             return (_index < _objects.size()) ? _objects.get(_index++)
339                     : newObject();
340         }
341
342         private Object JavaDoc newObject() {
343             MemoryArea.getMemoryArea(this).executeInArea(this);
344             _objects.add(_tmpObject);
345             _index++;
346             return _tmpObject;
347         }
348
349         // Implements ObjectPool abstract method.
350
public void recycle(Object JavaDoc obj) {
351             cleanup((Object JavaDoc/*{T}*/)obj);
352             for (int i = _index; --i >= 0;) {
353                 if (_objects.get(i) == obj) { // Found it.
354
// Exchange it with the last used object and adjust index.
355
Object JavaDoc lastObj = _objects.get(--_index);
356                     _objects.set(i, lastObj);
357                     _objects.set(_index, obj);
358                     return;
359                 }
360             }
361             throw new IllegalArgumentException JavaDoc("Object not in the pool");
362         }
363
364         // Implements ObjectPool abstract method.
365
protected void recycleAll() {
366             // Cleanups objects.
367
for (int i = 0; i < _index; i++) {
368                 if (!_doCleanup)
369                     break;
370                 Object JavaDoc obj = _objects.get(i);
371                 cleanup((Object JavaDoc/*{T}*/)obj);
372             }
373             _index = 0;
374         }
375
376         // Implements ObjectPool abstract method.
377
protected void clearAll() {
378             _objects.clear();
379             _index = 0;
380         }
381
382         // Implements Runnable for object creation in memory area.
383
public void run() {
384             _tmpObject = create();
385         }
386
387         private Object JavaDoc _tmpObject;
388     }
389
390 }
Popular Tags