User: mulder
Date: 00/08/30 05:41:52
Modified: src/main/org/jboss/minerva/pools ObjectPool.java
PoolObjectFactory.java
Log:
Updates to Minerva.
- You can kick an object out of the pool, and set it to do so
automatically when error events are received
- You can enable or disable Minerva logging with a jboss.jcml setting
- JDBC 1/2 wrappers return the same connection for multiple requests
within one transaction
- Remove some .* imports
Still outstanding:
- You can't keep a connection open across commits/rollbacks
- Think about removing "xa." and "jdbc." prefixes from JNDI names
- Think about renaming services to "Minerva XA" and "Minerva JDBC" or
something along those lines to make logging more helpful
Revision Changes Path
1.5 +78 -9 jboss/src/main/org/jboss/minerva/pools/ObjectPool.java
Index: ObjectPool.java
===================================================================
RCS file:
/products/cvs/ejboss/jboss/src/main/org/jboss/minerva/pools/ObjectPool.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- ObjectPool.java 2000/08/18 03:21:09 1.4
+++ ObjectPool.java 2000/08/30 12:41:52 1.5
@@ -6,8 +6,11 @@
*/
package org.jboss.minerva.pools;
-import java.io.*;
-import java.util.*;
+import java.io.PrintWriter;
+import java.util.ConcurrentModificationException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
import org.jboss.logging.Logger;
/**
* A generic object pool. You must provide a PoolObjectFactory (or the class
@@ -25,7 +28,7 @@
* <LI>Shut it down</LI>
* </OL>
* @see org.jboss.minerva.pools.PooledObject
- * @version $Revision: 1.4 $
+ * @version $Revision: 1.5 $
* @author Aaron Mulder ([EMAIL PROTECTED])
*/
public class ObjectPool implements PoolEventListener {
@@ -39,6 +42,7 @@
private String poolName;
private HashMap objects = null;
+ private HashSet deadObjects = null;
private int minSize = 0;
private int maxSize = 0;
private boolean shrinks = false;
@@ -50,6 +54,7 @@
private long lastGC = System.currentTimeMillis();
private boolean blocking = false;
private boolean trackLastUsed = false;
+ private boolean invalidateOnError = false;
private PrintWriter logWriter = null;
/**
@@ -434,6 +439,28 @@
public boolean isTimestampUsed() {return trackLastUsed;}
/**
+ * Sets the response for object errors. If this flag is set and an error
+ * event occurs, the object is removed from the pool entirely. Otherwise,
+ * the object is returned to the pool of available objects. For example, a
+ * SQL error may not indicate a bad database connection (flag not set),
+ * while a TCP/IP error probably indicates a bad network connection (flag
+ * set). If this flag is not set, you can still manually invalidate
+ * objects using markObjectAsInvalid.
+ * @see #markObjectAsInvalid
+ * @see #objectError
+ */
+ public void setInvalidateOnError(boolean invalidate) {
+ if(objects != null)
+ throw new IllegalStateException(INITIALIZED);
+ invalidateOnError = invalidate;
+ }
+
+ /**
+ * Gets whether objects are removed from the pool in case of errors.
+ */
+ public boolean isInvalidateOnError() {return invalidateOnError;}
+
+ /**
* Prepares the pool for use. This must be called exactly once before
* getObject is even called. The pool name and object factory must be set
* before this call will succeed.
@@ -446,6 +473,7 @@
throw new IllegalStateException("Factory and Name must be set before
pool initialization!");
if(objects != null)
throw new IllegalStateException("Cannot initialize more than once!");
+ deadObjects = new HashSet();
objects = new HashMap();
factory.poolStarted(this, logWriter);
lastGC = System.currentTimeMillis();
@@ -489,6 +517,10 @@
if(objects == null)
throw new IllegalStateException("Tried to use pool before it was
Initialized or after it was ShutDown!");
+ Object result = factory.isUniqueRequest();
+ if(result != null) // If this is identical to a previous request,
+ return result; // return the same result. This is unusual.
+
while(true) {
Iterator it = new HashSet(objects.values()).iterator();
while(it.hasNext()) {
@@ -497,7 +529,7 @@
try {
rec.setInUse(true);
Object ob = rec.getObject();
- Object result = factory.prepareObject(ob);
+ result = factory.prepareObject(ob);
if(result != ob) rec.setClientObject(result);
if(result instanceof PooledObject)
((PooledObject)result).addPoolEventListener(this);
@@ -513,7 +545,7 @@
Object ob = factory.createObject();
ObjectRecord rec = new ObjectRecord(ob);
objects.put(ob, rec);
- Object result = factory.prepareObject(ob);
+ result = factory.prepareObject(ob);
if(result != ob) rec.setClientObject(result);
if(result instanceof PooledObject)
((PooledObject)result).addPoolEventListener(this);
@@ -535,7 +567,7 @@
}
log("Pool "+this+" couldn't find an object to return!");
- return null;
+ return result;
}
/**
@@ -567,6 +599,22 @@
}
/**
+ * Indicates that an object is no longer valid, and should be removed from
+ * the pool entirely. This should be called before the object is returned
+ * to the pool (specifically, before factory.returnObject returns), or else
+ * the object may be given out again by the time this is called! Also, you
+ * still need to actually return the object to the pool by calling
+ * releaseObject, if you aren't calling this during that process already.
+ * @param Object The object to invalidate, which must be the exact object
+ * returned by getObject
+ */
+ public void markObjectAsInvalid(Object object) {
+ if(deadObjects == null)
+ throw new IllegalStateException("Tried to use pool before it was
Initialized or after it was ShutDown!");
+ deadObjects.add(object);
+ }
+
+ /**
* Returns an object to the pool. This must be the exact object that was
* given out by getObject, and it must be returned to the same pool that
* generated it. If other clients are blocked waiting on an object, the
@@ -577,6 +625,8 @@
public void releaseObject(Object object) {
if(objects == null)
throw new IllegalStateException("Tried to use pool before it was
Initialized or after it was ShutDown!");
+ boolean removed = false; // Whether we returned to the pool, or threw out
entirely
+
synchronized(object) {
Object pooled = null;
try {
@@ -593,9 +643,25 @@
if(object instanceof PooledObject)
((PooledObject)object).removePoolEventListener(this);
factory.returnObject(object);
- rec.setInUse(false);
+ if(deadObjects.contains(object)) {
+ objects.remove(pooled);
+ try {
+ factory.deleteObject(pooled);
+ } catch(Exception e) {
+ log("Pool "+this+" factory ("+factory.getClass().getName()+"
delete error: "+e);
+ }
+ rec.close();
+ deadObjects.remove(object);
+ removed = true;
+ } else {
+ rec.setInUse(false);
+ removed = false;
+ }
}
- log("Pool "+this+" returned object "+object+" to the pool.");
+ if(removed)
+ log("Pool "+this+" destroyed object "+object+".");
+ else
+ log("Pool "+this+" returned object "+object+" to the pool.");
if(blocking) {
synchronized(this) {
notify();
@@ -633,9 +699,12 @@
/**
* If the object had an error, we assume this will propogate and preclude it
- * from being closed, so we will close it.
+ * from being closed, so we will close it. If the invalidateOnError flag
+ * is set, the object will be removed from the pool entirely.
*/
public void objectError(PoolEvent evt) {
+ if(invalidateOnError)
+ markObjectAsInvalid(evt.getSource());
releaseObject(evt.getSource());
}
1.4 +14 -1 jboss/src/main/org/jboss/minerva/pools/PoolObjectFactory.java
Index: PoolObjectFactory.java
===================================================================
RCS file:
/products/cvs/ejboss/jboss/src/main/org/jboss/minerva/pools/PoolObjectFactory.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- PoolObjectFactory.java 2000/06/05 03:20:16 1.3
+++ PoolObjectFactory.java 2000/08/30 12:41:52 1.4
@@ -11,7 +11,7 @@
/**
* Creates objects to be used in an object pool. This is a class instead of
* an interface so you can ignore any of the methods you don't need.
- * @version $Revision: 1.3 $
+ * @version $Revision: 1.4 $
* @author Aaron Mulder ([EMAIL PROTECTED])
*/
public abstract class PoolObjectFactory {
@@ -107,5 +107,18 @@
* is called when the pool shrinks, and when the pool is shut down.
*/
public void deleteObject(Object pooledObject) {
+ }
+
+ /**
+ * Decides whether a request for an object should be fulfilled by an
+ * object checked out of the pool previously, or a new object. In general,
+ * every request should generate a new object, so this should return null.
+ * @return An existing object, if this request is effectively the same as
+ * a previous request and the result should be shared. <B>null</B>
+ * if this is a unique request and should be fulfilled by a unique
+ * object.
+ */
+ public Object isUniqueRequest() {
+ return null;
}
}