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;
       }
   }
  
  
  

Reply via email to