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]>
