Coverage Report - org.apache.ojb.otm.core.BaseConnection
 
Classes in this File Line Coverage Branch Coverage Complexity
BaseConnection
N/A
N/A
1.8
BaseConnection$OTMIterator
N/A
N/A
1.8
BaseConnection$OTMOQLQueryImpl
N/A
N/A
1.8
 
 1  
 package org.apache.ojb.otm.core;
 2  
 
 3  
 /* Copyright 2003-2005 The Apache Software Foundation
 4  
  *
 5  
  * Licensed under the Apache License, Version 2.0 (the "License");
 6  
  * you may not use this file except in compliance with the License.
 7  
  * You may obtain a copy of the License at
 8  
  *
 9  
  *     http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 
 18  
 import org.apache.ojb.broker.*;
 19  
 import org.apache.ojb.broker.cache.ObjectCache;
 20  
 import org.apache.ojb.broker.core.proxy.ProxyHelper;
 21  
 import org.apache.ojb.broker.accesslayer.OJBIterator;
 22  
 import org.apache.ojb.broker.metadata.ClassDescriptor;
 23  
 import org.apache.ojb.broker.query.Query;
 24  
 import org.apache.ojb.broker.query.ReportQuery;
 25  
 import org.apache.ojb.broker.util.configuration.ConfigurationException;
 26  
 import org.apache.ojb.broker.util.configuration.Configurator;
 27  
 import org.apache.ojb.odmg.oql.EnhancedOQLQuery;
 28  
 import org.apache.ojb.odmg.oql.OQLQueryImpl;
 29  
 import org.apache.ojb.otm.EditingContext;
 30  
 import org.apache.ojb.otm.OTMConnection;
 31  
 import org.apache.ojb.otm.copy.ObjectCopyStrategy;
 32  
 import org.apache.ojb.otm.lock.LockType;
 33  
 import org.apache.ojb.otm.lock.LockingException;
 34  
 import org.odmg.ODMGRuntimeException;
 35  
 import org.odmg.OQLQuery;
 36  
 
 37  
 import java.util.Collection;
 38  
 import java.util.Iterator;
 39  
 import java.util.ListIterator;
 40  
 import java.util.ArrayList;
 41  
 
 42  
 /**
 43  
  * 
 44  
  * <javadoc>
 45  
  * 
 46  
  * @author <a href="mailto:mattbaird@yahoo.com">Matthew Baird </a>
 47  
  * @author <a href="mailto:rraghuram@hotmail.com">Raghu Rajah </a>
 48  
  * @version $Id: BaseConnection.java,v 1.1 2007-08-24 22:17:37 ewestfal Exp $
 49  
  *  
 50  
  */
 51  
 public abstract class BaseConnection implements OTMConnection
 52  
 {
 53  
 
 54  
     private PersistenceBroker _pb;
 55  
     private Transaction _tx;
 56  
     private ConcreteEditingContext _editingContext;
 57  
     private Configurator m_configurator;
 58  
 
 59  
     /**
 60  
      * Constructor for BaseConnection.
 61  
      *  
 62  
      */
 63  
     public BaseConnection(PBKey pbKey)
 64  
     {
 65  
         _pb = PersistenceBrokerFactory.createPersistenceBroker(pbKey);
 66  
         m_configurator = PersistenceBrokerFactory.getConfigurator();
 67  
     }
 68  
 
 69  
     public void close()
 70  
     {
 71  
         _pb.close();
 72  
         _pb = null;
 73  
     }
 74  
 
 75  
     public boolean isClosed()
 76  
     {
 77  
         if (_pb == null)
 78  
             return true;
 79  
         else
 80  
             return _pb.isClosed();
 81  
     }
 82  
 
 83  
     public PersistenceBroker getKernelBroker()
 84  
     {
 85  
         return _pb;
 86  
     }
 87  
 
 88  
     public void setTransaction(Transaction transaction)
 89  
     {
 90  
         if (transaction == null)
 91  
         {
 92  
             _editingContext = null;
 93  
         }
 94  
         else if (_tx != null)
 95  
         {
 96  
             throw new IllegalStateException("OTMConnection is already bound to the transacaction "
 97  
                     + _tx);
 98  
         }
 99  
         else
 100  
         {
 101  
             _editingContext = new ConcreteEditingContext(transaction, _pb);
 102  
         }
 103  
         _tx = transaction;
 104  
     }
 105  
 
 106  
     public Transaction getTransaction()
 107  
     {
 108  
         return _tx;
 109  
     }
 110  
 
 111  
     //////////////////////////////////////
 112  
     // OTMConnection protocol
 113  
     //////////////////////////////////////
 114  
 
 115  
     /**
 116  
      * @see org.apache.ojb.otm.OTMConnection#getObjectByIdentity(Identity, int)
 117  
      */
 118  
     public Object getObjectByIdentity(Identity oid, int lock) throws LockingException
 119  
     {
 120  
         checkTransaction("getObjectByIdentity");
 121  
         Object userObject;
 122  
         Object cacheObject;
 123  
 
 124  
         cacheObject = _pb.getObjectByIdentity(oid);
 125  
         if (cacheObject == null)
 126  
         {
 127  
             // Possibly the object was inserted in this transaction
 128  
             // and was not stored to database yet
 129  
             userObject = _editingContext.lookup(oid);
 130  
         }
 131  
         else
 132  
         {
 133  
             userObject = getUserObject(oid, cacheObject);
 134  
             // userObject from editing context may be proxy
 135  
             userObject = ProxyHelper.getRealObject(userObject);
 136  
             _editingContext.insert(oid, userObject, lock);
 137  
         }
 138  
         return userObject;
 139  
     }
 140  
 
 141  
     private void checkTransaction(String methodBeingCalled)
 142  
     {
 143  
         if (null == _tx)
 144  
         {
 145  
             throw new TransactionNotInProgressException(
 146  
                     methodBeingCalled
 147  
                             + " requires a valid transaction. Please make sure you have created a new transaction, and called begin() on it.");
 148  
         }
 149  
         if (!_tx.isInProgress())
 150  
         {
 151  
             throw new TransactionNotInProgressException(methodBeingCalled
 152  
                     + " cannot be called before transaction begin() is called");
 153  
         }
 154  
     }
 155  
 
 156  
     /**
 157  
      * @see org.apache.ojb.otm.OTMConnection#getObjectByIdentity(Identity)
 158  
      */
 159  
     public Object getObjectByIdentity(Identity oid) throws LockingException
 160  
     {
 161  
         return getObjectByIdentity(oid, LockType.READ_LOCK);
 162  
     }
 163  
 
 164  
     /**
 165  
      * @param query The query to execute
 166  
      * @return an Iterator that iterates Objects. The returned objects are locked for read.
 167  
      */
 168  
     public Iterator getIteratorByQuery(Query query)
 169  
     {
 170  
         return getIteratorByQuery(query, LockType.READ_LOCK);
 171  
     }
 172  
 
 173  
     /**
 174  
      * @param query The query to execute
 175  
      * @param lock the lock that need to be acquired on the object Possible values are:
 176  
      *            LockType.NO_LOCK (aka read only) - changes to the object will not be written to
 177  
      *            database; LockType.READ_LOCK (aka optimistic lock) - changes to the object will
 178  
      *            be written to the database, in this case the lock will be automatically upgraded
 179  
      *            to the write lock on transaction commit; LockType.WRITE_LOCK (aka pessimistic
 180  
      *            lock) - changes to the object will be written to the database.
 181  
      * @return an Iterator that iterates Objects of class c if calling the .next() method. The
 182  
      *         returned objects are locked with the given lock value.
 183  
      */
 184  
     public Iterator getIteratorByQuery(Query query, int lock)
 185  
     {
 186  
         checkTransaction("getIteratorByQuery");
 187  
         return new OTMIterator((OJBIterator) _pb.getIteratorByQuery(query), lock, null);
 188  
     }
 189  
 
 190  
     /**
 191  
      * @param query The OQL query to execute. Use this method if you don't want to load all the
 192  
      *            collection at once as OQLQuery.execute() does.
 193  
      * @return an Iterator that iterates Objects. The returned objects are locked for read.
 194  
      */
 195  
     public Iterator getIteratorByOQLQuery(OQLQuery query)
 196  
     {
 197  
         return getIteratorByOQLQuery(query, LockType.READ_LOCK);
 198  
     }
 199  
 
 200  
     /**
 201  
      * @param query The OQL query to execute. Use this method if you don't want to load all the
 202  
      *            collection at once as OQLQuery.execute() does.
 203  
      * @return an Iterator that iterates Objects. The returned objects are locked for read.
 204  
      */
 205  
     public Iterator getIteratorByOQLQuery(OQLQuery query, int lock)
 206  
     {
 207  
         checkTransaction("getIteratorByOQLQuery");
 208  
         if (query instanceof OTMOQLQueryImpl)
 209  
         {
 210  
             OTMOQLQueryImpl q = (OTMOQLQueryImpl) query;
 211  
             return new OTMIterator((OJBIterator) _pb.getIteratorByQuery(q.getQuery()), lock, q);
 212  
         }
 213  
         else
 214  
         {
 215  
             throw new IllegalArgumentException("The OQLQuery where created not via OTM API");
 216  
         }
 217  
     }
 218  
 
 219  
     /**
 220  
      * @param query The query to execute
 221  
      * @param lock the lock that need to be acquired on the object Possible values are:
 222  
      *            LockType.NO_LOCK (aka read only) - changes to the object will not be written to
 223  
      *            database; LockType.READ_LOCK (aka optimistic lock) - changes to the object will
 224  
      *            be written to the database, in this case the lock will be automatically upgraded
 225  
      *            to the write lock on transaction commit; LockType.WRITE_LOCK (aka pessimistic
 226  
      *            lock) - changes to the object will be written to the database.
 227  
      * @return an Iterator that iterates Objects of class c if calling the .next() method. The
 228  
      *         returned objects are locked with the given lock value.
 229  
      */
 230  
     public Collection getCollectionByQuery(Query query, int lock)
 231  
     {
 232  
         checkTransaction("getCollectionByQuery");
 233  
         Collection col = _pb.getCollectionByQuery(query);
 234  
         Collection result = createCollectionOfTheSameClass(col);
 235  
         for (Iterator it = col.iterator(); it.hasNext();)
 236  
         {
 237  
             result.add(insertObject(it.next(), lock));
 238  
         }
 239  
         return result;
 240  
     }
 241  
 
 242  
     /**
 243  
      * @param query The query to execute
 244  
      * @return an Iterator that iterates Objects of class c if calling the .next() method. The
 245  
      *         returned objects are locked for read.
 246  
      */
 247  
     public Collection getCollectionByQuery(Query query)
 248  
     {
 249  
         return getCollectionByQuery(query, LockType.READ_LOCK);
 250  
     }
 251  
 
 252  
     /**
 253  
      * Get the identity of the object
 254  
      *
 255  
      * @param object The object
 256  
      * @return the identity of the object
 257  
      */
 258  
     public Identity getIdentity(Object object)
 259  
     {
 260  
         return new Identity(object, _pb);
 261  
     }
 262  
 
 263  
     /**
 264  
      * Get the class descriptor
 265  
      *
 266  
      * @param clazz The class
 267  
      * @return the descriptor of the class
 268  
      */
 269  
     public ClassDescriptor getDescriptorFor(Class clazz)
 270  
     {
 271  
         return _pb.getClassDescriptor(clazz);
 272  
     }
 273  
 
 274  
     /**
 275  
      * @see org.apache.ojb.otm.OTMConnection#invalidate(Identity)
 276  
      */
 277  
     public void invalidate(Identity oid) throws LockingException
 278  
     {
 279  
         if (null == _tx)
 280  
         {
 281  
             throw new TransactionNotInProgressException(
 282  
                     "invalidate requires a valid transaction. Please make sure you have created a new transaction, and called begin() on it.");
 283  
         }
 284  
         // mark as invalidated in the editing context, if it's found there
 285  
         _editingContext.insert(oid, null, LockType.READ_LOCK);
 286  
 
 287  
         // remove from the cache
 288  
         _pb.serviceObjectCache().remove(oid);
 289  
 
 290  
     }
 291  
 
 292  
     /**
 293  
      * @see org.apache.ojb.otm.OTMConnection#serviceObjectCache()
 294  
      */
 295  
     public ObjectCache serviceObjectCache()
 296  
     {
 297  
         return _pb.serviceObjectCache();
 298  
     }
 299  
 
 300  
     /**
 301  
      * TODO remove all from editing context.
 302  
      *
 303  
      * @throws LockingException
 304  
      */
 305  
     public void invalidateAll() throws LockingException
 306  
     {
 307  
         _pb.serviceObjectCache().clear();
 308  
     }
 309  
 
 310  
     /**
 311  
      * @see org.apache.ojb.otm.OTMConnection#lockForWrite(Object)
 312  
      */
 313  
     public void lockForWrite(Object object) throws LockingException
 314  
     {
 315  
         checkTransaction("lockForWrite");
 316  
         makePersistent(object);
 317  
     }
 318  
 
 319  
     /**
 320  
      * @see org.apache.ojb.otm.OTMConnection#makePersistent(Object)
 321  
      */
 322  
     public void makePersistent(Object userObject) throws LockingException
 323  
     {
 324  
         checkTransaction("makePersistent");
 325  
         Identity oid = new Identity(userObject, _pb);
 326  
         Object cacheObject = _pb.getObjectByIdentity(oid);
 327  
 
 328  
         if ((cacheObject != null) && (_editingContext.lookup(oid) == null))
 329  
         {
 330  
             // The object exists in the database, but is not yet in the editing
 331  
             // context, so we need to put it to the editing context in its
 332  
             // old state, then we will put the modified userObject.
 333  
             // This will allow the editing context to find changes
 334  
             ObjectCopyStrategy copyStrategy = _tx.getKit().getCopyStrategy(oid);
 335  
             Object origUserObject = copyStrategy.copy(cacheObject, _pb);
 336  
             _editingContext.insert(oid, origUserObject, LockType.WRITE_LOCK);
 337  
         }
 338  
         _editingContext.insert(oid, userObject, LockType.WRITE_LOCK);
 339  
     }
 340  
 
 341  
     /**
 342  
      * @see org.apache.ojb.otm.OTMConnection#deletePersistent(Object)
 343  
      */
 344  
     public void deletePersistent(Object userObject) throws LockingException
 345  
     {
 346  
         checkTransaction("deletePersistent");
 347  
         Identity oid = new Identity(userObject, _pb);
 348  
         Object cacheObject = _pb.getObjectByIdentity(oid);
 349  
         if (cacheObject == null)
 350  
         {
 351  
             // Possibly the object was inserted in this transaction
 352  
             // and was not stored to database yet, so we simply remove it
 353  
             // from editing context.
 354  
             _editingContext.remove(oid);
 355  
         }
 356  
         else
 357  
         {
 358  
             if (_editingContext.lookup(oid) == null)
 359  
             {
 360  
                 // The object exists in the database, but is not yet in the editing
 361  
                 // context, so we need to put it to the editing context
 362  
                 ObjectCopyStrategy copyStrategy = _tx.getKit().getCopyStrategy(oid);
 363  
                 Object origUserObject = copyStrategy.copy(cacheObject, _pb);
 364  
                 _editingContext.insert(oid, origUserObject, LockType.WRITE_LOCK);
 365  
             }
 366  
             _editingContext.deletePersistent(oid, userObject);
 367  
         }
 368  
     }
 369  
 
 370  
     /**
 371  
      * @see org.apache.ojb.otm.OTMConnection#refresh(Object)
 372  
      */
 373  
     public void refresh(Object userObject)
 374  
     {
 375  
         checkTransaction("refresh");
 376  
         Identity oid = new Identity(userObject, _pb);
 377  
         _editingContext.refresh(oid, userObject);
 378  
     }
 379  
 
 380  
     public EditingContext getEditingContext()
 381  
     {
 382  
         return _editingContext;
 383  
     }
 384  
 
 385  
     public EnhancedOQLQuery newOQLQuery()
 386  
     {
 387  
         return newOQLQuery(LockType.READ_LOCK);
 388  
     }
 389  
 
 390  
     public EnhancedOQLQuery newOQLQuery(int lock)
 391  
     {
 392  
         checkTransaction("newOQLQuery");
 393  
         OQLQueryImpl query = new OTMOQLQueryImpl(_pb.getPBKey(), lock);
 394  
         try
 395  
         {
 396  
             m_configurator.configure(query);
 397  
         }
 398  
         catch (ConfigurationException e)
 399  
         {
 400  
             throw new ODMGRuntimeException("Error in configuration of OQLQueryImpl instance: "
 401  
                     + e.getMessage());
 402  
         }
 403  
         return query;
 404  
     }
 405  
 
 406  
     public int getCount(Query query)
 407  
     {
 408  
         checkTransaction("getCount");
 409  
         return _pb.getCount(query);
 410  
     }
 411  
 
 412  
     private Object insertObject(Object cacheObject, int lock)
 413  
     {
 414  
         Object ctxObject;
 415  
         Identity oid;
 416  
         Object userObject;
 417  
 
 418  
 
 419  
         oid = getIdentity(cacheObject);
 420  
         userObject = getUserObject(oid, cacheObject);
 421  
         try
 422  
         {
 423  
             _editingContext.insert(oid, userObject, lock);
 424  
         }
 425  
         catch (LockingException ex)
 426  
         {
 427  
             throw new LockingPassthruException(ex);
 428  
         }
 429  
 
 430  
         return userObject;
 431  
     }
 432  
 
 433  
     /**
 434  
      * Get user object (from the editing context) with the given oid.
 435  
      * If not found, then create it as a copy of cacheObject.
 436  
      * User object and cache object must be separate.
 437  
      * @param oid The identity
 438  
      * @param cacheObject the object for user
 439  
      */
 440  
     private Object getUserObject(Identity oid, Object cacheObject)
 441  
     {
 442  
         Object userObject = _editingContext.lookup(oid);
 443  
 
 444  
         if (userObject == null)
 445  
         {
 446  
             ObjectCopyStrategy copyStrategy = _tx.getKit().getCopyStrategy(oid);
 447  
             userObject = copyStrategy.copy(cacheObject, _pb);
 448  
         }
 449  
         return userObject;
 450  
     }
 451  
 
 452  
     private Collection createCollectionOfTheSameClass(Collection col)
 453  
     {
 454  
         try
 455  
         {
 456  
             return (Collection) col.getClass().newInstance();
 457  
         }
 458  
         catch (Throwable ex)
 459  
         {
 460  
             return new ArrayList();
 461  
         }
 462  
     }
 463  
 
 464  
     ///////////////////////////////////////
 465  
     // Transaction Notifications
 466  
     ///////////////////////////////////////
 467  
 
 468  
     /**
 469  
      *
 470  
      * Notification issued by the driving transaction to begin this transaction
 471  
      *
 472  
      */
 473  
     public abstract void transactionBegin() throws TransactionException;
 474  
 
 475  
     /**
 476  
      *
 477  
      * Prepare for a commit. As part of a two phase commit protocol of the transaction.
 478  
      *
 479  
      */
 480  
     public abstract void transactionPrepare() throws TransactionException;
 481  
 
 482  
     /**
 483  
      *
 484  
      * Notification issued by the driving transaction to commit resources held by this connection.
 485  
      *
 486  
      */
 487  
     public abstract void transactionCommit() throws TransactionException;
 488  
 
 489  
     /**
 490  
      * 
 491  
      * Notification issued by the driving transaction to rollback resources held by this
 492  
      * connection.
 493  
      *  
 494  
      */
 495  
     public abstract void transactionRollback() throws TransactionException;
 496  
 
 497  
     ///////////////////////////////////////
 498  
     // Inner classes
 499  
     ///////////////////////////////////////
 500  
 
 501  
     private class OTMIterator implements OJBIterator
 502  
     {
 503  
         private final OJBIterator _it;
 504  
         private final int _lock;
 505  
         private final OTMOQLQueryImpl _oqlQuery;
 506  
 
 507  
         OTMIterator(OJBIterator it, int lock, OTMOQLQueryImpl oqlQuery)
 508  
         {
 509  
             _it = it;
 510  
             _lock = lock;
 511  
             _oqlQuery = oqlQuery;
 512  
         }
 513  
 
 514  
         public boolean hasNext()
 515  
         {
 516  
             boolean res = _it.hasNext();
 517  
 
 518  
             // once the result set is finished, close it
 519  
             if (!res)
 520  
             {
 521  
                 done();
 522  
             }
 523  
 
 524  
             return res;
 525  
         }
 526  
 
 527  
         public Object next()
 528  
         {
 529  
             Object object = _it.next();
 530  
             object = insertObject(object, _lock);
 531  
             return object;
 532  
         }
 533  
 
 534  
         public void remove()
 535  
         {
 536  
             throw new UnsupportedOperationException();
 537  
         }
 538  
 
 539  
         public void done()
 540  
         {
 541  
             releaseDbResources();
 542  
             if (_oqlQuery != null)
 543  
             {
 544  
                 _oqlQuery.resetBindIterator();
 545  
             }
 546  
         }
 547  
 
 548  
         protected void finalize()
 549  
         {
 550  
             done();
 551  
         }
 552  
 
 553  
         /*
 554  
          * (non-Javadoc)
 555  
          * 
 556  
          * @see org.apache.ojb.broker.accesslayer.OJBIterator#absolute(int)
 557  
          */
 558  
         public boolean absolute(int row) throws PersistenceBrokerException
 559  
         {
 560  
             return _it.absolute(row);
 561  
         }
 562  
 
 563  
         /*
 564  
          * (non-Javadoc)
 565  
          * 
 566  
          * @see org.apache.ojb.broker.accesslayer.OJBIterator#fullSize()
 567  
          */
 568  
         public int fullSize() throws PersistenceBrokerException
 569  
         {
 570  
             return _it.fullSize();
 571  
         }
 572  
 
 573  
         /*
 574  
          * (non-Javadoc)
 575  
          * 
 576  
          * @see org.apache.ojb.broker.accesslayer.OJBIterator#relative(int)
 577  
          */
 578  
         public boolean relative(int row) throws PersistenceBrokerException
 579  
         {
 580  
             return _it.relative(row);
 581  
         }
 582  
 
 583  
         /*
 584  
          * (non-Javadoc)
 585  
          * 
 586  
          * @see org.apache.ojb.broker.accesslayer.OJBIterator#releaseDbResources()
 587  
          */
 588  
         public void releaseDbResources()
 589  
         {
 590  
             _it.releaseDbResources();
 591  
         }
 592  
 
 593  
         /*
 594  
          * (non-Javadoc)
 595  
          * 
 596  
          * @see org.apache.ojb.broker.accesslayer.OJBIterator#size()
 597  
          */
 598  
         public int size() throws PersistenceBrokerException
 599  
         {
 600  
             return _it.size();
 601  
         }
 602  
 
 603  
         /**
 604  
          * @see org.apache.ojb.broker.accesslayer.OJBIterator#disableLifeCycleEvents()
 605  
          */
 606  
         public void disableLifeCycleEvents()
 607  
         {
 608  
             _it.disableLifeCycleEvents();
 609  
         }
 610  
     }
 611  
 
 612  
     private class OTMOQLQueryImpl extends OQLQueryImpl
 613  
     {
 614  
         int _lock;
 615  
 
 616  
         public OTMOQLQueryImpl(PBKey key, int lock)
 617  
         {
 618  
             super(key);
 619  
             _lock = lock;
 620  
         }
 621  
 
 622  
         /**
 623  
          * Execute the query. After executing a query, the parameter list is reset.
 624  
          *
 625  
          * @return The object that represents the result of the query. The returned data, whatever
 626  
          *         its OQL type, is encapsulated into an object. For instance, when OQL returns an
 627  
          *         integer, the result is put into an <code>Integer</code> object. When OQL
 628  
          *         returns a collection (literal or object), the result is always a Java collection
 629  
          *         object of the same kind (for instance, a <code>DList</code>).
 630  
          * @exception org.odmg.QueryException An exception has occurred while executing the query.
 631  
          */
 632  
         public Object execute() throws org.odmg.QueryException
 633  
         {
 634  
             Collection result;
 635  
             Iterator iter = null;
 636  
             Query query = getQuery();
 637  
 
 638  
             try
 639  
             {
 640  
                 if (!(query instanceof ReportQuery))
 641  
                 {
 642  
                     Collection res0 = _pb.getCollectionByQuery(query);
 643  
                     result = createCollectionOfTheSameClass(res0);
 644  
                     for (iter = res0.iterator(); iter.hasNext();)
 645  
                     {
 646  
                         result.add(insertObject(iter.next(), _lock));
 647  
                     }
 648  
                 }
 649  
                 else
 650  
                 {
 651  
                     result = new ArrayList();
 652  
                     iter = _pb.getReportQueryIteratorByQuery(query);
 653  
                     while (iter.hasNext())
 654  
                     {
 655  
                         Object[] res = (Object[]) iter.next();
 656  
 
 657  
                         if (res.length == 1)
 658  
                         {
 659  
                             if (res[0] != null) // skip null values
 660  
                             {
 661  
                                 result.add(res[0]);
 662  
                             }
 663  
                         }
 664  
                         else
 665  
                         {
 666  
                             // skip null tuples
 667  
                             for (int i = 0; i < res.length; i++)
 668  
                             {
 669  
                                 if (res[i] != null)
 670  
                                 {
 671  
                                     result.add(res);
 672  
                                     break;
 673  
                                 }
 674  
                             }
 675  
                         }
 676  
                     }
 677  
                 }
 678  
                 resetBindIterator();
 679  
             }
 680  
             finally
 681  
             {
 682  
                 if ((iter != null) && (iter instanceof OJBIterator))
 683  
                 {
 684  
                     ((OJBIterator) iter).releaseDbResources();
 685  
                 }
 686  
             }
 687  
             return result;
 688  
         }
 689  
 
 690  
         void resetBindIterator()
 691  
         {
 692  
             // reset iterator to start of list so we can reuse this query
 693  
             ListIterator it = getBindIterator();
 694  
             while (it.hasPrevious())
 695  
             {
 696  
                 it.previous();
 697  
             }
 698  
         }
 699  
     }
 700  
 
 701  
 }