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