/*
 * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
 * Copyright (C) 2005 - Javolution (http://javolution.org/)
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software is
 * freely granted, provided that this notice is preserved.
 */
package javolution37.javolution.realtime;

import javolution37.javolution.Configuration;
import javolution37.javolution.JavolutionError;
import javolution37.javolution.lang.ClassInitializer;

import java.lang.UnsupportedOperationException;
import javax.realtime.MemoryArea;

/**
 * 

This class represents an object factory; it allows for object * recycling and pre-allocation. * *

Object factories are recommended over class constructors (ref. "new" * keyword) in order to benefit from context-based allocation policies. * For example:[code] * static ObjectFactory BOARD_FACTORY = new ObjectFactory() { * protected int[][] create() { * return new int[8][8]; * } * }; * ... * int[][] board = BOARD_FACTORY.object(); // On the stack if current thread executes * ... // in a PoolContext; heap otherwise. * [/code]

* *

{@link ObjectFactory} instances are uniquely identified by their class * (one instance per sub-class). The number of instances is voluntarely * limited (see * Javolution Configuration for details).

* * @author Jean-Marie Dautelle * @version 3.7, January 1, 2006 */ public abstract class ObjectFactory { /** * Holds the maximum number of {@link ObjectFactory}. */ static final int MAX = Configuration.factories(); /** * Holds the factory instances. */ static ObjectFactory[] INSTANCES = new ObjectFactory[MAX]; /** * Holds the current number of instances. */ static volatile int Count; /** * Holds the factory index (range [0..MAX[). */ final int _index; /** * Holds the current pool when executing in a heap context. */ private final HeapPool _heapPool = new HeapPool(); /** * Default constructor. * * @throws UnsupportedOperationException if more than one instance per * factory sub-class or if the {@link #MAX} number of factories * has been reached. */ protected ObjectFactory() { _index = ObjectFactory.add(this); } private static synchronized int add(ObjectFactory factory) { final int count = ObjectFactory.Count; if (count >= MAX) { throw new UnsupportedOperationException( "Maximum number of factories (system property " + "\"javolution37.javolution.factories\", value " + MAX + ") has been reached"); } Class factoryClass = factory.getClass(); for (int i = 0; i < count; i++) { if (factoryClass == INSTANCES[i].getClass()) { throw new UnsupportedOperationException(factoryClass + " cannot have more than one instance"); } } INSTANCES[count] = factory; return ObjectFactory.Count++; } /** * Constructs a new object for this factory (using the new * keyword). * * @return a new factory object. */ protected abstract T create(); /** * Returns a factory object possibly recycled or preallocated. * This method is equivalent to object(PoolContext.current()). * * @return a recycled, pre-allocated or new factory object. */ public T object() { final PoolContext poolContext = Context.poolContext(Thread .currentThread()); return (poolContext == null) ? create() : ( T ) poolContext .getLocalPool(_index).next(); } /** * Returns the local pool for the current thread or the {@link #heapPool} * when the current thread executes in a {@link HeapContext}. * * @return the local pool or a pool representing the heap. */ public final ObjectPool currentPool() { PoolContext poolContext = Context.poolContext(Thread.currentThread()); return (poolContext != null) ? (ObjectPool ) poolContext .getLocalPool(_index) : _heapPool; } /** * Returns the pool representing the heap; this pool always returns * objects allocated on the heap. * * @return the heap pool for this factory. */ public final ObjectPool heapPool() { return _heapPool; } /** * Cleans-up this factory's objects for future reuse. * When overriden, this method is called on objects being recycled to * dispose of system resources or to clear references to external * objects potentially on the heap (it allows these external objects to * be garbage collected immediately and therefore reduces the memory * footprint). * * @param obj the object product of this factory being recycled. * @throws UnsupportedOperationException if this factory does not * support object clean-up (default). */ protected void cleanup( T obj) { throw new UnsupportedOperationException(); } /** * Returns a new local pool for this object factory. * Sub-classes may override this method in order to use specialized pools. * * @return a new pool for stack allocation. */ protected ObjectPool newPool() { return new LocalPool(); } /** * Returns the factory object of specified class. * * @return the corresponding factory or null. */ static ObjectFactory getInstance(Class factoryClass) { // Ensures that enclosing class if any is initialized. String className = factoryClass.getName(); int sep = className.lastIndexOf('$'); if (sep > 0) { ClassInitializer.initialize(className.substring(0, sep)); } ClassInitializer.initialize(factoryClass); for (int i = 0; i < ObjectFactory.Count; i++) { if (INSTANCES[i].getClass().equals(factoryClass)) return INSTANCES[i]; } return null; } /** * This class represents the heap pool. */ private final class HeapPool extends ObjectPool { // Implements ObjectPool abstract method. public int size() { return 0; } // Implements ObjectPool abstract method. public T next() { return create(); } // Implements ObjectPool abstract method. public void recycle( T obj) { // No effect for heap pool. } // Implements ObjectPool abstract method. protected void recycleAll() { // No effect for heap pool. } // Implements ObjectPool abstract method. protected void clearAll() { // No effect for heap pool. } } /** * This class represents the default local pool implementation. */ private final class LocalPool extends ObjectPool { /** * Holds the memory area of this pool. */ private final MemoryArea _memoryArea; /** * Indicates if clean-up has to be performed (switches to false if * UnsupportedOperationException raised during clean-up). */ private boolean _doCleanup = true; /** * Holds number of objects held by this pool. */ private int _size; /** * Holds used objects. */ private Node _usedNodes; /** * Holds available objects. */ private Node _availNodes; /** * Holds the tail node of the used list. */ private Node _usedNodesTail; /** * Default constructor. */ private LocalPool() { _memoryArea = MemoryArea.getMemoryArea(this); } // Implements ObjectPool abstract method. public int size() { return _size; } // Implements ObjectPool abstract method. public Object next() { if (_availNodes != null) { // Gets node from recycled. _node = _availNodes; _availNodes = _node._next; } else { // Object creation in the same memory area as the pool. _memoryArea.executeInArea(new Runnable() { public void run() { _node = new Node(); _node._object = create(); } }); _size++; } if (_usedNodes == null) { // Marks tail node. _usedNodesTail = _node; } _node._next = _usedNodes; _usedNodes = _node; return _node._object; } private Node _node; // Implements ObjectPool abstract method. public void recycle(Object obj) { // Cleanups object. if (_doCleanup) { try { cleanup(( T ) obj); } catch (UnsupportedOperationException ex) { _doCleanup = false; } } // Moves associated node from used to available list. if (_usedNodes._object == obj) { // Last one allocated. Node node = _usedNodes; if (node == _usedNodesTail) { // Only one node used. _usedNodesTail = null; if (node._next != null) // Sanity check. throw new JavolutionError("Pool Corrupted"); } _usedNodes = node._next; node._next = _availNodes; _availNodes = node; } else { // Search Node previous = _usedNodes; for (Node node = previous._next; node != null;) { if (node._object == obj) { // Found it. if (node == _usedNodesTail) { // Tail node being removed. _usedNodesTail = previous; } previous._next = node._next; node._next = _availNodes; _availNodes = node; return; } previous = node; node = node._next; } throw new IllegalArgumentException("Object not in the pool"); } } // Implements ObjectPool abstract method. protected void recycleAll() { // Cleanups objects. if (_doCleanup) { try { for (Node node = _usedNodes; node != null;) { cleanup(( T ) node._object); node = node._next; } } catch (UnsupportedOperationException ex) { _doCleanup = false; } } if (_usedNodes != null) { _usedNodesTail._next = _availNodes; _availNodes = _usedNodes; _usedNodes = null; _usedNodesTail = null; } } // Implements ObjectPool abstract method. protected void clearAll() { _availNodes = null; _usedNodes = null; _usedNodesTail = null; } } /** * This inner class represents a simple pool node. */ static final class Node { Object _object; Node _next; } }

Ads help maintain this website.