This likely is not an OJB issue.  Either that or somewhere OJB is
iterating over and modifying a collection at the same time. The two
should be split to prevent this from happening.

Here's the javadoc for this issue.

http://java.sun.com/j2se/1.4/docs/api/java/util/ConcurrentModificationException.html






On Wed, 2002-09-25 at 12:24, Cornelius Keller wrote:
> 
> a b wrote:
> > Hi all, insert seem to work. However, whenever I try
> > to edit an entry I get an exception as follows, can
> > anyone help me with this? thanks a lot
> > 
> > java.util.ConcurrentModificationException
> >     at
> > java.util.AbstractList$Itr.checkForComodification(AbstractList.java:445)
> >     at
> > java.util.AbstractList$Itr.next(AbstractList.java:418)
> >     at
> > org.apache.ojb.odmg.ObjectEnvelopeTable.commit(ObjectEnvelopeTable.java:120)
> >     at
> > org.apache.ojb.odmg.TransactionImpl.doCommit(TransactionImpl.java:285)
> >     at
> > org.apache.ojb.odmg.TransactionImpl.commit(TransactionImpl.java:469)
> >     at
> > org.apache.ojb.mytest.UCEditLogin.apply(UCEditProduct.java:60)
> >     at
> > org.apache.ojb.mytest.Application.run(Application.java:133)
> >     at
> > org.apache.ojb.mytest.Application.main(Application.java:89)
> > [org.apache.ojb.odmg.TransactionImpl] WARN: Abort
> > transaction was called on tx
> > org.apache.ojb.odmg.TransactionImpl@2a15cd, associated
> > PB was null
> > null
> 
> Hi,
> 
> I had the same Error and I found out that the PersistenceBroker 
> Implementation dont uses collections in a thrad safe way.
> I wrote a little patch and it solved the problem in my case, but I can 
> not garantee that it will help in yours.
> Anyway it i'll attach my patch to this mail in case it is usefull.
> 
> Regards
> - Cornelius Keller
> 
> ----
> 

> package org.apache.ojb.broker.singlevm;
> 
> /* ====================================================================
>  * The Apache Software License, Version 1.1
>  *
>  * Copyright (c) 2001 The Apache Software Foundation.  All rights
>  * reserved.
>  *
>  * Redistribution and use in source and binary forms, with or without
>  * modification, are permitted provided that the following conditions
>  * are met:
>  *
>  * 1. Redistributions of source code must retain the above copyright
>  *    notice, this list of conditions and the following disclaimer.
>  *
>  * 2. Redistributions in binary form must reproduce the above copyright
>  *    notice, this list of conditions and the following disclaimer in
>  *    the documentation and/or other materials provided with the
>  *    distribution.
>  *
>  * 3. The end-user documentation included with the redistribution,
>  *    if any, must include the following acknowledgment:
>  *       "This product includes software developed by the
>  *        Apache Software Foundation (http://www.apache.org/)."
>  *    Alternately, this acknowledgment may appear in the software itself,
>  *    if and wherever such third-party acknowledgments normally appear.
>  *
>  * 4. The names "Apache" and "Apache Software Foundation" and
>  *    "Apache ObjectRelationalBridge" must not be used to endorse or promote products
>  *    derived from this software without prior written permission. For
>  *    written permission, please contact [EMAIL PROTECTED]
>  *
>  * 5. Products derived from this software may not be called "Apache",
>  *    "Apache ObjectRelationalBridge", nor may "Apache" appear in their name, without
>  *    prior written permission of the Apache Software Foundation.
>  *
>  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
>  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
>  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
>  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
>  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
>  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
>  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
>  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
>  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
>  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
>  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
>  * SUCH DAMAGE.
>  * ====================================================================
>  *
>  * This software consists of voluntary contributions made by many
>  * individuals on behalf of the Apache Software Foundation.  For more
>  * information on the Apache Software Foundation, please see
>  * <http://www.apache.org/>.
>  */
> import java.lang.reflect.Array;
> import java.sql.Connection;
> import java.sql.SQLException;
> import java.util.*;
> import java.util.Collection;
> import java.util.Enumeration;
> import java.util.HashMap;
> import java.util.Hashtable;
> import java.util.Iterator;
> import java.util.Map;
> import java.util.Vector;
> 
> import org.apache.ojb.broker.*;
> import org.apache.ojb.broker.ta.PersistenceBrokerFactoryIF;
> import org.apache.ojb.broker.ta.PersistenceBrokerFactoryFactory;
> import org.apache.ojb.broker.accesslayer.*;
> import org.apache.ojb.broker.cache.ObjectCache;
> import org.apache.ojb.broker.cache.ObjectCacheFactory;
> import org.apache.ojb.broker.metadata.*;
> import org.apache.ojb.broker.platforms.Platform;
> import org.apache.ojb.broker.platforms.PlatformFactory;
> import org.apache.ojb.broker.query.Criteria;
> import org.apache.ojb.broker.query.Query;
> import org.apache.ojb.broker.query.QueryByCriteria;
> import org.apache.ojb.broker.query.QueryByExample;
> import org.apache.ojb.broker.query.QueryBySQL;
> import org.apache.ojb.broker.query.QueryFactory;
> import org.apache.ojb.broker.server.PersistenceBrokerClient;
> import org.apache.ojb.broker.server.ServerEntry;
> import org.apache.ojb.broker.server.ServerPool;
> import org.apache.ojb.broker.util.ArrayIterator;
> import org.apache.ojb.broker.util.IdentityHashMap;
> import org.apache.ojb.broker.util.ObjectModification;
> import org.apache.ojb.broker.util.collections.ManageableArrayList;
> import org.apache.ojb.broker.util.collections.ManageableVector;
> import org.apache.ojb.broker.util.configuration.Configuration;
> import org.apache.ojb.broker.util.configuration.ConfigurationException;
> import org.apache.ojb.broker.util.logging.Logger;
> import org.apache.ojb.broker.util.logging.LoggerFactory;
> import org.apache.ojb.broker.util.sequence.SequenceManager;
> import org.apache.ojb.broker.util.sequence.SequenceManagerFactory;
> import org.apache.commons.beanutils.BeanUtils;
> 
> 
> import java.lang.reflect.Proxy;
> 
> 
> /**
>  * The PersistenceBrokerImpl is an implementation of the PersistenceBroker
>  * Interface that specifies a persistence mechanism for Java objects.
>  * This Concrete implementation provides an object relational mapping
>  * and allows to store and retrieve arbitrary objects in/from relational
>  * databases accessed by JDBC.
>  *
>  * @see test.org.apache.ojb.tutorial1.Application for a sample application
>  * @author <a href="mailto:[EMAIL PROTECTED]";>Thomas Mahler<a>
>  */
> public class PersistenceBrokerImpl implements PersistenceBroker, PBState {
>     private Logger logger = LoggerFactory.getLogger(getClass());
>     /**
>      * m_DbAccess is used to do all Jdbc related work: connecting, executing...
>      */
>     
>     protected JdbcAccess dbAccess;
>     /**
>      * m_SqlGen is a simple SQL Generator that produces all SQL Queries
>      */
>     
>     private SqlGenerator sqlGenerator = SqlGenerator.getInstance();
>     /**
>      * m_ObjectCache caches object already loaded from db and protects the uniqueness
>      * of objects. When an object is loaded from the db it is stored in the cache.
>      * Any later lookups with the same pk values will return the cached object
>      * instead of performing another db lookup.
>      */
>     
>     private ObjectCache objectCache = ObjectCacheFactory.getObjectCache();
>     /**
>      * holds mapping information for all classes to be treated by PersistenceBroker
>      */
>     
>     protected DescriptorRepository descriptorRepository = null;
>     protected ConnectionManagerIF connectionManager = null;
>     protected SequenceManager sequenceManager = null;
>     protected StatementManagerIF statementManager = null;
>     protected PersistenceBrokerFactoryIF pbf;
>     
>     private ServerPool pool = null;
>     private boolean runningInServerMode;
>     protected PBKey pbKey;
>     
>     /**
>      * signs if this broker was closed
>      */
>     private boolean isClosed;
>     
>     /**
>      * this flag tells if the Broker is currently processing a Transaction
>      */
>     protected boolean inTransaction = false;
>     
>     protected PersistenceBrokerImpl() {
>     }
>     
>     /**
>      *
>      */
>     public PersistenceBrokerImpl(PBKey key, PersistenceBrokerFactoryIF pbf) {
>         this.descriptorRepository = DescriptorRepository.getInstance(key);
>         this.pbf = pbf;
>         this.pbKey = key;
>         connectionManager = new ConnectionManager(this);
>         dbAccess = new JdbcAccess(this);
>         sequenceManager = SequenceManagerFactory.getSequenceManager(this);
>         statementManager = new StatementManagerExt(this);
>     }
>     
>     /**
>      * @deprecated
>      */
>     public PersistenceBrokerImpl(DescriptorRepository repository) {
>         descriptorRepository = repository;
>         this.pbKey = repository.getPBkey();
>         this.pbf = PersistenceBrokerFactoryFactory.instance();
>         connectionManager = new ConnectionManager(this);
>         dbAccess = new JdbcAccess(this);
>         sequenceManager = SequenceManagerFactory.getSequenceManager(this);
>         statementManager = new StatementManagerExt(this);
>     }
>     
>     /**
>      * Release all resources used by this
>      * class - CAUTION: No further operations can be
>      * done with this instance after calling this method.
>      */
>     public void releaseAllResources() {
>         this.setClosed(true);
>         this.inTransaction = false;
>         this.descriptorRepository = null;
>         this.pbKey = null;
>         this.pbf = null;
>         this.connectionManager = null;
>         this.dbAccess = null;
>         this.objectCache = null;
>         this.pool = null;
>         this.sequenceManager = null;
>         this.sqlGenerator = null;
>         this.statementManager = null;
>     }
>     
>     public PBKey getPBKey() {
>         return pbKey;
>     }
>     
>     public void setPBKey(PBKey key) {
>         this.pbKey = key;
>     }
>     
>     public boolean isClosed() {
>         return this.isClosed;
>     }
>     
>     public void setClosed(boolean closed) {
>         this.isClosed = closed;
>     }
>     
>     /**
>      * @see PersistenceBroker#close()
>      */
>     public boolean close() {
>         if (logger.isDebugEnabled()) logger.debug("PB.close was called");
>         this.connectionManager.releaseConnection();
>         /*@todo while pbf.releaseInstance was public, we setClosed(true)
>         in further versions this method should only called by the pool*/
>         this.setClosed(true);
>         try {
>             this.pbf.releaseInstance(this);
>         }
>         catch (Throwable t) {
>         }
>         return true;
>     }
>     
>     /**
>      * Abort and close the transaction.
>      * Calling abort abandons all persistent object modifications and releases the
>      * associated locks.
>      * If transaction is not in progress a TransactionNotInProgressException is 
>thrown
>      */
>     public synchronized void abortTransaction()
>     throws TransactionNotInProgressException {
>         if (!inTransaction) {
>             throw new TransactionNotInProgressException();
>         }
>         inTransaction = false;
>         this.connectionManager.localRollback();
>     }
>     
>     /**
>      * begin a transaction against the underlying RDBMS.
>      * Calling <code>beginTransaction</code> multiple times,
>      * without an intervening call to <code>commitTransaction</code> or 
><code>abortTransaction</code>,
>      * causes the exception <code>TransactionInProgressException</code> to be thrown
>      * on the second and subsequent calls.
>      */
>     public synchronized void beginTransaction()
>     throws TransactionInProgressException, TransactionAbortedException {
>         if (inTransaction) {
>             throw new TransactionInProgressException();
>         }
>         this.connectionManager.localBegin();
>         inTransaction = true;
>     }
>     
>     /**
>      * Commit and close the transaction.
>      * Calling <code>commit</code> commits to the database all
>      * UPDATE, INSERT and DELETE statements called within the transaction and
>      * releases any locks held by the transaction.
>      * If beginTransaction() has not been called before a
>      * TransactionNotInProgressException exception is thrown.
>      * If the transaction cannot be commited a TransactionAbortedException exception 
>is thrown.
>      */
>     public synchronized void commitTransaction()
>     throws TransactionNotInProgressException, TransactionAbortedException {
>         if (!inTransaction) {
>             throw new TransactionNotInProgressException();
>         }
>         inTransaction = false;
>         this.connectionManager.localCommit();
>     }
>     
>     
>     public StatementManagerIF getStatementManager() {
>         return statementManager;
>     }
>     
>     public ConnectionManagerIF getConnectionManager() {
>         return connectionManager;
>     }
>     
>     /**
>      * deletes Object obj's representation in the underlying RDBMS
>      */
>     public void delete(Object obj) throws PersistenceBrokerException {
>         delete(obj, new HashMap());
>     }
>     
>     /**
>      * Internal delete will not recurse infinitely.
>      * @param obj
>      * @param markedForDelete
>      * @throws PersistenceBrokerException
>      */
>     private void delete(Object obj, Map markedForDelete)
>     throws PersistenceBrokerException {
>         //logger.info("DELETING " + obj);
>         
>         // only delete if object is not null
>         if (obj != null) {
>             
>             // if obj is a proxy we must delete its real subject !
>             if (obj instanceof VirtualProxy) {
>                 VirtualProxy proxy = (VirtualProxy) obj;
>                 obj = proxy.getRealSubject();
>             }
>             // same for dynamic Proxies
>             else if (Proxy.isProxyClass(obj.getClass())) {
>                 IndirectionHandler handler =
>                 (IndirectionHandler) Proxy.getInvocationHandler(obj);
>                 obj = handler.getRealSubject();
>             }
>             
>             /**
>              * MBAIRD
>              * 1. if we are marked for delete already, avoid recursing on this object
>              */
>             if (markedForDelete.containsKey(obj)) {
>                 return;
>             }
>             /**
>              * MBAIRD
>              * 2. register object in markedForDelete map.
>              */
>             markedForDelete.put(obj, obj);
>             
>             // invoke callback on PersistenceBrokerAware instances
>             if (obj instanceof PersistenceBrokerAware) {
>                 ((PersistenceBrokerAware) obj).beforeDelete();
>             }
>             ClassDescriptor cld =
>             descriptorRepository.getDescriptorFor(obj.getClass());
>             // 1. delete dependend collections
>             deleteCollections(
>             obj,
>             cld.getCollectionDescriptors(),
>             markedForDelete);
>             // 2. delete object from directly mapped table
>             Identity oid = new Identity(obj, this);
>             dbAccess.executeDelete(cld, obj); // use obj not oid to delete, BRJ
>             // 3. delete dependend upon objects last to avoid FK violations
>             deleteReferences(
>             obj,
>             cld.getObjectReferenceDescriptors(),
>             markedForDelete);
>             // remove obj from the object cache:
>             objectCache.remove(oid);
>             
>             // invoke callback on PersistenceBrokerAware instances
>             if (obj instanceof PersistenceBrokerAware) {
>                 ((PersistenceBrokerAware) obj).afterDelete();
>             }
>         }
>     }
>     
>     /**
>      * Deletes references that <b>obj</b> points to.
>      * All objects which we have a FK poiting to (Via ReferenceDescriptors) will be 
>deleted if auto-delete is true <b>AND</b>
>      * the member field containing the object reference if NOT null.
>      *
>      * @param obj Object which we will delete references for
>      * @param vecRds vector of ObjectRederenceDescriptors
>      * @throws PersistenceBrokerException if some goes wrong - please see the error 
>message for details
>      */
>     private void deleteReferences(
>     Object obj,
>     Vector vecRds,
>     Map markedForDelete)
>     throws PersistenceBrokerException {
>         // get all members of obj that are references and delete them
>         synchronized (vecRds) {
>             Iterator i = vecRds.iterator();
>             while (i.hasNext()) {
>                 ObjectReferenceDescriptor rds =
>                 (ObjectReferenceDescriptor) i.next();
>                 if (rds.getCascadeDelete()) {
>                     Object referencedObject = rds.getPersistentField().get(obj);
>                     if (referencedObject != null) {
>                         //logger.info("DELETING refence for "+obj);
>                         //logger.info("DELETING refence 
>"+rds.getItemClass()+"="+referencedObject);
>                         
>                         delete(referencedObject, markedForDelete);
>                     }
>                 }
>             }
>         }
>     }
>     
>     /**
>      * Deletes collections of objects poiting to <b>obj</b>.
>      * All object which have a FK poiting to this object (Via CollectionDescriptors) 
>will be deleted if auto-delete is true <b>AND</b>
>      * the member field containing the object reference if NOT null.
>      *
>      * @param obj Object which we will delete collections for
>      * @param vecRds vector of ObjectRederenceDescriptors
>      * @throws PersistenceBrokerException if some goes wrong - please see the error 
>message for details
>      */
>     private void deleteCollections(
>     Object obj,
>     Vector vecCds,
>     Map markedForDelete)
>     throws PersistenceBrokerException {
>         // get all members of obj that are collections and
>         // delete all their elements
>         synchronized (vecCds) {
>             Iterator i = vecCds.iterator();
>             
>             while (i.hasNext()) {
>                 CollectionDescriptor cds = (CollectionDescriptor) i.next();
>                 // if this is a m:n mapped table, remove entries from association 
>table
>                 if (cds.isMtoNRelation()) {
>                     deleteMtoNImplementor(cds, obj);
>                 }
>                 
>             /*
>              * if cascading delete is on, delete referenced items
>              * NOTE : this only works if auto-retrieve is true for this particular 
>collection
>              */
>                 if (cds.getCascadeDelete()) {
>                     try {
>                         Object col = cds.getPersistentField().get(obj);
>                         if (col != null) {
>                             //logger.info("DELETING collection for "+obj);
>                             //logger.info("DELETING collection 
>"+cds.getItemClass()+"="+col);
>                             synchronized (col) {
>                                 Iterator colIterator;
>                                 if (col instanceof ManageableCollection) {
>                                     colIterator =
>                                     ((ManageableCollection) col).ojbIterator();
>                                 }
>                                 else if (col instanceof Collection) {
>                                     colIterator = ((Collection) col).iterator();
>                                 }
>                                 else if (col.getClass().isArray()) {
>                                     colIterator = new ArrayIterator(col);
>                                 }
>                                 else {
>                                     throw new RuntimeException(
>                                     col.getClass()
>                                     + " can not be managed by OJB, use Array, 
>Collection or ManageableCollection instead !");
>                                 }
>                                 while (colIterator.hasNext()) {
>                                     delete(colIterator.next(), markedForDelete);
>                                 }
>                             }
>                         }
>                     }
>                     catch (Exception ex) {
>                         logger.error(ex);
>                         throw new PersistenceBrokerException(ex);
>                     }
>                 }
>             }
>         }
>     }
>     
>     /**
>      * Method declaration
>      *
>      *
>      * @param obj
>      *
>      * @throws PersistenceBrokerException
>      *
>      *
>      */
>     public void store(Object obj) throws PersistenceBrokerException {
>         store(obj, new HashMap());
>     }
>     
>     private void store(Object obj, Map markedForStore) {
>         //logger.info("STORING " + obj);
>         // only do something if obj != null
>         if (obj != null) {
>             // ProxyObjects only have to be updated if their real subjects have been 
>loaded
>             if (obj instanceof VirtualProxy) {
>                 VirtualProxy proxy = (VirtualProxy) obj;
>                 if (proxy.alreadyMaterialized()) {
>                     obj = proxy.getRealSubject();
>                 }
>                 else {
>                     return;
>                 }
>             }
>             else if (Proxy.isProxyClass(obj.getClass())) {
>                 IndirectionHandler handler =
>                 (IndirectionHandler) Proxy.getInvocationHandler(obj);
>                 if (handler.alreadyMaterialized()) {
>                     obj = handler.getRealSubject();
>                 }
>                 else {
>                     return;
>                 }
>             }
>             ClassDescriptor cld =
>             descriptorRepository.getDescriptorFor(obj.getClass());
>             Identity oid = new Identity(obj,this);
>             // check if update or insert is needed
>             boolean doInsert = false;
>             // lookup cache or db to see whether object needs insert or update
>             if (dbAccess.materializeObject(cld, oid) == null) {
>                 doInsert = true;
>                 // now store it:
>             }
>             store(obj, doInsert, markedForStore);
>         }
>         // if Object == null do nothing
>         else
>             return;
>     }
>     
>     /**
>      * Store all object references that <b>obj</b> points to.
>      * All objects which we have a FK pointing to (Via ReferenceDescriptors) will be 
>stored if auto-update is true <b>AND</b>
>      * the member field containing the object reference is NOT null.
>      *
>      * @param obj Object which we will store references for
>      * @param vecRds - Vector with all ObjectReferenceDescriptors that should be 
>stored
>      */
>     private void storeReferences(Object obj, Vector vecRds, Map markedForStore) {
>         // get all members of obj that are references and store them
>         synchronized (vecRds) {
>             Iterator i = vecRds.iterator();
>             
>             while (i.hasNext()) {
>                 ObjectReferenceDescriptor rds =
>                 (ObjectReferenceDescriptor) i.next();
>                 Object ref = rds.getPersistentField().get(obj);
>                 if (rds.getCascadeStore()) {
>                     //logger.info("STORING reference for "+obj);
>                     //logger.info("STORING reference "+rds.getItemClass()+"="+ref);
>                     
>                     store(ref, markedForStore);
>                 }
>             }
>         }
>     }
>     
>     private void assertFkAssignment(
>     Object obj,
>     Object ref,
>     ObjectReferenceDescriptor rds) {
>         /**
>          * MBAIRD
>          * we have 'disassociated' this object from the referenced object, the 
>object representing the ord is now null,
>          * so set the fk to null.
>          *
>          * Note: I can't believe this wasn't tested (as of June9/2002), attaching 
>and removing objects seems to be a
>          * pretty important piece of functionality.
>          *
>          */
>         if (ref == null) {
>             ClassDescriptor cld =
>             descriptorRepository.getDescriptorFor(obj.getClass());
>             FieldDescriptor f[] = rds.getForeignKeyFieldDescriptors(cld);
>             if (f != null) {
>                 for (int i = 0; i < f.length; i++) {
>                     f[i].getPersistentField().set(obj, null);
>                 }
>             }
>             
>         }
>         
>         if ((!(obj instanceof VirtualProxy))
>         && (!(obj instanceof Proxy))
>         && (ref != null)
>         && (!(ref instanceof VirtualProxy))
>         && (!(ref instanceof Proxy))) {
>             ClassDescriptor refCld =
>             descriptorRepository.getDescriptorFor(ref.getClass());
>             Object[] refPkValues = refCld.getKeyValues(ref);
>             ClassDescriptor objCld =
>             descriptorRepository.getDescriptorFor(obj.getClass());
>             FieldDescriptor[] objFkFields =
>             rds.getForeignKeyFieldDescriptors(objCld);
>             if (objFkFields != null) {
>                 FieldDescriptor fld = null;
>                 for (int i = 0; i < objFkFields.length; i++) {
>                     fld = objFkFields[i];
>                     fld.getPersistentField().set(obj, refPkValues[i]);
>                 }
>             }
>         }
>     }
>     
>     /**
>      * Store collections of objects poiting to <b>obj</b>.
>      * All object which have a FK poiting to this object (Via CollectionDescriptors) 
>will be stored if auto-update is true <b>AND</b>
>      * the member field containing the object reference if NOT null.
>      *
>      * @param obj Object which we will store collections for
>      * @param vecRds vector of ObjectRederenceDescriptors
>      * @throws PersistenceBrokerException if some goes wrong - please see the error 
>message for details
>      */
>     private void storeCollections(
>     Object obj,
>     Vector vecCds,
>     Map markedForStore)
>     throws PersistenceBrokerException {
>         // get all members of obj that are collections and store all their elements
>         synchronized (vecCds) {
>             Iterator i = vecCds.iterator();
>             while (i.hasNext()) {
>                 CollectionDescriptor cds = (CollectionDescriptor) i.next();
>                 Object col = cds.getPersistentField().get(obj);
>                 
>                 if (cds.isMtoNRelation()) {
>                 /* LEANDRO
>                  * Clear all MtoN implementors.
>                  * All new MtoN implementors are going to be added bellow
>                  */
>                     //logger.info("STORE COLLECTIONS: deleting all MtoN implementors 
>for field "+cds.getPersistentField().getName());
>                     deleteMtoNImplementor(cds, obj);
>                 }
>                 
>                 if (col != null) {
>                     // MBAIRD
>                     // if the collection is a collectionproxy and it's not already 
>loaded
>                     // no need to store it.
>                     if (col instanceof CollectionProxy && 
>!((CollectionProxy)col).isLoaded()) {
>                         continue;
>                     }
>                     
>                     synchronized (col) {
>                         Iterator colIterator;
>                         if (col instanceof ManageableCollection) {
>                             colIterator = ((ManageableCollection) col).ojbIterator();
>                         }
>                         else if (col instanceof Collection) {
>                             colIterator = ((Collection) col).iterator();
>                         }
>                         else if (col.getClass().isArray()) {
>                             colIterator = new ArrayIterator(col);
>                         }
>                         else {
>                             throw new RuntimeException(
>                             col.getClass()
>                             + " can not be managed by OJB, use Array, Collection or 
>ManageableCollection instead !");
>                         }
>                         while (colIterator.hasNext()) {
>                             Object otherObj = colIterator.next();
>                             // for m:n mapped collections store association 
>implementing entries
>                             if (cds.isMtoNRelation()) {
>                                 // 1. Store depended upon object first to avoid FK 
>violation
>                                 storeCollectionObject(cds, otherObj, markedForStore);
>                                 // 2. Store indirection record
>                                 storeMtoNImplementor(cds, obj, otherObj);
>                             }
>                             // for 1:n mapped collection assert proper fk assignment
>                             else {
>                                 assertFkAssignment(otherObj, obj, cds);
>                                 storeCollectionObject(cds, otherObj, markedForStore);
>                             }
>                         }
>                     }
>                 }
>             }
>         }
>     }
>     
>     /**
>      * Store an object which is a part of a collection of another object (Via 
>CollectionDescriptors)
>      * <b>otherObject</b> will be stored if auto-update is true
>      *
>      * @param otherObject Object which is contained into other's object collection
>      * @param cds CollectionDescriptor providing metadata about the collection in 
>which <b>otherObject</b> is part of
>      * @throws PersistenceBrokerException if some goes wrong - please see the error 
>message for details
>      */
>     private void storeCollectionObject(
>     CollectionDescriptor cds,
>     Object otherObject,
>     Map markedForStore) {
>         // if cascade store: store associated object
>         if (cds.getCascadeStore()) {
>             //logger.info("STORING collection object 
>"+cds.getItemClass()+"="+otherObject);
>             
>             store(otherObject, markedForStore);
>         }
>     }
>     
>     /**
>      * This method is used to store values of a M:N association in a indirection 
>table.
>      *
>      */
>     private void storeMtoNImplementor(
>     CollectionDescriptor cod,
>     Object obj,
>     Object otherObj) {
>         ClassDescriptor cld =
>         getDescriptorRepository().getDescriptorFor(obj.getClass());
>         Object[] pkValues = cld.getKeyValues(obj);
>         Object[] pkColumns = cod.getFksToThisClass();
>         ClassDescriptor otherCld =
>         getDescriptorRepository().getDescriptorFor(
>         otherObj.getClass());
>         Object[] otherPkValues = otherCld.getKeyValues(otherObj);
>         Object[] otherPkColumns = cod.getFksToItemClass();
>         Object[] values = new Object[pkValues.length + otherPkValues.length];
>         System.arraycopy(pkValues, 0, values, 0, pkValues.length);
>         System.arraycopy(
>         otherPkValues,
>         0,
>         values,
>         pkValues.length,
>         otherPkValues.length);
>         Object[] columns = new Object[pkColumns.length + otherPkColumns.length];
>         System.arraycopy(pkColumns, 0, columns, 0, pkColumns.length);
>         System.arraycopy(
>         otherPkColumns,
>         0,
>         columns,
>         pkColumns.length,
>         otherPkColumns.length);
>         String table = cod.getIndirectionTable();
>         String insertStmt =
>         sqlGenerator.getInsertStatement(table, columns, values);
>         try {
>             dbAccess.executeUpdateSQL(insertStmt, cld);
>         }
>         catch (PersistenceBrokerException e) {
>             // attempts to store existing entries are ignored
>         }
>     }
>     
>     private void deleteMtoNImplementor(CollectionDescriptor cod, Object obj) {
>         ClassDescriptor cld =
>         getDescriptorRepository().getDescriptorFor(obj.getClass());
>         Object[] pkValues = cld.getKeyValues(obj);
>         Object[] pkColumns = cod.getFksToThisClass();
>         String table = cod.getIndirectionTable();
>         String deleteStmt =
>         sqlGenerator.getDeleteStatement(table, pkColumns, pkValues);
>         try {
>             dbAccess.executeUpdateSQL(deleteStmt, cld);
>         }
>         catch (PersistenceBrokerException e) {
>             logger.debug(
>             "// attempts to del existing entries are ignored:"
>             + e.getMessage(),
>             e);
>             // attempts to del existing entries are ignored
>         }
>     }
>     
>     /**
>      * Retrieve all References
>      *
>      *
>      * @param newObj
>      * @param cld
>      *
>      */
>     public void retrieveReferences(Object newObj, ClassDescriptor cld)
>     throws PersistenceBrokerException {
>         synchronized (cld.getObjectReferenceDescriptors()) {
>             Iterator i = cld.getObjectReferenceDescriptors().iterator();
>             ObjectReferenceDescriptor rds = null;
>             while (i.hasNext()) {
>                 rds = (ObjectReferenceDescriptor) i.next();
>                 retrieveReference(newObj, cld, rds);
>             }
>         }
>     }
>     
>     /**
>      * Retrieve a single Reference.
>      * This implementation retrieves a referenced object from the data backend if 
><b>cascade-retrieve</b> is true.
>      *
>      *
>      * @param obj - object that will have it's field set with a referenced object.
>      * @param cld
>      * @param rds
>      */
>     private void retrieveReference(
>     Object obj,
>     ClassDescriptor cld,
>     ObjectReferenceDescriptor rds) {
>         PersistentField refField;
>         Object refObj;
>         if (rds.getCascadeRetrieve()) {
>             refObj = getReferencedObject(obj, rds, cld);
>             refField = rds.getPersistentField();
>             //logger.info("RETRIEVING reference for "+obj);
>             //logger.info("RETRIEVING reference field 
>"+refField.getName()+"="+refObj);
>             
>             refField.set(obj, refObj);
>         }
>     }
>     
>     /**
>      * Retrieve a single Collection on behalf of <b>obj</b>.
>      * The Collection is retrieved only if <b>cascade.retrieve is true</b>
>      *
>      *
>      * @param obj
>      * @param cld
>      * @param cds
>      *
>      */
>     private void retrieveCollection(
>     Object obj,
>     ClassDescriptor cld,
>     CollectionDescriptor cds) {
>         if (cds.getCascadeRetrieve()) {
>             // this collection type will be used:
>             Class collectionClass = cds.getCollectionClass();
>             PersistentField collectionField = cds.getPersistentField();
>             Query fkQuery = null;
>             
>             if (cds.isMtoNRelation()) {
>                 fkQuery = getMtoNQuery(obj, cld, cds);
>             }
>             else {
>                 fkQuery = getForeignKeyQuery(obj, cld, cds);
>             }
>             
>             // check if collection must be ordered
>             if (cds.getOrderBy() != null) {
>                 fkQuery.getCriteria().addOrderBy(
>                 cds.getOrderBy(),
>                 cds.isAscending());
>             }
>             if (collectionClass == null) {
>                 Collection result = getCollectionByQuery(fkQuery, cds.isLazy());
>                 
>                 //logger.info("RETRIEVING collection for "+obj);
>                 //logger.info("RETRIEVING collection field 
>"+collectionField.getName()+"="+result);
>                 
>                 // assign collection to objects attribute
>                 // if attribute has an array type build an array, else assign 
>collection directly
>                 if (collectionField.getType().isArray()) {
>                     int length = result.size();
>                     Class itemtype =
>                     collectionField.getType().getComponentType();
>                     Object resultArray = Array.newInstance(itemtype, length);
>                     for (int j = 0; j < length; j++) {
>                         Array.set(resultArray, j, ((Vector) result).get(j));
>                     }
>                     collectionField.set(obj, resultArray);
>                 }
>                 else {
>                     collectionField.set(obj, result);
>                 }
>             }
>             else {
>                 ManageableCollection result =
>                 getCollectionByQuery(
>                 collectionClass,
>                 fkQuery,
>                 cds.isLazy());
>                 // assign collection to objects attribute
>                 collectionField.set(obj, result);
>             }
>         }
>     }
>     
>     /**
>      * Retrieve all Collections
>      *
>      * @param newObj
>      * @param cld
>      *
>      */
>     public void retrieveCollections(Object newObj, ClassDescriptor cld)
>     throws PersistenceBrokerException {
>         synchronized (cld.getCollectionDescriptors()) {
>             Iterator i = cld.getCollectionDescriptors().iterator();
>             CollectionDescriptor cds;
>             while (i.hasNext()) {
>                 cds = (CollectionDescriptor) i.next();
>                 retrieveCollection(newObj, cld, cds);
>             }
>         }
>     }
>     
>     /**
>      * Refresh Relationships
>      *
>      * @throws PersistenceBrokerException if there is a error refreshing collections 
>or references
>      * @param obj
>      * @param cld
>      */
>     public void refreshRelationships(Object obj, ClassDescriptor cld) {
>         Iterator iter;
>         CollectionDescriptor cds;
>         ObjectReferenceDescriptor rds;
>         synchronized (cld.getCollectionDescriptors()) {
>             iter = cld.getCollectionDescriptors().iterator();
>             while (iter.hasNext()) {
>                 cds = (CollectionDescriptor) iter.next();
>                 if (cds.isRefresh()) {
>                     retrieveCollection(obj, cld, cds);
>                 }
>             }
>         }
>         //
>         //    Refresh References
>         //
>         synchronized (cld.getObjectReferenceDescriptors()) {
>             iter = cld.getObjectReferenceDescriptors().iterator();
>             while (iter.hasNext()) {
>                 rds = (ObjectReferenceDescriptor) iter.next();
>                 if (rds.isRefresh()) {
>                     retrieveReference(obj, cld, rds);
>                 }
>             }
>         }
>     }
>     
>     /**
>      * retrieves an Object reference.
>      * <br>
>      * If there is a Proxy-class is defined in the ReferenceDescriptor or
>      * if the ReferenceDescriptor is lazy, a Proxy-object is returned.
>      * <br>
>      * If no Proxy-class is defined, a getObjectByIdentity(...) lookup is performed.
>      * <br>
>      * Null is returned if all foreign keys are null
>      */
>     private Object getReferencedObject(
>     Object obj,
>     ObjectReferenceDescriptor rds,
>     ClassDescriptor cld) {
>         Class referencedClass = rds.getItemClass();
>         // ensure that top-level extents are used for Identities
>         referencedClass = descriptorRepository.getExtentClass(referencedClass);
>         Object[] pkVals = rds.getForeignKeyValues(obj, cld);
>         Identity id;
>         Class referencedProxy;
>         boolean allPkNull = true;
>         
>         //
>         // BRJ : check if we have non null pk values
>         //
>         for (int i = 0; i < pkVals.length; i++) {
>             if (pkVals[i] != null) {
>                 allPkNull = false;
>                 break;
>             }
>         }
>         //
>         // BRJ : if all pk values are null there's no referenced object
>         //
>         if (allPkNull) {
>             return null;
>         }
>         
>         id = new Identity(referencedClass, pkVals);
>         if (rds.isLazy()) {
>             referencedProxy =
>             getClassDescriptor(referencedClass).getDynamicProxyClass();
>         }
>         else {
>             referencedProxy = rds.getItemProxyClass();
>         }
>         
>         if (referencedProxy != null) {
>             try {
>                 return VirtualProxy.createProxy(referencedProxy, id);
>             }
>             catch (Exception e) {
>                 logger.error("Error instantiating obj: " + e.getMessage(), e);
>                 throw new PersistenceBrokerException(e);
>             }
>         }
>         else {
>             return getObjectByIdentity(id);
>         }
>     }
>     
>     
>     
>     
>     
>     /**
>      * retrieve a collection of itemClass Objects matching the Query query
>      * @param collectionClass type the collection to be returned
>      * @param itemClass Class of item in collection
>      * @param query the query
>      */
>     private ManageableCollection getCollectionByQuery(
>     Class collectionClass,
>     Class itemClass,
>     Query query)
>     throws ClassNotPersistenceCapableException, PersistenceBrokerException {
>         logger.debug(
>         "getCollectionByQuery ("
>         + collectionClass
>         + ", "
>         + itemClass
>         + ", "
>         + query
>         + ")");
>         
>         ClassDescriptor cld = descriptorRepository.getDescriptorFor(itemClass);
>         ManageableCollection result = null;
>         try {
>             result = (ManageableCollection) collectionClass.newInstance();
>             // now iterate over all elements and add them to the new collection
>             
>             OJBIterator i = getIteratorFromQuery(query, cld);
>             /**
>              * if the query has specified a start at index, and an end at index move 
>to the start at index.
>              */
>             int size = i.size();
>             /**
>              * set full size of query to pass back to client.
>              */
>             query.fullSize(size);
>             int startAt = query.getStartAtIndex();
>             int endAt = query.getEndAtIndex();
>             if ((startAt > 1) && (startAt < size)) {
>                 i.absolute(startAt);
>             }
>             int numberOfObjectsToFetch = endAt - startAt;
>             int retrievedCount = 0;
>             boolean hasProjectionAttribute = true;
>             /**
>              * keep retrieving objects while retrievedCount is less than the 
>retrievalCount, or the
>              * retrievalCount is -1 meaning get all results.
>              * be sure not to go over the actual size of the iterator.
>              */
>             while (i.hasNext()
>             && ((endAt == Query.NO_END_AT_INDEX)
>             || (retrievedCount < numberOfObjectsToFetch))) {
>                 Object candidate = i.next();
>                 /**
>                  * MBAIRD
>                  * candidate CAN be null in the case of materializing from an 
>iterator based
>                  * on a query for a class that is mapped to a table that has other 
>classes
>                  * mapped to that table as well, but aren't extents.
>                  */
>                 if (candidate != null) {
>                     if ((itemClass.isAssignableFrom(candidate.getClass()))
>                     || (Proxy.isProxyClass(candidate.getClass()))
>                     || (candidate instanceof VirtualProxy)) {
>                         boolean added = false;
>                         if ((query.getRequestedAttribute() != null)
>                         && (hasProjectionAttribute)) {
>                             /**
>                              * someone requested a nested attribute, say from an OQL 
>statement like:
>                              * select x.y.z.pkField from com.someclass, so we need 
>to walk the path and
>                              * get the attribute as requested.
>                              */
>                             int indexOfDot =
>                             query.getRequestedAttribute().indexOf(".");
>                             if (indexOfDot != -1) {
>                                 String attr =
>                                 query.getRequestedAttribute().substring(
>                                 indexOfDot + 1);
>                                 try {
>                                     /**
>                                      * this will fail if the attribute requested is 
>invalid.
>                                      */
>                                     Object projectedAttribute =
>                                     BeanUtils.getNestedProperty(
>                                     candidate,
>                                     attr);
>                                     /**
>                                      * MBAIRD:
>                                      * When we are getting projection attributes, we 
>need to use a collections
>                                      * class that doesn't try to get an identity or 
>lock the object, since there
>                                      * is a chance it is not persistence capable.
>                                      */
>                                     if (!descriptorRepository
>                                     .hasDescriptorFor(
>                                     projectedAttribute.getClass())
>                                     && (!(result
>                                     instanceof ManageableArrayList))) {
>                                         result = new ManageableArrayList();
>                                     }
>                                     result.ojbAdd(projectedAttribute);
>                                     retrievedCount++;
>                                     added = true;
>                                 }
>                                 catch (Exception e) {
>                                     /**
>                                      * probably an invalid projection attribute, so 
>let's just ignore it.
>                                      */
>                                     hasProjectionAttribute = false;
>                                 }
>                             }
>                             else
>                                 hasProjectionAttribute = false;
>                         }
>                         if (!added) {
>                             if (result == null)
>                                 result =
>                                 (ManageableCollection) collectionClass
>                                 .newInstance();
>                             result.ojbAdd(candidate);
>                             retrievedCount++;
>                         }
>                     }
>                 }
>             }
>         }
>         catch (InstantiationException ex) {
>             logger.error(ex);
>             throw new PersistenceBrokerException(ex);
>         }
>         catch (IllegalAccessException ex) {
>             logger.error(ex);
>             throw new PersistenceBrokerException(ex);
>         }
>         return result;
>     }
>     
>     /**
>      * retrieve a collection of itemClass Objects matching the Query query
>      * @param itemClass Class of item in collection
>      * @param query the query
>      */
>     private Collection getCollectionFromQuery(Class itemClass, Query query)
>     throws ClassNotPersistenceCapableException {
>         logger.debug("getCollectionByQuery " + itemClass + ", " + query);
>         
>         ClassDescriptor cld = descriptorRepository.getDescriptorFor(itemClass);
>         Vector res = new Vector();
>         Iterator i = getIteratorFromQuery(query, cld);
>         while (i.hasNext()) {
>             res.add(i.next());
>         }
>         return res;
>     }
>     
>     /**
>      *
>      * retrieve a collection of type collectionClass matching the Query query
>      *
>      */
>     public ManageableCollection getCollectionByQuery(
>     Class collectionClass,
>     Query query)
>     throws PersistenceBrokerException {
>         return getCollectionByQuery(collectionClass, query, false);
>     }
>     
>     public ManageableCollection getCollectionByQuery(Class collectionClass, Query 
>query, boolean lazy)
>     throws PersistenceBrokerException {
>         Class itemClass = query.getSearchClass();
>         ClassDescriptor cld = descriptorRepository.getDescriptorFor(itemClass);
>         ManageableCollection result = null;
>         String lastUsedTable = cld.getFullTableName();
>         
>         // if class is NOT an interface we can start searching its directly mapped 
>table
>         if (!cld.isInterface()) {
>             if (lazy) {
>                 return new CollectionProxy(collectionClass, query);
>             }
>             else {
>                 result = getCollectionByQuery(collectionClass, itemClass, query);
>             }
>         }
>         
>         // if class is an extent, we have to search through all extent classes too
>         if (cld.isExtent()) {
>             List tmpList = new ArrayList();
>             Vector extentClasses = cld.getExtentClasses();
>             for (int i = 0; i < extentClasses.size(); i++) {
>                 Class ec = (Class) extentClasses.get(i);
>                 cld = getClassDescriptor(ec);
>                 
>                 /**
>                  * BRJ
>                  * query the same table only once.
>                  * queries multiple classes maping to one table
>                  * will have the ojbConcreteClass criteria set
>                  * ie: ojbConcreteClass IN ('A','B').
>                  * executing the query for each extent would return
>                  * too many objects
>                  */
>                 if(cld.getFullTableName().equals(lastUsedTable)) {
>                     continue;
>                 }
>                 
>                 lastUsedTable = cld.getFullTableName();
>                 
>                 /**
>                  * BRJ
>                  * use getIteratorFromQuery and filter candidates only once
>                  * when using getCollectionByQuery(...,concreteItemClass,...)
>                  * legal candidates are filtered
>                  */
>                 //              ManageableCollection tmp = 
>getCollectionByQuery(collectionClass, concreteItemClass, query);
>                 //              Iterator iter = tmp.ojbIterator();
>                 Iterator iter = getIteratorFromQuery(query, cld);
>                 
>                 while (iter.hasNext()) {
>                     IndirectionHandler handler = null;
>                     Class candidateClass = null;
>                     Object candidate = iter.next();
>                     
>                     // if candidate is a proxy, get candidateClass from
>                     // the proxies IndirectionHandler.
>                     if (candidate instanceof VirtualProxy) {
>                         handler = VirtualProxy.getIndirectionHandler((VirtualProxy) 
>candidate);
>                     }
>                     else if (candidate instanceof Proxy) {
>                         handler = (IndirectionHandler) 
>Proxy.getInvocationHandler(candidate);
>                     }
>                     if (handler != null) {
>                         candidateClass = handler.getIdentity().getObjectsClass();
>                     }
>                     // if candidate is no proxy use getClass()
>                     else {
>                         candidateClass = candidate.getClass();
>                     }
>                     // only add candidates with matching class
>                     if (itemClass.isAssignableFrom(candidateClass)) {
>                         tmpList.add(candidate);
>                     }
>                 }
>             }
>             
>             if (result == null) {
>                 try {
>                     result = (ManageableCollection) collectionClass.newInstance();
>                 }
>                 catch (Exception e) {
>                     logger.error("Error instantiating obj: " + e.getMessage(), e);
>                     throw new PersistenceBrokerException(e);
>                 }
>             }
>             
>             if (tmpList.size() > 0) {
>                 Iterator iter = tmpList.iterator();
>                 while (iter.hasNext()) {
>                     result.ojbAdd(iter.next());
>                 }
>             }
>         }
>         
>         return result;
>     }
>     
>     
>     /**
>      *
>      * retrieve a collection of itemClass Objects matching the Query query
>      *
>      */
>     public Collection getCollectionByQuery(Query query)
>     throws PersistenceBrokerException {
>         return getCollectionByQuery(query, false);
>     }
>     
>     /**
>      *
>      * retrieve a collection of itemClass Objects matching the Query query
>      *
>      */
>     public Collection getCollectionByQuery(Query query, boolean lazy)
>     throws PersistenceBrokerException {
>         // thma: the following cast is safe because:
>         // 1. ManageableVector implements Collection (will be returned if lazy == 
>false)
>         // 2. CollectionProxy implements Collection (will be returned if lazy == 
>true)
>         return (Collection) getCollectionByQuery(
>         ManageableVector.class,
>         query,
>         lazy);
>     }
>     
>     /**
>      * Method declaration
>      *
>      * @param oid
>      * @return
>      * @throws ClassNotPersistenceCapableException
>      */
>     private Object getDBObject(Identity oid)
>     throws ClassNotPersistenceCapableException {
>         Class c = oid.getObjectsRealClass();
>         
>         if (c == null) {
>             c = oid.getObjectsClass();
>         }
>         
>         ClassDescriptor cld = descriptorRepository.getDescriptorFor(c);
>         Object newObj = null;
>         
>         // Class is NOT an Interface: it has a directly mapped table and we lookup 
>this table first:
>         if (!cld.isInterface()) {
>             // 1. try to retrieve skalar fields from directly mapped table columns
>             newObj = dbAccess.materializeObject(cld, oid);
>             
>             if (newObj != null && oid.getObjectsRealClass() == null) {
>                 oid.setObjectsRealClass(newObj.getClass());
>             }
>             
>         }
>         // if we did not find the object yet AND if the cld represents an Extent,
>         // we can lookup all tables of the extent classes:
>         if (newObj == null && cld.isExtent()) {
>             Vector extentClasses = cld.getExtentClasses();
>             for (int i = 0; i < extentClasses.size(); i++) {
>                 Class ec = (Class) extentClasses.get(i);
>                 cld = descriptorRepository.getDescriptorFor(ec);
>                 // 1a. try to retrieve skalar fields from extent table columns
>                 newObj = dbAccess.materializeObject(cld, oid);
>                 if (newObj != null) {
>                     if (oid.getObjectsRealClass() == null) {
>                         oid.setObjectsRealClass(newObj.getClass());
>                     }
>                     break; // found object in one of the extent classes
>                 }
>             }
>         }
>         // loading references is useful only when the Object could be found in db:
>         if (newObj != null) {
>             /*
>              * synchronize on newObj so the ODMG-layer can take a snapshot only of
>              * fully cached (i.e. with all references + collections) objects
>              */
>             synchronized(newObj) {
>                 // cache object immediately , so that references
>                 // can be established from referenced Objects back to this Object
>                 objectCache.cache(oid, newObj);
>                 // 2. retrieve non-skalar fields that contain objects retrievable 
>from other tables
>                 retrieveReferences(newObj, cld);
>                 // 3. retrieve collection fields from foreign-key related tables:
>                 retrieveCollections(newObj, cld);
>             }
>         }
>         return newObj;
>     }
>     
>     /**
>      * returns an Iterator that iterates Objects of class c if calling the .next()
>      * method. The Elements returned come from a SELECT ... WHERE Statement
>      * that is defined by the Query query.
>      * If itemProxy is null, no proxies are used.
>      */
>     public Iterator getIteratorByQuery(Query query)
>     throws PersistenceBrokerException {
>         Class itemClass = query.getSearchClass();
>         ClassDescriptor cld = descriptorRepository.getDescriptorFor(itemClass);
>         return getIteratorFromQuery(query, cld);
>     }
>     
>     /**
>      * Get an Iterator based on the Query
>      *
>      * @param query
>      * @param cld the ClassDescriptor
>      *
>      * @return Iterator
>      */
>     private OJBIterator getIteratorFromQuery(Query query, ClassDescriptor cld)
>     throws PersistenceBrokerException {
>         logger.debug(
>         "getIteratorFromQuery " + query.getSearchClass() + ", " + query);
>         
>         OJBIterator iter = null;
>         if (query instanceof QueryBySQL) {
>             iter =
>             new SqlBasedRsIterator(
>             cld,
>             ((QueryBySQL) query).getSql(),
>             this);
>         }
>         else {
>             iter = new RsIterator(query, cld, this);
>         }
>         return iter;
>     }
>     
>     /**
>      *
>      * retrieve an instance of Class c from the underlying persistence system
>      *
>      * by using a sample object for providing primary key information.
>      *
>      */
>     private Object getObjectByExample(Object exampleObj)
>     throws PersistenceBrokerException {
>         Identity oid = new Identity(exampleObj);
>         return getObjectByIdentity(oid);
>     }
>     
>     /**
>      * Method declaration
>      *
>      * @param id
>      * @return
>      * @throws PersistenceBrokerException
>      */
>     public Object getObjectByIdentity(Identity id)
>     throws PersistenceBrokerException {
>         logger.debug("getObjectByIdentity " + id);
>         
>         // check if object is present in ObjectCache:
>         Object obj = objectCache.lookup(id);
>         // only perform a db lookup if necessary (object not cached yet)
>         if (obj == null) {
>             obj = getDBObject(id);
>         }
>         else {
>             ClassDescriptor cld =
>             descriptorRepository.getDescriptorFor(obj.getClass());
>             refreshRelationships(obj, cld);
>         }
>         
>         // invoke callback on PersistenceBrokerAware instances
>         if (obj instanceof PersistenceBrokerAware) {
>             ((PersistenceBrokerAware) obj).afterLookup();
>         }
>         
>         //logger.info("RETRIEVING object " + obj);
>         return obj;
>     }
>     
>     /**
>      * retrieve an Object by query
>      * I.e perform a SELECT ... FROM ... WHERE ...  in an RDBMS
>      */
>     public Object getObjectByQuery(Query query)
>     throws PersistenceBrokerException {
>         if (query instanceof QueryByExample) {
>             Object obj = query.getExampleObject();
>             if (obj instanceof Identity) {
>                 return getObjectByIdentity((Identity) obj);
>             }
>             else {
>                 return getObjectByExample(obj);
>             }
>         }
>         else {
>             Vector coll = (Vector) getCollectionByQuery(query);
>             if ((coll == null) || (coll.size() == 0)) {
>                 return null;
>             }
>             else {
>                 return coll.get(0);
>             }
>         }
>     }
>     
>     /**
>      * returns an Enumeration of PrimaryKey Objects for objects of class DataClass.
>      * The Elements returned come from a SELECT ... WHERE Statement
>      * that is defined by the fields and their coresponding values of vecFields
>      * and vecValues.
>      * Useful for EJB Finder Methods...
>      * @param primaryKeyClass the pk class for the searched objects
>      * @param query the query
>      */
>     public Enumeration getPKEnumerationByQuery(
>     Class primaryKeyClass,
>     Query query)
>     throws PersistenceBrokerException {
>         logger.debug("getPKEnumerationByQuery " + query);
>         
>         ClassDescriptor cld =
>         descriptorRepository.getDescriptorFor(query.getSearchClass());
>         return new PkEnumeration(query, cld, primaryKeyClass, this);
>     }
>     
>     /**
>      * makes object obj persistent in the underlying persistence system.
>      * E.G. by INSERT INTO ... or UPDATE ...  in an RDBMS.
>      * The ObjectModification parameter can be used to determine whether INSERT or 
>update is to be used.
>      * This functionality is typically called from transaction managers, that
>      * track which objects have to be stored.
>      */
>     public void store(Object obj, ObjectModification mod)
>     throws PersistenceBrokerException {
>         store(obj, mod, new HashMap());
>     }
>     
>     private void store(Object obj, ObjectModification mod, Map markedForStore)
>     throws PersistenceBrokerException {
>         // this call ensures that all autoincremented primary key attributes are 
>filled
>         Identity oid = new Identity(obj,this);
>         // select flag for insert / update selection by checking the 
>ObjectModification
>         if (mod.needsInsert()) {
>             store(obj, true, markedForStore);
>         }
>         else if (mod.needsUpdate()) {
>             store(obj, false, markedForStore);
>         }
>         else {
>             PersistenceBrokerException ex =
>             new PersistenceBrokerException("called store(), but ObjectModification 
>tells: don't store...");
>             logger.error(ex);
>             throw ex;
>         }
>     }
>     /**
>      * makes object obj persistent in the underlying persistence system.
>      * E.G. by INSERT INTO ... or UPDATE ...  in an RDBMS.
>      * The ModificationState parameter can be used to generate optimized SQL code.
>      * This functionality is typically called from transaction managers, that
>      * track which objects have to be stored. Thus this store method does not
>      * use update cascading to referenced objects.
>      *
>      */
>     private void store(Object obj, boolean insert, Map markedForStore) {
>         // invoke callback on PersistenceBrokerAware instances
>         if (obj instanceof PersistenceBrokerAware) {
>             ((PersistenceBrokerAware) obj).beforeStore();
>         }
>         
>         //logger.info("STORING :" + obj + ", doInsert ? " + insert);
>         
>         // proxies have to be stored only when their real subjects have been 
>materialized
>         if (obj != null) {
>             /**
>              * MBAIRD
>              * 1. if we are marked for delete already, avoid recursing on this object
>              * do this AFTER we check if it's a proxy and it's materialized 
>otherwise we will
>              * materialize the proxy by putting it in the map.
>              */
>             if (markedForStore.containsKey(obj)) {
>                 Boolean insertUpdateMarker = (Boolean) markedForStore.get(obj);
>                 if (insertUpdateMarker.booleanValue() == insert) {
>                     return;
>                 }
>             }
>             /**
>              * MBAIRD
>              * 2. register object in markedForDelete map with proper marker (insert 
>flag)
>              */
>             markedForStore.put(obj, new Boolean(insert));
>             
>             ClassDescriptor cld =
>             descriptorRepository.getDescriptorFor(obj.getClass());
>             Identity oid = new Identity(obj,this);
>             /**
>              * only do the update/insert if the primary key is autoincrement, or is 
>already a valid
>              * value.
>              */
>             if (isPKautoIncrement(cld.getPkFields())
>             || isPKvalid(oid.getPrimaryKeyValues())) {
>                 // 1. assign foreign key values so that they can be stored in step 2
>                 assignReferenceFKs(obj, cld.getObjectReferenceDescriptors());
>                 // 2. store references (1:1) associations to avoid FK violations
>                 storeReferences(
>                 obj,
>                 cld.getObjectReferenceDescriptors(),
>                 markedForStore);
>                 // 3. store primitive typed attributes (Or is THIS step 3 ?)
>                 // if obj not present in db use INSERT
>                 if (insert) {
>                     dbAccess.executeInsert(cld, obj);
>                 }
>                 // else use UPDATE
>                 else {
>                     dbAccess.executeUpdate(cld, obj);
>                 }
>                 // cache object for symmetry with getObjectByXXX()
>                 objectCache.cache(obj);
>                 // 4. store 1:n and m:n associations
>                 storeCollections(
>                 obj,
>                 cld.getCollectionDescriptors(),
>                 markedForStore);
>             }
>         }
>         else
>             return;
>         
>         // invoke callback on PersistenceBrokerAware instances
>         if (obj instanceof PersistenceBrokerAware) {
>             ((PersistenceBrokerAware) obj).afterStore();
>         }
>     }
>     
>     /**
>      *        assigns all foreign key attributes of the Object obj.
>      *  used during store(obj, boolean);
>      */
>     private void assignReferenceFKs(Object obj, Vector vecRds)
>     throws PersistenceBrokerException {
>         // get all members of obj that are references and assign FKs
>         synchronized (vecRds) {
>             Iterator i = vecRds.iterator();
>             while (i.hasNext()) {
>                 ObjectReferenceDescriptor rds =
>                 (ObjectReferenceDescriptor) i.next();
>                 Object ref = rds.getPersistentField().get(obj);
>                 assertFkAssignment(obj, ref, rds);
>             }
>         }
>     }
>     
>     /**
>      * returns true if the broker is currently running a transaction.
>      * @return boolean
>      */
>     public boolean isInTransaction() {
>         return inTransaction;
>     }
>     
>     /**
>      * Get Foreign key query for 1:n
>      * @return org.apache.ojb.broker.query.Query
>      * @param obj
>      * @param cld
>      * @param cod
>      */
>     private Query getForeignKeyQuery(
>     Object obj,
>     ClassDescriptor cld,
>     CollectionDescriptor cod) {
>         Object[] values = cld.getKeyValues(obj);
>         ClassDescriptor refCld = getClassDescriptor(cod.getItemClass());
>         FieldDescriptor[] fields = cod.getForeignKeyFieldDescriptors(refCld);
>         Criteria criteria = new Criteria();
>         
>         for (int i = 0; i < fields.length; i++) {
>             FieldDescriptor fld = (FieldDescriptor) fields[i];
>             criteria.addEqualTo(fld.getAttributeName(), values[i]);
>         }
>         
>         Query result =
>         QueryFactory.newQuery(refCld.getClassOfObject(), criteria);
>         
>         return result;
>     }
>     
>     /**
>      * Get Foreign key query for m:n <br>
>      * supports UNIDIRECTIONAL m:n using QueryByMtoNCriteria
>      * @return org.apache.ojb.broker.query.Query
>      * @param obj the owner of the relationship
>      * @param cld the ClassDescriptor for the owner
>      * @param cod the CollectionDescriptor
>      */
>     private Query getMtoNQuery(
>     Object obj,
>     ClassDescriptor cld,
>     CollectionDescriptor cod) {
>         Object[] values = cld.getKeyValues(obj);
>         Object[] thisClassFks = cod.getFksToThisClass();
>         Object[] itemClassFks = cod.getFksToItemClass();
>         ClassDescriptor refCld = getClassDescriptor(cod.getItemClass());
>         Criteria criteria = new Criteria();
>         Query query;
>         
>         for (int i = 0; i < thisClassFks.length; i++) {
>             criteria.addEqualTo(
>             cod.getIndirectionTable() + "." + thisClassFks[i],
>             values[i]);
>         }
>         for (int i = 0; i < itemClassFks.length; i++) {
>             criteria.addEqualToColumn(
>             cod.getIndirectionTable() + "." + itemClassFks[i].toString(),
>             refCld.getPkFields()[i].getAttributeName());
>         }
>         
>         query =
>         QueryFactory.newQuery(
>         refCld.getClassOfObject(),
>         cod.getIndirectionTable(),
>         criteria);
>         return query;
>     }
>     
>     /**
>      * Get Foreign key query for m:n <br>
>      * uses inverse relationship, does NOT work with unidirectional m:n <br>
>      * THIS METHOD IS NOT YET USED
>      * @return org.apache.ojb.broker.query.Query
>      * @param obj the owner of the relationship
>      * @param cld the ClassDescriptor for the owner
>      * @param cod the CollectionDescriptor
>      * @throws PersistenceBrokerException if no inverse relationship defined
>      */
>     private Query getMtoNQuery_inverse(
>     Object obj,
>     ClassDescriptor cld,
>     CollectionDescriptor cod) {
>         Object[] values = cld.getKeyValues(obj);
>         ClassDescriptor refCld = getClassDescriptor(cod.getItemClass());
>         FieldDescriptor[] pks = cld.getPkFields();
>         CollectionDescriptor inverseCod = null;
>         CollectionDescriptor icod;
>         Class itemClass = cld.getClassOfObject();
>         Class baseClass = getExtentClass(itemClass);
>         Criteria criteria = new Criteria();
>         QueryByCriteria query;
>         
>         //
>         // find the inverse relationship of m:n
>         //
>         Vector v = refCld.getCollectionDescriptors();
>         for (int i = 0; i < v.size(); i++) {
>             icod = (CollectionDescriptor) v.elementAt(i);
>             if (icod.getItemClass() == baseClass) {
>                 inverseCod = icod;
>                 break;
>             }
>         }
>         
>         if (inverseCod == null) {
>             throw new PersistenceBrokerException(
>             "No inverse relationship found for :" + cod.getAttributeName());
>         }
>         
>         //
>         // build the criteria using inverse relationship
>         //
>         for (int i = 0; i < pks.length; i++) {
>             criteria.addEqualTo(
>             inverseCod.getAttributeName() + "." + pks[i].getAttributeName(),
>             values[i]);
>         }
>         
>         query = new QueryByCriteria(refCld.getClassOfObject(), criteria);
>         if (baseClass != itemClass) {
>             query.addPathClass(inverseCod.getAttributeName(), itemClass);
>             // Set the hint
>         }
>         
>         return query;
>     }
>     
>     public int getUniqueId(Class extent, String attribute) {
>         return sequenceManager.getUniqueId(extent, attribute);
>     }
>     
>     /**
>      * removes the objects obj from the brokers internal cache.
>      */
>     public void removeFromCache(Object obj) throws PersistenceBrokerException {
>         objectCache.remove(obj);
>     }
>     
>     /**
>      * returns a unique String for class extent and field attribute.
>      *
>      * the returned String is unique accross all tables in the extent of class 
>extent.
>      *
>      */
>     public String getUniqueString(Class extent, String attribute)
>     throws PersistenceBrokerException {
>         return sequenceManager.getUniqueString(extent, attribute);
>     }
>     
>     /**
>      * returns a unique Object for class extent and field attribute.
>      * the returned Object is unique accross all tables in the extent of class 
>extent.
>      */
>     public Object getUniqueObject(Class extent, String attribute)
>     throws PersistenceBrokerException {
>         return sequenceManager.getUniqueObject(extent, attribute);
>     }
>     
>     /**
>      * returns a ClassDescriptor for the persistence capable class clazz.
>      * throws a PersistenceBrokerException if clazz is not persistence capable,
>      * i.e. if clazz is not defined in the DescriptorRepository.
>      */
>     public ClassDescriptor getClassDescriptor(Class clazz)
>     throws PersistenceBrokerException {
>         return descriptorRepository.getDescriptorFor(clazz);
>     }
>     
>     public boolean hasClassDescriptor(Class clazz) {
>         return descriptorRepository.hasDescriptorFor(clazz);
>     }
>     /**
>      * clears the brokers internal cache.
>      * removing is recursive. That is referenced Objects are also
>      * removed from the cache, if the auto-retrieve flag is set
>      * for obj.getClass() in the metadata repository.
>      *
>      */
>     public void clearCache() throws PersistenceBrokerException {
>         objectCache.clear();
>     }
>     
>     /**
>      * adds a new or replaces an existing ClassDescriptor to the 
>DescriptorRepository.
>      */
>     public void setClassDescriptor(ClassDescriptor modifiedOrNewDescriptor)
>     throws PersistenceBrokerException {
>         descriptorRepository.put(
>         modifiedOrNewDescriptor.getClassOfObject(),
>         modifiedOrNewDescriptor);
>     }
>     
>     /**
>      * returns the Extent to which the class clazz belongs.
>      * This may be a baseclass,an interface or clazz itself, if no Extent
>      * is defined.
>      * throws a PersistenceBrokerException if clazz is not persistence capable,
>      * i.e. if clazz is not defined in the DescriptorRepository.
>      * @param clazz the class to lookup the Extent for
>      */
>     public Class getExtentClass(Class clazz) throws PersistenceBrokerException {
>         return descriptorRepository.getExtentClass(clazz);
>     }
>     
>     /**
>      *
>      * removes the objects obj from the brokers internal cache and
>      * inform other caches in OJB cluster about invalidation.
>      */
>     public void invalidate(Identity oid) throws PersistenceBrokerException {
>         // if running in servermode inform other caches
>         if (isRunningInServerMode()) {
>             // call all other servers in OJB cluster to remove Object from theirs 
>caches
>             synchronized (getPool()) {
>                 Iterator iter = getPool().getAllEntries();
>                 while (iter.hasNext()) {
>                     ServerEntry entry = (ServerEntry) iter.next();
>                     PersistenceBrokerClient client =
>                     new PersistenceBrokerClient(entry);
>                     client.removeFromCache(oid);
>                 }
>             }
>         }
>         // if running in singlevm mode simply remove from local cache
>         else {
>             removeFromCache(oid);
>         }
>     }
>     private synchronized ServerPool getPool() {
>         return pool;
>     }
>     
>     /**
>      * returns a unique long for class extent and field attribute.
>      * the returned number is unique accross all tables in the extent of class 
>extent.
>      */
>     public long getUniqueLong(Class extent, String attribute)
>     throws PersistenceBrokerException {
>         return sequenceManager.getUniqueLong(extent, attribute);
>     }
>     
>     /*
>      * @see PersistenceBroker#getCount(Query)
>      */
>     public int getCount(Query query) throws PersistenceBrokerException {
>         int result = 0;
>         Class itemClass = query.getSearchClass();
>         ClassDescriptor cld = getClassDescriptor(itemClass);
>         String lastUsedTable = cld.getFullTableName();
>         
>         // if class is NOT an interface we can count its directly mapped table
>         if (!cld.isInterface()) {
>             result = dbAccess.executeCount(query, cld);
>         }
>         
>         // if class is an extent, we have to search through all extent classes too
>         if (cld.isExtent()) {
>             Vector extentClasses = cld.getExtentClasses();
>             for (int i = 0; i < extentClasses.size(); i++) {
>                 itemClass = (Class) extentClasses.get(i);
>                 cld = getClassDescriptor(itemClass);
>                 Class concreteItemClass = cld.getClassOfObject();
>                 ClassDescriptor concreteCld = getClassDescriptor(concreteItemClass);
>                 
>                 /**
>                  * BRJ
>                  * query the same table only once.
>                  * queries multiple classes maping to one table
>                  * will have the ojbConcreteClass criteria set
>                  * ie: ojbConcreteClass IN ('A','B').
>                  * executing the query for each extent would return
>                  * wrong result
>                  */
>                 if(concreteCld.getFullTableName().equals(lastUsedTable)) {
>                     continue;
>                 }
>                 
>                 lastUsedTable = concreteCld.getFullTableName();
>                 int extentCount = dbAccess.executeCount(query, concreteCld);
>                 result += extentCount;
>             }
>         }
>         
>         return result;
>     }
>     
>     /*
>      * @see PersistenceBroker#getReportQueryIteratorByQuery(Query)
>      */
>     public Iterator getReportQueryIteratorByQuery(Query query)
>     throws PersistenceBrokerException {
>         ClassDescriptor cld =
>         descriptorRepository.getDescriptorFor(query.getSearchClass());
>         if (query instanceof QueryBySQL) {
>             String sql = ((QueryBySQL) query).getSql();
>             return new SqlBasedReportQueryRsIterator(cld, sql, this);
>         }
>         else {
>             return new ReportQueryRsIterator(query, cld, this);
>         }
>     }
>     
>     /*
>      * @deprecated
>      */
>     public boolean open(String repositoryFileName, String user, String passwd) {
>         PBKey key = new PBKey(repositoryFileName, user, passwd);
>         DescriptorRepository rep = DescriptorRepository.getInstance(key);
>         if (user != null) {
>             rep.getDefaultJdbcConnection().setUserName(user);
>         }
>         if (passwd != null) {
>             rep.getDefaultJdbcConnection().setPassWord(passwd);
>         }
>         this.descriptorRepository = rep;
>         return true;
>     }
>     
>     /*
>      * @see Configurable#configure(Configuration)
>      */
>     public void configure(Configuration pConfig) throws ConfigurationException {
>         PersistenceBrokerConfiguration config =
>         (PersistenceBrokerConfiguration) pConfig;
>         
>         pool = new ServerPool(config.getServers());
>         runningInServerMode = config.isRunningInServerMode();
>     }
>     
>     /**
>      * Gets the runningInServerMode value.
>      * @return Returns a boolean
>      */
>     public boolean isRunningInServerMode() {
>         return runningInServerMode;
>     }
>     
>     /**
>      * return true if any of the FieldDescriptors is autoIncrement.
>      * also return true if NO FieldDescriptors available
>      * @param fdesc the primary key FieldDescriptor[]
>      */
>     private boolean isPKautoIncrement(FieldDescriptor[] fdesc) {
>         boolean retval = false;
>         int fieldDescriptorSize = fdesc.length;
>         
>         /**
>          * if the fdesc array is 0 length, we don't have a primary key valid 
>identified for this table.
>          * that is valid in a way, so set retval to true
>          */
>         if (fieldDescriptorSize == 0) {
>             retval = true;
>         }
>         
>         for (int i = 0; i < fieldDescriptorSize; i++) {
>             /**
>              * if any of the keys in the primary key FieldDescriptor array
>              * are autoincrement we return that this is an autoincrement PK.
>              * We check all fields, in the case of a composite key.
>              */
>             if (fdesc[i].isAutoIncrement()) {
>                 retval = true;
>                 break;
>             }
>         }
>         
>         return retval;
>     }
>     
>     /**
>      * only checks string type keys for validity, since the default of other types 
>of keys is
>      * unknown (ie int)
>      * @param pkValues
>      * @return true if valid
>      */
>     private boolean isPKvalid(Object[] pkValues) {
>         int size = pkValues.length;
>         
>         for (int i = 0; i < size; i++) {
>             Object pkValue = pkValues[i];
>             // null as value of a primary key is not acceptable
>             if (pkValue == null) {
>                 return false;
>             }
>             
>             if (pkValue instanceof String) {
>                 // the toString() method on a String-object is maybe faster
>                 // than the downcast to String. Also use length() to test
>                 // if a String empty or not, this is faster than the comparing
>                 // a String-object with an empty string using the equals()-method.
>                 if (pkValue.toString().trim().length() == 0) {
>                     return false;
>                 }
>             }
>         }
>         
>         return true;
>     }
>     
>     /*
>      * @see ObjectContainer#query()
>      */
>     public org.odbms.Query query() {
>         return new org.apache.ojb.soda.QueryImpl();
>     }
>     
>     /**
>      * @return DescriptorRepository
>      */
>     public DescriptorRepository getDescriptorRepository() {
>         return descriptorRepository;
>     }
>     
> }
> 
> ----
> 

> --
> To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>



--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to