/Users/lyon/j4p/src/classUtils/pack/util/pool2/ObjectPool.java
|
1 package classUtils.pack.util.pool2;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.io.PrintStream;
6 import java.lang.reflect.Constructor;
7 import java.lang.reflect.InvocationTargetException;
8
9 import classUtils.pack.util.Setup;
10 import classUtils.pack.util.pool2.test.ObjectWithID;
11
12 /**
13 * <font color=red>NOT COMPLETE YET</font>.
14 * <p>
15 * A pool of object which handles transparent passivation/activation.
16 * <p>
17 * This pool create and allocate pooled objects referencing the original objects
18 * and implementing the same interface(s).
19 * <p>
20 * The pool can be used either accessing objects by interface or by class.
21 * <p>
22 * The given object class should implement one or more specific interface(s). The instances
23 * returned by the {@link classUtils.pack.util.pool.ObjectPool#acquire() acquire()} method
24 * can be directly cast to that interface(s). For example, if a class
25 * <tt>MyTestObject</tt> implements the <tt>javax.swing.Action</tt> interface,
26 * the following code can be used:
27 * <pre>
28 * ObjectPool pool = new ObjectPool("test pool", 10, MyTestObject.class);
29 * ...
30 * Action action = (Action)pool.acquire();
31 * Object obj = action.getValue();
32 * ...
33 * action.release();
34 * ...
35 * pool.dispose();
36 * </pre>
37 * <p>
38 * If the given object is used directly as a class (rather than interface), the
39 * following conditions hold:
40 * <p>
41 * <ul>
42 * <li> The object returned by the pool's {@link classUtils.pack.util.pool.ObjectPool#acquire() acquire()}
43 * method cannot be cast to the original class directly, but to the {@link PooledObject
44 * PooledObject} interface.
45 * <li> The returned object implements all the methods of the original object, but since it's
46 * type is possibly generated at runtime, the methods are only available trhough reflection.
47 * <li> The original object can be obtained by invoking {@link PooledObject#_getOriginal() _getOriginal()}
48 * on the returned object, and must be released by {@link PooledObject#_getOriginal() _releaseOriginal()}.
49 * </ul>
50 * <p>
51 * For example:
52 * <pre>
53 * ObjectPool pool = new ObjectPool("test pool", 10, MyTestObject.class);
54 * ...
55 * PooledObject pObj = (PooledObject)pool.acquire();
56 * MyTestObject obj = (MyTestObject)pObj._getOriginal();
57 * obj.myTestMethod();
58 * pObj._releaseOriginal();
59 * </pre>.
60 *
61 * @version 1.0
62 * @author Cristiano Sadun
63 */
64 public class ObjectPool extends classUtils.pack.util.pool.ObjectPool {
65
66 private String name;
67 private PrintStream logStream;
68 private static PrintStream defaultLogStream;
69 private Configuration configuration;
70 private BasePassivationManager passivationManager;
71
72 /**
73 * A base class for a factory of {@link BasePassivationManager BasePassivationManager}s.
74 * It can be extended to produce a specific subclass of {@link BasePassivationManager
75 * BasePassivationManager}.
76 */
77 protected abstract static class PassivationManagerFactory {
78 /**
79 * Return a specific subclass of {@link BasePassivationManager
80 * BasePassivationManager} implementing a certain passivation
81 * policy.
82 *
83 * @return a concrete subclass of {@link BasePassivationManager
84 * BasePassivationManager}
85 */
86 protected abstract BasePassivationManager createPassivationThread();
87 }
88
89 /**
90 * An {@link ObjectPool.PassivationManagerFactory ObjectPool.PassivationManagerFactory} which
91 * produces {@link DefaultPassivationManager DefaultPassivationManager}s
92 */
93 public final static class DefaultPassivationManagerFactory
94 extends PassivationManagerFactory {
95 /**
96 * Return the single instance of {@link DefaultPassivationManager DefaultPassivationManager}.
97 * @return the single instance of {@link DefaultPassivationManager DefaultPassivationManager}.
98 */
99 protected BasePassivationManager createPassivationThread() {
100 return DefaultPassivationManager.getInstance();
101 }
102 }
103
104 /**
105 * A {@link classUtils.pack.util.pool.ObjectPool.Factory object factory} which produces {@link BasePooledObject BasePooledObject}
106 * wrappers for other classes.
107 * <p>
108 * In detail, this class uses an existing
109 * {@link classUtils.pack.util.pool.ObjectPool.Factory object factory}
110 * to produce objects of class C, obtains an appropriate <tt>Pooled<i>C</i></tt> subclass of
111 * {@link BasePooledObject BasePooledObject} and then wraps the objects in instances of <tt>Pooled<i>C</i></tt>.
112 */
113 protected static class PooledObjectFactory
114 implements classUtils.pack.util.pool.ObjectPool.Factory {
115
116 private Class pooledClass;
117 private Factory factory;
118 private Constructor pooledClassConstructor;
119 private ObjectPool pool;
120 private static StubClassLoader scl;
121 private static Object lock = new Object();
122
123 /**
124 * Create a factory which is used by the given {@link ObjectPool ObjectPool} and employs the given
125 * {@link classUtils.pack.util.pool.ObjectPool.Factory org.sadun.util.pool.ObjectPool.Factory}
126 * @param pool the {@link ObjectPool ObjectPool} using this factory to create pooled objects
127 * @param factory the {@link classUtils.pack.util.pool.ObjectPool.Factory org.sadun.util.pool.ObjectPool.Factory} to produce
128 * the original instances
129 */
130 protected PooledObjectFactory(ObjectPool pool, Factory factory)
131 throws ObjectPoolException {
132
133 this.factory = factory;
134 this.pool = pool;
135
136 // Create the stub class loader
137 createStubClassLoader();
138
139 // Load the pooled class
140 try {
141 pooledClass =
142 scl.loadClass(
143 scl.getPooledClassName(factory.getProducedClass()));
144
145 try {
146 pooledClassConstructor =
147 pooledClass.getConstructor(
148 new Class[] {
149 ObjectPool.class,
150 factory.getProducedClass()});
151 } catch (NoSuchMethodException e) {
152 // This shouldn't happen, since the wrapper is generated on purpose...
153 throw new RuntimeException(
154 "Corrupted class " + pooledClass.getName(),
155 e);
156 }
157
158 } catch (ClassNotFoundException e) {
159 throw new ObjectPoolException(
160 "Could not generate/load the pooled class for "
161 + factory.getProducedClass().getName(),
162 e);
163 }
164 }
165
166 private static void createStubClassLoader()
167 throws ObjectPoolException {
168 if (scl == null)
169 synchronized (lock) {
170
171 Class cls = BasePooledObject.class;
172 try {
173 scl = new StubClassLoader(cls);
174 scl.setLogStream(getDefaultLogStream());
175 } catch (IOException e) {
176 e.printStackTrace();
177 throw new IllegalStateException(
178 "Cannot create StubClassLoader using "
179 + cls.getName());
180 }
181 }
182 }
183
184 /**
185 * @see classUtils.pack.util.pool.ObjectPool.Factory#create()
186 */
187 public Object create() throws ObjectPoolException {
188 // Use the original factory to create the object
189 try {
190 BasePooledObject obj =
191 (BasePooledObject) pooledClassConstructor.newInstance(
192 new Object[] { null, factory.create()});
193 obj.setObjectPool(pool);
194 return obj;
195 } catch (InstantiationException e) {
196 throw new ObjectPoolException(
197 "Cannot instantiate pooled object for "
198 + factory.getProducedClass().getName(),
199 e);
200 } catch (IllegalAccessException e) {
201 throw new ObjectPoolException(
202 "Cannot instantiate pooled object for "
203 + factory.getProducedClass().getName(),
204 e);
205 } catch (InvocationTargetException e) {
206 throw new ObjectPoolException(
207 "Cannot instantiate pooled object for "
208 + factory.getProducedClass().getName(),
209 e);
210 }
211
212 }
213
214 /**
215 * @see classUtils.pack.util.pool.ObjectPool.Factory#getProducedClass()
216 */
217 public Class getProducedClass() {
218 return pooledClass;
219 }
220
221 }
222
223 /**
224 * Create a named object pool of objects of the given class and
225 * the given {@link Configuration Configuration} (which also provides
226 * the size of the pool).
227 * <p>
228 * The objects are created by invoking their default constructor.
229 * @param poolName the name of the pool
230 * @param configuration a {@link Configuration Configuration} object
231 * @param objectType the class of objects to create
232 */
233 public ObjectPool(
234 String poolName,
235 Configuration configuration,
236 Class objectType)
237 throws ObjectPoolException {
238 this(poolName, configuration, objectType, (Setup) null);
239 }
240
241 /**
242 * Create a named object pool of objects of the given class and
243 * the given {@link Configuration Configuration} (which also provides
244 * the size of the pool).
245 * <p>
246 * The objects are created by invoking their default constructor.
247 * <p>
248 * After the creation, each object is passed by the given {@link
249 * org.sadun.util.Setup Setup object}.
250 *
251 * @param poolName the name of the pool
252 * @param configuration a {@link Configuration Configuration} object
253 * @param objectType the class of objects to create
254 * @param setupObject the {@link classUtils.pack.util.Setup Setup object} used
255 * for post-construction setup
256 */
257 public ObjectPool(
258 String poolName,
259 Configuration configuration,
260 Class objectType,
261 Setup setupObject)
262 throws ObjectPoolException {
263 this(poolName, configuration, objectType, new Object[] {
264 }, setupObject);
265 }
266
267 /**
268 * Create a named object pool of objects of the given class and
269 * the given {@link Configuration Configuration} (which also provides
270 * the size of the pool).
271 * <p>
272 * The objects are created by invoking the constructor matching the types
273 * of the given parameter objects.
274 *
275 * @param poolName the name of the pool
276 * @param configuration a {@link Configuration Configuration} object
277 * @param objectType the class of objects to create
278 * @param params the array of parameters used for constructing the object
279 */
280 public ObjectPool(
281 String poolName,
282 Configuration configuration,
283 Class objectType,
284 Object[] params) {
285 this(poolName, configuration, objectType, params, null);
286 }
287
288 /**
289 * Create a named object pool of objects of the given class and
290 * the given {@link Configuration Configuration} (which also provides
291 * the size of the pool).
292 * <p>
293 * The objects are created by invoking the constructor matching the types
294 * of the given parameter objects.
295 * <p>
296 * After the creation, each object is passed by the given {@link
297 * org.sadun.util.Setup Setup object}.
298 *
299 * @param poolName the name of the pool
300 * @param configuration a {@link Configuration Configuration} object
301 * @param objectType the class of objects to create
302 * @param params the array of parameters used for constructing the object
303 * @param setupObject the {@link classUtils.pack.util.Setup Setup object} used
304 * for post-construction setup
305 */
306 public ObjectPool(
307 String poolName,
308 Configuration configuration,
309 Class objectType,
310 Object[] params,
311 Setup setupObject)
312 throws ObjectPoolException {
313 this(
314 poolName,
315 configuration,
316 new ObjectFactory(objectType, params, setupObject));
317 }
318
319 /**
320 * Create a named object pool of <tt>n</tt> objects of the given class and
321 * a default {@link Configuration Configuration}.
322 * <p>
323 * The objects are created by invoking the constructor matching the types
324 * of the given parameter objects.
325 *
326 * @param n the number of objects to create
327 * @param poolName the name of the pool
328 * @param objectType the class of objects to create
329 * @param params the array of parameters used for constructing the object
330 */
331 public ObjectPool(
332 String poolName,
333 int n,
334 Class objectType,
335 Object[] params) {
336 this(poolName, new Configuration(n), objectType, params);
337 }
338
339 /**
340 * Create a named object pool of <tt>n</tt> objects of the given class and
341 * a default {@link Configuration Configuration}.
342 * <p>
343 * The objects are created by invoking their default constructor.
344 *
345 * @param n the number of objects to create
346 * @param poolName the name of the pool
347 * @param objectType the class of objects to create
348 * @param params the array of parameters used for constructing the object
349 */
350 public ObjectPool(String poolName, int n, Class objectType) {
351 this(poolName, new Configuration(n), objectType, new Object[0]);
352 }
353
354 /**
355 * Create a named object pool of objects of the given class and
356 * the given {@link Configuration Configuration} (which also provides
357 * the size of the pool).
358 * <p>
359 * The objects are created by using the given {@link classUtils.pack.util.pool.ObjectPool.Factory
360 * object factory}.
361 * <p>
362 * @param poolName the name of the pool
363 * @param configuration a {@link Configuration Configuration} object
364 * @param factory the {@link classUtils.pack.util.pool.ObjectPool.Factory object factory} which produces the instances to pool.
365 */
366 public ObjectPool(
367 String poolName,
368 Configuration configuration,
369 Factory factory)
370 throws ObjectPoolException {
371 super(
372 configuration.getPoolSize(),
373 new PooledObjectFactory(null, factory));
374 setPool(createObjectsArray(), this);
375
376 this.configuration = configuration;
377 this.name = poolName;
378 this.logStream = getDefaultLogStream();
379
380 passivationManager =
381 configuration
382 .getPassivationManagerFactory()
383 .createPassivationThread();
384 passivationManager.setLogStream(logStream);
385
386 passivationManager.addPool(this);
387
388 // Initialize
389 if (logStream != null)
390 logStream.println(
391 "Pool of "
392 + getSize()
393 + " instances of "
394 + factory.getProducedClass()
395 + " created.");
396
397 passivationManager.start();
398 }
399
400 /**
401 * Returns the defaultLogStream.
402 * @return PrintStream
403 */
404 public static PrintStream getDefaultLogStream() {
405 return defaultLogStream;
406 }
407
408 /**
409 * Sets the defaultLogStream.
410 * @param defaultLogStream The defaultLogStream to set
411 */
412 public static void setDefaultLogStream(PrintStream defaultLogStream) {
413 ObjectPool.defaultLogStream = defaultLogStream;
414 }
415
416 /**
417 * Returns the logStream.
418 * @return PrintStream
419 */
420 public PrintStream getLogStream() {
421 return logStream;
422 }
423
424 /**
425 * Sets the logStream.
426 * @param logStream The logStream to set
427 */
428 public void setLogStream(PrintStream logStream) {
429 this.logStream = logStream;
430 PooledObjectFactory.scl.setLogStream(logStream);
431 }
432
433 /**
434 * Returns the configuration.
435 * @return Configuration
436 */
437 public Configuration getConfiguration() {
438 return configuration;
439 }
440
441 Object[] createObjectsArray() {
442 Object[] pool2 = new Object[pool.length];
443 for (int i = 0; i < pool.length; i++) {
444 pool2[i] = pool[i].getObject();
445 }
446 return pool2;
447 }
448
449 synchronized boolean isAcquired(PooledObject obj) {
450 //assert(used.contains(obj) || free.contains(obj));
451 return used.contains(obj);
452 }
453
454 /**
455 * A convenience method which already casts the result of {@link classUtils.pack.util.pool.ObjectPool#acquire() acquire()}
456 * to the {@link PooledObject PooledObject} type.
457 * @return one object in the pool, obtained invoking {@link classUtils.pack.util.pool.ObjectPool#acquire() acquire()}
458 */
459 public PooledObject acquireInstance() {
460 return (PooledObject) acquire();
461 }
462
463 /**
464 * Returns the name.
465 * @return String
466 */
467 public String getName() {
468 return name;
469 }
470
471 public void dispose() {
472 passivationManager.shutdown();
473 }
474
475 /**
476 * Returns the passivationManager.
477 * @return BasePassivationManager
478 */
479 public BasePassivationManager getPassivationManager() {
480 return passivationManager;
481 }
482
483 /**
484 * Method setPool. Set the given pool as the pool refrenced by each BasePooledObject.
485 * @param objects
486 * @param objectPool
487 */
488 private void setPool(Object[] objects, ObjectPool objectPool) {
489 for (int i = 0; i < objects.length; i++) {
490 ((BasePooledObject) objects[i]).setObjectPool(objectPool);
491 }
492 }
493
494 /**
495 * Test method
496 */
497 public static void main(String[] args) throws Exception {
498 //ObjectPool.setDefaultLogStream(System.out);
499 DefaultPassivationManager.setDefaultPassivationThreshold(1000L);
500 ObjectPool pool =
501 new ObjectPool(
502 "Test pool",
503 new Configuration(new File(File.separator + "temp"), 10),
504 classUtils.pack.util.pool2.test.PassivableObject.class);
505 // Thread.sleep(10000);
506 // Pick an object
507 ObjectWithID obj = (ObjectWithID) pool.acquire();
508 System.out.println("Object ID: "+obj.getId());
509 pool.release(obj);
510 // Thread.sleep(5000);
511 pool.dispose();
512 }
513
514 }
515