📄 poolmanager.java
字号:
/*------------------------------------------------------------------------------Name: PoolManager.javaProject: xmlBlaster.orgCopyright: xmlBlaster.org, see xmlBlaster-LICENSE file------------------------------------------------------------------------------*/package org.xmlBlaster.util.pool;import org.xmlBlaster.util.XmlBlasterException;import org.xmlBlaster.util.Timeout;import org.xmlBlaster.util.def.ErrorCode;import java.util.Hashtable;import java.util.Vector;import java.util.Enumeration;/** * A little framework to handle a pool of limited resources. * <p /> * You can use this pool as a base class handling of your limited resources * like a 'JDBC connection pool' or a 'thread pool'. * <p /> * The important attributes of a resource are gathered in the <code>ResourceWrapper</code> class. * <p /> * You can easily handle bigger number of resources with good performance. * <p /> * To find out how to use it see the TestPool example in the main() method of this class. * <p /> * <pre> * State chart of resource handling: * * +<------- reserve() if(numIdle==0) ---------------------+ * | | * | +<- reserve() --+ +<-preReserve() *-+ | * | | if(numIdle>0) | | | | * | | | | | | * ######### ########## ########## * # # # # # # * # busy # # idle # # undef # * # # # # # # * ######### ########## ########## * | | | | | | | | | | | | * | | | Explicit | | | | | Explicit | | | | * | | +-- release() ->+ | | | +-- erase() ----->+ | | | * | | | | | | | | * | +busyToIdleTimeout()>+ | +idleToEraseTimeout()>+ | | * | | | | * | +-- erase on max cycles *->+ | * | | * +--------- busyToEraseTimeout() since creation *-------->+ * * </pre> * There are three states: * <ul> * <li>busy: The resource is in use * </li> * <li>idle: The resource is allocated and ready but not in use * </li> * <li>undef: The resource is not yet allocated or it is erased again * </li> * </ul> * <p> * Note that state transitions marked with '*' are not yet implemented. * If you need one of them, code it and contribute it please. * <p> * You can choose which states you wish for your resource and how timeouts * are used to handle state transitions.<br /> * </p> * <p> * For example if you want to pool user login sessions and want to do * an auto logout after 60 minutes, you would use the busyToIdleTimeout and set it to 60*60*1000.<br /> * If a user is active you can refresh the session with busyRefresh().<br /> * Often you want to use your own generated sessionId as the primary key * for this resource, you can pass it as the instanceId argument to reserve(sessionId).<br /> * (See example [2] in this main() method) * </p> * <p> * If you want to pool JDBC connections, reserve() a connection before you do your query * and release() it immediately again. If you * want to close connections after peak usage, you could set a idleToEraseTimeout, * to erase your JDBC connection after some time not used (reducing the current pool size).<br /> * Note that in this example the connections are anonymous (all are logged in to the database * with the same user name), it is not important which you receive.<br /> * (See example [1] in this main() method) * </p> * <p> * For an implementation example see TestPoolManager.java * </p> * * <p>This code is derived from the org.jutils.pool package.</p> * @author "Marcel Ruff" <ruff@swand.lake.de> * @see org.xmlBlaster.util.pool.ResourceWrapper * @see org.xmlBlaster.test.classtest.TestPoolManager */public final class PoolManager{ /** Nice, unique name for logging output */ private String ME = "PoolManager"; /** A nice name for the generated id */ private String poolName = "Resource"; /** The callback into the using application, which needs to implement the interface I_PoolManager */ private I_PoolManager callback = null; /** Holds busy resources */ private java.util.Hashtable busy = null; /** Holds free resources */ private java.util.Vector idle = null; /** Default maximum pool size (number of resources) */ private int maxInstances = 100; /** Default maximum busy time of a resource, on timeout it changes state from 'busy' to 'idle' */ private long busyToIdleTimeout = 0; /* Default maximum life span of a resource, on timeout it changes state from 'busy' to 'undef' (it is deleted) */ //private long busyToEraseTimeout = 0; /** Default maximum idle span of a resource, on timeout it changes state from 'idle' to 'undef' (it is deleted) */ private long idleToEraseTimeout = 0; /** Unique counter to generate IDs */ private long counter = 1; /** Use this constant with the reserve() method, the PoolManager uses the hashCode() of your object */ public final static String USE_HASH_CODE = "h"; /** Use this constant with the reserve() method, the PoolManager uses the toString() of your object, if no toString() exists the object reference is used, e.g. "oracle.jdbc.driver.OracleConnection@443226" */ public final static String USE_OBJECT_REF = "o"; /** Use this constant with the reserve() method, the PoolManager generates a random, unique in universe session ID */ public final static String GENERATE_RANDOM = "r"; /** Triggers transitions */ private Timeout transitionTimer; private final Object meetingPoint = new Object(); /** * Create a new pool instance with the desired behavior. * <p /> * Implementation:<br /> * There are two list in this class * <ul> * <li>busy: Holds resources which are currently busy</li> * <li>idle: Holds resources in the free pool, waiting to be reused</li> * </ul> * If you ask for a new resource, this will move into the busy list<br /> * Is a resource released or a specified timeout occurred, it is moved into the idle list. * <p /> * @param poolName A nice name for this pool manager instance. * @param callback The interface 'I_PoolManager' callback * @param maxInstances Max. number of resources in this pool. * @param busyToIdleTimeout Max. busy time of this resource in milli seconds<br /> * On timeout it changes state from 'busy' to 'idle'.<br /> * You can overwrite this value for each resource instance<br /> * 0 switches it off<br /> * You get called back through I_PoolManager.busyToIdle() on timeout * allowing you to code some specific handling. * @param idleToEraseTimeout Max. idle time span of this resource in milli seconds<br /> * On timeout it changes state from 'idle' to 'undef' (it is deleted).<br /> * You can overwrite this value for each resource instance<br /> * 0 switches it off<br /> * You get called back through I_PoolManager.toErased() on timeout * allowing you to code some specific handling. */ public PoolManager(String poolName, I_PoolManager callback, int maxInstances, long busyToIdleTimeout, long idleToEraseTimeout) { this.poolName = poolName; // e.g. "SessionId" this.callback = callback; this.ME = poolName + "-PoolManager"; // e.g. "SessionId-PoolManager" this.setMaxInstances(maxInstances); this.setBusyToIdleTimeout(busyToIdleTimeout); this.setIdleToEraseTimeout(idleToEraseTimeout); this.busy = new java.util.Hashtable(maxInstances); this.idle = new java.util.Vector(maxInstances); /* if (busyToIdleTimeout > 0 || idleToEraseTimeout > 0) { System.err.println(ME + ": Created PoolManager with a maximum of " + maxInstances + " instances" + " and a default busy recycling-timeout of " + TimeHelper.millisToNice(this.busyToIdleTimeout) + " and a default idle recycling-timeout of " + TimeHelper.millisToNice(this.idleToEraseTimeout)); } else System.err.println(ME + ": Created PoolManager with a maximum of " + maxInstances + " instances without auto-recycling."); */ } public Timeout getTransistionTimer() { if (this.transitionTimer == null) { synchronized(this) { if (this.transitionTimer == null) this.transitionTimer = new Timeout("XmlBlaster.PoolManagerTimer"); } } return this.transitionTimer; } /** * Set the maximum pool size. * @param maxInstances How many resources are allowed */ private void setMaxInstances(int maxInstances) { this.maxInstances = maxInstances; } /** * On timeout, the resource changes state from 'busy' to 'idle'.<br /> * @param busyToIdleTimeout Max. busy time of this resource in milli seconds<br /> * On timeout it changes state from 'busy' to 'idle'.<br /> * You can overwrite this value for each resource instance<br /> * 0 switches it off */ private void setBusyToIdleTimeout(long busyToIdleTimeout) { if (busyToIdleTimeout > 0 && busyToIdleTimeout < 100) { // System.err.println(ME + ": Setting minimum release timeout from " + busyToIdleTimeout + " to 100 milli seconds."); this.busyToIdleTimeout = 100; } else this.busyToIdleTimeout = busyToIdleTimeout; } /** * Set the max. life span of the resources. * @param idleToEraseTimeout Max. idle time of this resource in milli seconds<br /> * You can overwrite this value for each resource instance<br /> * 0 switches it off */ private void setIdleToEraseTimeout(long idleToEraseTimeout) { if (idleToEraseTimeout > 0 && idleToEraseTimeout < 100) { // System.err.println(ME + ": Setting minimum idleErase timeout from " + idleToEraseTimeout + " to 100 milli seconds."); this.idleToEraseTimeout = 100; } else this.idleToEraseTimeout = idleToEraseTimeout; } /** * Get a new resource. * <p /> * The life span is set to the default value of the pool. * <p /> * The instance Id is random and unique generated. * @exception XmlBlasterException Error with random generator */ public ResourceWrapper reserve() throws XmlBlasterException { return reserve(busyToIdleTimeout, idleToEraseTimeout, GENERATE_RANDOM); } /** * Get a new resource. * <p /> * The life span is set to the default value of the pool. * <p /> * @param instanceId See description in other reserve() method. * @exception XmlBlasterException Error with random generator */ public ResourceWrapper reserve(String instanceId) throws XmlBlasterException { return reserve(busyToIdleTimeout, idleToEraseTimeout, instanceId); } /** * Get a new resource. * * @param localBusyToIdleTimeout Max. busy time of this resource in milli seconds, * only for this current resource<br /> * Overwrite locally the default<br /> * 0 switches busy timeout off * * @param localIdleToEraseTimeout Max. idle time of this resource in milli seconds, * only for this current resource<br /> * Overwrite locally the default<br /> * 0 switches idle timeout off * * @param instanceId If given and string length > 1, the delivered ID is used: * If in busy list found, this is returned, else a new is created.<br /> * USE_HASH_CODE - The PoolManager generates a simple one (hashCode())<br /> * USE_OBJECT_REF - The object reference is used<br /> * GENERATE_RANDOM - The PoolManager generates a random, unique in universe session ID * * @return rw The resource handle (always != null) * * @exception XmlBlasterException Error with random generator */ public ResourceWrapper reserve(long localBusyToIdleTimeout, long localIdleToEraseTimeout, String instanceId) throws XmlBlasterException { synchronized (meetingPoint) { ResourceWrapper rw = null; if (instanceId != null && instanceId.length() > 1) { rw = findBusySilent(instanceId); if (rw != null) { // System.out.println(ME + ": Reconnected to busy resource '" + instanceId + "' ..."); return rw; } } if (idle.size() > 0) { // System.out.println(ME + ": Resource is recycled from idle pool ..."); rw = (ResourceWrapper) idle.lastElement(); rw.init(createId(instanceId), rw.getResource(), localBusyToIdleTimeout, localIdleToEraseTimeout); swap(rw, true); // System.out.println(ME + ": Access on cached resource '" + rw.getInstanceId() + "' granted"); // dumpState(rw.getInstanceId()); } else if (busy.size() >= maxInstances) { // CAUTION: ErrorCode.RESOURCE_EXHAUST is a well defined string which may not be changed, it is used from the caller to identify the situation XmlBlasterException e = new XmlBlasterException("ResourceExhaust", "Sorry, " + maxInstances + " resources consumed, no more resources available"); e.changeErrorCode(ErrorCode.RESOURCE_EXHAUST); throw e; } else { instanceId = createId(instanceId); Object resource = callback.toCreate(instanceId); rw = new ResourceWrapper(this, instanceId, resource, localBusyToIdleTimeout, idleToEraseTimeout); rw.toBusy(); busy.put(rw.getInstanceId(), rw); // System.out.println(ME + ": Granted access to new resource '" + rw.getInstanceId() + "'"); // dumpState(rw.getInstanceId()); } return rw; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -