Source Code Cross Referenced for TransactionImpl.java in  » Database-ORM » db-ojb » org » apache » ojb » odmg » 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.odmg 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package org.apache.ojb.odmg;
0002:
0003:        /* Copyright 2002-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 javax.transaction.Status;
0019:        import java.util.ArrayList;
0020:        import java.util.Collection;
0021:        import java.util.Enumeration;
0022:        import java.util.HashMap;
0023:        import java.util.Iterator;
0024:        import java.util.List;
0025:
0026:        import org.apache.commons.lang.SystemUtils;
0027:        import org.apache.ojb.broker.Identity;
0028:        import org.apache.ojb.broker.OJBRuntimeException;
0029:        import org.apache.ojb.broker.PBFactoryException;
0030:        import org.apache.ojb.broker.PersistenceBroker;
0031:        import org.apache.ojb.broker.PersistenceBrokerException;
0032:        import org.apache.ojb.broker.PersistenceBrokerInternal;
0033:        import org.apache.ojb.broker.core.PersistenceBrokerFactoryFactory;
0034:        import org.apache.ojb.broker.core.proxy.CollectionProxy;
0035:        import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl;
0036:        import org.apache.ojb.broker.core.proxy.CollectionProxyListener;
0037:        import org.apache.ojb.broker.core.proxy.IndirectionHandler;
0038:        import org.apache.ojb.broker.core.proxy.MaterializationListener;
0039:        import org.apache.ojb.broker.core.proxy.ProxyHelper;
0040:        import org.apache.ojb.broker.metadata.ClassDescriptor;
0041:        import org.apache.ojb.broker.metadata.CollectionDescriptor;
0042:        import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
0043:        import org.apache.ojb.broker.util.BrokerHelper;
0044:        import org.apache.ojb.broker.util.GUID;
0045:        import org.apache.ojb.broker.util.configuration.Configurable;
0046:        import org.apache.ojb.broker.util.configuration.Configuration;
0047:        import org.apache.ojb.broker.util.configuration.ConfigurationException;
0048:        import org.apache.ojb.broker.util.logging.Logger;
0049:        import org.apache.ojb.broker.util.logging.LoggerFactory;
0050:        import org.apache.ojb.odmg.locking.LockManager;
0051:        import org.odmg.DatabaseClosedException;
0052:        import org.odmg.LockNotGrantedException;
0053:        import org.odmg.ODMGRuntimeException;
0054:        import org.odmg.Transaction;
0055:        import org.odmg.TransactionAbortedException;
0056:        import org.odmg.TransactionNotInProgressException;
0057:
0058:        /**
0059:         *
0060:         * Implementation of Transaction for org.odmg.Transaction.
0061:         *
0062:         * @author     Thomas Mahler & David Dixon-Peugh
0063:         * @author <a href="mailto:mattbaird@yahoo.com">Matthew Baird</a>
0064:         * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
0065:         * @author <a href="mailto:brianm@apache.org">Brian McCallister</a>
0066:         * @version $Id: TransactionImpl.java,v 1.59.2.25 2005/12/21 22:29:21 tomdz Exp $
0067:         *
0068:         */
0069:        public class TransactionImpl implements  Transaction,
0070:                MaterializationListener, Configurable, CollectionProxyListener,
0071:                TransactionExt {
0072:            private Logger log = LoggerFactory.getLogger(TransactionImpl.class);
0073:            private boolean impliciteWriteLocks;
0074:            private boolean implicitLocking;
0075:            private boolean ordering;
0076:
0077:            private String txGUID;
0078:            protected PersistenceBrokerInternal broker = null;
0079:            private ArrayList registrationList = new ArrayList();
0080:            private ImplementationImpl implementation;
0081:            private NamedRootsMap namedRootsMap;
0082:
0083:            /**
0084:             * The status of the current transaction, as specified by the
0085:             * javax.transaction package.
0086:             * See {@link javax.transaction.Status} for list of valid values.
0087:             */
0088:            private int txStatus = Status.STATUS_NO_TRANSACTION;
0089:
0090:            /**
0091:             * the internal table containing all Objects "touched" by this tx and their
0092:             * respective transactional state
0093:             */
0094:            protected ObjectEnvelopeTable objectEnvelopeTable = null;
0095:
0096:            /**
0097:             * reference to the currently opened database
0098:             */
0099:            private DatabaseImpl curDB;
0100:            /**
0101:             * The tx may me listening to a number of IndirectionHandlers.
0102:             * on abort or commit these Handlers must be informed to remove
0103:             * tx from their List of Listeners.
0104:             */
0105:            private ArrayList registeredIndirectionHandlers = new ArrayList();
0106:
0107:            /**
0108:             * Unloaded collection proxies which will be registered with tx when
0109:             * collection is loaded
0110:             */
0111:            private ArrayList registeredCollectionProxies = new ArrayList();
0112:
0113:            /**
0114:             * list of proxy objects that were locked, but haven't been materialized yet.
0115:             * This is necessary so the locks can be released on closing the transaction
0116:             */
0117:            private ArrayList unmaterializedLocks = new ArrayList();
0118:
0119:            /**
0120:             * Creates new Transaction
0121:             * @param implementation The odmg Implementation class
0122:             */
0123:            public TransactionImpl(ImplementationImpl implementation) {
0124:                this .implementation = implementation;
0125:                this .impliciteWriteLocks = implementation
0126:                        .isImpliciteWriteLocks();
0127:                this .implicitLocking = implementation.isImplicitLocking();
0128:                this .ordering = implementation.isOrdering();
0129:                //this.noteUserOrdering = implementation.isNoteUserOrder();
0130:
0131:                // assign a globally uniqe id to this tx
0132:                txGUID = new GUID().toString();
0133:                curDB = implementation.getCurrentDatabase();
0134:                namedRootsMap = new NamedRootsMap(this );
0135:            }
0136:
0137:            public ImplementationImpl getImplementation() {
0138:                return implementation;
0139:            }
0140:
0141:            public NamedRootsMap getNamedRootsMap() {
0142:                return namedRootsMap;
0143:            }
0144:
0145:            /**
0146:             * Returns the associated database
0147:             */
0148:            public DatabaseImpl getAssociatedDatabase() {
0149:                return this .curDB;
0150:            }
0151:
0152:            protected int getStatus() {
0153:                return txStatus;
0154:            }
0155:
0156:            protected void setStatus(int status) {
0157:                this .txStatus = status;
0158:            }
0159:
0160:            private void checkForDB() {
0161:                if (curDB == null || !curDB.isOpen()) {
0162:                    log
0163:                            .error("Transaction without a associated open Database.");
0164:                    throw new TransactionAbortedExceptionOJB(
0165:                            "No open database found. Open the database before handling transactions");
0166:                }
0167:            }
0168:
0169:            /**
0170:             * Determine whether the transaction is open or not. A transaction is open if
0171:             * a call has been made to <code>begin</code> , but a subsequent call to
0172:             * either <code>commit</code> or <code>abort</code> has not been made.
0173:             * @return    True if the transaction is open, otherwise false.
0174:             */
0175:            public boolean isOpen() {
0176:                return (getStatus() == Status.STATUS_ACTIVE
0177:                        || getStatus() == Status.STATUS_MARKED_ROLLBACK
0178:                        || getStatus() == Status.STATUS_PREPARED
0179:                        || getStatus() == Status.STATUS_PREPARING || getStatus() == Status.STATUS_COMMITTING);
0180:            }
0181:
0182:            private void checkOpen() {
0183:                if (!isOpen()) {
0184:                    throw new TransactionNotInProgressException(
0185:                            "Transaction was not open, call tx.begin() before perform action, current status is: "
0186:                                    + TxUtil.getStatusString(getStatus()));
0187:                }
0188:            }
0189:
0190:            /**
0191:             * Attach the caller's thread to this <code>Transaction</code> and detach the
0192:             * thread from any former <code>Transaction</code> the thread may have been
0193:             * associated with.
0194:             */
0195:            public void join() {
0196:                checkOpen();
0197:                implementation.getTxManager().deregisterTx(this );
0198:                implementation.getTxManager().registerTx(this );
0199:            }
0200:
0201:            /**
0202:             * Upgrade the lock on the given object to the given lock mode. The call has
0203:             * no effect if the object's current lock is already at or above that level of
0204:             * lock mode.
0205:             *
0206:             * @param  obj       object to acquire a lock on.
0207:             * @param  lockMode  lock mode to acquire. The lock modes
0208:             * are <code>READ</code> , <code>UPGRADE</code> , and <code>WRITE</code> .
0209:             *
0210:             * @exception  LockNotGrantedException    Description of Exception
0211:             */
0212:            public void lock(Object obj, int lockMode)
0213:                    throws LockNotGrantedException {
0214:                if (log.isDebugEnabled())
0215:                    log.debug("lock object was called on tx " + this 
0216:                            + ", object is " + obj.toString());
0217:                checkOpen();
0218:                RuntimeObject rtObject = new RuntimeObject(obj, this );
0219:                lockAndRegister(rtObject, lockMode, isImplicitLocking(),
0220:                        getRegistrationList());
0221:                //        if(isImplicitLocking()) moveToLastInOrderList(rtObject.getIdentity());
0222:            }
0223:
0224:            /**
0225:             * Returns an empty List for registration of processed object Identity.
0226:             */
0227:            public ArrayList getRegistrationList() {
0228:                clearRegistrationList();
0229:                return registrationList;
0230:            }
0231:
0232:            /**
0233:             * Clears the list of processed object Identity.
0234:             */
0235:            public void clearRegistrationList() {
0236:                registrationList.clear();
0237:            }
0238:
0239:            /**
0240:             * Lock and register the specified object, make sure that when cascading locking and register
0241:             * is enabled to specify a List to register the already processed object Identiy.
0242:             */
0243:            public void lockAndRegister(RuntimeObject rtObject, int lockMode,
0244:                    List registeredObjects) {
0245:                lockAndRegister(rtObject, lockMode, isImplicitLocking(),
0246:                        registeredObjects);
0247:            }
0248:
0249:            /**
0250:             * Lock and register the specified object, make sure that when cascading locking and register
0251:             * is enabled to specify a List to register the already processed object Identiy.
0252:             */
0253:            public synchronized void lockAndRegister(RuntimeObject rtObject,
0254:                    int lockMode, boolean cascade, List registeredObjects) {
0255:                if (log.isDebugEnabled())
0256:                    log.debug("Lock and register called for "
0257:                            + rtObject.getIdentity());
0258:                // if current object was already locked, do nothing
0259:                // avoid endless loops when circular object references are used
0260:                if (!registeredObjects.contains(rtObject.getIdentity())) {
0261:                    if (cascade) {
0262:                        // if implicite locking is enabled, first add the current object to
0263:                        // list of registered objects to avoid endless loops on circular objects
0264:                        registeredObjects.add(rtObject.getIdentity());
0265:                        // lock and register 1:1 references first
0266:                        //
0267:                        // If implicit locking is used, we have materialize the main object
0268:                        // to lock the referenced objects too
0269:                        lockAndRegisterReferences(rtObject.getCld(), rtObject
0270:                                .getObjMaterialized(), lockMode,
0271:                                registeredObjects);
0272:                    }
0273:                    try {
0274:                        // perform the lock on the object
0275:                        // we don't need to lock new objects
0276:                        if (!rtObject.isNew()) {
0277:                            doSingleLock(rtObject.getCld(), rtObject.getObj(),
0278:                                    rtObject.getIdentity(), lockMode);
0279:                        }
0280:                        // after we locked the object, register it to detect status and changes while tx
0281:                        doSingleRegister(rtObject, lockMode);
0282:                    } catch (Throwable t) {
0283:                        //log.error("Locking of obj " + rtObject.getIdentity() + " failed", t);
0284:                        // if registering of object fails release lock on object, because later we don't
0285:                        // get a change to do this.
0286:                        implementation.getLockManager().releaseLock(this ,
0287:                                rtObject.getIdentity(), rtObject.getObj());
0288:                        if (t instanceof  LockNotGrantedException) {
0289:                            throw (LockNotGrantedException) t;
0290:                        } else {
0291:                            log.error("Unexpected failure while locking", t);
0292:                            throw new LockNotGrantedException(
0293:                                    "Locking failed for "
0294:                                            + rtObject.getIdentity()
0295:                                            + ", nested exception is: ["
0296:                                            + t.getClass().getName() + ": "
0297:                                            + t.getMessage() + "]");
0298:                        }
0299:                    }
0300:                    if (cascade) {
0301:                        // perform locks and register 1:n and m:n references
0302:                        // If implicit locking is used, we have materialize the main object
0303:                        // to lock the referenced objects too
0304:                        lockAndRegisterCollections(rtObject.getCld(), rtObject
0305:                                .getObjMaterialized(), lockMode,
0306:                                registeredObjects);
0307:                    }
0308:                }
0309:            }
0310:
0311:            /**
0312:             * Only lock the specified object, represented by
0313:             * the {@link RuntimeObject} instance.
0314:             *
0315:             * @param  cld       The {@link org.apache.ojb.broker.metadata.ClassDescriptor}
0316:             * of the object to acquire a lock on.
0317:             * @param  oid The {@link org.apache.ojb.broker.Identity} of the object to lock.
0318:             * @param  lockMode  lock mode to acquire. The lock modes
0319:             * are <code>READ</code> , <code>UPGRADE</code> , and <code>WRITE</code>.
0320:             *
0321:             * @exception  LockNotGrantedException    Description of Exception
0322:             */
0323:            void doSingleLock(ClassDescriptor cld, Object obj, Identity oid,
0324:                    int lockMode) throws LockNotGrantedException {
0325:                LockManager lm = implementation.getLockManager();
0326:                if (cld.isAcceptLocks()) {
0327:                    if (lockMode == Transaction.READ) {
0328:                        if (log.isDebugEnabled())
0329:                            log.debug("Do READ lock on object: " + oid);
0330:                        if (!lm.readLock(this , oid, obj)) {
0331:                            throw new LockNotGrantedException(
0332:                                    "Can not lock for READ: " + oid);
0333:                        }
0334:                    } else if (lockMode == Transaction.WRITE) {
0335:                        if (log.isDebugEnabled())
0336:                            log.debug("Do WRITE lock on object: " + oid);
0337:                        if (!lm.writeLock(this , oid, obj)) {
0338:                            throw new LockNotGrantedException(
0339:                                    "Can not lock for WRITE: " + oid);
0340:                        }
0341:                    } else if (lockMode == Transaction.UPGRADE) {
0342:                        if (log.isDebugEnabled())
0343:                            log.debug("Do UPGRADE lock on object: " + oid);
0344:                        if (!lm.upgradeLock(this , oid, obj)) {
0345:                            throw new LockNotGrantedException(
0346:                                    "Can not lock for UPGRADE: " + oid);
0347:                        }
0348:                    }
0349:                } else {
0350:                    if (log.isDebugEnabled()) {
0351:                        log
0352:                                .debug("Class '"
0353:                                        + cld.getClassNameOfObject()
0354:                                        + "' doesn't accept locks"
0355:                                        + " (accept-locks=false) when implicite locked, so OJB skip this object: "
0356:                                        + oid);
0357:                    }
0358:                }
0359:            }
0360:
0361:            /**
0362:             * Detach the caller's thread from this <code>Transaction</code> , but do not
0363:             * attach the thread to another <code>Transaction</code> .
0364:             */
0365:            public void leave() {
0366:                checkOpen();
0367:                implementation.getTxManager().deregisterTx(this );
0368:            }
0369:
0370:            /**
0371:             * Write objects to data store, but don't release the locks.
0372:             * I don't know what we should do if we are in a checkpoint and
0373:             * we need to abort.
0374:             */
0375:            protected synchronized void doWriteObjects(boolean isFlush)
0376:                    throws TransactionAbortedException, LockNotGrantedException {
0377:                /*
0378:                arminw:
0379:                if broker isn't in PB-tx, start tx
0380:                 */
0381:                if (!getBroker().isInTransaction()) {
0382:                    if (log.isDebugEnabled())
0383:                        log.debug("call beginTransaction() on PB instance");
0384:                    broker.beginTransaction();
0385:                }
0386:
0387:                // Notify objects of impending commits.
0388:                performTransactionAwareBeforeCommit();
0389:
0390:                // Now perfom the real work
0391:                objectEnvelopeTable.writeObjects(isFlush);
0392:                // now we have to perform the named objects
0393:                namedRootsMap.performDeletion();
0394:                namedRootsMap.performInsert();
0395:                namedRootsMap.afterWriteCleanup();
0396:            }
0397:
0398:            /**
0399:             * Do the Aborts, but don't release the locks.
0400:             * Do the aborts on the NamedRootsMap first, then
0401:             * abort the other stuff.
0402:             */
0403:            protected synchronized void doAbort() {
0404:                // Notify objects of impending aborts.
0405:                performTransactionAwareBeforeRollback();
0406:
0407:                // Now, we abort everything. . .
0408:                objectEnvelopeTable.rollback();
0409:
0410:                // Now, we notify everything the abort is done.
0411:                performTransactionAwareAfterRollback();
0412:            }
0413:
0414:            /**
0415:             * Close a transaction and do all the cleanup associated with it.
0416:             */
0417:            protected synchronized void doClose() {
0418:                try {
0419:                    LockManager lm = getImplementation().getLockManager();
0420:                    Enumeration en = objectEnvelopeTable.elements();
0421:                    while (en.hasMoreElements()) {
0422:                        ObjectEnvelope oe = (ObjectEnvelope) en.nextElement();
0423:                        lm.releaseLock(this , oe.getIdentity(), oe.getObject());
0424:                    }
0425:
0426:                    //remove locks for objects which haven't been materialized yet
0427:                    for (Iterator it = unmaterializedLocks.iterator(); it
0428:                            .hasNext();) {
0429:                        lm.releaseLock(this , it.next());
0430:                    }
0431:
0432:                    // this tx is no longer interested in materialization callbacks
0433:                    unRegisterFromAllIndirectionHandlers();
0434:                    unRegisterFromAllCollectionProxies();
0435:                } finally {
0436:                    /**
0437:                     * MBAIRD: Be nice and close the table to release all refs
0438:                     */
0439:                    if (log.isDebugEnabled())
0440:                        log.debug("Close Transaction and release current PB "
0441:                                + broker + " on tx " + this );
0442:                    // remove current thread from LocalTxManager
0443:                    // to avoid problems for succeeding calls of the same thread
0444:                    implementation.getTxManager().deregisterTx(this );
0445:                    // now cleanup and prepare for reuse
0446:                    refresh();
0447:                }
0448:            }
0449:
0450:            /**
0451:             * cleanup tx and prepare for reuse
0452:             */
0453:            protected void refresh() {
0454:                if (log.isDebugEnabled())
0455:                    log.debug("Refresh this transaction for reuse: " + this );
0456:                try {
0457:                    // we reuse ObjectEnvelopeTable instance
0458:                    objectEnvelopeTable.refresh();
0459:                } catch (Exception e) {
0460:                    if (log.isDebugEnabled()) {
0461:                        log.debug("error closing object envelope table : "
0462:                                + e.getMessage());
0463:                        e.printStackTrace();
0464:                    }
0465:                }
0466:                cleanupBroker();
0467:                // clear the temporary used named roots map
0468:                // we should do that, because same tx instance
0469:                // could be used several times
0470:                broker = null;
0471:                clearRegistrationList();
0472:                unmaterializedLocks.clear();
0473:                txStatus = Status.STATUS_NO_TRANSACTION;
0474:            }
0475:
0476:            /**
0477:             * Commit the transaction, but reopen the transaction, retaining all locks.
0478:             * Calling <code>checkpoint</code> commits persistent object modifications
0479:             * made within the transaction since the last checkpoint to the database. The
0480:             * transaction retains all locks it held on those objects at the time the
0481:             * checkpoint was invoked.
0482:             */
0483:            public void checkpoint() {
0484:                if (log.isDebugEnabled())
0485:                    log
0486:                            .debug("Checkpoint was called, commit changes hold locks on tx "
0487:                                    + this );
0488:                try {
0489:                    checkOpen();
0490:                    doWriteObjects(true);
0491:                    // do commit on PB
0492:                    if (hasBroker() && broker.isInTransaction())
0493:                        broker.commitTransaction();
0494:                } catch (Throwable t) {
0495:                    log
0496:                            .error(
0497:                                    "Checkpoint call failed, do abort transaction",
0498:                                    t);
0499:                    txStatus = Status.STATUS_MARKED_ROLLBACK;
0500:                    abort();
0501:                    if (!(t instanceof  ODMGRuntimeException)) {
0502:                        throw new TransactionAbortedExceptionOJB(
0503:                                "Can't tx.checkpoint() objects: "
0504:                                        + t.getMessage(), t);
0505:                    } else {
0506:                        throw (ODMGRuntimeException) t;
0507:                    }
0508:                }
0509:            }
0510:
0511:            /**
0512:             * @see org.apache.ojb.odmg.TransactionExt#flush
0513:             */
0514:            public void flush() {
0515:                if (log.isDebugEnabled()) {
0516:                    log
0517:                            .debug("Flush was called - write changes to database, do not commit, hold locks on tx "
0518:                                    + this );
0519:                }
0520:
0521:                try {
0522:                    checkOpen();
0523:                    doWriteObjects(true);
0524:                } catch (Throwable t) {
0525:                    log.error("Calling method 'tx.flush()' failed", t);
0526:                    txStatus = Status.STATUS_MARKED_ROLLBACK;
0527:                    abort();
0528:                    if (!(t instanceof  ODMGRuntimeException)) {
0529:                        throw new TransactionAbortedExceptionOJB(
0530:                                "Can't tx.flush() objects: " + t.getMessage(),
0531:                                t);
0532:                    } else {
0533:                        throw (ODMGRuntimeException) t;
0534:                    }
0535:                }
0536:            }
0537:
0538:            /**
0539:             * @see org.apache.ojb.odmg.TransactionExt#markDelete
0540:             */
0541:            public void markDelete(Object anObject) {
0542:                ObjectEnvelope otw = objectEnvelopeTable.get(anObject, false);
0543:                // not needed on delete - or?
0544:                //otw.refreshObjectIfNeeded(anObject);
0545:                otw.setModificationState(otw.getModificationState()
0546:                        .markDelete());
0547:            }
0548:
0549:            public void deletePersistent(RuntimeObject rt) {
0550:                //        if(rt.isNew())
0551:                //        {
0552:                //            throw new ObjectNotPersistentException("Object " + rt.getIdentity() + " is not yet persistent");
0553:                //        }
0554:                if (rt.isProxy()) {
0555:                    Object realObj = rt.getHandler().getRealSubject();
0556:                    rt = new RuntimeObject(realObj, rt.getIdentity(), this ,
0557:                            false);
0558:                }
0559:                lockAndRegister(rt, Transaction.WRITE, getRegistrationList());
0560:                ObjectEnvelope oe = objectEnvelopeTable.getByIdentity(rt
0561:                        .getIdentity());
0562:                // TODO: not needed on delete - or? When optimistic locking is used we should always use the
0563:                // specified object instance to use the last version of the object
0564:                oe.refreshObjectIfNeeded(rt.getObj());
0565:                oe.setModificationState(oe.getModificationState().markDelete());
0566:            }
0567:
0568:            /**
0569:             * @see org.apache.ojb.odmg.TransactionExt#markDirty
0570:             */
0571:            public void markDirty(Object anObject) {
0572:                ObjectEnvelope otw = objectEnvelopeTable.get(anObject, false);
0573:                otw.refreshObjectIfNeeded(anObject);
0574:                otw
0575:                        .setModificationState(otw.getModificationState()
0576:                                .markDirty());
0577:            }
0578:
0579:            void markDirty(RuntimeObject rt) {
0580:                ObjectEnvelope otw = objectEnvelopeTable.get(rt.getIdentity(),
0581:                        rt.getObj(), rt.isNew());
0582:                otw.refreshObjectIfNeeded(rt.getObj());
0583:                otw
0584:                        .setModificationState(otw.getModificationState()
0585:                                .markDirty());
0586:            }
0587:
0588:            void markPersistent(RuntimeObject rtObj) {
0589:                ObjectEnvelope oe = objectEnvelopeTable.getByIdentity(rtObj
0590:                        .getIdentity());
0591:                if (oe == null) {
0592:                    oe = objectEnvelopeTable.get(rtObj.getIdentity(), rtObj
0593:                            .getObj(), rtObj.isNew());
0594:                }
0595:                if (oe.needsDelete()) {
0596:                    oe
0597:                            .setModificationState(oe.getModificationState()
0598:                                    .markNew());
0599:                } else {
0600:                    oe.setModificationState(oe.getModificationState()
0601:                            .markDirty());
0602:                }
0603:                oe.refreshObjectIfNeeded(rtObj.getObj());
0604:            }
0605:
0606:            void makePersistent(RuntimeObject rt) {
0607:                try {
0608:                    lockAndRegister(rt, Transaction.WRITE,
0609:                            getRegistrationList());
0610:                    markPersistent(rt);
0611:                } catch (org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException ex) {
0612:                    log.error("Can't persist object: " + rt.getIdentity(), ex);
0613:                    throw new org.odmg.ClassNotPersistenceCapableException(ex
0614:                            .getMessage());
0615:                }
0616:            }
0617:
0618:            /**
0619:             * @see org.apache.ojb.odmg.TransactionExt#isDeleted(org.apache.ojb.broker.Identity)
0620:             */
0621:            public boolean isDeleted(Identity id) {
0622:                ObjectEnvelope envelope = objectEnvelopeTable.getByIdentity(id);
0623:                return (envelope != null && envelope.needsDelete());
0624:            }
0625:
0626:            /**
0627:             * Upgrade the lock on the given object to the given lock mode. Method <code>
0628:             * tryLock</code> is the same as <code>lock</code> except it returns a boolean
0629:             * indicating whether the lock was granted instead of generating an exception.
0630:             * @param  obj          Description of Parameter
0631:             * @param  lockMode     Description of Parameter
0632:             * @return              Description of the Returned Value
0633:             * </code>, <code>UPGRADE</code> , and <code>WRITE</code> .
0634:             * @return true          if the lock has been acquired, otherwise false.
0635:             */
0636:            public boolean tryLock(Object obj, int lockMode) {
0637:                if (log.isDebugEnabled())
0638:                    log.debug("Try to lock object was called on tx " + this );
0639:                checkOpen();
0640:                try {
0641:                    lock(obj, lockMode);
0642:                    return true;
0643:                } catch (LockNotGrantedException ex) {
0644:                    return false;
0645:                }
0646:            }
0647:
0648:            /**
0649:             * Commit and close the transaction. Calling <code>commit</code> commits to
0650:             * the database all persistent object modifications within the transaction and
0651:             * releases any locks held by the transaction. A persistent object
0652:             * modification is an update of any field of an existing persistent object, or
0653:             * an update or creation of a new named object in the database. If a
0654:             * persistent object modification results in a reference from an existing
0655:             * persistent object to a transient object, the transient object is moved to
0656:             * the database, and all references to it updated accordingly. Note that the
0657:             * act of moving a transient object to the database may create still more
0658:             * persistent references to transient objects, so its referents must be
0659:             * examined and moved as well. This process continues until the database
0660:             * contains no references to transient objects, a condition that is guaranteed
0661:             * as part of transaction commit. Committing a transaction does not remove
0662:             * from memory transient objects created during the transaction.
0663:             *
0664:             * The updateObjectList contains a list of all objects for which this transaction
0665:             * has write privledge to.  We need to update these objects.
0666:             */
0667:            public void commit() {
0668:                checkOpen();
0669:                try {
0670:                    prepareCommit();
0671:                    checkForCommit();
0672:
0673:                    txStatus = Status.STATUS_COMMITTING;
0674:                    if (log.isDebugEnabled())
0675:                        log.debug("Commit transaction " + this );
0676:                    // now do real commit on broker
0677:                    if (hasBroker())
0678:                        getBroker().commitTransaction();
0679:
0680:                    // Now, we notify everything the commit is done.
0681:                    performTransactionAwareAfterCommit();
0682:
0683:                    doClose();
0684:                    txStatus = Status.STATUS_COMMITTED;
0685:                } catch (Exception ex) {
0686:                    log.error("Error while commit objects, do abort tx " + this 
0687:                            + ", " + ex.getMessage(), ex);
0688:                    txStatus = Status.STATUS_MARKED_ROLLBACK;
0689:                    abort();
0690:                    if (!(ex instanceof  ODMGRuntimeException)) {
0691:                        throw new TransactionAbortedExceptionOJB(
0692:                                "Can't commit objects: " + ex.getMessage(), ex);
0693:                    } else {
0694:                        throw (ODMGRuntimeException) ex;
0695:                    }
0696:                }
0697:            }
0698:
0699:            protected void checkForCommit() {
0700:                // Never commit transaction that has been marked for rollback
0701:                if (txStatus == Status.STATUS_MARKED_ROLLBACK)
0702:                    throw new TransactionAbortedExceptionOJB(
0703:                            "Illegal tx-status: tx is already markedRollback");
0704:                // Don't commit if not prepared
0705:                if (txStatus != Status.STATUS_PREPARED)
0706:                    throw new IllegalStateException(
0707:                            "Illegal tx-status: Do prepare commit before commit");
0708:            }
0709:
0710:            /**
0711:             * Prepare does the actual work of moving the changes at the object level
0712:             * into storage (the underlying rdbms for instance). prepare Can be called multiple times, and
0713:             * does not release locks.
0714:             *
0715:             * @throws TransactionAbortedException if the transaction has been aborted
0716:             * for any reason.
0717:             * @throws  IllegalStateException Method called if transaction is
0718:             *  not in the proper state to perform this operation
0719:             * @throws TransactionNotInProgressException if the transaction is closed.
0720:             */
0721:            protected void prepareCommit() throws TransactionAbortedException,
0722:                    LockNotGrantedException {
0723:                if (txStatus == Status.STATUS_MARKED_ROLLBACK) {
0724:                    throw new TransactionAbortedExceptionOJB(
0725:                            "Prepare Transaction: tx already marked for rollback");
0726:                }
0727:                if (txStatus != Status.STATUS_ACTIVE) {
0728:                    throw new IllegalStateException(
0729:                            "Prepare Transaction: tx status is not 'active', status is "
0730:                                    + TxUtil.getStatusString(txStatus));
0731:                }
0732:                try {
0733:                    txStatus = Status.STATUS_PREPARING;
0734:                    doWriteObjects(false);
0735:                    txStatus = Status.STATUS_PREPARED;
0736:                } catch (RuntimeException e) {
0737:                    log.error("Could not prepare for commit", e);
0738:                    txStatus = Status.STATUS_MARKED_ROLLBACK;
0739:                    throw e;
0740:                }
0741:            }
0742:
0743:            /**
0744:             * Abort and close the transaction. Calling abort abandons all persistent
0745:             * object modifications and releases the associated locks. Aborting a
0746:             * transaction does not restore the state of modified transient objects
0747:             */
0748:            public void abort() {
0749:                /*
0750:                do nothing if already rolledback
0751:                 */
0752:                if (txStatus == Status.STATUS_NO_TRANSACTION
0753:                        || txStatus == Status.STATUS_UNKNOWN
0754:                        || txStatus == Status.STATUS_ROLLEDBACK) {
0755:                    log.info("Nothing to abort, tx is not active - status is "
0756:                            + TxUtil.getStatusString(txStatus));
0757:                    return;
0758:                }
0759:                // check status of tx
0760:                if (txStatus != Status.STATUS_ACTIVE
0761:                        && txStatus != Status.STATUS_PREPARED
0762:                        && txStatus != Status.STATUS_MARKED_ROLLBACK) {
0763:                    throw new IllegalStateException(
0764:                            "Illegal state for abort call, state was '"
0765:                                    + TxUtil.getStatusString(txStatus) + "'");
0766:                }
0767:                if (log.isEnabledFor(Logger.INFO)) {
0768:                    log.info("Abort transaction was called on tx " + this );
0769:                }
0770:                try {
0771:                    try {
0772:                        doAbort();
0773:                    } catch (Exception e) {
0774:                        log
0775:                                .error(
0776:                                        "Error while abort transaction, will be skipped",
0777:                                        e);
0778:                    }
0779:
0780:                    // used in managed environments, ignored in non-managed
0781:                    this .implementation.getTxManager().abortExternalTx(this );
0782:
0783:                    try {
0784:                        if (hasBroker() && getBroker().isInTransaction()) {
0785:                            getBroker().abortTransaction();
0786:                        }
0787:                    } catch (Exception e) {
0788:                        log
0789:                                .error(
0790:                                        "Error while do abort used broker instance, will be skipped",
0791:                                        e);
0792:                    }
0793:                } finally {
0794:                    txStatus = Status.STATUS_ROLLEDBACK;
0795:                    // cleanup things, e.g. release all locks
0796:                    doClose();
0797:                }
0798:            }
0799:
0800:            /**
0801:             * Start a transaction. Calling <code>begin</code> multiple times on the same
0802:             * transaction object, without an intervening call to <code>commit</code> or
0803:             * <code>abort</code> , causes the exception <code>
0804:             * TransactionInProgressException</code> to be thrown on the second and
0805:             * subsequent calls. Operations executed before a transaction has been opened,
0806:             * or before reopening after a transaction is aborted or committed, have
0807:             * undefined results; these may throw a <code>
0808:             * TransactionNotInProgressException</code> exception.
0809:             */
0810:            public synchronized void begin() {
0811:                checkForBegin();
0812:                if (log.isDebugEnabled())
0813:                    log.debug("Begin transaction was called on tx " + this );
0814:                // initialize the ObjectEnvelope table
0815:                objectEnvelopeTable = new ObjectEnvelopeTable(this );
0816:                // register transaction
0817:                implementation.getTxManager().registerTx(this );
0818:                // mark tx as active (open)
0819:                txStatus = Status.STATUS_ACTIVE;
0820:            }
0821:
0822:            protected void checkForBegin() {
0823:                /**
0824:                 * Is the associated database non-null and open? ODMG 3.0 says it must be.
0825:                 */
0826:                if ((curDB == null) || !curDB.isOpen()) {
0827:                    throw new DatabaseClosedException(
0828:                            "Database is not open. Must have an open DB to begin the Tx.");
0829:                }
0830:                if (isOpen()) {
0831:                    log.error("Transaction is already open");
0832:                    throw new org.odmg.TransactionInProgressException(
0833:                            "Impossible to call begin on already opened tx");
0834:                }
0835:            }
0836:
0837:            public String getGUID() {
0838:                return txGUID;
0839:            }
0840:
0841:            /**
0842:             * Get object by identity. First lookup among objects registered in the
0843:             * transaction, then in persistent storage.
0844:             * @param id The identity
0845:             * @return The object
0846:             * @throws PersistenceBrokerException
0847:             */
0848:            public Object getObjectByIdentity(Identity id)
0849:                    throws PersistenceBrokerException {
0850:                checkOpen();
0851:                ObjectEnvelope envelope = objectEnvelopeTable.getByIdentity(id);
0852:                if (envelope != null) {
0853:                    return (envelope.needsDelete() ? null : envelope
0854:                            .getObject());
0855:                } else {
0856:                    return getBroker().getObjectByIdentity(id);
0857:                }
0858:            }
0859:
0860:            /**
0861:             * Registers the object (without locking) with this transaction. This method
0862:             * expects that the object was already locked, no check is done!!!
0863:             */
0864:            void doSingleRegister(RuntimeObject rtObject, int lockMode)
0865:                    throws LockNotGrantedException, PersistenceBrokerException {
0866:                if (log.isDebugEnabled())
0867:                    log.debug("Register object " + rtObject.getIdentity());
0868:                Object objectToRegister = rtObject.getObj();
0869:                /*
0870:                if the object is a Proxy there are two options:
0871:                1. The proxies real subject has already been materialized:
0872:                   we take this real subject as the object to register and proceed
0873:                   as if it were a ordinary object.
0874:                2. The real subject has not been materialized: Then there is nothing
0875:                   to be registered now!
0876:                   Of course we might just materialize the real subject to have something
0877:                   to register. But this would make proxies useless for ODMG as proxies would
0878:                   get materialized even if their real subjects were not used by the
0879:                   client app.
0880:                   Thus we register the current transaction as a Listener to the IndirectionHandler
0881:                   of the Proxy.
0882:                   Only when the IndirectionHandler performs the materialization of the real subject
0883:                   at some later point in time it invokes callbacks on all it's listeners.
0884:                   Using this callback we can defer the registering until it's really needed.
0885:                 */
0886:                if (rtObject.isProxy()) {
0887:                    IndirectionHandler handler = rtObject.getHandler();
0888:                    if (handler == null) {
0889:                        throw new OJBRuntimeException(
0890:                                "Unexpected error, expect an proxy object as indicated: "
0891:                                        + rtObject);
0892:                    }
0893:                    if (handler.alreadyMaterialized()) {
0894:                        objectToRegister = handler.getRealSubject();
0895:                    } else {
0896:                        registerToIndirectionHandler(handler);
0897:                        registerUnmaterializedLocks(rtObject.getObj());
0898:                        // all work is done, so set to null
0899:                        objectToRegister = null;
0900:                    }
0901:                }
0902:                // no Proxy and is not null, register real object
0903:                if (objectToRegister != null) {
0904:                    ObjectEnvelope envelope = objectEnvelopeTable
0905:                            .getByIdentity(rtObject.getIdentity());
0906:                    // if we found an envelope, object is already registered --> we do nothing
0907:                    // than refreshing the object!
0908:                    if ((envelope == null)) {
0909:                        // register object itself
0910:                        envelope = objectEnvelopeTable.get(rtObject
0911:                                .getIdentity(), objectToRegister, rtObject
0912:                                .isNew());
0913:                    } else {
0914:                        /*
0915:                        arminw:
0916:                        if an different instance of the same object was locked again
0917:                        we should replace the old instance with new one to make
0918:                        accessible the changed fields
0919:                         */
0920:                        envelope.refreshObjectIfNeeded(objectToRegister);
0921:                    }
0922:                    /*
0923:                    arminw:
0924:                    For better performance we check if this object has already a write lock
0925:                    in this case we don't need to acquire a write lock on commit
0926:                     */
0927:                    if (lockMode == Transaction.WRITE) {
0928:                        // signal ObjectEnvelope that a WRITE lock is already acquired
0929:                        envelope.setWriteLocked(true);
0930:                    }
0931:                }
0932:            }
0933:
0934:            /**
0935:             * we only use the registrationList map if the object is not a proxy. During the
0936:             * reference locking, we will materialize objects and they will enter the registered for
0937:             * lock map.
0938:             */
0939:            private void lockAndRegisterReferences(ClassDescriptor cld,
0940:                    Object sourceObject, int lockMode, List registeredObjects)
0941:                    throws LockNotGrantedException {
0942:                if (implicitLocking) {
0943:                    Iterator i = cld.getObjectReferenceDescriptors(true)
0944:                            .iterator();
0945:                    while (i.hasNext()) {
0946:                        ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) i
0947:                                .next();
0948:                        Object refObj = rds.getPersistentField().get(
0949:                                sourceObject);
0950:                        if (refObj != null) {
0951:                            boolean isProxy = ProxyHelper.isProxy(refObj);
0952:                            RuntimeObject rt = isProxy ? new RuntimeObject(
0953:                                    refObj, this , false) : new RuntimeObject(
0954:                                    refObj, this );
0955:                            if (!registrationList.contains(rt.getIdentity())) {
0956:                                lockAndRegister(rt, lockMode, registeredObjects);
0957:                            }
0958:                        }
0959:                    }
0960:                }
0961:            }
0962:
0963:            private void lockAndRegisterCollections(ClassDescriptor cld,
0964:                    Object sourceObject, int lockMode, List registeredObjects)
0965:                    throws LockNotGrantedException {
0966:                if (implicitLocking) {
0967:                    Iterator i = cld.getCollectionDescriptors(true).iterator();
0968:                    while (i.hasNext()) {
0969:                        CollectionDescriptor cds = (CollectionDescriptor) i
0970:                                .next();
0971:                        Object col = cds.getPersistentField().get(sourceObject);
0972:                        if (col != null) {
0973:                            CollectionProxy proxy = ProxyHelper
0974:                                    .getCollectionProxy(col);
0975:                            if (proxy != null) {
0976:                                if (!proxy.isLoaded()) {
0977:                                    if (log.isDebugEnabled())
0978:                                        log
0979:                                                .debug("adding self as listener to collection proxy");
0980:                                    proxy.addListener(this );
0981:                                    registeredCollectionProxies.add(proxy);
0982:                                    continue;
0983:                                }
0984:                            }
0985:                            Iterator colIterator = BrokerHelper
0986:                                    .getCollectionIterator(col);
0987:                            Object item = null;
0988:                            try {
0989:                                while (colIterator.hasNext()) {
0990:                                    item = colIterator.next();
0991:                                    RuntimeObject rt = new RuntimeObject(item,
0992:                                            this );
0993:                                    if (rt.isProxy()) {
0994:                                        IndirectionHandler handler = ProxyHelper
0995:                                                .getIndirectionHandler(item);
0996:                                        if (!handler.alreadyMaterialized()) {
0997:                                            registerToIndirectionHandler(handler);
0998:                                            continue;
0999:                                        } else {
1000:                                            // @todo consider registering to hear when this is
1001:                                            // derefernced instead of just loading here -bmc
1002:                                            item = handler.getRealSubject();
1003:                                        }
1004:                                    }
1005:                                    if (!registrationList.contains(rt
1006:                                            .getIdentity())) {
1007:                                        lockAndRegister(rt, lockMode,
1008:                                                registeredObjects);
1009:                                    }
1010:                                }
1011:                            } catch (LockNotGrantedException e) {
1012:                                String eol = SystemUtils.LINE_SEPARATOR;
1013:                                log
1014:                                        .error(
1015:                                                "Lock not granted, while lock collection references["
1016:                                                        + eol
1017:                                                        + "current reference descriptor:"
1018:                                                        + eol
1019:                                                        + cds.toXML()
1020:                                                        + eol
1021:                                                        + "object to lock: "
1022:                                                        + item
1023:                                                        + eol
1024:                                                        + "main object class: "
1025:                                                        + sourceObject
1026:                                                                .getClass()
1027:                                                                .getName()
1028:                                                        + eol + "]", e);
1029:                                throw e;
1030:                            }
1031:                        }
1032:                    }
1033:                }
1034:            }
1035:
1036:            /**
1037:             *  this callback is invoked before an Object is materialized
1038:             *  within an IndirectionHandler.
1039:             *  @param handler the invoking handler
1040:             *  @param oid the identity of the object to be materialized
1041:             */
1042:            public void beforeMaterialization(IndirectionHandler handler,
1043:                    Identity oid) {
1044:                //noop
1045:            }
1046:
1047:            /**
1048:             *  this callback is invoked after an Object is materialized
1049:             *  within an IndirectionHandler.
1050:             *  this callback allows to defer registration of objects until
1051:             *  it's really neccessary.
1052:             *  @param handler the invoking handler
1053:             *  @param materializedObject the materialized Object
1054:             */
1055:            public void afterMaterialization(IndirectionHandler handler,
1056:                    Object materializedObject) {
1057:                try {
1058:                    Identity oid = handler.getIdentity();
1059:                    if (log.isDebugEnabled())
1060:                        log.debug("deferred registration: " + oid);
1061:                    if (!isOpen()) {
1062:                        log
1063:                                .error("Proxy object materialization outside of a running tx, obj="
1064:                                        + oid);
1065:                        try {
1066:                            throw new Exception(
1067:                                    "Proxy object materialization outside of a running tx, obj="
1068:                                            + oid);
1069:                        } catch (Exception e) {
1070:                            e.printStackTrace();
1071:                        }
1072:                    }
1073:                    ClassDescriptor cld = getBroker().getClassDescriptor(
1074:                            materializedObject.getClass());
1075:                    RuntimeObject rt = new RuntimeObject(materializedObject,
1076:                            oid, cld, false, false);
1077:                    lockAndRegister(rt, Transaction.READ, isImplicitLocking(),
1078:                            getRegistrationList());
1079:                } catch (Throwable t) {
1080:                    log.error(
1081:                            "Register materialized object with this tx failed",
1082:                            t);
1083:                    throw new LockNotGrantedException(t.getMessage());
1084:                }
1085:                unregisterFromIndirectionHandler(handler);
1086:            }
1087:
1088:            protected synchronized void unRegisterFromAllIndirectionHandlers() {
1089:                // unregistering manipulates the registeredIndirectionHandlers vector
1090:                // we have to loop through this vector to avoid index proplems.
1091:                for (int i = registeredIndirectionHandlers.size() - 1; i >= 0; i--) {
1092:                    unregisterFromIndirectionHandler((IndirectionHandler) registeredIndirectionHandlers
1093:                            .get(i));
1094:                }
1095:            }
1096:
1097:            protected synchronized void unRegisterFromAllCollectionProxies() {
1098:                for (int i = registeredCollectionProxies.size() - 1; i >= 0; i--) {
1099:                    unregisterFromCollectionProxy((CollectionProxy) registeredCollectionProxies
1100:                            .get(i));
1101:                }
1102:            }
1103:
1104:            protected synchronized void unregisterFromCollectionProxy(
1105:                    CollectionProxy handler) {
1106:                handler.removeListener(this );
1107:                registeredCollectionProxies.remove(handler);
1108:            }
1109:
1110:            protected synchronized void unregisterFromIndirectionHandler(
1111:                    IndirectionHandler handler) {
1112:                handler.removeListener(this );
1113:                registeredIndirectionHandlers.remove(handler);
1114:            }
1115:
1116:            protected synchronized void registerToIndirectionHandler(
1117:                    IndirectionHandler handler) {
1118:                handler.addListener(this );
1119:                registeredIndirectionHandlers.add(handler);
1120:            }
1121:
1122:            /**
1123:             * register proxy objects that were locked but haven't been materialized yet
1124:             * so they can be unlocked when closing the transaction
1125:             */
1126:            protected void registerUnmaterializedLocks(Object obj) {
1127:                unmaterializedLocks.add(obj);
1128:            }
1129:
1130:            /**
1131:             * Gets the broker associated with the transaction.
1132:             * MBAIRD: only return the associated broker if the transaction is open,
1133:             * if it's closed, throw a TransactionNotInProgressException. If we allow
1134:             * brokers to be reaquired by an already closed transaction, there is a
1135:             * very good chance the broker will be leaked as the doClose() method of
1136:             * transactionImpl will never be called and thus the broker will never
1137:             * be closed and returned to the pool.
1138:             * @return Returns a PersistenceBroker
1139:             * @throws TransactionNotInProgressException is the transaction is not open;
1140:             */
1141:            public PersistenceBrokerInternal getBrokerInternal() {
1142:                if (broker == null || broker.isClosed()) {
1143:                    checkOpen();
1144:                    try {
1145:                        checkForDB();
1146:                        broker = PersistenceBrokerFactoryFactory.instance()
1147:                                .createPersistenceBroker(curDB.getPBKey());
1148:                    } catch (PBFactoryException e) {
1149:                        log
1150:                                .error(
1151:                                        "Cannot obtain PersistenceBroker from PersistenceBrokerFactory, "
1152:                                                + "found PBKey was "
1153:                                                + curDB.getPBKey(), e);
1154:                        throw new PersistenceBrokerException(e);
1155:                    }
1156:                }
1157:                return broker;
1158:            }
1159:
1160:            public PersistenceBroker getBroker() {
1161:                return getBrokerInternal();
1162:            }
1163:
1164:            /**
1165:             * Returns true if an {@link org.apache.ojb.broker.PersistenceBroker} was associated with this
1166:             * tx instance.
1167:             */
1168:            protected boolean hasBroker() {
1169:                return broker != null && !broker.isClosed();
1170:            }
1171:
1172:            protected void cleanupBroker() {
1173:                if (hasBroker()) {
1174:                    try {
1175:                        if (broker.isInTransaction()) {
1176:                            broker.abortTransaction();
1177:                        }
1178:                    } finally {
1179:                        broker.close();
1180:                        broker = null;
1181:                    }
1182:                }
1183:            }
1184:
1185:            /*
1186:             * @see Configurable#configure(Configuration)
1187:             */
1188:            public void configure(Configuration config)
1189:                    throws ConfigurationException {
1190:            }
1191:
1192:            /**
1193:             * @see org.apache.ojb.odmg.TransactionExt#setImplicitLocking(boolean)
1194:             */
1195:            public synchronized void setImplicitLocking(boolean value) {
1196:                implicitLocking = value;
1197:            }
1198:
1199:            public boolean isImplicitLocking() {
1200:                return implicitLocking;
1201:            }
1202:
1203:            /**
1204:             * noop -- here for interface
1205:             */
1206:            public void beforeLoading(CollectionProxyDefaultImpl colProxy) {
1207:                // noop
1208:            }
1209:
1210:            /**
1211:             * Remove colProxy from list of pending collections and
1212:             * register its contents with the transaction.
1213:             */
1214:            public void afterLoading(CollectionProxyDefaultImpl colProxy) {
1215:                if (log.isDebugEnabled())
1216:                    log.debug("loading a proxied collection a collection: "
1217:                            + colProxy);
1218:                Collection data = colProxy.getData();
1219:                for (Iterator iterator = data.iterator(); iterator.hasNext();) {
1220:                    Object o = iterator.next();
1221:                    if (!isOpen()) {
1222:                        log
1223:                                .error("Collection proxy materialization outside of a running tx, obj="
1224:                                        + o);
1225:                        try {
1226:                            throw new Exception(
1227:                                    "Collection proxy materialization outside of a running tx, obj="
1228:                                            + o);
1229:                        } catch (Exception e) {
1230:                            e.printStackTrace();
1231:                        }
1232:                    } else {
1233:                        Identity oid = getBroker().serviceIdentity()
1234:                                .buildIdentity(o);
1235:                        ClassDescriptor cld = getBroker().getClassDescriptor(
1236:                                ProxyHelper.getRealClass(o));
1237:                        RuntimeObject rt = new RuntimeObject(o, oid, cld,
1238:                                false, ProxyHelper.isProxy(o));
1239:                        lockAndRegister(rt, Transaction.READ,
1240:                                isImplicitLocking(), getRegistrationList());
1241:                    }
1242:                }
1243:                unregisterFromCollectionProxy(colProxy);
1244:            }
1245:
1246:            protected void performTransactionAwareBeforeCommit() {
1247:                Enumeration en = objectEnvelopeTable.elements();
1248:                while (en.hasMoreElements()) {
1249:                    ((ObjectEnvelope) en.nextElement()).beforeCommit();
1250:                }
1251:            }
1252:
1253:            protected void performTransactionAwareAfterCommit() {
1254:                Enumeration en = objectEnvelopeTable.elements();
1255:                try {
1256:                    while (en.hasMoreElements()) {
1257:                        ((ObjectEnvelope) en.nextElement()).afterCommit();
1258:                    }
1259:                } catch (Exception e) {
1260:                    log
1261:                            .error(
1262:                                    "Unexpected error while perform 'TransactionAware#afterCommit()' listener after commit of objects,"
1263:                                            + " after commit you can't rollback - exception will be skipped.",
1264:                                    e);
1265:                }
1266:            }
1267:
1268:            protected void performTransactionAwareBeforeRollback() {
1269:                Enumeration en = objectEnvelopeTable.elements();
1270:                while (en.hasMoreElements()) {
1271:                    try {
1272:                        ((ObjectEnvelope) en.nextElement()).beforeAbort();
1273:                    } catch (Exception e) {
1274:                        log
1275:                                .error(
1276:                                        "Unexpected error while perform 'TransactionAware#beforeAbort()' listener before rollback of objects"
1277:                                                + " - exception will be skipped to complete rollback.",
1278:                                        e);
1279:                    }
1280:                }
1281:            }
1282:
1283:            protected void performTransactionAwareAfterRollback() {
1284:                Enumeration en = objectEnvelopeTable.elements();
1285:                try {
1286:                    while (en.hasMoreElements()) {
1287:                        ((ObjectEnvelope) en.nextElement()).afterAbort();
1288:                    }
1289:                } catch (Exception e) {
1290:                    log
1291:                            .error(
1292:                                    "Unexpected error while perform 'TransactionAware#afterAbort()' listener after rollback of objects"
1293:                                            + " - exception will be skipped.",
1294:                                    e);
1295:                }
1296:            }
1297:
1298:            /**
1299:             * Detect new objects.
1300:             */
1301:            protected boolean isTransient(ClassDescriptor cld, Object obj,
1302:                    Identity oid) {
1303:                // if the Identity is transient we assume a non-persistent object
1304:                boolean isNew = oid != null && oid.isTransient();
1305:                /*
1306:                detection of new objects is costly (select of ID in DB to check if object
1307:                already exists) we do:
1308:                a. check if the object has nullified PK field
1309:                b. check if the object is already registered
1310:                c. lookup from cache and if not found, last option select on DB
1311:                 */
1312:                if (!isNew) {
1313:                    final PersistenceBroker pb = getBroker();
1314:                    if (cld == null) {
1315:                        cld = pb.getClassDescriptor(obj.getClass());
1316:                    }
1317:                    isNew = pb.serviceBrokerHelper().hasNullPKField(cld, obj);
1318:                    if (!isNew) {
1319:                        if (oid == null) {
1320:                            oid = pb.serviceIdentity().buildIdentity(cld, obj);
1321:                        }
1322:                        final ObjectEnvelope mod = objectEnvelopeTable
1323:                                .getByIdentity(oid);
1324:                        if (mod != null) {
1325:                            // already registered object, use current state
1326:                            isNew = mod.needsInsert();
1327:                        } else {
1328:                            // if object was found cache, assume it's old
1329:                            // else make costly check against the DB
1330:                            isNew = pb.serviceObjectCache().lookup(oid) == null
1331:                                    && !pb.serviceBrokerHelper().doesExist(cld,
1332:                                            oid, obj);
1333:                        }
1334:                    }
1335:                }
1336:                return isNew;
1337:            }
1338:
1339:            /**
1340:             * Allows to change the <em>cascading delete</em> behavior of the specified reference
1341:             * of the target class while this transaction is in use.
1342:             *
1343:             * @param target The class to change cascading delete behavior of the references.
1344:             * @param referenceField The field name of the 1:1, 1:n or 1:n reference.
1345:             * @param doCascade If <em>true</em> cascading delete is enabled, <em>false</em> disabled.
1346:             */
1347:            public void setCascadingDelete(Class target, String referenceField,
1348:                    boolean doCascade) {
1349:                ClassDescriptor cld = getBroker().getClassDescriptor(target);
1350:                ObjectReferenceDescriptor ord = cld
1351:                        .getObjectReferenceDescriptorByName(referenceField);
1352:                if (ord == null) {
1353:                    ord = cld.getCollectionDescriptorByName(referenceField);
1354:                }
1355:                if (ord == null) {
1356:                    throw new CascadeSettingException(
1357:                            "Invalid reference field name '"
1358:                                    + referenceField
1359:                                    + "', can't find 1:1, 1:n or m:n relation with that name in "
1360:                                    + target);
1361:                }
1362:                runtimeCascadeDeleteMap.put(ord, (doCascade ? Boolean.TRUE
1363:                        : Boolean.FALSE));
1364:            }
1365:
1366:            /**
1367:             * Allows to change the <em>cascading delete</em> behavior of all references of the
1368:             * specified class while this transaction is in use - if the specified class is an
1369:             * interface, abstract class or class with "extent" classes the cascading flag will
1370:             * be propagated.
1371:             *
1372:             * @param target The class to change cascading delete behavior of all references.
1373:             * @param doCascade If <em>true</em> cascading delete is enabled, <em>false</em> disabled.
1374:             */
1375:            public void setCascadingDelete(Class target, boolean doCascade) {
1376:                ClassDescriptor cld = getBroker().getClassDescriptor(target);
1377:                List extents = cld.getExtentClasses();
1378:                Boolean result = doCascade ? Boolean.TRUE : Boolean.FALSE;
1379:                setCascadingDelete(cld, result);
1380:                if (extents != null && extents.size() > 0) {
1381:                    for (int i = 0; i < extents.size(); i++) {
1382:                        Class extent = (Class) extents.get(i);
1383:                        ClassDescriptor tmp = getBroker().getClassDescriptor(
1384:                                extent);
1385:                        setCascadingDelete(tmp, result);
1386:                    }
1387:                }
1388:            }
1389:
1390:            private void setCascadingDelete(ClassDescriptor cld, Boolean cascade) {
1391:                List singleRefs = cld.getObjectReferenceDescriptors(true);
1392:                for (int i = 0; i < singleRefs.size(); i++) {
1393:                    Object o = singleRefs.get(i);
1394:                    runtimeCascadeDeleteMap.put(o, cascade);
1395:                }
1396:                List collectionRefs = cld.getCollectionDescriptors(true);
1397:                for (int i = 0; i < collectionRefs.size(); i++) {
1398:                    Object o = collectionRefs.get(i);
1399:                    runtimeCascadeDeleteMap.put(o, cascade);
1400:                }
1401:            }
1402:
1403:            private HashMap runtimeCascadeDeleteMap = new HashMap();
1404:
1405:            /**
1406:             * Returns <em>true</em> if cascading delete is enabled for the specified
1407:             * single or collection descriptor.
1408:             */
1409:            protected boolean cascadeDeleteFor(ObjectReferenceDescriptor ord) {
1410:                boolean result;
1411:                Boolean runtimeSetting = (Boolean) runtimeCascadeDeleteMap
1412:                        .get(ord);
1413:                if (runtimeSetting == null) {
1414:                    /*
1415:                    arminw: Here we use the auto-delete flag defined in metadata
1416:                     */
1417:                    result = ord.getCascadingDelete() == ObjectReferenceDescriptor.CASCADE_OBJECT;
1418:                } else {
1419:                    result = runtimeSetting.booleanValue();
1420:                }
1421:                return result;
1422:            }
1423:
1424:            int getImpliciteLockType(int parentLockMode) {
1425:                return (parentLockMode == Transaction.WRITE && impliciteWriteLocks) ? Transaction.WRITE
1426:                        : Transaction.READ;
1427:            }
1428:
1429:            /**
1430:             * Return <em>true</em> if the OJB ordering algorithm is enabled.
1431:             * @see #setOrdering(boolean)
1432:             */
1433:            public boolean isOrdering() {
1434:                return ordering;
1435:            }
1436:
1437:            /**
1438:             * Allows to enable/disable the OJB persistent object ordering algorithm. If
1439:             * <em>true</em> OJB try to order the modified/new/deleted objects in a correct order
1440:             * (based on a algorithm) before the objects are written to the persistent storage.
1441:             * <br/>
1442:             * If <em>false</em> the order of the objects rely on the order specified by
1443:             * the user and on settings like {@link #setImplicitLocking(boolean)}.
1444:             *
1445:             * @param ordering Set <em>true</em> to enable object ordering on commit.
1446:             */
1447:            public void setOrdering(boolean ordering) {
1448:                this .ordering = ordering;
1449:            }
1450:
1451:            //============================================================
1452:            // inner class
1453:            //============================================================
1454:            /**
1455:             * This was thrown when something wrong with the cascading delete setting.
1456:             */
1457:            static class CascadeSettingException extends OJBRuntimeException {
1458:                public CascadeSettingException() {
1459:                }
1460:
1461:                public CascadeSettingException(String msg) {
1462:                    super (msg);
1463:                }
1464:
1465:                public CascadeSettingException(Throwable cause) {
1466:                    super (cause);
1467:                }
1468:
1469:                public CascadeSettingException(String msg, Throwable cause) {
1470:                    super(msg, cause);
1471:                }
1472:            }
1473:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.