001: /*
002: * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
003: * Copyright (C) 2006 - 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.util.FastMap;
012: import j2me.lang.ThreadLocal;
013:
014: /**
015: * <p> This class represents an object factory; it allows for object
016: * recycling, pre-allocation and stack allocations.
017: *
018: * <p> Object factories are recommended over class constructors (ref. "new"
019: * keyword) to allows for custom allocation policy (see
020: * {@link AllocatorContext}). For example:[code]
021: * static ObjectFactory<int[][]> BOARD_FACTORY = new ObjectFactory<int[][]>() {
022: * protected int[][] create() {
023: * return new int[8][8];
024: * }
025: * };
026: * ...
027: * int[][] board = BOARD_FACTORY.object();
028: * // The board object might have been preallocated at start-up,
029: * // it might also be on the thread "stack/pool" for threads
030: * // executing in a StackContext.
031: * ...
032: * BOARD_FACTORY.recycle(board); // Immediate recycling of the board object (optional).
033: * [/code]</p>
034: *
035: * <p> For arrays of variable length {@link ArrayFactory} is recommended.</p>
036: *
037: * <p> For convenience, this class provides a static {@link #getInstance} method
038: * to retrieve a factory implementation for any given class.
039: * For example:[code]
040: * ObjectFactory<ArrayList> listFactory = ObjectFactory.getInstance(ArrayList.class);
041: * ArrayList list = listFactory.object();
042: * ... // Do something.
043: * listFactory.recycle(list); // Optional.
044: * [/code]</p>
045: *
046: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
047: * @version 5.2, August 14, 2007
048: */
049: public abstract class ObjectFactory/*<T>*/{
050:
051: /**
052: * Indicates if the objects products of this factory require
053: * {@link #cleanup(Object) cleanup} when recycled.
054: */
055: private boolean _doCleanup = true;
056:
057: /**
058: * Default constructor.
059: */
060: protected ObjectFactory() {
061: }
062:
063: /**
064: * Returns a factory implementation producing instances of the specified
065: * class. By default this method returns a factory creating new objects
066: * using the class public no-arg constructor (through reflection).
067: * If that constructor is not accessible, the factory instance can be
068: * {@link #setInstance set explicitly}:[code]
069: * class LogContext {
070: * public static final Class<LogContext> NULL = Null.class;
071: * ...
072: * private static class Null extends LogContext ... // Private.
073: * static {
074: * // Allows Null instances to be factory produced (even so the class is not accessible).
075: * ObjectFactory.setInstance(new ObjectFactory<Null> {
076: * protected Null create() { return new Null() }},
077: * Null.class);
078: * }
079: * }[/code]
080: *
081: * @param forClass the class for which an object factory is returned.
082: * @return an object factory producing instances of the specified class.
083: */
084: public static/*<T>*/ObjectFactory/*<T>*/getInstance(
085: Class/*<T>*/forClass) {
086: ObjectFactory factory = (ObjectFactory) Generic.CLASS_TO_FACTORY
087: .get(forClass);
088: return factory != null ? factory : Generic
089: .newInstance(forClass);
090: }
091:
092: /**
093: * Sets explicitely the factory to be used for the specified class
094: * (see {@link #getInstance}).
095: *
096: * @param factory the factory to use.
097: * @param forClass the associated class.
098: * @see #getInstance(Class)
099: */
100: public static/*<T>*/void setInstance(ObjectFactory/*<T>*/factory,
101: Class/*<T>*/forClass) {
102: Generic.CLASS_TO_FACTORY.put(forClass, factory);
103: }
104:
105: /**
106: * Returns a factory object possibly recycled or preallocated.
107: * This method is equivalent to <code>currentAllocator().nextInQueue()</code>.
108: *
109: * @return a recycled, pre-allocated or new factory object.
110: */
111: public final Object/*{T}*/object() {
112: final Allocator/*<T>*/allocator = _allocator;
113: return allocator.user == Thread.currentThread() ? allocator
114: .next() : currentAllocator().next();
115: }
116:
117: private Allocator/*<T>*/_allocator = NULL_ALLOCATOR; // Hopefully in the cache.
118:
119: private static final Allocator NULL_ALLOCATOR = new Allocator() {
120: protected Object allocate() {
121: return null;
122: }
123:
124: protected void recycle(Object object) {
125: }
126: };
127:
128: /**
129: * Recycles the specified object.
130: * This method is equivalent to <code>getAllocator().recycle(obj)</code>.
131: *
132: * @param obj the object to be recycled.
133: */
134: public final void recycle(Object/*{T}*/obj) {
135: currentAllocator().recycle(obj);
136: }
137:
138: /**
139: * Returns the factory allocator for the current thread (equivalent
140: * to <code>AllocatorContext.current().getAllocator(this)</code>).
141: *
142: * @return the current object queue for this factory.
143: */
144: public final Allocator/*<T>*/currentAllocator() {
145:
146: // Search thread-local value first.
147: Allocator allocator = (Allocator) _localAllocator.get();
148: if (allocator.user != null) // Active.
149: return _allocator = allocator;
150:
151: // Retrieves allocator from current allocator context.
152: allocator = ((AllocatorContext) AllocatorContext.getCurrent())
153: .getAllocator(this );
154:
155: // Sets diverse shortcuts.
156: _localAllocator.set(allocator);
157: _allocator = allocator;
158:
159: // Returns the queue.
160: return allocator;
161: }
162:
163: private ThreadLocal _localAllocator = new ThreadLocal() {
164: protected Object initialValue() {
165: return NULL_ALLOCATOR;
166: }
167: };
168:
169: /**
170: * Constructs a new object for this factory (using the <code>new</code>
171: * keyword).
172: *
173: * @return a new factory object.
174: */
175: protected abstract Object/*{T}*/create();
176:
177: /**
178: * Cleans-up this factory's objects for future reuse.
179: * When overriden, this method is called on objects being recycled to
180: * dispose of system resources or to clear references to external
181: * objects potentially on the heap (it allows these external objects to
182: * be garbage collected immediately and therefore reduces the memory
183: * footprint). For example:[code]
184: * static ObjectFactory<ArrayList> ARRAY_LIST_FACTORY = new ObjectFactory<ArrayList>() {
185: * protected ArrayList create() {
186: * return new ArrayList();
187: * }
188: * protected void cleanup(ArrayList obj) {
189: * obj.clear(); // Clears external references.
190: * }
191: * };[/code]
192: *
193: * @param obj the factory object being recycled.
194: */
195: protected void cleanup(Object/*{T}*/obj) {
196: _doCleanup = false;
197: }
198:
199: /**
200: * Indicates if this factory requires cleanup.
201: *
202: * @return <code>true</code> if {@link #cleanup} is overriden and
203: * {@link #cleanup} has been called at least once;
204: * <code>false</code> otherwise.
205: */
206: protected final boolean doCleanup() {
207: return _doCleanup;
208: }
209:
210: // Generic implementation using public no-arg constructor (reflection).
211: private static class Generic extends ObjectFactory {
212: private static final FastMap CLASS_TO_FACTORY = new FastMap()
213: .setShared(true);
214:
215: private final Class _class;
216:
217: private Generic(Class cls) {
218: _class = cls;
219: }
220:
221: private static Generic newInstance(Class cls) {
222: Generic generic = new Generic(cls);
223: CLASS_TO_FACTORY.put(cls, generic);
224: return generic;
225: }
226:
227: protected Object create() {
228: try {
229: return _class.newInstance();
230: } catch (InstantiationException e) {
231: throw new Error(
232: "Cannot instantiate no-arg constructor for "
233: + _class.getName()
234: + ", the factory should be set explicitly using ObjectFactory.setInstance");
235: } catch (IllegalAccessException e) {
236: throw new Error(
237: "Cannot access no-arg constructor for "
238: + _class.getName()
239: + ", the factory should be set explicitly using ObjectFactory.setInstance");
240: }
241: }
242: }
243:
244: }
|