You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ojb-dev@db.apache.org by ar...@apache.org on 2003/12/13 18:50:40 UTC

cvs commit: db-ojb/src/test/org/apache/ojb/broker RsIteratorTest.java

arminw      2003/12/13 09:50:40

  Modified:    src/java/org/apache/ojb/broker/accesslayer RsIterator.java
                        ResultSetAndStatement.java
               src/test/org/apache/ojb/broker RsIteratorTest.java
  Log:
  made RsIterator more strict in handling used StatementAndResultSet
  resources. Now we close all resources when associate PB instance
  closed/commit../abort... methods were called (add RsIterator as
  PBStateListener)
  
  change log level of finalze method calls of
  RsIterator and StatementAndResultSet
  
  Revision  Changes    Path
  1.54      +261 -132  db-ojb/src/java/org/apache/ojb/broker/accesslayer/RsIterator.java
  
  Index: RsIterator.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/RsIterator.java,v
  retrieving revision 1.53
  retrieving revision 1.54
  diff -u -r1.53 -r1.54
  --- RsIterator.java	9 Dec 2003 17:19:59 -0000	1.53
  +++ RsIterator.java	13 Dec 2003 17:50:40 -0000	1.54
  @@ -51,11 +51,15 @@
   import java.util.Map;
   import java.util.NoSuchElementException;
   import java.util.Vector;
  +import java.lang.ref.WeakReference;
   
   import org.apache.ojb.broker.Identity;
   import org.apache.ojb.broker.PBLifeCycleEvent;
   import org.apache.ojb.broker.PersistenceBrokerException;
   import org.apache.ojb.broker.VirtualProxy;
  +import org.apache.ojb.broker.PBStateListener;
  +import org.apache.ojb.broker.PBStateEvent;
  +import org.apache.ojb.broker.OJBRuntimeException;
   import org.apache.ojb.broker.cache.ObjectCache;
   import org.apache.ojb.broker.core.PersistenceBrokerImpl;
   import org.apache.ojb.broker.metadata.ClassDescriptor;
  @@ -73,10 +77,23 @@
    * PersistenceBroker::getCollectionByQuery(...) method uses a RsIterator
    * internally to build up a Collection of objects
    *
  + * <p>
  + * NOTE: OJB is very strict in handling <tt>RsIterator</tt> instances. <tt>RsIterator</tt> is
  + * bound very closely to the used {@link org.apache.ojb.broker.PersistenceBroker} instance.
  + * Thus if you do a
  + * <br/> - {@link org.apache.ojb.broker.PersistenceBroker#close}
  + * <br/> - {@link org.apache.ojb.broker.PersistenceBroker#commitTransaction}
  + * <br/> - {@link org.apache.ojb.broker.PersistenceBroker#abortTransaction}
  + * <br/>
  + * call, the current <tt>RsIterator</tt> instance resources will be cleaned up automatic
  + * and invalidate current instance.
  + * </p>
  + *
  + * <p>
    * NOTE: this code uses features that only JDBC 2.0 compliant Drivers support.
    * It will NOT work with JDBC 1.0 Drivers (e.g. SUN's JdbcOdbcDriver) If you
    * are forced to use such a driver, you can use code from the 0.1.30 release.
  - *
  + * </p>
    * @author <a href="mailto:thma@apache.org">Thomas Mahler <a>
    * @author <a href="mailto:mattbaird@yahoo.com">Matthew Baird <a>- added the
    *         support for extents mapped to single table - added the .size
  @@ -96,66 +113,66 @@
       private ObjectCache m_cache;
   
       /**
  -	 * reference to the PersistenceBroker
  -	 */
  +     * reference to the PersistenceBroker
  +     */
       private PersistenceBrokerImpl m_broker;
   
       /**
  -	 * the underlying resultset
  -	 */
  +     * the underlying resultset
  +     */
       private ResultSetAndStatement m_rsAndStmt;
   
       /**
  -	 * the underlying query object
  -	 */
  +     * the underlying query object
  +     */
       private RsQueryObject m_queryObject;
   
       /**
  -	 * the proxy class to be used or null
  -	 */
  +     * the proxy class to be used or null
  +     */
       private Class m_itemProxyClass;
   
       /**
  -	 * the top-level class of the item objects
  -	 */
  +     * the top-level class of the item objects
  +     */
       private Class m_itemTopLevelClass = null;
   
       /**
  -	 * this container holds the values of the current ro during materialisation
  -	 */
  +     * this container holds the values of the current ro during materialisation
  +     */
       private Map m_row = null;
   
       /**
  -	 * flag that indicates wether hasNext on m_rs has allready been called
  -	 */
  +     * flag that indicates wether hasNext on m_rs has allready been called
  +     */
       private boolean m_hasCalledCheck = false;
   
       /**
  -	 * prefetch relationship: inBatchedMode true prevents releasing of
  -	 * DbResources IN_LIMIT defines the max number of values of sql (IN) , -1
  -	 * for no limits
  -	 */
  +     * prefetch relationship: inBatchedMode true prevents releasing of
  +     * DbResources IN_LIMIT defines the max number of values of sql (IN) , -1
  +     * for no limits
  +     */
       private boolean m_inBatchedMode = false;
   
       /**
  -	 * return value of the previously called hasNext from m_rs
  -	 */
  +     * return value of the previously called hasNext from m_rs
  +     */
       private boolean hasNext = false;
   
       private boolean advancedJDBCSupport = false;
       private boolean JDBCSupportAssessed = false;
       private int m_current_row = 0;
       /**
  -	 * Tracks whether or not the resources that are used by this class have been released.
  -	 */
  +     * Tracks whether or not the resources that are used by this class have been released.
  +     */
       private boolean resourcesAreReleased = false;
   
       /**
  -	 * RsIterator constructor.
  -	 *
  -	 * @param queryObject query object
  -	 * @param broker the broker we should use.
  -	 */
  +     * RsIterator constructor.
  +     *
  +     * @param queryObject query object
  +     * @param broker the broker we should use.
  +     */
       public RsIterator(RsQueryObject queryObject, final PersistenceBrokerImpl broker)
       {
           setCache(broker.serviceObjectCache());
  @@ -198,6 +215,13 @@
               releaseDbResources();
               throw e;
           }
  +
  +        /*
  +        now RsIterator instance is created, we wrap this instance with a
  +        PBStateListener to make sure that resources of this instance will be
  +        released. Add this as temporary PBStateListener.
  +        */
  +        m_broker.addListener(new ResourceWrapper(this));
       }
   
       protected Class getTopLevelClass()
  @@ -210,9 +234,9 @@
       }
   
       /**
  -	 * returns true if there are still more rows in the underlying ResultSet.
  -	 * Returns false if ResultSet is exhausted.
  -	 */
  +     * returns true if there are still more rows in the underlying ResultSet.
  +     * Returns false if ResultSet is exhausted.
  +     */
       public synchronized boolean hasNext()
       {
           try
  @@ -231,6 +255,10 @@
           {
               setHasNext(false);
               releaseDbResources();
  +            if(ex instanceof ResourceClosedException)
  +            {
  +                throw (ResourceClosedException)ex;
  +            }
           }
           if (logger.isDebugEnabled())
               logger.debug("hasNext() -> " + getHasNext());
  @@ -239,9 +267,9 @@
       }
   
       /**
  -	 * moves to the next row of the underlying ResultSet and returns the
  -	 * corresponding Object materialized from this row.
  -	 */
  +     * moves to the next row of the underlying ResultSet and returns the
  +     * corresponding Object materialized from this row.
  +     */
       public synchronized Object next() throws NoSuchElementException
       {
           try
  @@ -271,23 +299,30 @@
           catch (Exception ex)
           {
               releaseDbResources();
  -            ex.printStackTrace();
  -            logger.error(ex);
  -            throw new NoSuchElementException("Could not obtain next object: " + ex.getMessage());
  +            // ex.printStackTrace();
  +            if(ex instanceof ResourceClosedException)
  +            {
  +                throw (ResourceClosedException) ex;
  +            }
  +            else
  +            {
  +                logger.error("Error while iterate ResultSet for query " + m_queryObject, ex);
  +                throw new NoSuchElementException("Could not obtain next object: " + ex.getMessage());
  +            }
           }
       }
   
       /**
  -	 * removing is not supported
  -	 */
  +     * removing is not supported
  +     */
       public void remove()
       {
           throw new UnsupportedOperationException("removing not supported by RsIterator");
       }
   
       /**
  -	 * read all objects of this iterator. objects will be placed in cache
  -	 */
  +     * read all objects of this iterator. objects will be placed in cache
  +     */
       private Collection getOwnerObjects()
       {
           Collection owners = new Vector();
  @@ -299,9 +334,9 @@
       }
   
       /**
  -	 * prefetch defined relationships requires JDBC level 2.0, does not work
  -	 * with Arrays
  -	 */
  +     * prefetch defined relationships requires JDBC level 2.0, does not work
  +     * with Arrays
  +     */
       private void prefetchRelationships(Query query)
       {
           List prefetchedRel;
  @@ -331,7 +366,7 @@
           {
               relName = (String) prefetchedRel.get(i);
               prefetchers[i] =
  -                RelationshipPrefetcherFactory.createRelationshipPrefetcher(getBroker(), getQueryObject().getClassDescriptor(), relName);
  +                    RelationshipPrefetcherFactory.createRelationshipPrefetcher(getBroker(), getQueryObject().getClassDescriptor(), relName);
               prefetchers[i].prepareRelationshipSettings();
           }
   
  @@ -364,8 +399,8 @@
       }
   
       /**
  -	 * returns an Identity object representing the current resultset row
  -	 */
  +     * returns an Identity object representing the current resultset row
  +     */
       protected Identity getIdentityFromResultSet() throws PersistenceBrokerException
       {
           // fill primary key values from Resultset
  @@ -384,22 +419,22 @@
       }
   
       /**
  -	 * returns a fully materialized Object from the current row of the
  -	 * underlying resultset. Works as follows: - read Identity from the primary
  -	 * key values of current row - check if Object is in cache - return cached
  -	 * object or read it from current row and put it in cache
  -	 */
  +     * returns a fully materialized Object from the current row of the
  +     * underlying resultset. Works as follows: - read Identity from the primary
  +     * key values of current row - check if Object is in cache - return cached
  +     * object or read it from current row and put it in cache
  +     */
       protected Object getObjectFromResultSet() throws PersistenceBrokerException
       {
           /**
  -		 * MBAIRD if a proxy is to be used, return a proxy instance and dont
  -		 * perfom a full materialization. NOTE: Potential problem here with
  -		 * multi-mapped table. The itemProxyClass is for the m_cld
  -		 * classdescriptor. The object you are materializing might not be of
  -		 * that type, it could be a subclass. We should get the concrete class
  -		 * type out of the resultset then check the proxy from that.
  -		 * itemProxyClass should NOT be a member variable.
  -		 */
  +         * MBAIRD if a proxy is to be used, return a proxy instance and dont
  +         * perfom a full materialization. NOTE: Potential problem here with
  +         * multi-mapped table. The itemProxyClass is for the m_cld
  +         * classdescriptor. The object you are materializing might not be of
  +         * that type, it could be a subclass. We should get the concrete class
  +         * type out of the resultset then check the proxy from that.
  +         * itemProxyClass should NOT be a member variable.
  +         */
   
           if (getItemProxyClass() != null)
           {
  @@ -424,7 +459,7 @@
               {
                   // 3. If Object is not in cache
                   // materialize Object with primitive attributes filled from
  -				// current row
  +                // current row
                   result = getQueryObject().getClassDescriptor().getRowReader().readObjectFrom(getRow());
                   // result may still be null!
                   if (result != null)
  @@ -442,12 +477,12 @@
   						 */
                           // LoadedObjectsRegistry.register(result);
                           /**
  -						 * MBAIRD if you have multiple classes mapped to a
  -						 * table, and you query on the base class you could get
  -						 * back NON base class objects, so we shouldn't pass
  -						 * m_cld, but rather the class descriptor for the
  -						 * actual class.
  -						 */
  +                         * MBAIRD if you have multiple classes mapped to a
  +                         * table, and you query on the base class you could get
  +                         * back NON base class objects, so we shouldn't pass
  +                         * m_cld, but rather the class descriptor for the
  +                         * actual class.
  +                         */
                           // fill reference and collection attributes
                           ClassDescriptor cld = getQueryObject().getClassDescriptor().getRepository().getDescriptorFor(result.getClass());
                           // don't force loading of reference
  @@ -459,10 +494,10 @@
                   }
               }
               else // Object is in cache
  -                {
  +            {
                   ClassDescriptor cld = getQueryObject().getClassDescriptor().getRepository().getDescriptorFor(result.getClass());
                   // if refresh is required, update the cache instance from the
  -				// db
  +                // db
                   if (cld.isAlwaysRefresh())
                   {
                       getQueryObject().getClassDescriptor().getRowReader().refreshObject(result, getRow());
  @@ -475,13 +510,13 @@
       }
   
       /**
  -	 * Reads primary key information from current RS row and generates a
  -	 *
  -	 * corresponding Identity, and returns a proxy from the Identity.
  -	 *
  -	 * @throws PersistenceBrokerException
  -	 *             if there was an error creating the proxy class
  -	 */
  +     * Reads primary key information from current RS row and generates a
  +     *
  +     * corresponding Identity, and returns a proxy from the Identity.
  +     *
  +     * @throws PersistenceBrokerException
  +     *             if there was an error creating the proxy class
  +     */
       protected Object getProxyFromResultSet() throws PersistenceBrokerException
       {
           // 1. get Identity of current row:
  @@ -492,12 +527,12 @@
       }
   
       /**
  -	 * with a new batch of JDBC 3.0 drivers coming out we can't just check for
  -	 * begins with 2, we need to check the actual version and see if it's
  -	 * greater than or equal to 2
  -	 *
  -	 * @return
  -	 */
  +     * with a new batch of JDBC 3.0 drivers coming out we can't just check for
  +     * begins with 2, we need to check the actual version and see if it's
  +     * greater than or equal to 2
  +     *
  +     * @return
  +     */
       private boolean supportsAdvancedJDBCCursorControl()
       {
           if (!JDBCSupportAssessed)
  @@ -510,10 +545,10 @@
       }
   
       /**
  -	 * Answer the counted size
  -	 *
  -	 * @return int
  -	 */
  +     * Answer the counted size
  +     *
  +     * @return int
  +     */
       protected int countedSize() throws PersistenceBrokerException
       {
           Query countQuery = getBroker().serviceBrokerHelper().getCountQuery(getQueryObject().getQuery());
  @@ -553,9 +588,9 @@
       }
   
       /**
  -	 * @return the size of the iterator, aka the number of rows in this
  -	 *         iterator.
  -	 */
  +     * @return the size of the iterator, aka the number of rows in this
  +     *         iterator.
  +     */
       public int size() throws PersistenceBrokerException
       {
           int retval = 0; // default size is 0;
  @@ -568,14 +603,14 @@
           {
           }
           if (!supportsAdvancedJDBCCursorControl()
  -            || getBroker().serviceConnectionManager().getSupportedPlatform().useCountForResultsetSize()
  -            || forwardOnly)
  +                || getBroker().serviceConnectionManager().getSupportedPlatform().useCountForResultsetSize()
  +                || forwardOnly)
           {
               /**
  -			 * MBAIRD: doesn't support the .last .getRow method, use the
  -			 * .getCount on the persistenceBroker which executes a count(*)
  -			 * query.
  -			 */
  +             * MBAIRD: doesn't support the .last .getRow method, use the
  +             * .getCount on the persistenceBroker which executes a count(*)
  +             * query.
  +             */
               if (logger.isDebugEnabled())
                   logger.debug("Executing count(*) to get size()");
               retval = countedSize();
  @@ -583,11 +618,11 @@
           else
           {
               /**
  -			 * Use the .last .getRow method of finding size. The reason for
  -			 * supplying an alternative method is effeciency, some driver/db
  -			 * combos are a lot more efficient at just moving the cursor and
  -			 * returning the row in a real (not -1) number.
  -			 */
  +             * Use the .last .getRow method of finding size. The reason for
  +             * supplying an alternative method is effeciency, some driver/db
  +             * combos are a lot more efficient at just moving the cursor and
  +             * returning the row in a real (not -1) number.
  +             */
               int whereIAm = 1; // first
               try
               {
  @@ -630,14 +665,14 @@
       }
   
       /**
  -	 * Moves the cursor to the given row number in the iterator. If the row
  -	 * number is positive, the cursor moves to the given row number with
  -	 * respect to the beginning of the iterator. The first row is row 1, the
  -	 * second is row 2, and so on.
  -	 *
  -	 * @param row
  -	 *            the row to move to in this iterator, by absolute number
  -	 */
  +     * Moves the cursor to the given row number in the iterator. If the row
  +     * number is positive, the cursor moves to the given row number with
  +     * respect to the beginning of the iterator. The first row is row 1, the
  +     * second is row 2, and so on.
  +     *
  +     * @param row
  +     *            the row to move to in this iterator, by absolute number
  +     */
       public boolean absolute(int row) throws PersistenceBrokerException
       {
           boolean retval = false;
  @@ -689,21 +724,21 @@
               else
               {
                   logger.info(
  -                    "Your driver does not support advanced JDBC Functionality, you cannot call absolute() with a position < current");
  +                        "Your driver does not support advanced JDBC Functionality, you cannot call absolute() with a position < current");
               }
           }
           return retval;
       }
   
       /**
  -	 * Moves the cursor a relative number of rows, either positive or negative.
  -	 * Attempting to move beyond the first/last row in the iterator positions
  -	 * the cursor before/after the the first/last row. Calling relative(0) is
  -	 * valid, but does not change the cursor position.
  -	 *
  -	 * @param row
  -	 *            the row to move to in this iterator, by relative number
  -	 */
  +     * Moves the cursor a relative number of rows, either positive or negative.
  +     * Attempting to move beyond the first/last row in the iterator positions
  +     * the cursor before/after the the first/last row. Calling relative(0) is
  +     * valid, but does not change the cursor position.
  +     *
  +     * @param row
  +     *            the row to move to in this iterator, by relative number
  +     */
       public boolean relative(int row) throws SQLException
       {
           boolean retval = false;
  @@ -737,11 +772,11 @@
       }
   
       /**
  -	 * Release all internally used Database resources of the iterator. Clients
  -	 * must call this methods explicitely if the iterator is not exhausted by
  -	 * the client application. If the Iterator is exhauseted this method will
  -	 * be called implicitely.
  -	 */
  +     * Release all internally used Database resources of the iterator. Clients
  +     * must call this methods explicitely if the iterator is not exhausted by
  +     * the client application. If the Iterator is exhauseted this method will
  +     * be called implicitely.
  +     */
       public void releaseDbResources()
       {
           if (!isInBatchedMode()) // resources are reused in batched mode
  @@ -750,7 +785,7 @@
               if (!this.resourcesAreReleased)
               {
                   this.resourcesAreReleased = true;
  -                if(m_rsAndStmt != null)
  +                if (m_rsAndStmt != null)
                   {
                       m_rsAndStmt.close();
                       m_rsAndStmt = null;
  @@ -760,8 +795,8 @@
       }
   
       /**
  -	 * Return the DescriptorRepository
  -	 */
  +     * Return the DescriptorRepository
  +     */
       protected DescriptorRepository getDescriptorRepository()
       {
           return getBroker().getDescriptorRepository();
  @@ -773,13 +808,14 @@
       }
   
       /**
  -	 * safety just in case someone leaks.
  -	 */
  +     * safety just in case someone leaks.
  +     */
       protected void finalize()
       {
  -        if(m_rsAndStmt != null)
  +        if (m_rsAndStmt != null)
           {
  -            logger.warn("Found unclosed resources while finalize (causer class: "+this.getClass().getName()+")");
  +            logger.info("Found unclosed resources while finalize (causer class: " + this.getClass().getName() + ")" +
  +                    " Do automatic cleanup");
               releaseDbResources();
           }
       }
  @@ -790,8 +826,8 @@
       }
   
       /**
  -	 * @return Returns the cld.
  -	 */
  +     * @return Returns the cld.
  +     */
       public ClassDescriptor getClassDescriptor()
       {
           return getQueryObject().getClassDescriptor();
  @@ -815,6 +851,11 @@
   
       protected ResultSetAndStatement getRsAndStmt()
       {
  +        if(resourcesAreReleased)
  +        {
  +            throw new ResourceClosedException("Resources no longer reachable, RsIterator will be automatic" +
  +                    " cleaned up on PB.close/.commitTransaction/.abortTransaction");
  +        }
           return m_rsAndStmt;
       }
   
  @@ -896,5 +937,93 @@
       protected boolean isInBatchedMode()
       {
           return m_inBatchedMode;
  +    }
  +
  +    //***********************************************************
  +    // inner classes
  +    //***********************************************************
  +    /**
  +     * Wraps a {@link RsIterator} instance as {@link WeakReference}.
  +     */
  +    public static class ResourceWrapper implements PBStateListener
  +    {
  +        /*
  +        we do register a PBStateListener to PB instance
  +        to make sure that this instance will be cleaned up at PB.close() call.
  +        If PB was in tx, we cleanup on PB.commit/abort because we create
  +        RsIterator instance within a tx.
  +        TODO: Check beforeRollback, beforeCommit method calls - is this too strict?
  +        */
  +        WeakReference ref;
  +
  +        public ResourceWrapper(RsIterator rs)
  +        {
  +            ref = new WeakReference(rs);
  +        }
  +
  +        public void beforeClose(PBStateEvent event)
  +        {
  +            if(ref != null && ref.get() != null)
  +            {
  +                ((RsIterator)ref.get()).releaseDbResources();
  +                ref = null;
  +            }
  +        }
  +
  +        public void beforeRollback(PBStateEvent event)
  +        {
  +            if(ref != null && ref.get() != null)
  +            {
  +                ((RsIterator)ref.get()).releaseDbResources();
  +                ref = null;
  +            }
  +        }
  +
  +        public void beforeCommit(PBStateEvent event)
  +        {
  +            if(ref != null && ref.get() != null)
  +            {
  +                ((RsIterator)ref.get()).releaseDbResources();
  +                ref = null;
  +            }
  +        }
  +
  +        public void afterCommit(PBStateEvent event)
  +        {
  +        }
  +        public void afterRollback(PBStateEvent event)
  +        {
  +        }
  +        public void afterBegin(PBStateEvent event)
  +        {
  +        }
  +        public void beforeBegin(PBStateEvent event)
  +        {
  +        }
  +        public void afterOpen(PBStateEvent event)
  +        {
  +        }
  +    }
  +
  +    public static class ResourceClosedException extends OJBRuntimeException
  +    {
  +        public ResourceClosedException()
  +        {
  +        }
  +
  +        public ResourceClosedException(String msg)
  +        {
  +            super(msg);
  +        }
  +
  +        public ResourceClosedException(Throwable cause)
  +        {
  +            super(cause);
  +        }
  +
  +        public ResourceClosedException(String msg, Throwable cause)
  +        {
  +            super(msg, cause);
  +        }
       }
   }
  
  
  
  1.10      +10 -3     db-ojb/src/java/org/apache/ojb/broker/accesslayer/ResultSetAndStatement.java
  
  Index: ResultSetAndStatement.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/ResultSetAndStatement.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- ResultSetAndStatement.java	27 Nov 2003 14:50:23 -0000	1.9
  +++ ResultSetAndStatement.java	13 Dec 2003 17:50:40 -0000	1.10
  @@ -137,8 +137,15 @@
           super.finalize();
           if(!isClosed && (m_stmt != null || m_rs != null))
           {
  -            log.error("** Associated resources (Statement/ResultSet) not closed!" +
  -                    " This could lead in leaking resources **");
  +            log.warn("** Associated resources (Statement/ResultSet) not closed!" +
  +                    " Try automatic cleanup **");
  +            try
  +            {
  +                close();
  +            }
  +            catch (Exception ignore)
  +            {
  +            }
           }
       }
   }
  
  
  
  1.4       +191 -43   db-ojb/src/test/org/apache/ojb/broker/RsIteratorTest.java
  
  Index: RsIteratorTest.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/test/org/apache/ojb/broker/RsIteratorTest.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- RsIteratorTest.java	7 Jun 2003 10:18:33 -0000	1.3
  +++ RsIteratorTest.java	13 Dec 2003 17:50:40 -0000	1.4
  @@ -1,7 +1,10 @@
   package org.apache.ojb.broker;
   
  +import java.util.Iterator;
  +
   import junit.framework.TestCase;
   import org.apache.ojb.broker.query.*;
  +import org.apache.ojb.broker.accesslayer.RsIterator;
   
   /**
    * Test case for the RsIterator
  @@ -9,67 +12,212 @@
    * @author <a href="mailto:rongallagher@bellsouth.net">Ron Gallagher<a>
    * @version $Id$
    */
  -public class RsIteratorTest extends TestCase {
  -    private static Class CLASS = RsIteratorTest.class;
  -    private int COUNT = 10;
  -
  -    public static void main(String[] args){
  -        String[] arr = {CLASS.getName()};
  +public class RsIteratorTest extends TestCase
  +{
  +    private PersistenceBroker broker;
  +
  +    public static void main(String[] args)
  +    {
  +        String[] arr = {RsIteratorTest.class.getName()};
           junit.textui.TestRunner.main(arr);
       }
   
  -    /**
  -     * Insert the method's description here.
  -     * Creation date: (24.12.2000 00:33:40)
  -     */
  -    public RsIteratorTest(String name){
  +    public RsIteratorTest(String name)
  +    {
           super(name);
       }
   
  +    public void setUp()
  +    {
  +        broker = PersistenceBrokerFactory.defaultPersistenceBroker();
  +    }
  +
  +    public void tearDown()
  +    {
  +        if(broker != null)
  +        {
  +            broker.close();
  +        }
  +    }
  +
  +    public void testRsIterator() throws Exception
  +    {
  +        String name = "testRsIterator_" + System.currentTimeMillis();
  +        prepareTest(name);
  +
  +        Criteria criteria = new Criteria();
  +        criteria.addLike("name", name+"*");
  +        Query query = new QueryByCriteria(ObjectRepository.Component.class, criteria);
  +
  +        Iterator it = broker.getIteratorByQuery(query);
  +        int k = 0;
  +        while(it.hasNext())
  +        {
  +            it.next();
  +            k++;
  +        }
  +        assertEquals("Wrong number of items found", 2, k);
  +    }
  +
       /**
  -     * Insert the method's description here.
  -     * Creation date: (06.12.2000 21:58:53)
  +     * Test RsIterator cleanup on PB.commitTransaction()
        */
  -    public void setUp(){
  +    public void testRsIteratorAutomaticCleanupCheck_1() throws Exception
  +    {
  +        String name = "testRsIteratorAutomaticCleanupCheck_1_" + System.currentTimeMillis();
  +        prepareTest(name);
  +
  +        Criteria criteria = new Criteria();
  +        criteria.addLike("name", name+"*");
  +        Query query = new QueryByCriteria(ObjectRepository.Component.class, criteria);
  +
  +        Iterator it = broker.getIteratorByQuery(query);
  +        it.hasNext();
  +        broker.beginTransaction();
  +        broker.commitTransaction();
  +        /*
  +        if tx was commited we invalidate RsIterator instance
  +        */
  +        try
  +        {
  +            it.next();
  +            fail("We expect RsIterator has released resources on pb.commit..");
  +        }
  +        catch (RsIterator.ResourceClosedException e)
  +        {
  +            assertTrue(true);
  +        }
  +
  +
  +        it = broker.getIteratorByQuery(query);
  +        it.hasNext();
  +        it.next();
  +        broker.beginTransaction();
  +        broker.commitTransaction();
  +        /*
  +        if tx was commited we invalidate RsIterator instance
  +        */
  +        try
  +        {
  +            it.hasNext();
  +            it.next();
  +            fail("We expect RsIterator has released resources on pb.commit..");
  +        }
  +        catch (RsIterator.ResourceClosedException e)
  +        {
  +            assertTrue(true);
  +        }
       }
   
       /**
  -     * Test retrieving data via the rsIterator
  +     * Test RsIterator cleanup on PB.abortTransaction()
        */
  -    public void testIterator()
  -    throws Exception{
  +    public void testRsIteratorAutomaticCleanupCheck_2() throws Exception
  +    {
  +        String name = "testRsIteratorAutomaticCleanupCheck_" + System.currentTimeMillis();
  +        prepareTest(name);
  +
  +        Criteria criteria = new Criteria();
  +        criteria.addLike("name", name+"*");
  +        Query query = new QueryByCriteria(ObjectRepository.Component.class, criteria);
  +
  +        Iterator it = broker.getIteratorByQuery(query);
  +        it.hasNext();
  +        broker.beginTransaction();
  +        broker.abortTransaction();
  +        /*
  +        if tx was aborted we invalidate RsIterator instance
  +        */
  +        try
  +        {
  +            it.next();
  +            fail("We expect RsIterator has released resources on pb.commit..");
  +        }
  +        catch (RsIterator.ResourceClosedException e)
  +        {
  +            assertTrue(true);
  +        }
   
  -        // Get the broker
  -        PersistenceBroker broker = PersistenceBrokerFactory.defaultPersistenceBroker();
  -        try {
  -            // Build the query
  -            Criteria criteria = new Criteria();
  -            criteria.addEqualTo("id",new Integer(1));
  -            Query query = new QueryByCriteria(Person.class,criteria);
  -            // Run the query.
  -            Person person = (Person)broker.getObjectByQuery(query);
  -            // The previous call may or may not return a 'real' Person
  -            // object.  What it returns is not important.  The test here
  -            // is whether or not this call raises an error or not.  When
  -            // this code runs using hsqldb, it works fine.  However, when
  -            // this code runs against Oracle, it fails with a null pointer
  -            // exception.
  -        } catch ( Exception e ) {
  -            fail(e.toString());
  -            e.printStackTrace();
  -            throw e;
  -        } finally {
  -            // Release resources
  -            broker.close();
  +
  +        it = broker.getIteratorByQuery(query);
  +        it.hasNext();
  +        it.next();
  +        broker.beginTransaction();
  +        broker.abortTransaction();
  +        /*
  +        if tx was aborted we invalidate RsIterator instance
  +        */
  +        try
  +        {
  +            it.hasNext();
  +            it.next();
  +            fail("We expect RsIterator has released resources on pb.commit..");
  +        }
  +        catch (RsIterator.ResourceClosedException e)
  +        {
  +            assertTrue(true);
           }
       }
   
       /**
  -     * Insert the method's description here.
  -     * Creation date: (06.12.2000 21:59:14)
  +     * Test RsIterator cleanup on PB.close()
        */
  -    public void tearDown(){
  +    public void testRsIteratorAutomaticCleanupCheck_3() throws Exception
  +    {
  +        String name = "testRsIteratorAutomaticCleanupCheck_" + System.currentTimeMillis();
  +        prepareTest(name);
  +
  +        Criteria criteria = new Criteria();
  +        criteria.addLike("name", name+"*");
  +        Query query = new QueryByCriteria(ObjectRepository.Component.class, criteria);
  +
  +        Iterator it = broker.getIteratorByQuery(query);
  +        broker.close();
  +        /*
  +        if was closed we invalidate RsIterator instance
  +        */
  +        try
  +        {
  +            if(it.hasNext()) it.next();
  +            fail("We expect RsIterator has released resources on pb.commit..");
  +        }
  +        catch (RsIterator.ResourceClosedException e)
  +        {
  +            assertTrue(true);
  +        }
  +    }
  +
  +    private void prepareTest(String objectName)
  +    {
  +        ObjectRepository.Component c1 = new ObjectRepository.Component();
  +        c1.setName(objectName + "_1");
  +        ObjectRepository.Component c2 = new ObjectRepository.Component();
  +        c2.setName(objectName + "_2");
  +
  +        broker.beginTransaction();
  +        broker.store(c1);
  +        broker.store(c2);
  +        broker.commitTransaction();
       }
   
  +    /**
  +     * Test retrieving data via the rsIterator
  +     * test by Ron Gallagher
  +     */
  +    public void testInternUsedRsIterator() throws Exception
  +    {
  +        // Build the query
  +        Criteria criteria = new Criteria();
  +        criteria.addEqualTo("id", new Integer(1));
  +        Query query = new QueryByCriteria(Person.class, criteria);
  +        // Run the query.
  +        Person person = (Person) broker.getObjectByQuery(query);
  +        // The previous call may or may not return a 'real' Person
  +        // object.  What it returns is not important.  The test here
  +        // is whether or not this call raises an error or not.  When
  +        // this code runs using hsqldb, it works fine.  However, when
  +        // this code runs against Oracle, it fails with a null pointer
  +        // exception.
  +    }
   }
   
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org