Source Code Cross Referenced for PersistenceBrokerImpl.java in  » Database-ORM » db-ojb » org » apache » ojb » broker » core » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database ORM » db ojb » org.apache.ojb.broker.core 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package org.apache.ojb.broker.core;
0002:
0003:        /* Copyright 2003-2005 The Apache Software Foundation
0004:         *
0005:         * Licensed under the Apache License, Version 2.0 (the "License");
0006:         * you may not use this file except in compliance with the License.
0007:         * You may obtain a copy of the License at
0008:         *
0009:         *     http://www.apache.org/licenses/LICENSE-2.0
0010:         *
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         */
0017:
0018:        import java.lang.reflect.Constructor;
0019:        import java.util.Collection;
0020:        import java.util.Collections;
0021:        import java.util.Enumeration;
0022:        import java.util.HashSet;
0023:        import java.util.Iterator;
0024:        import java.util.List;
0025:        import java.util.Set;
0026:
0027:        import org.apache.commons.lang.ObjectUtils;
0028:        import org.apache.ojb.broker.Identity;
0029:        import org.apache.ojb.broker.IdentityFactory;
0030:        import org.apache.ojb.broker.ManageableCollection;
0031:        import org.apache.ojb.broker.MtoNImplementor;
0032:        import org.apache.ojb.broker.OptimisticLockException;
0033:        import org.apache.ojb.broker.PBKey;
0034:        import org.apache.ojb.broker.PBState;
0035:        import org.apache.ojb.broker.PersistenceBrokerException;
0036:        import org.apache.ojb.broker.TransactionAbortedException;
0037:        import org.apache.ojb.broker.TransactionInProgressException;
0038:        import org.apache.ojb.broker.TransactionNotInProgressException;
0039:        import org.apache.ojb.broker.accesslayer.ChainingIterator;
0040:        import org.apache.ojb.broker.accesslayer.ConnectionManagerFactory;
0041:        import org.apache.ojb.broker.accesslayer.ConnectionManagerIF;
0042:        import org.apache.ojb.broker.accesslayer.JdbcAccess;
0043:        import org.apache.ojb.broker.accesslayer.JdbcAccessFactory;
0044:        import org.apache.ojb.broker.accesslayer.OJBIterator;
0045:        import org.apache.ojb.broker.accesslayer.PagingIterator;
0046:        import org.apache.ojb.broker.accesslayer.PkEnumeration;
0047:        import org.apache.ojb.broker.accesslayer.RelationshipPrefetcherFactory;
0048:        import org.apache.ojb.broker.accesslayer.StatementManagerFactory;
0049:        import org.apache.ojb.broker.accesslayer.StatementManagerIF;
0050:        import org.apache.ojb.broker.accesslayer.sql.SqlGenerator;
0051:        import org.apache.ojb.broker.accesslayer.sql.SqlGeneratorFactory;
0052:        import org.apache.ojb.broker.cache.MaterializationCache;
0053:        import org.apache.ojb.broker.cache.ObjectCache;
0054:        import org.apache.ojb.broker.cache.ObjectCacheFactory;
0055:        import org.apache.ojb.broker.cache.ObjectCacheInternal;
0056:        import org.apache.ojb.broker.core.proxy.AbstractProxyFactory;
0057:        import org.apache.ojb.broker.core.proxy.CollectionProxy;
0058:        import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl;
0059:        import org.apache.ojb.broker.core.proxy.IndirectionHandler;
0060:        import org.apache.ojb.broker.core.proxy.ProxyFactory;
0061:        import org.apache.ojb.broker.core.proxy.VirtualProxy;
0062:        import org.apache.ojb.broker.metadata.ClassDescriptor;
0063:        import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException;
0064:        import org.apache.ojb.broker.metadata.CollectionDescriptor;
0065:        import org.apache.ojb.broker.metadata.DescriptorRepository;
0066:        import org.apache.ojb.broker.metadata.FieldDescriptor;
0067:        import org.apache.ojb.broker.metadata.MetadataManager;
0068:        import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
0069:        import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
0070:        import org.apache.ojb.broker.query.Query;
0071:        import org.apache.ojb.broker.query.QueryByIdentity;
0072:        import org.apache.ojb.broker.query.QueryBySQL;
0073:        import org.apache.ojb.broker.util.BrokerHelper;
0074:        import org.apache.ojb.broker.util.IdentityArrayList;
0075:        import org.apache.ojb.broker.util.ObjectModification;
0076:        import org.apache.ojb.broker.util.logging.Logger;
0077:        import org.apache.ojb.broker.util.logging.LoggerFactory;
0078:        import org.apache.ojb.broker.util.sequence.SequenceManager;
0079:        import org.apache.ojb.broker.util.sequence.SequenceManagerFactory;
0080:
0081:        /**
0082:         * The PersistenceBrokerImpl is an implementation of the PersistenceBroker
0083:         * Interface that specifies a persistence mechanism for Java objects.
0084:         * This Concrete implementation provides an object relational mapping
0085:         * and allows to store and retrieve arbitrary objects in/from relational
0086:         * databases accessed by JDBC.
0087:         *
0088:         * @author <a href="mailto:thma@apache.org">Thomas Mahler<a>
0089:         * @author <a href="mailto:leandro@ibnetwork.com.br">Leandro Rodrigo Saad Cruz<a>
0090:         * @author <a href="mailto:mattbaird@yahoo.com">Matthew Baird<a>
0091:         * @author <a href="mailto:jbraeuchi@gmx.ch">Jakob Braeuchi</a>
0092:         *
0093:         * @version $Id: PersistenceBrokerImpl.java,v 1.83.2.30 2005/12/13 18:21:23 arminw Exp $
0094:         */
0095:        public class PersistenceBrokerImpl extends
0096:                PersistenceBrokerAbstractImpl implements  PBState {
0097:            private Logger logger = LoggerFactory
0098:                    .getLogger(PersistenceBrokerImpl.class);
0099:
0100:            protected PersistenceBrokerFactoryIF pbf;
0101:            protected BrokerHelper brokerHelper;
0102:            protected MtoNBroker mtoNBroker;
0103:            protected QueryReferenceBroker referencesBroker;
0104:
0105:            /**
0106:             * signs if this broker was closed
0107:             */
0108:            private boolean isClosed;
0109:            /**
0110:             * Reflects the transaction status of this instance.
0111:             */
0112:            private boolean inTransaction;
0113:            /**
0114:             * Flag indicate that this PB instance is handled
0115:             * in a managed environment.
0116:             */
0117:            private boolean managed;
0118:            private MaterializationCache objectCache;
0119:            /**
0120:             * m_DbAccess is used to do all Jdbc related work: connecting, executing...
0121:             */
0122:            private JdbcAccess dbAccess;
0123:            /**
0124:             * holds mapping information for all classes to be treated by PersistenceBroker
0125:             */
0126:            private DescriptorRepository descriptorRepository = null;
0127:            private ConnectionManagerIF connectionManager = null;
0128:            private SequenceManager sequenceManager = null;
0129:            private StatementManagerIF statementManager = null;
0130:            private SqlGenerator sqlGenerator;
0131:            private IdentityFactory identityFactory;
0132:            private RelationshipPrefetcherFactory relationshipPrefetcherFactory;
0133:            private ProxyFactory proxyFactory;
0134:            private PBKey pbKey;
0135:
0136:            /**
0137:             * List of objects being stored now, allows to avoid infinite
0138:             * recursion storeCollections -> storeReferences -> storeCollections...
0139:             *
0140:             */
0141:            /*
0142:            we use an object identity based List to compare objects to prevent problems
0143:            with user implemented equals/hashCode methods of persistence capable objects
0144:            (e.g. objects are equals but PK fields not)
0145:             */
0146:            private List nowStoring = new IdentityArrayList();
0147:
0148:            /**
0149:             * Lists for object registration during delete operations.
0150:             * We reuse these list to avoid excessive object creation.
0151:             * @see #clearRegistrationLists
0152:             */
0153:            /*
0154:            arminw: list was cleared before delete method end. Internal we only
0155:            call doDelete(...) method. Same procedure as 'nowStoring'
0156:
0157:            we use an object identity based List to compare objects to prevent problems
0158:            with user implemented equals/hashCode methods of persistence capable objects
0159:            (e.g. objects are equals but PK fields not)
0160:             */
0161:            private List markedForDelete = new IdentityArrayList();
0162:
0163:            /**
0164:             * The set of identities of all deleted objects during current transaction
0165:             */
0166:            /*
0167:            olegnitz: this is the only way I know that solves the following problem
0168:            of batch mode: if one does store() after delete() for the same OID,
0169:            the broker checks whether the given OID exists in database to decide
0170:            which action to do: INSERT or UPDATE. If the preceding DELETE statement is
0171:            still in batch (not executed yet), then the OID exists in database so
0172:            the broker does UPDATE. Due the the following set of deleted OIDs
0173:            the broker will know that it should do INSERT.
0174:             */
0175:            private Set deletedDuringTransaction = new HashSet();
0176:
0177:            /**
0178:             * Constructor used by {@link PersistenceBrokerFactoryIF} implementation.
0179:             */
0180:            public PersistenceBrokerImpl(PBKey key,
0181:                    PersistenceBrokerFactoryIF pbf) {
0182:                refresh();
0183:                if (key == null)
0184:                    throw new PersistenceBrokerException(
0185:                            "Could not instantiate broker with PBKey 'null'");
0186:                this .pbf = pbf;
0187:                this .pbKey = key;
0188:                /*
0189:                be careful when changing initializing order
0190:                 */
0191:                brokerHelper = new BrokerHelper(this );
0192:                connectionManager = ConnectionManagerFactory.getInstance()
0193:                        .createConnectionManager(this );
0194:                /*
0195:                TODO: find better solution
0196:                MaterializationCache is a interim solution help to solve the problem of not full
0197:                materialized object reads by concurrent threads and will be replaced when
0198:                the new real two-level cache was introduced
0199:                 */
0200:                objectCache = ObjectCacheFactory.getInstance()
0201:                        .createObjectCache(this );
0202:                sequenceManager = SequenceManagerFactory
0203:                        .getSequenceManager(this );
0204:                dbAccess = JdbcAccessFactory.getInstance().createJdbcAccess(
0205:                        this );
0206:                statementManager = StatementManagerFactory.getInstance()
0207:                        .createStatementManager(this );
0208:                sqlGenerator = SqlGeneratorFactory.getInstance()
0209:                        .createSqlGenerator(
0210:                                connectionManager.getSupportedPlatform());
0211:                mtoNBroker = new MtoNBroker(this );
0212:                referencesBroker = new QueryReferenceBroker(this );
0213:                identityFactory = new IdentityFactoryImpl(this );
0214:                relationshipPrefetcherFactory = new RelationshipPrefetcherFactory(
0215:                        this );
0216:                proxyFactory = AbstractProxyFactory.getProxyFactory();
0217:            }
0218:
0219:            public MaterializationCache getInternalCache() {
0220:                return objectCache;
0221:            }
0222:
0223:            public IdentityFactory serviceIdentity() {
0224:                return this .identityFactory;
0225:            }
0226:
0227:            public SqlGenerator serviceSqlGenerator() {
0228:                return this .sqlGenerator;
0229:            }
0230:
0231:            public StatementManagerIF serviceStatementManager() {
0232:                return statementManager;
0233:            }
0234:
0235:            public JdbcAccess serviceJdbcAccess() {
0236:                return dbAccess;
0237:            }
0238:
0239:            public ConnectionManagerIF serviceConnectionManager() {
0240:                return connectionManager;
0241:            }
0242:
0243:            public SequenceManager serviceSequenceManager() {
0244:                return this .sequenceManager;
0245:            }
0246:
0247:            public BrokerHelper serviceBrokerHelper() {
0248:                return this .brokerHelper;
0249:            }
0250:
0251:            public ObjectCache serviceObjectCache() {
0252:                return this .objectCache;
0253:            }
0254:
0255:            public QueryReferenceBroker getReferenceBroker() {
0256:                return this .referencesBroker;
0257:            }
0258:
0259:            public RelationshipPrefetcherFactory getRelationshipPrefetcherFactory() {
0260:                return relationshipPrefetcherFactory;
0261:            }
0262:
0263:            public boolean isClosed() {
0264:                return this .isClosed;
0265:            }
0266:
0267:            public void setClosed(boolean closed) {
0268:                // When lookup the PB instance from pool method setClosed(false)
0269:                // was called before returning instance from pool, in this case
0270:                // OJB have to refresh the instance.
0271:                if (!closed) {
0272:                    refresh();
0273:                }
0274:                this .isClosed = closed;
0275:            }
0276:
0277:            /**
0278:             * If <em>true</em> this instance is handled by a managed
0279:             * environment - registered within a JTA transaction.
0280:             */
0281:            public boolean isManaged() {
0282:                return managed;
0283:            }
0284:
0285:            /**
0286:             * Set <em>true</em> if this instance is registered within a
0287:             * JTA transaction. On {@link #close()} call this flag was reset
0288:             * to <em>false</em> automatic.
0289:             */
0290:            public void setManaged(boolean managed) {
0291:                this .managed = managed;
0292:            }
0293:
0294:            /**
0295:             * Lookup the current {@link DescriptorRepository} for
0296:             * this class. This method is responsible to keep this
0297:             * PB instance in sync with {@link MetadataManager}.
0298:             */
0299:            public void refresh() {
0300:                // guarantee that refreshed use initial status
0301:                setInTransaction(false);
0302:                this .descriptorRepository = MetadataManager.getInstance()
0303:                        .getRepository();
0304:            }
0305:
0306:            /**
0307:             * Release all resources used by this
0308:             * class - CAUTION: No further operations can be
0309:             * done with this instance after calling this method.
0310:             */
0311:            public void destroy() {
0312:                removeAllListeners();
0313:                if (connectionManager != null) {
0314:                    if (connectionManager.isInLocalTransaction()) {
0315:                        connectionManager.localRollback();
0316:                    }
0317:                    connectionManager.releaseConnection();
0318:                }
0319:                this .setClosed(true);
0320:
0321:                this .descriptorRepository = null;
0322:                this .pbKey = null;
0323:                this .pbf = null;
0324:                this .connectionManager = null;
0325:                this .dbAccess = null;
0326:                this .objectCache = null;
0327:                this .sequenceManager = null;
0328:                this .sqlGenerator = null;
0329:                this .statementManager = null;
0330:            }
0331:
0332:            public PBKey getPBKey() {
0333:                return pbKey;
0334:            }
0335:
0336:            public void setPBKey(PBKey key) {
0337:                this .pbKey = key;
0338:            }
0339:
0340:            /**
0341:             * @see org.apache.ojb.broker.PersistenceBroker#close()
0342:             */
0343:            public boolean close() {
0344:                /**
0345:                 * MBAIRD: if we call close on a broker that is in a transaction,
0346:                 * we should just abort whatever it's doing.
0347:                 */
0348:                if (isInTransaction()) {
0349:                    logger
0350:                            .error("Broker is still in PB-transaction, do automatic abort before close!");
0351:                    abortTransaction();
0352:                }
0353:                if (logger.isDebugEnabled()) {
0354:                    logger.debug("PB.close was called: " + this );
0355:                }
0356:                try {
0357:                    fireBrokerEvent(BEFORE_CLOSE_EVENT);
0358:                    clearRegistrationLists();
0359:                    referencesBroker.removePrefetchingListeners();
0360:                    if (connectionManager != null) {
0361:                        connectionManager.releaseConnection();
0362:                        /*
0363:                        arminw:
0364:                        set batch mode explicit to 'false'. Using
0365:
0366:                        connectionManager.setBatchMode(
0367:                                connectionManager.getConnectionDescriptor().getBatchMode());
0368:
0369:                        cause many unexpected junit failures/errors when running
0370:                        test suite with batch-mode 'true' setting.
0371:                         */
0372:                        connectionManager.setBatchMode(false);
0373:                    }
0374:                } finally {
0375:                    // reset flag indicating use in managed environment
0376:                    setManaged(false);
0377:                    // free current used DescriptorRepository reference
0378:                    descriptorRepository = null;
0379:                    removeAllListeners();
0380:                    this .setClosed(true);
0381:                }
0382:                return true;
0383:            }
0384:
0385:            /**
0386:             * Abort and close the transaction.
0387:             * Calling abort abandons all persistent object modifications and releases the
0388:             * associated locks.
0389:             * If transaction is not in progress a TransactionNotInProgressException is thrown
0390:             */
0391:            public synchronized void abortTransaction()
0392:                    throws TransactionNotInProgressException {
0393:                if (isInTransaction()) {
0394:                    fireBrokerEvent(BEFORE_ROLLBACK_EVENT);
0395:                    setInTransaction(false);
0396:                    clearRegistrationLists();
0397:                    referencesBroker.removePrefetchingListeners();
0398:                    /*
0399:                    arminw:
0400:                    check if we in local tx, before do local rollback
0401:                    Necessary, because ConnectionManager may do a rollback by itself
0402:                    or in managed environments the used connection is already be closed
0403:                     */
0404:                    if (connectionManager.isInLocalTransaction())
0405:                        this .connectionManager.localRollback();
0406:                    fireBrokerEvent(AFTER_ROLLBACK_EVENT);
0407:                }
0408:            }
0409:
0410:            /**
0411:             * begin a transaction against the underlying RDBMS.
0412:             * Calling <code>beginTransaction</code> multiple times,
0413:             * without an intervening call to <code>commitTransaction</code> or <code>abortTransaction</code>,
0414:             * causes the exception <code>TransactionInProgressException</code> to be thrown
0415:             * on the second and subsequent calls.
0416:             */
0417:            public synchronized void beginTransaction()
0418:                    throws TransactionInProgressException,
0419:                    TransactionAbortedException {
0420:                if (isInTransaction()) {
0421:                    throw new TransactionInProgressException(
0422:                            "PersistenceBroker is already in transaction");
0423:                }
0424:                fireBrokerEvent(BEFORE_BEGIN_EVENT);
0425:                setInTransaction(true);
0426:                this .connectionManager.localBegin();
0427:                fireBrokerEvent(AFTER_BEGIN_EVENT);
0428:            }
0429:
0430:            /**
0431:             * Commit and close the transaction.
0432:             * Calling <code>commit</code> commits to the database all
0433:             * UPDATE, INSERT and DELETE statements called within the transaction and
0434:             * releases any locks held by the transaction.
0435:             * If beginTransaction() has not been called before a
0436:             * TransactionNotInProgressException exception is thrown.
0437:             * If the transaction cannot be commited a TransactionAbortedException exception is thrown.
0438:             */
0439:            public synchronized void commitTransaction()
0440:                    throws TransactionNotInProgressException,
0441:                    TransactionAbortedException {
0442:                if (!isInTransaction()) {
0443:                    throw new TransactionNotInProgressException(
0444:                            "PersistenceBroker is NOT in transaction, can't commit");
0445:                }
0446:                fireBrokerEvent(BEFORE_COMMIT_EVENT);
0447:                setInTransaction(false);
0448:                clearRegistrationLists();
0449:                referencesBroker.removePrefetchingListeners();
0450:                /*
0451:                arminw:
0452:                In managed environments it should be possible to close a used connection before
0453:                the tx was commited, thus it will be possible that the PB instance is in PB-tx, but
0454:                the connection is already closed. To avoid problems check if CM is in local tx before
0455:                do the CM.commit call
0456:                 */
0457:                if (connectionManager.isInLocalTransaction()) {
0458:                    this .connectionManager.localCommit();
0459:                }
0460:                fireBrokerEvent(AFTER_COMMIT_EVENT);
0461:            }
0462:
0463:            /**
0464:             * Deletes the concrete representation of the specified object in the underlying
0465:             * persistence system. This method is intended for use in top-level api or
0466:             * by internal calls.
0467:             *
0468:             * @param obj The object to delete.
0469:             * @param ignoreReferences With this flag the automatic deletion/unlinking
0470:             * of references can be suppressed (independent of the used auto-delete setting in metadata),
0471:             * except {@link org.apache.ojb.broker.metadata.SuperReferenceDescriptor}
0472:             * these kind of reference (descriptor) will always be performed. If <em>true</em>
0473:             * all "normal" referenced objects will be ignored, only the specified object is handled.
0474:             * @throws PersistenceBrokerException
0475:             */
0476:            public void delete(Object obj, boolean ignoreReferences)
0477:                    throws PersistenceBrokerException {
0478:                if (isTxCheck() && !isInTransaction()) {
0479:                    if (logger.isEnabledFor(Logger.ERROR)) {
0480:                        String msg = "No running PB-tx found. Please, only delete objects in context of a PB-transaction"
0481:                                + " to avoid side-effects - e.g. when rollback of complex objects.";
0482:                        try {
0483:                            throw new Exception(
0484:                                    "** Delete object without active PersistenceBroker transaction **");
0485:                        } catch (Exception e) {
0486:                            logger.error(msg, e);
0487:                        }
0488:                    }
0489:                }
0490:                try {
0491:                    doDelete(obj, ignoreReferences);
0492:                } finally {
0493:                    markedForDelete.clear();
0494:                }
0495:            }
0496:
0497:            /**
0498:             * @see org.apache.ojb.broker.PersistenceBroker#delete
0499:             */
0500:            public void delete(Object obj) throws PersistenceBrokerException {
0501:                delete(obj, false);
0502:            }
0503:
0504:            /**
0505:             * do delete given object. Should be used by all intern classes to delete
0506:             * objects.
0507:             */
0508:            private void doDelete(Object obj, boolean ignoreReferences)
0509:                    throws PersistenceBrokerException {
0510:                //logger.info("DELETING " + obj);
0511:                // object is not null
0512:                if (obj != null) {
0513:                    obj = getProxyFactory().getRealObject(obj);
0514:                    /**
0515:                     * MBAIRD
0516:                     * 1. if we are marked for delete already, avoid recursing on this object
0517:                     *
0518:                     * arminw:
0519:                     * use object instead Identity object in markedForDelete List,
0520:                     * because using objects we get a better performance. I can't find
0521:                     * side-effects in doing so.
0522:                     */
0523:                    if (markedForDelete.contains(obj)) {
0524:                        return;
0525:                    }
0526:
0527:                    ClassDescriptor cld = getClassDescriptor(obj.getClass());
0528:                    //BRJ: check for valid pk
0529:                    if (!serviceBrokerHelper().assertValidPkForDelete(cld, obj)) {
0530:                        String msg = "Cannot delete object without valid PKs. "
0531:                                + obj;
0532:                        logger.error(msg);
0533:                        return;
0534:                    }
0535:
0536:                    /**
0537:                     * MBAIRD
0538:                     * 2. register object in markedForDelete map.
0539:                     */
0540:                    markedForDelete.add(obj);
0541:                    Identity oid = serviceIdentity().buildIdentity(cld, obj);
0542:
0543:                    // Invoke events on PersistenceBrokerAware instances and listeners
0544:                    BEFORE_DELETE_EVENT.setTarget(obj);
0545:                    fireBrokerEvent(BEFORE_DELETE_EVENT);
0546:                    BEFORE_DELETE_EVENT.setTarget(null);
0547:
0548:                    // 1. delete dependend collections
0549:                    if (!ignoreReferences
0550:                            && cld.getCollectionDescriptors().size() > 0) {
0551:                        deleteCollections(obj, cld.getCollectionDescriptors());
0552:                    }
0553:                    // 2. delete object from directly mapped table
0554:                    try {
0555:                        dbAccess.executeDelete(cld, obj); // use obj not oid to delete, BRJ
0556:                    } catch (OptimisticLockException e) {
0557:                        // ensure that the outdated object be removed from cache
0558:                        objectCache.remove(oid);
0559:                        throw e;
0560:                    }
0561:
0562:                    // 3. Add OID to the set of deleted objects
0563:                    deletedDuringTransaction.add(oid);
0564:
0565:                    // 4. delete dependend upon objects last to avoid FK violations
0566:                    if (cld.getObjectReferenceDescriptors().size() > 0) {
0567:                        deleteReferences(obj, cld
0568:                                .getObjectReferenceDescriptors(),
0569:                                ignoreReferences);
0570:                    }
0571:                    // remove obj from the object cache:
0572:                    objectCache.remove(oid);
0573:
0574:                    // Invoke events on PersistenceBrokerAware instances and listeners
0575:                    AFTER_DELETE_EVENT.setTarget(obj);
0576:                    fireBrokerEvent(AFTER_DELETE_EVENT);
0577:                    AFTER_DELETE_EVENT.setTarget(null);
0578:
0579:                    // let the connection manager to execute batch
0580:                    connectionManager.executeBatchIfNecessary();
0581:                }
0582:            }
0583:
0584:            /**
0585:             * Extent aware Delete by Query
0586:             * @param query
0587:             * @param cld
0588:             * @throws PersistenceBrokerException
0589:             */
0590:            private void deleteByQuery(Query query, ClassDescriptor cld)
0591:                    throws PersistenceBrokerException {
0592:                if (logger.isDebugEnabled()) {
0593:                    logger.debug("deleteByQuery " + cld.getClassNameOfObject()
0594:                            + ", " + query);
0595:                }
0596:
0597:                if (query instanceof  QueryBySQL) {
0598:                    String sql = ((QueryBySQL) query).getSql();
0599:                    this .dbAccess.executeUpdateSQL(sql, cld);
0600:                } else {
0601:                    // if query is Identity based transform it to a criteria based query first
0602:                    if (query instanceof  QueryByIdentity) {
0603:                        QueryByIdentity qbi = (QueryByIdentity) query;
0604:                        Object oid = qbi.getExampleObject();
0605:                        // make sure it's an Identity
0606:                        if (!(oid instanceof  Identity)) {
0607:                            oid = serviceIdentity().buildIdentity(oid);
0608:                        }
0609:                        query = referencesBroker.getPKQuery((Identity) oid);
0610:                    }
0611:
0612:                    if (!cld.isInterface()) {
0613:                        this .dbAccess.executeDelete(query, cld);
0614:                    }
0615:
0616:                    // if class is an extent, we have to delete all extent classes too
0617:                    String lastUsedTable = cld.getFullTableName();
0618:                    if (cld.isExtent()) {
0619:                        Iterator extents = getDescriptorRepository()
0620:                                .getAllConcreteSubclassDescriptors(cld)
0621:                                .iterator();
0622:
0623:                        while (extents.hasNext()) {
0624:                            ClassDescriptor extCld = (ClassDescriptor) extents
0625:                                    .next();
0626:
0627:                            // read same table only once
0628:                            if (!extCld.getFullTableName()
0629:                                    .equals(lastUsedTable)) {
0630:                                lastUsedTable = extCld.getFullTableName();
0631:                                this .dbAccess.executeDelete(query, extCld);
0632:                            }
0633:                        }
0634:                    }
0635:
0636:                }
0637:            }
0638:
0639:            /**
0640:             * @see org.apache.ojb.broker.PersistenceBroker#deleteByQuery(Query)
0641:             */
0642:            public void deleteByQuery(Query query)
0643:                    throws PersistenceBrokerException {
0644:                ClassDescriptor cld = getClassDescriptor(query.getSearchClass());
0645:                deleteByQuery(query, cld);
0646:            }
0647:
0648:            /**
0649:             * Deletes references that <b>obj</b> points to.
0650:             * All objects which we have a FK poiting to (Via ReferenceDescriptors)
0651:             * will be deleted if auto-delete is true <b>AND</b>
0652:             * the member field containing the object reference is NOT null.
0653:             *
0654:             * @param obj Object which we will delete references for
0655:             * @param listRds list of ObjectRederenceDescriptors
0656:             * @param ignoreReferences With this flag the automatic deletion/unlinking
0657:             * of references can be suppressed (independent of the used auto-delete setting in metadata),
0658:             * except {@link org.apache.ojb.broker.metadata.SuperReferenceDescriptor}
0659:             * these kind of reference (descriptor) will always be performed.
0660:             * @throws PersistenceBrokerException if some goes wrong - please see the error message for details
0661:             */
0662:            private void deleteReferences(Object obj, List listRds,
0663:                    boolean ignoreReferences) throws PersistenceBrokerException {
0664:                // get all members of obj that are references and delete them
0665:                Iterator i = listRds.iterator();
0666:                while (i.hasNext()) {
0667:                    ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) i
0668:                            .next();
0669:                    if ((!ignoreReferences && rds.getCascadingDelete() == ObjectReferenceDescriptor.CASCADE_OBJECT)
0670:                            || rds.isSuperReferenceDescriptor()) {
0671:                        Object referencedObject = rds.getPersistentField().get(
0672:                                obj);
0673:                        if (referencedObject != null) {
0674:                            doDelete(referencedObject, ignoreReferences);
0675:                        }
0676:                    }
0677:                }
0678:            }
0679:
0680:            /**
0681:             * Deletes collections of objects poiting to <b>obj</b>.
0682:             * All object which have a FK poiting to this object (Via CollectionDescriptors)
0683:             * will be deleted if auto-delete is true <b>AND</b>
0684:             * the member field containing the object reference if NOT null.
0685:             *
0686:             * @param obj Object which we will delete collections for
0687:             * @param listCds list of ObjectReferenceDescriptors
0688:             * @throws PersistenceBrokerException if some goes wrong - please see the error message for details
0689:             */
0690:            private void deleteCollections(Object obj, List listCds)
0691:                    throws PersistenceBrokerException {
0692:                // get all members of obj that are collections and delete all their elements
0693:                Iterator i = listCds.iterator();
0694:
0695:                while (i.hasNext()) {
0696:                    CollectionDescriptor cds = (CollectionDescriptor) i.next();
0697:                    if (cds.getCascadingDelete() != ObjectReferenceDescriptor.CASCADE_NONE) {
0698:                        if (cds.isMtoNRelation()) {
0699:                            // if this is a m:n mapped table, remove entries from indirection table
0700:                            mtoNBroker.deleteMtoNImplementor(cds, obj);
0701:                        }
0702:                        /*
0703:                        if cascading delete is on, delete all referenced objects.
0704:                        NOTE: User has to take care to populate all referenced objects before delete
0705:                        the main object to avoid referential constraint violation
0706:                         */
0707:                        if (cds.getCascadingDelete() == ObjectReferenceDescriptor.CASCADE_OBJECT) {
0708:                            Object col = cds.getPersistentField().get(obj);
0709:                            if (col != null) {
0710:                                Iterator colIterator = BrokerHelper
0711:                                        .getCollectionIterator(col);
0712:                                while (colIterator.hasNext()) {
0713:                                    doDelete(colIterator.next(), false);
0714:                                }
0715:                            }
0716:                        }
0717:                    }
0718:                }
0719:            }
0720:
0721:            /**
0722:             * Store an Object.
0723:             * @see org.apache.ojb.broker.PersistenceBroker#store(Object)
0724:             */
0725:            public void store(Object obj) throws PersistenceBrokerException {
0726:                obj = extractObjectToStore(obj);
0727:                // only do something if obj != null
0728:                if (obj == null)
0729:                    return;
0730:
0731:                ClassDescriptor cld = getClassDescriptor(obj.getClass());
0732:                /*
0733:                if one of the PK fields was null, we assume the objects
0734:                was new and needs insert
0735:                 */
0736:                boolean insert = serviceBrokerHelper().hasNullPKField(cld, obj);
0737:                Identity oid = serviceIdentity().buildIdentity(cld, obj);
0738:                /*
0739:                if PK values are set, lookup cache or db to see whether object
0740:                needs insert or update
0741:                 */
0742:                if (!insert) {
0743:                    insert = objectCache.lookup(oid) == null
0744:                            && !serviceBrokerHelper().doesExist(cld, oid, obj);
0745:                }
0746:                store(obj, oid, cld, insert);
0747:            }
0748:
0749:            /**
0750:             * Check if the given object is <code>null</code> or an unmaterialized proxy object - in
0751:             * both cases <code>null</code> will be returned, else the given object itself or the
0752:             * materialized proxy object will be returned.
0753:             */
0754:            private Object extractObjectToStore(Object obj) {
0755:                Object result = obj;
0756:                // only do something if obj != null
0757:                if (result != null) {
0758:                    // ProxyObjects only have to be updated if their real
0759:                    // subjects have been loaded
0760:                    result = getProxyFactory().getRealObjectIfMaterialized(obj);
0761:                    // null for unmaterialized Proxy
0762:                    if (result == null) {
0763:                        if (logger.isDebugEnabled())
0764:                            logger
0765:                                    .debug("No materialized object could be found -> nothing to store,"
0766:                                            + " object was "
0767:                                            + ObjectUtils.identityToString(obj));
0768:                    }
0769:                }
0770:                return result;
0771:            }
0772:
0773:            /**
0774:             * Method which start the real store work (insert or update)
0775:             * and is intended for use by top-level api or internal calls.
0776:             *
0777:             * @param obj The object to store.
0778:             * @param oid The {@link Identity} of the object to store.
0779:             * @param cld The {@link org.apache.ojb.broker.metadata.ClassDescriptor} of the object.
0780:             * @param insert If <em>true</em> an insert operation will be performed, else update operation.
0781:             * @param ignoreReferences With this flag the automatic storing/linking
0782:             * of references can be suppressed (independent of the used auto-update setting in metadata),
0783:             * except {@link org.apache.ojb.broker.metadata.SuperReferenceDescriptor}
0784:             * these kind of reference (descriptor) will always be performed. If <em>true</em>
0785:             * all "normal" referenced objects will be ignored, only the specified object is handled.
0786:             */
0787:            public void store(Object obj, Identity oid, ClassDescriptor cld,
0788:                    boolean insert, boolean ignoreReferences) {
0789:                if (obj == null || nowStoring.contains(obj)) {
0790:                    return;
0791:                }
0792:
0793:                /*
0794:                if the object has been deleted during this transaction,
0795:                then we must insert it
0796:                 */
0797:                //System.out.println("## insert: " +insert + " / deleted: " + deletedDuringTransaction);
0798:                if (!insert) {
0799:                    insert = deletedDuringTransaction.contains(oid);
0800:                }
0801:
0802:                //************************************************
0803:                // now store it:
0804:                if (isTxCheck() && !isInTransaction()) {
0805:                    if (logger.isEnabledFor(Logger.ERROR)) {
0806:                        try {
0807:                            throw new Exception(
0808:                                    "** Try to store object without active PersistenceBroker transaction **");
0809:                        } catch (Exception e) {
0810:                            logger
0811:                                    .error(
0812:                                            "No running tx found, please only store in context of an PB-transaction"
0813:                                                    + ", to avoid side-effects - e.g. when rollback of complex objects",
0814:                                            e);
0815:                        }
0816:                    }
0817:                }
0818:                // Invoke events on PersistenceBrokerAware instances and listeners
0819:                if (insert) {
0820:                    BEFORE_STORE_EVENT.setTarget(obj);
0821:                    fireBrokerEvent(BEFORE_STORE_EVENT);
0822:                    BEFORE_STORE_EVENT.setTarget(null);
0823:                } else {
0824:                    BEFORE_UPDATE_EVENT.setTarget(obj);
0825:                    fireBrokerEvent(BEFORE_UPDATE_EVENT);
0826:                    BEFORE_UPDATE_EVENT.setTarget(null);
0827:                }
0828:
0829:                try {
0830:                    nowStoring.add(obj);
0831:                    storeToDb(obj, cld, oid, insert, ignoreReferences);
0832:                } finally {
0833:                    // to optimize calls to DB don't remove already stored objects
0834:                    nowStoring.remove(obj);
0835:                }
0836:
0837:                // Invoke events on PersistenceBrokerAware instances and listeners
0838:                if (insert) {
0839:                    AFTER_STORE_EVENT.setTarget(obj);
0840:                    fireBrokerEvent(AFTER_STORE_EVENT);
0841:                    AFTER_STORE_EVENT.setTarget(null);
0842:                } else {
0843:                    AFTER_UPDATE_EVENT.setTarget(obj);
0844:                    fireBrokerEvent(AFTER_UPDATE_EVENT);
0845:                    AFTER_UPDATE_EVENT.setTarget(null);
0846:                }
0847:                // end of store operation
0848:                //************************************************
0849:
0850:                // if the object was stored, remove it from deleted set
0851:                if (deletedDuringTransaction.size() > 0)
0852:                    deletedDuringTransaction.remove(oid);
0853:
0854:                // let the connection manager to execute batch
0855:                connectionManager.executeBatchIfNecessary();
0856:            }
0857:
0858:            /**
0859:             * Internal used method which start the real store work.
0860:             */
0861:            protected void store(Object obj, Identity oid, ClassDescriptor cld,
0862:                    boolean insert) {
0863:                store(obj, oid, cld, insert, false);
0864:            }
0865:
0866:            /**
0867:             * Store all object references that <b>obj</b> points to.
0868:             * All objects which we have a FK pointing to (Via ReferenceDescriptors) will be
0869:             * stored if auto-update is true <b>AND</b> the member field containing the object
0870:             * reference is NOT null.
0871:             * With flag <em>ignoreReferences</em> the storing/linking
0872:             * of references can be suppressed (independent of the used auto-update setting),
0873:             * except {@link org.apache.ojb.broker.metadata.SuperReferenceDescriptor}
0874:             * these kind of reference (descriptor) will always be performed.
0875:             *
0876:             * @param obj Object which we will store references for
0877:             */
0878:            private void storeReferences(Object obj, ClassDescriptor cld,
0879:                    boolean insert, boolean ignoreReferences) {
0880:                // get all members of obj that are references and store them
0881:                Collection listRds = cld.getObjectReferenceDescriptors();
0882:                // return if nothing to do
0883:                if (listRds == null || listRds.size() == 0) {
0884:                    return;
0885:                }
0886:                Iterator i = listRds.iterator();
0887:                while (i.hasNext()) {
0888:                    ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) i
0889:                            .next();
0890:                    /*
0891:                    arminw: the super-references (used for table per subclass inheritance) must
0892:                    be performed in any case. The "normal" 1:1 references can be ignored when
0893:                    flag "ignoreReferences" is set
0894:                     */
0895:                    if ((!ignoreReferences && rds.getCascadingStore() != ObjectReferenceDescriptor.CASCADE_NONE)
0896:                            || rds.isSuperReferenceDescriptor()) {
0897:                        storeAndLinkOneToOne(false, obj, cld, rds, insert);
0898:                    }
0899:                }
0900:            }
0901:
0902:            /**
0903:             * Store/Link 1:1 reference.
0904:             *
0905:             * @param obj real object the reference starts
0906:             * @param rds {@link ObjectReferenceDescriptor} of the real object
0907:             * @param insert flag for insert operation
0908:             */
0909:            private void storeAndLinkOneToOne(boolean onlyLink, Object obj,
0910:                    ClassDescriptor cld, ObjectReferenceDescriptor rds,
0911:                    boolean insert) {
0912:                Object ref = rds.getPersistentField().get(obj);
0913:                if (!onlyLink
0914:                        && rds.getCascadingStore() == ObjectReferenceDescriptor.CASCADE_OBJECT) {
0915:                    if (rds.isSuperReferenceDescriptor()) {
0916:                        ClassDescriptor super Cld = rds.getClassDescriptor()
0917:                                .getSuperClassDescriptor();
0918:                        Identity oid = serviceIdentity().buildIdentity(
0919:                                super Cld, ref);
0920:                        storeToDb(ref, super Cld, oid, insert);
0921:                    } else
0922:                        store(ref);
0923:                }
0924:                link(obj, cld, rds, ref, insert);
0925:            }
0926:
0927:            /**
0928:             * Store/Link collections of objects poiting to <b>obj</b>.
0929:             * More info please see comments in source.
0930:             *
0931:             * @param obj real object which we will store collections for
0932:             * @throws PersistenceBrokerException if some goes wrong - please see the error message for details
0933:             */
0934:            private void storeCollections(Object obj, ClassDescriptor cld,
0935:                    boolean insert) throws PersistenceBrokerException {
0936:                // get all members of obj that are collections and store all their elements
0937:                Collection listCods = cld.getCollectionDescriptors();
0938:                // return if nothing to do
0939:                if (listCods.size() == 0) {
0940:                    return;
0941:                }
0942:                Iterator i = listCods.iterator();
0943:                while (i.hasNext()) {
0944:                    CollectionDescriptor cod = (CollectionDescriptor) i.next();
0945:
0946:                    // if CASCADE_NONE was set, do nothing with referenced objects
0947:                    if (cod.getCascadingStore() != ObjectReferenceDescriptor.CASCADE_NONE) {
0948:                        Object referencedObjects = cod.getPersistentField()
0949:                                .get(obj);
0950:                        if (cod.isMtoNRelation()) {
0951:                            storeAndLinkMtoN(false, obj, cod,
0952:                                    referencedObjects, insert);
0953:                        } else {
0954:                            storeAndLinkOneToMany(false, obj, cod,
0955:                                    referencedObjects, insert);
0956:                        }
0957:
0958:                        // BRJ: only when auto-update = object (CASCADE_OBJECT)
0959:                        //
0960:                        if ((cod.getCascadingStore() == ObjectReferenceDescriptor.CASCADE_OBJECT)
0961:                                && (referencedObjects instanceof  ManageableCollection)) {
0962:                            ((ManageableCollection) referencedObjects)
0963:                                    .afterStore(this );
0964:                        }
0965:                    }
0966:                }
0967:            }
0968:
0969:            /**
0970:             * Store/Link m:n collection references.
0971:             *
0972:             * @param obj real object the reference starts
0973:             * @param cod {@link CollectionDescriptor} of the real object
0974:             * @param referencedObjects the referenced objects ({@link ManageableCollection} or Collection or Array) or null
0975:             * @param insert flag for insert operation
0976:             */
0977:            private void storeAndLinkMtoN(boolean onlyLink, Object obj,
0978:                    CollectionDescriptor cod, Object referencedObjects,
0979:                    boolean insert) {
0980:                /*
0981:                - if the collection is a collectionproxy and it's not already loaded
0982:                no need to perform an update on the referenced objects
0983:                - on insert we link and insert the referenced objects, because the proxy
0984:                collection maybe "inherited" from the object before the PK was replaced
0985:                 */
0986:                if (insert
0987:                        || !(referencedObjects instanceof  CollectionProxy && !((CollectionProxy) referencedObjects)
0988:                                .isLoaded())) {
0989:                    // if referenced objects are null, assign empty list
0990:                    if (referencedObjects == null) {
0991:                        referencedObjects = Collections.EMPTY_LIST;
0992:                    }
0993:                    /*
0994:                    NOTE: Take care of referenced objects, they could be of type Collection or
0995:                    an Array or of type ManageableCollection, thus it is not guaranteed that we
0996:                    can cast to Collection!!!
0997:
0998:                    if we store an object with m:n reference and no references could be
0999:                    found, we remove all entires of given object in indirection table
1000:                     */
1001:                    Iterator referencedObjectsIterator;
1002:
1003:                    if (!onlyLink
1004:                            && cod.getCascadingStore() == ObjectReferenceDescriptor.CASCADE_OBJECT) {
1005:                        referencedObjectsIterator = BrokerHelper
1006:                                .getCollectionIterator(referencedObjects);
1007:                        while (referencedObjectsIterator.hasNext()) {
1008:                            store(referencedObjectsIterator.next());
1009:                        }
1010:                    }
1011:
1012:                    Collection existingMtoNKeys;
1013:                    if (!insert) {
1014:                        existingMtoNKeys = mtoNBroker.getMtoNImplementor(cod,
1015:                                obj);
1016:                        // we can't reuse iterator
1017:                        referencedObjectsIterator = BrokerHelper
1018:                                .getCollectionIterator(referencedObjects);
1019:                        // remove all entries in indirection table which not be part of referenced objects
1020:                        mtoNBroker.deleteMtoNImplementor(cod, obj,
1021:                                referencedObjectsIterator, existingMtoNKeys);
1022:                    } else {
1023:                        existingMtoNKeys = Collections.EMPTY_LIST;
1024:                    }
1025:                    // we can't reuse iterator
1026:                    referencedObjectsIterator = BrokerHelper
1027:                            .getCollectionIterator(referencedObjects);
1028:                    while (referencedObjectsIterator.hasNext()) {
1029:                        Object refObj = referencedObjectsIterator.next();
1030:                        // Now store indirection record
1031:                        // BRJ: this could cause integrity problems because
1032:                        // obj may not be stored depending on auto-update
1033:                        mtoNBroker.storeMtoNImplementor(cod, obj, refObj,
1034:                                existingMtoNKeys);
1035:                    }
1036:                }
1037:            }
1038:
1039:            /**
1040:             * Store/Link 1:n collection references.
1041:             *
1042:             * @param obj real object the reference starts
1043:             * @param linkOnly if true the referenced objects will only be linked (FK set, no reference store).
1044:             * Reference store setting in descriptor will be ignored in this case
1045:             * @param cod {@link CollectionDescriptor} of the real object
1046:             * @param referencedObjects the referenced objects ({@link ManageableCollection} or Collection or Array) or null
1047:             * @param insert flag for insert operation
1048:             */
1049:            private void storeAndLinkOneToMany(boolean linkOnly, Object obj,
1050:                    CollectionDescriptor cod, Object referencedObjects,
1051:                    boolean insert) {
1052:                if (referencedObjects == null) {
1053:                    return;
1054:                }
1055:                /*
1056:                Only make sense to perform (link or/and store) real referenced objects
1057:                or materialized collection proxy objects, because on unmaterialized collection
1058:                nothing has changed.
1059:
1060:                - if the collection is a collectionproxy and it's not already loaded
1061:                no need to perform an update on the referenced objects
1062:                - on insert we link and insert the referenced objects, because the proxy
1063:                collection maybe "inherited" from the object before the PK was replaced
1064:                 */
1065:                if (insert
1066:                        || !(referencedObjects instanceof  CollectionProxyDefaultImpl && !((CollectionProxyDefaultImpl) referencedObjects)
1067:                                .isLoaded())) {
1068:                    Iterator it = BrokerHelper
1069:                            .getCollectionIterator(referencedObjects);
1070:                    Object refObj;
1071:                    while (it.hasNext()) {
1072:                        refObj = it.next();
1073:                        /*
1074:                        TODO: Check this!
1075:                        arminw:
1076:                        When it's necessary to 'link' (set the FK) the 1:n reference objects?
1077:                        1. set FK in refObj if it is materialized
1078:                        2. if the referenced object is a proxy AND the main object needs insert
1079:                        we have to materialize the real object, because the user may move a collection
1080:                        of proxy objects from object A to new object B. In this case we have to replace the
1081:                        FK in the proxy object with new key of object B.
1082:                         */
1083:                        if (insert || getProxyFactory().isMaterialized(refObj)) {
1084:                            ClassDescriptor refCld = getClassDescriptor(getProxyFactory()
1085:                                    .getRealClass(refObj));
1086:                            // get the real object before linking
1087:                            refObj = getProxyFactory().getRealObject(refObj);
1088:                            link(refObj, refCld, cod, obj, insert);
1089:                            // if enabled cascade store and not only link, store the refObj
1090:                            if (!linkOnly
1091:                                    && cod.getCascadingStore() == ObjectReferenceDescriptor.CASCADE_OBJECT) {
1092:                                store(refObj);
1093:                            }
1094:                        }
1095:                    }
1096:                }
1097:            }
1098:
1099:            /**
1100:             * Assign FK value to target object by reading PK values of referenced object.
1101:             *
1102:             * @param targetObject real (non-proxy) target object
1103:             * @param cld {@link ClassDescriptor} of the real target object
1104:             * @param rds An {@link ObjectReferenceDescriptor} or {@link CollectionDescriptor}
1105:             * associated with the real object.
1106:             * @param referencedObject referenced object or proxy
1107:             * @param insert Show if "linking" is done while insert or update.
1108:             */
1109:            public void link(Object targetObject, ClassDescriptor cld,
1110:                    ObjectReferenceDescriptor rds, Object referencedObject,
1111:                    boolean insert) {
1112:                // MBAIRD: we have 'disassociated' this object from the referenced object,
1113:                // the object represented by the reference descriptor is now null, so set
1114:                // the fk in the target object to null.
1115:                // arminw: if an insert was done and ref object was null, we should allow
1116:                // to pass FK fields of main object (maybe only the FK fields are set)
1117:                if (referencedObject == null) {
1118:                    /*
1119:                    arminw:
1120:                    if update we set FK fields to 'null', because reference was disassociated
1121:                    We do nothing on insert, maybe only the FK fields of main object (without
1122:                    materialization of the reference object) are set by the user
1123:                     */
1124:                    if (!insert) {
1125:                        unlinkFK(targetObject, cld, rds);
1126:                    }
1127:                } else {
1128:                    setFKField(targetObject, cld, rds, referencedObject);
1129:                }
1130:            }
1131:
1132:            /**
1133:             * Unkink FK fields of target object.
1134:             *
1135:             * @param targetObject real (non-proxy) target object
1136:             * @param cld {@link ClassDescriptor} of the real target object
1137:             * @param rds An {@link ObjectReferenceDescriptor} or {@link CollectionDescriptor}
1138:             * associated with the real object.
1139:             */
1140:            public void unlinkFK(Object targetObject, ClassDescriptor cld,
1141:                    ObjectReferenceDescriptor rds) {
1142:                setFKField(targetObject, cld, rds, null);
1143:            }
1144:
1145:            /**
1146:             * Set the FK value on the target object, extracted from the referenced object. If the referenced object was
1147:             * <i>null</i> the FK values were set to <i>null</i>, expect when the FK field was declared as PK.
1148:             *
1149:             * @param targetObject real (non-proxy) target object
1150:             * @param cld {@link ClassDescriptor} of the real target object
1151:             * @param rds An {@link ObjectReferenceDescriptor} or {@link CollectionDescriptor}
1152:             * @param referencedObject The referenced object or <i>null</i>
1153:             */
1154:            private void setFKField(Object targetObject, ClassDescriptor cld,
1155:                    ObjectReferenceDescriptor rds, Object referencedObject) {
1156:                ValueContainer[] refPkValues;
1157:                FieldDescriptor fld;
1158:                FieldDescriptor[] objFkFields = rds
1159:                        .getForeignKeyFieldDescriptors(cld);
1160:                if (objFkFields == null) {
1161:                    throw new PersistenceBrokerException(
1162:                            "No foreign key fields defined for class '"
1163:                                    + cld.getClassNameOfObject() + "'");
1164:                }
1165:                if (referencedObject == null) {
1166:                    refPkValues = null;
1167:                } else {
1168:                    Class refClass = proxyFactory
1169:                            .getRealClass(referencedObject);
1170:                    ClassDescriptor refCld = getClassDescriptor(refClass);
1171:                    refPkValues = brokerHelper.getKeyValues(refCld,
1172:                            referencedObject, false);
1173:                }
1174:                for (int i = 0; i < objFkFields.length; i++) {
1175:                    fld = objFkFields[i];
1176:                    /*
1177:                    arminw:
1178:                    we set the FK value when the extracted PK fields from the referenced object are not null at all
1179:                    or if null, the FK field was not a PK field of target object too.
1180:                    Should be ok, because the values of the extracted PK field values should never be null and never
1181:                    change, so it doesn't matter if the target field is a PK too.
1182:                     */
1183:                    if (refPkValues != null || !fld.isPrimaryKey()) {
1184:                        fld.getPersistentField().set(
1185:                                targetObject,
1186:                                refPkValues != null ? refPkValues[i].getValue()
1187:                                        : null);
1188:                    }
1189:                }
1190:            }
1191:
1192:            /**
1193:             * Assign FK value of main object with PK values of the reference object.
1194:             *
1195:             * @param obj real object with reference (proxy) object (or real object with set FK values on insert)
1196:             * @param cld {@link ClassDescriptor} of the real object
1197:             * @param rds An {@link ObjectReferenceDescriptor} of real object.
1198:             * @param insert Show if "linking" is done while insert or update.
1199:             */
1200:            public void linkOneToOne(Object obj, ClassDescriptor cld,
1201:                    ObjectReferenceDescriptor rds, boolean insert) {
1202:                storeAndLinkOneToOne(true, obj, cld, rds, true);
1203:            }
1204:
1205:            /**
1206:             * Assign FK value to all n-side objects referenced by given object.
1207:             *
1208:             * @param obj real object with 1:n reference
1209:             * @param cod {@link CollectionDescriptor} of referenced 1:n objects
1210:             * @param insert flag signal insert operation, false signals update operation
1211:             */
1212:            public void linkOneToMany(Object obj, CollectionDescriptor cod,
1213:                    boolean insert) {
1214:                Object referencedObjects = cod.getPersistentField().get(obj);
1215:                storeAndLinkOneToMany(true, obj, cod, referencedObjects, insert);
1216:            }
1217:
1218:            /**
1219:             * Assign FK values and store entries in indirection table
1220:             * for all objects referenced by given object.
1221:             *
1222:             * @param obj real object with 1:n reference
1223:             * @param cod {@link CollectionDescriptor} of referenced 1:n objects
1224:             * @param insert flag signal insert operation, false signals update operation
1225:             */
1226:            public void linkMtoN(Object obj, CollectionDescriptor cod,
1227:                    boolean insert) {
1228:                Object referencedObjects = cod.getPersistentField().get(obj);
1229:                storeAndLinkMtoN(true, obj, cod, referencedObjects, insert);
1230:            }
1231:
1232:            public void unlinkXtoN(Object obj, CollectionDescriptor col) {
1233:                if (col.isMtoNRelation()) {
1234:                    // if this is a m:n mapped table, remove entries from indirection table
1235:                    mtoNBroker.deleteMtoNImplementor(col, obj);
1236:                } else {
1237:                    Object collectionObject = col.getPersistentField().get(obj);
1238:                    if (collectionObject != null) {
1239:                        Iterator colIterator = BrokerHelper
1240:                                .getCollectionIterator(collectionObject);
1241:                        ClassDescriptor cld = null;
1242:                        while (colIterator.hasNext()) {
1243:                            Object target = colIterator.next();
1244:                            if (cld == null)
1245:                                cld = getClassDescriptor(getProxyFactory()
1246:                                        .getRealClass(target));
1247:                            unlinkFK(target, cld, col);
1248:                        }
1249:                    }
1250:                }
1251:            }
1252:
1253:            /**
1254:             * Retrieve all References (also Collection-attributes) of a given instance.
1255:             * Loading is forced, even if the collection- and reference-descriptors differ.
1256:             * @param pInstance the persistent instance to work with
1257:             */
1258:            public void retrieveAllReferences(Object pInstance)
1259:                    throws PersistenceBrokerException {
1260:                if (logger.isDebugEnabled()) {
1261:                    logger
1262:                            .debug("Manually retrieving all references for object "
1263:                                    + serviceIdentity()
1264:                                            .buildIdentity(pInstance));
1265:                }
1266:                ClassDescriptor cld = getClassDescriptor(pInstance.getClass());
1267:                getInternalCache().enableMaterializationCache();
1268:                // to avoid problems with circular references, locally cache the current object instance
1269:                Identity oid = serviceIdentity().buildIdentity(pInstance);
1270:                //        boolean needLocalRemove = false;
1271:                if (getInternalCache().doLocalLookup(oid) == null) {
1272:                    getInternalCache().doInternalCache(oid, pInstance,
1273:                            MaterializationCache.TYPE_TEMP);
1274:                    //            needLocalRemove = true;
1275:                }
1276:                try {
1277:                    referencesBroker.retrieveReferences(pInstance, cld, true);
1278:                    referencesBroker.retrieveCollections(pInstance, cld, true);
1279:                    // arminw: should no longer needed since we use TYPE_TEMP for this kind of objects
1280:                    //            // do locally remove the object to avoid problems with object state detection (insert/update),
1281:                    //            // because objects found in the cache detected as 'old' means 'update'
1282:                    //            if(needLocalRemove) getInternalCache().doLocalRemove(oid);
1283:                    getInternalCache().disableMaterializationCache();
1284:                } catch (RuntimeException e) {
1285:                    getInternalCache().doLocalClear();
1286:                    throw e;
1287:                }
1288:            }
1289:
1290:            /**
1291:             * retrieve a single reference- or collection attribute
1292:             * of a persistent instance.
1293:             * @param pInstance the persistent instance
1294:             * @param pAttributeName the name of the Attribute to load
1295:             */
1296:            public void retrieveReference(Object pInstance,
1297:                    String pAttributeName) throws PersistenceBrokerException {
1298:                if (logger.isDebugEnabled()) {
1299:                    logger.debug("Retrieving reference named ["
1300:                            + pAttributeName + "] on object of type ["
1301:                            + pInstance.getClass().getName() + "]");
1302:                }
1303:                ClassDescriptor cld = getClassDescriptor(pInstance.getClass());
1304:                CollectionDescriptor cod = cld
1305:                        .getCollectionDescriptorByName(pAttributeName);
1306:                getInternalCache().enableMaterializationCache();
1307:                // to avoid problems with circular references, locally cache the current object instance
1308:                Identity oid = serviceIdentity().buildIdentity(pInstance);
1309:                boolean needLocalRemove = false;
1310:                if (getInternalCache().doLocalLookup(oid) == null) {
1311:                    getInternalCache().doInternalCache(oid, pInstance,
1312:                            MaterializationCache.TYPE_TEMP);
1313:                    needLocalRemove = true;
1314:                }
1315:                try {
1316:                    if (cod != null) {
1317:                        referencesBroker.retrieveCollection(pInstance, cld,
1318:                                cod, true);
1319:                    } else {
1320:                        ObjectReferenceDescriptor ord = cld
1321:                                .getObjectReferenceDescriptorByName(pAttributeName);
1322:                        if (ord != null) {
1323:                            referencesBroker.retrieveReference(pInstance, cld,
1324:                                    ord, true);
1325:                        } else {
1326:                            throw new PersistenceBrokerException(
1327:                                    "did not find attribute " + pAttributeName
1328:                                            + " for class "
1329:                                            + pInstance.getClass().getName());
1330:                        }
1331:                    }
1332:                    // do locally remove the object to avoid problems with object state detection (insert/update),
1333:                    // because objects found in the cache detected as 'old' means 'update'
1334:                    if (needLocalRemove)
1335:                        getInternalCache().doLocalRemove(oid);
1336:                    getInternalCache().disableMaterializationCache();
1337:                } catch (RuntimeException e) {
1338:                    getInternalCache().doLocalClear();
1339:                    throw e;
1340:                }
1341:            }
1342:
1343:            /**
1344:             * Check if the references of the specified object have enabled
1345:             * the <em>refresh</em> attribute and refresh the reference if set <em>true</em>.
1346:             *
1347:             * @throws PersistenceBrokerException if there is a error refreshing collections or references
1348:             * @param obj The object to check.
1349:             * @param oid The {@link Identity} of the object.
1350:             * @param cld The {@link org.apache.ojb.broker.metadata.ClassDescriptor} of the object.
1351:             */
1352:            public void checkRefreshRelationships(Object obj, Identity oid,
1353:                    ClassDescriptor cld) {
1354:                Iterator iter;
1355:                CollectionDescriptor cds;
1356:                ObjectReferenceDescriptor rds;
1357:                // to avoid problems with circular references, locally cache the current object instance
1358:                Object tmp = getInternalCache().doLocalLookup(oid);
1359:                if (tmp != null
1360:                        && getInternalCache().isEnabledMaterialisationCache()) {
1361:                    /*
1362:                    arminw: This should fix OJB-29, infinite loops on bidirectional 1:1 relations with
1363:                    refresh attribute 'true' for both references. OJB now assume that the object is already
1364:                    refreshed when it's cached in the materialisation cache
1365:                     */
1366:                    return;
1367:                }
1368:                try {
1369:                    getInternalCache().enableMaterializationCache();
1370:                    if (tmp == null) {
1371:                        getInternalCache().doInternalCache(oid, obj,
1372:                                MaterializationCache.TYPE_TEMP);
1373:                    }
1374:                    if (logger.isDebugEnabled())
1375:                        logger.debug("Refresh relationships for " + oid);
1376:                    iter = cld.getCollectionDescriptors().iterator();
1377:                    while (iter.hasNext()) {
1378:                        cds = (CollectionDescriptor) iter.next();
1379:                        if (cds.isRefresh()) {
1380:                            referencesBroker.retrieveCollection(obj, cld, cds,
1381:                                    false);
1382:                        }
1383:                    }
1384:                    iter = cld.getObjectReferenceDescriptors().iterator();
1385:                    while (iter.hasNext()) {
1386:                        rds = (ObjectReferenceDescriptor) iter.next();
1387:                        if (rds.isRefresh()) {
1388:                            referencesBroker.retrieveReference(obj, cld, rds,
1389:                                    false);
1390:                        }
1391:                    }
1392:                    getInternalCache().disableMaterializationCache();
1393:                } catch (RuntimeException e) {
1394:                    getInternalCache().doLocalClear();
1395:                    throw e;
1396:                }
1397:            }
1398:
1399:            /**
1400:             * retrieve a collection of type collectionClass matching the Query query
1401:             *
1402:             * @see org.apache.ojb.broker.PersistenceBroker#getCollectionByQuery(Class, Query)
1403:             */
1404:            public ManageableCollection getCollectionByQuery(
1405:                    Class collectionClass, Query query)
1406:                    throws PersistenceBrokerException {
1407:                return referencesBroker.getCollectionByQuery(collectionClass,
1408:                        query, false);
1409:            }
1410:
1411:            /**
1412:             * retrieve a collection of itemClass Objects matching the Query query
1413:             */
1414:            public Collection getCollectionByQuery(Query query)
1415:                    throws PersistenceBrokerException {
1416:                return referencesBroker.getCollectionByQuery(query, false);
1417:            }
1418:
1419:            /**
1420:             * Retrieve an plain object (without populated references) by it's identity
1421:             * from the database
1422:             *
1423:             * @param cld the real {@link org.apache.ojb.broker.metadata.ClassDescriptor} of the object to refresh
1424:             * @param oid the {@link org.apache.ojb.broker.Identity} of the object
1425:             * @return A new plain object read from the database or <em>null</em> if not found
1426:             * @throws ClassNotPersistenceCapableException
1427:             */
1428:            private Object getPlainDBObject(ClassDescriptor cld, Identity oid)
1429:                    throws ClassNotPersistenceCapableException {
1430:                Object newObj = null;
1431:
1432:                // Class is NOT an Interface: it has a directly mapped table and we lookup this table first:
1433:                if (!cld.isInterface()) {
1434:                    // 1. try to retrieve skalar fields from directly mapped table columns
1435:                    newObj = dbAccess.materializeObject(cld, oid);
1436:                }
1437:
1438:                // if we did not find the object yet AND if the cld represents an Extent,
1439:                // we can lookup all tables of the extent classes:
1440:                if (newObj == null && cld.isExtent()) {
1441:                    Iterator extents = getDescriptorRepository()
1442:                            .getAllConcreteSubclassDescriptors(cld).iterator();
1443:
1444:                    while (extents.hasNext()) {
1445:                        ClassDescriptor extCld = (ClassDescriptor) extents
1446:                                .next();
1447:
1448:                        newObj = dbAccess.materializeObject(extCld, oid);
1449:                        if (newObj != null) {
1450:                            break;
1451:                        }
1452:                    }
1453:                }
1454:                return newObj;
1455:            }
1456:
1457:            /**
1458:             * Retrieve an full materialized (dependent on the metadata settings)
1459:             * object by it's identity from the database, as well as caching the
1460:             * object
1461:             *
1462:             * @param oid The {@link org.apache.ojb.broker.Identity} of the object to for
1463:             * @return A new object read from the database or <em>null</em> if not found
1464:             * @throws ClassNotPersistenceCapableException
1465:             */
1466:            private Object getDBObject(Identity oid)
1467:                    throws ClassNotPersistenceCapableException {
1468:                Class c = oid.getObjectsRealClass();
1469:
1470:                if (c == null) {
1471:                    logger
1472:                            .info("Real class for used Identity object is 'null', use top-level class instead");
1473:                    c = oid.getObjectsTopLevelClass();
1474:                }
1475:
1476:                ClassDescriptor cld = getClassDescriptor(c);
1477:                Object newObj = getPlainDBObject(cld, oid);
1478:
1479:                // loading references is useful only when the Object could be found in db:
1480:                if (newObj != null) {
1481:                    if (oid.getObjectsRealClass() == null) {
1482:                        oid.setObjectsRealClass(newObj.getClass());
1483:                    }
1484:
1485:                    /*
1486:                     * synchronize on newObj so the ODMG-layer can take a snapshot only of
1487:                     * fully cached (i.e. with all references + collections) objects
1488:                     */
1489:                    synchronized (newObj) {
1490:                        objectCache.enableMaterializationCache();
1491:                        try {
1492:                            // cache object immediately , so that references
1493:                            // can be established from referenced Objects back to this Object
1494:                            objectCache.doInternalCache(oid, newObj,
1495:                                    ObjectCacheInternal.TYPE_NEW_MATERIALIZED);
1496:
1497:                            /*
1498:                             * Chris Lewington: can cause problems with multiple objects
1499:                             * mapped to one table, as follows:
1500:                             *
1501:                             * if the class searched on does not match the retrieved
1502:                             * class, eg a search on an OID retrieves a row but it could
1503:                             * be a different class (OJB gets all column values),
1504:                             * then trying to resolve references will fail as the object
1505:                             * will not match the Class Descriptor.
1506:                             *
1507:                             * To be safe, get the descriptor of the retrieved object
1508:                             * BEFORE resolving refs
1509:                             */
1510:                            ClassDescriptor newObjCld = getClassDescriptor(newObj
1511:                                    .getClass());
1512:                            // don't force loading of references:
1513:                            final boolean unforced = false;
1514:
1515:                            // 2. retrieve non-skalar fields that contain objects retrievable from other tables
1516:                            referencesBroker.retrieveReferences(newObj,
1517:                                    newObjCld, unforced);
1518:                            // 3. retrieve collection fields from foreign-key related tables:
1519:                            referencesBroker.retrieveCollections(newObj,
1520:                                    newObjCld, unforced);
1521:                            objectCache.disableMaterializationCache();
1522:                        } catch (RuntimeException e) {
1523:                            objectCache.doLocalClear();
1524:                            throw e;
1525:                        }
1526:                    }
1527:                }
1528:
1529:                return newObj;
1530:            }
1531:
1532:            /**
1533:             * returns an Iterator that iterates Objects of class c if calling the .next()
1534:             * method. The Elements returned come from a SELECT ... WHERE Statement
1535:             * that is defined by the Query query.
1536:             * If itemProxy is null, no proxies are used.
1537:             */
1538:            public Iterator getIteratorByQuery(Query query)
1539:                    throws PersistenceBrokerException {
1540:                Class itemClass = query.getSearchClass();
1541:                ClassDescriptor cld = getClassDescriptor(itemClass);
1542:                return getIteratorFromQuery(query, cld);
1543:            }
1544:
1545:            /**
1546:             * Get an extent aware Iterator based on the Query
1547:             *
1548:             * @param query
1549:             * @param cld the ClassDescriptor
1550:             * @return OJBIterator
1551:             */
1552:            protected OJBIterator getIteratorFromQuery(Query query,
1553:                    ClassDescriptor cld) throws PersistenceBrokerException {
1554:                RsIteratorFactory factory = RsIteratorFactoryImpl.getInstance();
1555:                OJBIterator result = getRsIteratorFromQuery(query, cld, factory);
1556:
1557:                if (query.usePaging()) {
1558:                    result = new PagingIterator(result,
1559:                            query.getStartAtIndex(), query.getEndAtIndex());
1560:                }
1561:                return result;
1562:            }
1563:
1564:            public Object getObjectByIdentity(Identity id)
1565:                    throws PersistenceBrokerException {
1566:                objectCache.enableMaterializationCache();
1567:                Object result = null;
1568:                try {
1569:                    result = doGetObjectByIdentity(id);
1570:                    objectCache.disableMaterializationCache();
1571:                } catch (RuntimeException e) {
1572:                    // catch runtime exc. to guarantee clearing of internal buffer on failure
1573:                    objectCache.doLocalClear();
1574:                    throw e;
1575:                }
1576:                return result;
1577:            }
1578:
1579:            /**
1580:             * Internal used method to retrieve object based on Identity.
1581:             *
1582:             * @param id
1583:             * @return
1584:             * @throws PersistenceBrokerException
1585:             */
1586:            public Object doGetObjectByIdentity(Identity id)
1587:                    throws PersistenceBrokerException {
1588:                if (logger.isDebugEnabled())
1589:                    logger.debug("getObjectByIdentity " + id);
1590:
1591:                // check if object is present in ObjectCache:
1592:                Object obj = objectCache.lookup(id);
1593:                // only perform a db lookup if necessary (object not cached yet)
1594:                if (obj == null) {
1595:                    obj = getDBObject(id);
1596:                } else {
1597:                    ClassDescriptor cld = getClassDescriptor(obj.getClass());
1598:                    // if specified in the ClassDescriptor the instance must be refreshed
1599:                    if (cld.isAlwaysRefresh()) {
1600:                        refreshInstance(obj, id, cld);
1601:                    }
1602:                    // now refresh all references
1603:                    checkRefreshRelationships(obj, id, cld);
1604:                }
1605:
1606:                // Invoke events on PersistenceBrokerAware instances and listeners
1607:                AFTER_LOOKUP_EVENT.setTarget(obj);
1608:                fireBrokerEvent(AFTER_LOOKUP_EVENT);
1609:                AFTER_LOOKUP_EVENT.setTarget(null);
1610:
1611:                //logger.info("RETRIEVING object " + obj);
1612:                return obj;
1613:            }
1614:
1615:            /**
1616:             * refresh all primitive typed attributes of a cached instance
1617:             * with the current values from the database.
1618:             * refreshing of reference and collection attributes is not done
1619:             * here.
1620:             * @param cachedInstance the cached instance to be refreshed
1621:             * @param oid the Identity of the cached instance
1622:             * @param cld the ClassDescriptor of cachedInstance
1623:             */
1624:            private void refreshInstance(Object cachedInstance, Identity oid,
1625:                    ClassDescriptor cld) {
1626:                // read in fresh copy from the db, but do not cache it
1627:                Object freshInstance = getPlainDBObject(cld, oid);
1628:
1629:                // update all primitive typed attributes
1630:                FieldDescriptor[] fields = cld.getFieldDescriptions();
1631:                FieldDescriptor fmd;
1632:                PersistentField fld;
1633:                for (int i = 0; i < fields.length; i++) {
1634:                    fmd = fields[i];
1635:                    fld = fmd.getPersistentField();
1636:                    fld.set(cachedInstance, fld.get(freshInstance));
1637:                }
1638:            }
1639:
1640:            /**
1641:             * retrieve an Object by query
1642:             * I.e perform a SELECT ... FROM ... WHERE ...  in an RDBMS
1643:             */
1644:            public Object getObjectByQuery(Query query)
1645:                    throws PersistenceBrokerException {
1646:                Object result = null;
1647:                if (query instanceof  QueryByIdentity) {
1648:                    // example obj may be an entity or an Identity
1649:                    Object obj = query.getExampleObject();
1650:                    if (obj instanceof  Identity) {
1651:                        Identity oid = (Identity) obj;
1652:                        result = getObjectByIdentity(oid);
1653:                    } else {
1654:                        // TODO: This workaround doesn't allow 'null' for PK fields
1655:                        if (!serviceBrokerHelper().hasNullPKField(
1656:                                getClassDescriptor(obj.getClass()), obj)) {
1657:                            Identity oid = serviceIdentity().buildIdentity(obj);
1658:                            result = getObjectByIdentity(oid);
1659:                        }
1660:                    }
1661:                } else {
1662:                    Class itemClass = query.getSearchClass();
1663:                    ClassDescriptor cld = getClassDescriptor(itemClass);
1664:                    /*
1665:                    use OJB intern Iterator, thus we are able to close used
1666:                    resources instantly
1667:                     */
1668:                    OJBIterator it = getIteratorFromQuery(query, cld);
1669:                    /*
1670:                    arminw:
1671:                    patch by Andre Clute, instead of taking the first found result
1672:                    try to get the first found none null result.
1673:                    He wrote:
1674:                    I have a situation where an item with a certain criteria is in my
1675:                    database twice -- once deleted, and then a non-deleted version of it.
1676:                    When I do a PB.getObjectByQuery(), the RsIterator get's both results
1677:                    from the database, but the first row is the deleted row, so my RowReader
1678:                    filters it out, and do not get the right result.
1679:                     */
1680:                    try {
1681:                        while (result == null && it.hasNext()) {
1682:                            result = it.next();
1683:                        }
1684:                    } // make sure that we close the used resources
1685:                    finally {
1686:                        if (it != null)
1687:                            it.releaseDbResources();
1688:                    }
1689:                }
1690:                return result;
1691:            }
1692:
1693:            /**
1694:             * returns an Enumeration of PrimaryKey Objects for objects of class DataClass.
1695:             * The Elements returned come from a SELECT ... WHERE Statement
1696:             * that is defined by the fields and their coresponding values of listFields
1697:             * and listValues.
1698:             * Useful for EJB Finder Methods...
1699:             * @param primaryKeyClass the pk class for the searched objects
1700:             * @param query the query
1701:             */
1702:            public Enumeration getPKEnumerationByQuery(Class primaryKeyClass,
1703:                    Query query) throws PersistenceBrokerException {
1704:                if (logger.isDebugEnabled())
1705:                    logger.debug("getPKEnumerationByQuery " + query);
1706:
1707:                query.setFetchSize(1);
1708:                ClassDescriptor cld = getClassDescriptor(query.getSearchClass());
1709:                return new PkEnumeration(query, cld, primaryKeyClass, this );
1710:            }
1711:
1712:            /**
1713:             * Makes object obj persistent in the underlying persistence system.
1714:             * E.G. by INSERT INTO ... or UPDATE ...  in an RDBMS.
1715:             * The ObjectModification parameter can be used to determine whether INSERT or update is to be used.
1716:             * This functionality is typically called from transaction managers, that
1717:             * track which objects have to be stored. If the object is an unmaterialized
1718:             * proxy the method return immediately.
1719:             */
1720:            public void store(Object obj, ObjectModification mod)
1721:                    throws PersistenceBrokerException {
1722:                obj = extractObjectToStore(obj);
1723:                // null for unmaterialized Proxy
1724:                if (obj == null) {
1725:                    return;
1726:                }
1727:
1728:                ClassDescriptor cld = getClassDescriptor(obj.getClass());
1729:                // this call ensures that all autoincremented primary key attributes are filled
1730:                Identity oid = serviceIdentity().buildIdentity(cld, obj);
1731:                // select flag for insert / update selection by checking the ObjectModification
1732:                if (mod.needsInsert()) {
1733:                    store(obj, oid, cld, true);
1734:                } else if (mod.needsUpdate()) {
1735:                    store(obj, oid, cld, false);
1736:                }
1737:                /*
1738:                arminw
1739:                TODO: Why we need this behaviour? What about 1:1 relations?
1740:                 */
1741:                else {
1742:                    // just store 1:n and m:n associations
1743:                    storeCollections(obj, cld, mod.needsInsert());
1744:                }
1745:            }
1746:
1747:            /**
1748:             * I pulled this out of internal store so that when doing multiple table
1749:             * inheritance, i can recurse this function.
1750:             *
1751:             * @param obj
1752:             * @param cld
1753:             * @param oid   BRJ: what is it good for ???
1754:             * @param insert
1755:             * @param ignoreReferences
1756:             */
1757:            private void storeToDb(Object obj, ClassDescriptor cld,
1758:                    Identity oid, boolean insert, boolean ignoreReferences) {
1759:                // 1. link and store 1:1 references
1760:                storeReferences(obj, cld, insert, ignoreReferences);
1761:
1762:                Object[] pkValues = oid.getPrimaryKeyValues();
1763:                if (!serviceBrokerHelper().assertValidPksForStore(
1764:                        cld.getPkFields(), pkValues)) {
1765:                    // BRJ: fk values may be part of pk, but the are not known during
1766:                    // creation of Identity. so we have to get them here
1767:                    pkValues = serviceBrokerHelper().getKeyValues(cld, obj);
1768:                    if (!serviceBrokerHelper().assertValidPksForStore(
1769:                            cld.getPkFields(), pkValues)) {
1770:                        String append = insert ? " on insert" : " on update";
1771:                        throw new PersistenceBrokerException(
1772:                                "assertValidPkFields failed for Object of type: "
1773:                                        + cld.getClassNameOfObject() + append);
1774:                    }
1775:                }
1776:
1777:                // get super class cld then store it with the object
1778:                /*
1779:                now for multiple table inheritance
1780:                1. store super classes, topmost parent first
1781:                2. go down through heirarchy until current class
1782:                3. todo: store to full extent?
1783:
1784:                // arminw: TODO: The extend-attribute feature dosn't work, should we remove this stuff?
1785:                This if-clause will go up the inheritance heirarchy to store all the super classes.
1786:                The id for the top most super class will be the id for all the subclasses too
1787:                 */
1788:                if (cld.getSuperClass() != null) {
1789:
1790:                    ClassDescriptor super Cld = getDescriptorRepository()
1791:                            .getDescriptorFor(cld.getSuperClass());
1792:                    storeToDb(obj, super Cld, oid, insert);
1793:                    // arminw: why this?? I comment out this section
1794:                    // storeCollections(obj, cld.getCollectionDescriptors(), insert);
1795:                }
1796:
1797:                // 2. store primitive typed attributes (Or is THIS step 3 ?)
1798:                // if obj not present in db use INSERT
1799:                if (insert) {
1800:                    dbAccess.executeInsert(cld, obj);
1801:                    if (oid.isTransient()) {
1802:                        // Create a new Identity based on the current set of primary key values.
1803:                        oid = serviceIdentity().buildIdentity(cld, obj);
1804:                    }
1805:                }
1806:                // else use UPDATE
1807:                else {
1808:                    try {
1809:                        dbAccess.executeUpdate(cld, obj);
1810:                    } catch (OptimisticLockException e) {
1811:                        // ensure that the outdated object be removed from cache
1812:                        objectCache.remove(oid);
1813:                        throw e;
1814:                    }
1815:                }
1816:                // cache object for symmetry with getObjectByXXX()
1817:                // Add the object to the cache.
1818:                objectCache.doInternalCache(oid, obj,
1819:                        ObjectCacheInternal.TYPE_WRITE);
1820:                // 3. store 1:n and m:n associations
1821:                if (!ignoreReferences)
1822:                    storeCollections(obj, cld, insert);
1823:            }
1824:
1825:            /**
1826:             * I pulled this out of internal store so that when doing multiple table
1827:             * inheritance, i can recurse this function.
1828:             *
1829:             * @param obj
1830:             * @param cld
1831:             * @param oid   BRJ: what is it good for ???
1832:             * @param insert
1833:             */
1834:            private void storeToDb(Object obj, ClassDescriptor cld,
1835:                    Identity oid, boolean insert) {
1836:                storeToDb(obj, cld, oid, insert, false);
1837:            }
1838:
1839:            /**
1840:             * returns true if the broker is currently running a transaction.
1841:             * @return boolean
1842:             */
1843:            public boolean isInTransaction() {
1844:                // return this.connectionManager.isInLocalTransaction();
1845:                return inTransaction;
1846:            }
1847:
1848:            public void setInTransaction(boolean inTransaction) {
1849:                this .inTransaction = inTransaction;
1850:            }
1851:
1852:            /**
1853:             * @see org.apache.ojb.broker.PersistenceBroker#removeFromCache
1854:             */
1855:            public void removeFromCache(Object objectOrIdentity)
1856:                    throws PersistenceBrokerException {
1857:                Identity identity;
1858:                if (objectOrIdentity instanceof  Identity) {
1859:                    identity = (Identity) objectOrIdentity;
1860:                } else {
1861:                    identity = serviceIdentity()
1862:                            .buildIdentity(objectOrIdentity);
1863:                }
1864:                objectCache.remove(identity);
1865:            }
1866:
1867:            /**
1868:             * returns a ClassDescriptor for the persistence capable class clazz.
1869:             * throws a PersistenceBrokerException if clazz is not persistence capable,
1870:             * i.e. if clazz is not defined in the DescriptorRepository.
1871:             */
1872:            public ClassDescriptor getClassDescriptor(Class clazz)
1873:                    throws PersistenceBrokerException {
1874:                return descriptorRepository.getDescriptorFor(clazz);
1875:            }
1876:
1877:            public boolean hasClassDescriptor(Class clazz) {
1878:                return descriptorRepository.hasDescriptorFor(clazz);
1879:            }
1880:
1881:            /**
1882:             * clears the brokers internal cache.
1883:             * removing is recursive. That is referenced Objects are also
1884:             * removed from the cache, if the auto-retrieve flag is set
1885:             * for obj.getClass() in the metadata repository.
1886:             *
1887:             */
1888:            public void clearCache() throws PersistenceBrokerException {
1889:                objectCache.clear();
1890:            }
1891:
1892:            /**
1893:             * @see org.apache.ojb.broker.PersistenceBroker#getTopLevelClass
1894:             */
1895:            public Class getTopLevelClass(Class clazz)
1896:                    throws PersistenceBrokerException {
1897:                try {
1898:                    return descriptorRepository.getTopLevelClass(clazz);
1899:                } catch (ClassNotPersistenceCapableException e) {
1900:                    throw new PersistenceBrokerException(e);
1901:                }
1902:            }
1903:
1904:            /**
1905:             * @see org.apache.ojb.broker.PersistenceBroker#getCount(Query)
1906:             */
1907:            public int getCount(Query query) throws PersistenceBrokerException {
1908:                Query countQuery = serviceBrokerHelper().getCountQuery(query);
1909:                Iterator iter;
1910:                int result = 0;
1911:
1912:                if (logger.isDebugEnabled())
1913:                    logger.debug("getCount " + countQuery.getSearchClass()
1914:                            + ", " + countQuery);
1915:
1916:                iter = getReportQueryIteratorByQuery(countQuery);
1917:                try {
1918:                    while (iter.hasNext()) {
1919:                        Object[] row = (Object[]) iter.next();
1920:                        result += ((Number) row[0]).intValue();
1921:                    }
1922:                } finally {
1923:                    if (iter instanceof  OJBIterator) {
1924:                        ((OJBIterator) iter).releaseDbResources();
1925:                    }
1926:                }
1927:
1928:                return result;
1929:            }
1930:
1931:            /**
1932:             * Get an Iterator based on the ReportQuery
1933:             *
1934:             * @param query
1935:             * @return Iterator
1936:             */
1937:            public Iterator getReportQueryIteratorByQuery(Query query)
1938:                    throws PersistenceBrokerException {
1939:                ClassDescriptor cld = getClassDescriptor(query.getSearchClass());
1940:                return getReportQueryIteratorFromQuery(query, cld);
1941:            }
1942:
1943:            /**
1944:             * Get an extent aware RsIterator based on the Query
1945:             *
1946:             * @param query
1947:             * @param cld
1948:             * @param factory the Factory for the RsIterator
1949:             * @return OJBIterator
1950:             */
1951:            private OJBIterator getRsIteratorFromQuery(Query query,
1952:                    ClassDescriptor cld, RsIteratorFactory factory)
1953:                    throws PersistenceBrokerException {
1954:                query.setFetchSize(1);
1955:                if (query instanceof  QueryBySQL) {
1956:                    if (logger.isDebugEnabled())
1957:                        logger.debug("Creating SQL-RsIterator for class ["
1958:                                + cld.getClassNameOfObject() + "]");
1959:                    return factory.createRsIterator((QueryBySQL) query, cld,
1960:                            this );
1961:                }
1962:
1963:                if (!cld.isExtent() || !query.getWithExtents()) {
1964:                    // no extents just use the plain vanilla RsIterator
1965:                    if (logger.isDebugEnabled())
1966:                        logger.debug("Creating RsIterator for class ["
1967:                                + cld.getClassNameOfObject() + "]");
1968:
1969:                    return factory.createRsIterator(query, cld, this );
1970:                }
1971:
1972:                if (logger.isDebugEnabled())
1973:                    logger.debug("Creating ChainingIterator for class ["
1974:                            + cld.getClassNameOfObject() + "]");
1975:
1976:                ChainingIterator chainingIter = new ChainingIterator();
1977:
1978:                // BRJ: add base class iterator
1979:                if (!cld.isInterface()) {
1980:                    if (logger.isDebugEnabled())
1981:                        logger.debug("Adding RsIterator for class ["
1982:                                + cld.getClassNameOfObject()
1983:                                + "] to ChainingIterator");
1984:
1985:                    chainingIter.addIterator(factory.createRsIterator(query,
1986:                            cld, this ));
1987:                }
1988:
1989:                Iterator extents = getDescriptorRepository()
1990:                        .getAllConcreteSubclassDescriptors(cld).iterator();
1991:                while (extents.hasNext()) {
1992:                    ClassDescriptor extCld = (ClassDescriptor) extents.next();
1993:
1994:                    // read same table only once
1995:                    if (chainingIter.containsIteratorForTable(extCld
1996:                            .getFullTableName())) {
1997:                        if (logger.isDebugEnabled())
1998:                            logger.debug("Skipping class ["
1999:                                    + extCld.getClassNameOfObject() + "]");
2000:                    } else {
2001:                        if (logger.isDebugEnabled())
2002:                            logger.debug("Adding RsIterator of class ["
2003:                                    + extCld.getClassNameOfObject()
2004:                                    + "] to ChainingIterator");
2005:
2006:                        // add the iterator to the chaining iterator.
2007:                        chainingIter.addIterator(factory.createRsIterator(
2008:                                query, extCld, this ));
2009:                    }
2010:                }
2011:
2012:                return chainingIter;
2013:            }
2014:
2015:            /**
2016:             * Get an extent aware Iterator based on the ReportQuery
2017:             *
2018:             * @param query
2019:             * @param cld
2020:             * @return OJBIterator
2021:             */
2022:            private OJBIterator getReportQueryIteratorFromQuery(Query query,
2023:                    ClassDescriptor cld) throws PersistenceBrokerException {
2024:                RsIteratorFactory factory = ReportRsIteratorFactoryImpl
2025:                        .getInstance();
2026:                OJBIterator result = getRsIteratorFromQuery(query, cld, factory);
2027:
2028:                if (query.usePaging()) {
2029:                    result = new PagingIterator(result,
2030:                            query.getStartAtIndex(), query.getEndAtIndex());
2031:                }
2032:
2033:                return result;
2034:            }
2035:
2036:            /**
2037:             * @see org.odbms.ObjectContainer#query()
2038:             */
2039:            public org.odbms.Query query() {
2040:                return new org.apache.ojb.soda.QueryImpl(this );
2041:            }
2042:
2043:            /**
2044:             * @return DescriptorRepository
2045:             */
2046:            public DescriptorRepository getDescriptorRepository() {
2047:                return descriptorRepository;
2048:            }
2049:
2050:            protected void finalize() {
2051:                if (!isClosed) {
2052:                    close();
2053:                }
2054:            }
2055:
2056:            /**
2057:             * clean up the maps for reuse by the next transaction.
2058:             */
2059:            private void clearRegistrationLists() {
2060:                nowStoring.clear();
2061:                objectCache.doLocalClear();
2062:                deletedDuringTransaction.clear();
2063:                /*
2064:                arminw:
2065:                for better performance I don't register MtoNBroker as listner,
2066:                so use this method to reset on commit/rollback
2067:                 */
2068:                mtoNBroker.reset();
2069:            }
2070:
2071:            /**
2072:             * @see org.apache.ojb.broker.PersistenceBroker#deleteMtoNImplementor
2073:             */
2074:            public void deleteMtoNImplementor(MtoNImplementor m2nImpl)
2075:                    throws PersistenceBrokerException {
2076:                mtoNBroker.deleteMtoNImplementor(m2nImpl);
2077:            }
2078:
2079:            /**
2080:             * @see org.apache.ojb.broker.PersistenceBroker#addMtoNImplementor
2081:             */
2082:            public void addMtoNImplementor(MtoNImplementor m2n)
2083:                    throws PersistenceBrokerException {
2084:                mtoNBroker.storeMtoNImplementor(m2n);
2085:            }
2086:
2087:            public ProxyFactory getProxyFactory() {
2088:                return proxyFactory;
2089:            }
2090:
2091:            /**
2092:             * Creates a proxy instance.
2093:             * 
2094:             * @param baseClassForProxy  The base class that the Proxy should extend. For dynamic Proxies, the method of 
2095:             *                           generation is dependent on the ProxyFactory implementation.
2096:             * @param realSubjectsIdentity The identity of the subject
2097:             * @return An instance of the proxy subclass
2098:             * @throws PersistenceBrokerException If there is an error creating the proxy object
2099:             */
2100:            public Object createProxy(Class baseClassForProxy,
2101:                    Identity realSubjectsIdentity) {
2102:                try {
2103:                    // the invocation handler manages all delegation stuff
2104:                    IndirectionHandler handler = getProxyFactory()
2105:                            .createIndirectionHandler(pbKey,
2106:                                    realSubjectsIdentity);
2107:
2108:                    // the proxy simply provides the interface of the real subject
2109:                    if (VirtualProxy.class.isAssignableFrom(baseClassForProxy)) {
2110:                        Constructor constructor = baseClassForProxy
2111:                                .getDeclaredConstructor(new Class[] { IndirectionHandler.class });
2112:                        return constructor
2113:                                .newInstance(new Object[] { handler });
2114:                    } else {
2115:                        return getProxyFactory().createProxy(baseClassForProxy,
2116:                                handler);
2117:                    }
2118:
2119:                } catch (Exception ex) {
2120:                    throw new PersistenceBrokerException(
2121:                            "Unable to create proxy using class:"
2122:                                    + baseClassForProxy.getName(), ex);
2123:                }
2124:            }
2125:
2126:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.