Source Code Cross Referenced for ObjectEnvelopeTable.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) 


001:        package org.apache.ojb.odmg;
002:
003:        /* Copyright 2002-2005 The Apache Software Foundation
004:         *
005:         * Licensed under the Apache License, Version 2.0 (the "License");
006:         * you may not use this file except in compliance with the License.
007:         * You may obtain a copy of the License at
008:         *
009:         *     http://www.apache.org/licenses/LICENSE-2.0
010:         *
011:         * Unless required by applicable law or agreed to in writing, software
012:         * distributed under the License is distributed on an "AS IS" BASIS,
013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         * See the License for the specific language governing permissions and
015:         * limitations under the License.
016:         */
017:
018:        import java.util.ArrayList;
019:        import java.util.Enumeration;
020:        import java.util.HashMap;
021:        import java.util.Iterator;
022:        import java.util.List;
023:        import java.util.Map;
024:
025:        import org.apache.commons.lang.builder.ToStringBuilder;
026:        import org.apache.commons.lang.builder.ToStringStyle;
027:        import org.apache.commons.lang.SystemUtils;
028:        import org.apache.ojb.broker.Identity;
029:        import org.apache.ojb.broker.OJBRuntimeException;
030:        import org.apache.ojb.broker.OptimisticLockException;
031:        import org.apache.ojb.broker.PersistenceBroker;
032:        import org.apache.ojb.broker.accesslayer.ConnectionManagerIF;
033:        import org.apache.ojb.broker.core.proxy.CollectionProxy;
034:        import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl;
035:        import org.apache.ojb.broker.core.proxy.IndirectionHandler;
036:        import org.apache.ojb.broker.core.proxy.ProxyHelper;
037:        import org.apache.ojb.broker.metadata.ClassDescriptor;
038:        import org.apache.ojb.broker.metadata.CollectionDescriptor;
039:        import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
040:        import org.apache.ojb.broker.util.BrokerHelper;
041:        import org.apache.ojb.broker.util.logging.Logger;
042:        import org.apache.ojb.broker.util.logging.LoggerFactory;
043:        import org.apache.ojb.odmg.link.LinkEntry;
044:        import org.apache.ojb.odmg.link.LinkEntryMtoN;
045:        import org.apache.ojb.odmg.states.StateOldClean;
046:        import org.odmg.LockNotGrantedException;
047:        import org.odmg.ODMGRuntimeException;
048:        import org.odmg.Transaction;
049:        import org.odmg.TransactionAbortedException;
050:
051:        /**
052:         * manages all ObjectEnvelopes included by a transaction.
053:         * Performs commit, and rollack operations on all included Envelopes.
054:         *
055:         * @author Thomas Mahler
056:         * @author <a href="mailto:mattbaird@yahoo.com">Matthew Baird</a>
057:         *
058:         *         MBAIRD: added explicit closing and de-referencing to prevent any
059:         *         GC issues.
060:         */
061:        public class ObjectEnvelopeTable {
062:            private Logger log = LoggerFactory
063:                    .getLogger(ObjectEnvelopeTable.class);
064:            private TransactionImpl transaction;
065:
066:            /**
067:             * A list of {@link org.apache.ojb.broker.Identity} objects which are
068:             * new associated with an object and should be protected from being marked
069:             * as "delete". E.g. if a collection reference C is moved from object A1 to A2,
070:             * then A1 wants to "delete" C and A2 wants to mark the new C object as "new".
071:             */
072:            private List newAssociatedIdentites = new ArrayList();
073:            private List m2nLinkList = new ArrayList();
074:            private List m2nUnlinkList = new ArrayList();
075:            private List markedForDeletionList = new ArrayList();
076:            private List markedForInsertList = new ArrayList();
077:
078:            /** the internal table mapping Objects to their ObjectTransactionWrappers */
079:            private Map mhtObjectEnvelopes = new HashMap();
080:
081:            /**
082:             * a vector containing the ObjectEnvelope objects representing modifications
083:             * in the order they were added. If an ObjectEnvelope is added twice, only
084:             * the the second addition is ignored.
085:             */
086:            private ArrayList mvOrderOfIds = new ArrayList();
087:
088:            /** marker used to avoid superfluous reordering and commiting */
089:            private boolean needsCommit = false;
090:
091:            /** Creates new ObjectEnvelopeTable */
092:            public ObjectEnvelopeTable(TransactionImpl myTransaction) {
093:                transaction = myTransaction;
094:            }
095:
096:            TransactionImpl getTransaction() {
097:                return transaction;
098:            }
099:
100:            /** prepare this instance for reuse */
101:            public void refresh() {
102:                needsCommit = false;
103:                mhtObjectEnvelopes = new HashMap();
104:                mvOrderOfIds = new ArrayList();
105:                afterWriteCleanup();
106:            }
107:
108:            void afterWriteCleanup() {
109:                m2nLinkList.clear();
110:                m2nUnlinkList.clear();
111:                newAssociatedIdentites.clear();
112:                markedForDeletionList.clear();
113:                markedForInsertList.clear();
114:            }
115:
116:            /**
117:             * Perform write to DB on all registered object wrapper ({@link ObjectEnvelope})
118:             *
119:             * @param reuse When all registered objects be re-used after writing to
120:             * DB set <em>true</em>, else set <em>false</em> to improve performance.
121:             */
122:            public void writeObjects(boolean reuse)
123:                    throws TransactionAbortedException, LockNotGrantedException {
124:                PersistenceBroker broker = transaction.getBroker();
125:                ConnectionManagerIF connMan = broker.serviceConnectionManager();
126:                boolean saveBatchMode = connMan.isBatchMode();
127:
128:                try {
129:                    if (log.isDebugEnabled()) {
130:                        log.debug("PB is in internal tx: "
131:                                + broker.isInTransaction() + "  broker was: "
132:                                + broker);
133:                    }
134:                    // all neccessary db operations are executed within a PersistenceBroker transaction:
135:                    if (!broker.isInTransaction()) {
136:                        log
137:                                .error("PB associated with current odmg-tx is not in tx");
138:                        throw new TransactionAbortedException(
139:                                "Underlying PB is not in tx, was begin call done before commit?");
140:                    }
141:
142:                    // Committing has to be done in two phases. First implicitly upgrade to lock on all related
143:                    // objects of objects in this transaction. Then the list of locked objects has to be
144:                    // reordered to solve referential integrity dependencies, then the objects are
145:                    // written into the database.
146:
147:                    // 0. turn on the batch mode
148:                    connMan.setBatchMode(true);
149:
150:                    // 1. mark objects no longer available in collection
151:                    // for delete and add new found objects
152:                    checkAllEnvelopes(broker);
153:
154:                    // 2. mark all dependend objects for cascading insert/delete
155:                    cascadingDependents();
156:
157:                    // 3. upgrade implicit locks.
158:                    //upgradeImplicitLocksAndCheckIfCommitIsNeeded();
159:                    upgradeLockIfNeeded();
160:
161:                    // 4. Reorder objects
162:                    reorder();
163:                    //            System.out.println("## ordering: ");
164:                    //            for(int i = 0; i < mvOrderOfIds.size(); i++)
165:                    //            {
166:                    //                System.out.println("" + mvOrderOfIds.get(i));
167:                    //            }
168:                    //            System.out.println("## ordering end");
169:
170:                    // 5. write objects.
171:                    writeAllEnvelopes(reuse);
172:
173:                    // 6. execute batch
174:                    connMan.executeBatch();
175:
176:                    // 7. Update all Envelopes to new CleanState
177:                    prepareForReuse(reuse);
178:
179:                    // 6. commit cleanup
180:                    afterWriteCleanup();
181:
182:                } catch (Exception e) {
183:                    connMan.clearBatch();
184:                    /*
185:                    arminw:
186:                    log only a warn message, because in top-level methods
187:                    a error log will be done ditto
188:                     */
189:                    if (e instanceof  OptimisticLockException) {
190:                        // make error log to show the full stack trace one time
191:                        log
192:                                .error(
193:                                        "Optimistic lock exception while write objects",
194:                                        e);
195:                        // PB OptimisticLockException should be clearly signalled to the user
196:                        Object sourceObject = ((OptimisticLockException) e)
197:                                .getSourceObject();
198:                        throw new LockNotGrantedException(
199:                                "Optimistic lock exception occur, source object was ("
200:                                        + sourceObject + "),"
201:                                        + " message was (" + e.getMessage()
202:                                        + ")");
203:                    } else if (!(e instanceof  RuntimeException)) {
204:                        log.warn("Error while write objects for tx "
205:                                + transaction, e);
206:                        throw new ODMGRuntimeException(
207:                                "Unexpected error while write objects: "
208:                                        + e.getMessage());
209:                    } else {
210:                        log.warn("Error while write objects for tx "
211:                                + transaction, e);
212:                        throw (RuntimeException) e;
213:                    }
214:                } finally {
215:                    needsCommit = false;
216:                    connMan.setBatchMode(saveBatchMode);
217:                }
218:            }
219:
220:            /** commit all envelopes against the current broker */
221:            private void writeAllEnvelopes(boolean reuse) {
222:                // perform remove of m:n indirection table entries first
223:                performM2NUnlinkEntries();
224:
225:                Iterator iter;
226:                // using clone to avoid ConcurentModificationException
227:                iter = ((List) mvOrderOfIds.clone()).iterator();
228:                while (iter.hasNext()) {
229:                    ObjectEnvelope mod = (ObjectEnvelope) mhtObjectEnvelopes
230:                            .get(iter.next());
231:                    boolean insert = false;
232:                    if (needsCommit) {
233:                        insert = mod.needsInsert();
234:                        mod.getModificationState().commit(mod);
235:                        if (reuse && insert) {
236:                            getTransaction().doSingleLock(
237:                                    mod.getClassDescriptor(), mod.getObject(),
238:                                    mod.getIdentity(), Transaction.WRITE);
239:                        }
240:                    }
241:                    /*
242:                    arminw: important to call this cleanup method for each registered
243:                    ObjectEnvelope, because this method will e.g. remove proxy listener
244:                    objects for registered objects.
245:                     */
246:                    mod.cleanup(reuse, insert);
247:                }
248:                // add m:n indirection table entries
249:                performM2NLinkEntries();
250:            }
251:
252:            /**
253:             * Mark objects no longer available in collection for delete and new objects for insert.
254:             *
255:             * @param broker the PB to persist all objects
256:             */
257:            private void checkAllEnvelopes(PersistenceBroker broker) {
258:                Iterator iter = ((List) mvOrderOfIds.clone()).iterator();
259:                while (iter.hasNext()) {
260:                    ObjectEnvelope mod = (ObjectEnvelope) mhtObjectEnvelopes
261:                            .get(iter.next());
262:                    // only non transient objects should be performed
263:                    if (!mod.getModificationState().isTransient()) {
264:                        mod.markReferenceElements(broker);
265:                    }
266:                }
267:            }
268:
269:            /**
270:             * This method have to be called to reuse all registered {@link ObjectEnvelope}
271:             * objects after transaction commit/flush/checkpoint call.
272:             */
273:            private void prepareForReuse(boolean reuse) {
274:                if (reuse) {
275:                    // using clone to avoid ConcurentModificationException
276:                    Iterator iter = ((List) mvOrderOfIds.clone()).iterator();
277:                    while (iter.hasNext()) {
278:                        ObjectEnvelope mod = (ObjectEnvelope) mhtObjectEnvelopes
279:                                .get(iter.next());
280:                        if (!needsCommit
281:                                || (mod.getModificationState() == StateOldClean
282:                                        .getInstance() || mod
283:                                        .getModificationState().isTransient())) {
284:                            // nothing to do
285:                        } else {
286:                            mod.setModificationState(mod.getModificationState()
287:                                    .markClean());
288:                        }
289:                    }
290:                }
291:            }
292:
293:            /**
294:             * Checks the status of all modified objects and
295:             * upgrade the lock if needed, cleanup the {@link ObjectEnvelope}
296:             * objects.
297:             */
298:            private void upgradeLockIfNeeded() {
299:                // using clone to avoid ConcurentModificationException
300:                Iterator iter = ((List) mvOrderOfIds.clone()).iterator();
301:                TransactionImpl tx = getTransaction();
302:                ObjectEnvelope mod;
303:                while (iter.hasNext()) {
304:                    mod = (ObjectEnvelope) mhtObjectEnvelopes.get(iter.next());
305:                    // ignore transient objects
306:                    if (!mod.getModificationState().isTransient()) {
307:                        /*
308:                        now we check if all modified objects has a write lock. On insert of new
309:                        objects we don't need a write lock.
310:                         */
311:                        if (!mod.needsInsert()) {
312:                            if ((mod.needsDelete() || mod.needsUpdate() || mod
313:                                    .hasChanged(tx.getBroker()))) {
314:                                needsCommit = true;
315:                                // mark object dirty
316:                                mod.setModificationState(mod
317:                                        .getModificationState().markDirty());
318:                                ClassDescriptor cld = mod.getClassDescriptor();
319:                                // if the object isn't already locked, we will do it now
320:                                if (!mod.isWriteLocked()) {
321:                                    tx.doSingleLock(cld, mod.getObject(), mod
322:                                            .getIdentity(), Transaction.WRITE);
323:                                }
324:                            }
325:                        } else {
326:                            needsCommit = true;
327:                        }
328:                    }
329:                }
330:            }
331:
332:            /** perform rollback on all tx-states */
333:            public void rollback() {
334:                try {
335:                    Iterator iter = mvOrderOfIds.iterator();
336:                    while (iter.hasNext()) {
337:                        ObjectEnvelope mod = (ObjectEnvelope) mhtObjectEnvelopes
338:                                .get(iter.next());
339:                        if (log.isDebugEnabled())
340:                            log.debug("rollback: " + mod);
341:                        // if the Object has been modified by transaction, mark object as dirty
342:                        if (mod.hasChanged(transaction.getBroker())) {
343:                            mod.setModificationState(mod.getModificationState()
344:                                    .markDirty());
345:                        }
346:                        mod.getModificationState().rollback(mod);
347:                    }
348:                } finally {
349:                    needsCommit = false;
350:                }
351:                afterWriteCleanup();
352:            }
353:
354:            /** remove an objects entry from the object registry */
355:            public void remove(Object pKey) {
356:                Identity id;
357:                if (pKey instanceof  Identity) {
358:                    id = (Identity) pKey;
359:                } else {
360:                    id = transaction.getBroker().serviceIdentity()
361:                            .buildIdentity(pKey);
362:                }
363:                mhtObjectEnvelopes.remove(id);
364:                mvOrderOfIds.remove(id);
365:            }
366:
367:            /**
368:             * Get an enumeration of all the elements in this ObjectEnvelopeTable
369:             * in random order.
370:             *
371:             * @return Enumeration an enumeration of all elements managed by this ObjectEnvelopeTable
372:             */
373:            public Enumeration elements() {
374:                return java.util.Collections.enumeration(mhtObjectEnvelopes
375:                        .values());
376:            }
377:
378:            /** retrieve an objects ObjectModification state from the hashtable */
379:            public ObjectEnvelope getByIdentity(Identity id) {
380:                return (ObjectEnvelope) mhtObjectEnvelopes.get(id);
381:            }
382:
383:            /**
384:             * retrieve an objects ObjectEnvelope state from the hashtable.
385:             * If no ObjectEnvelope is found, a new one is created and returned.
386:             *
387:             * @return the resulting ObjectEnvelope
388:             */
389:            public ObjectEnvelope get(Object pKey, boolean isNew) {
390:                PersistenceBroker broker = transaction.getBroker();
391:                Identity oid = broker.serviceIdentity().buildIdentity(pKey);
392:                return get(oid, pKey, isNew);
393:            }
394:
395:            /**
396:             * retrieve an objects ObjectEnvelope state from the hashtable.
397:             * If no ObjectEnvelope is found, a new one is created and returned.
398:             *
399:             * @return the resulting ObjectEnvelope
400:             */
401:            public ObjectEnvelope get(Identity oid, Object pKey, boolean isNew) {
402:                ObjectEnvelope result = getByIdentity(oid);
403:                if (result == null) {
404:                    result = new ObjectEnvelope(this , oid, pKey, isNew);
405:                    mhtObjectEnvelopes.put(oid, result);
406:                    mvOrderOfIds.add(oid);
407:                    if (log.isDebugEnabled())
408:                        log.debug("register: " + result);
409:                }
410:                return result;
411:            }
412:
413:            /** Returns a String representation of this object */
414:            public String toString() {
415:                ToStringBuilder buf = new ToStringBuilder(this ,
416:                        ToStringStyle.MULTI_LINE_STYLE);
417:                String eol = SystemUtils.LINE_SEPARATOR;
418:                buf.append("# ObjectEnvelopeTable dump:" + eol + "start[");
419:                Enumeration en = elements();
420:                while (en.hasMoreElements()) {
421:                    ObjectEnvelope mod = (ObjectEnvelope) en.nextElement();
422:                    buf.append(mod.toString() + eol);
423:                }
424:                buf.append("]end");
425:                return buf.toString();
426:            }
427:
428:            /** retrieve an objects ObjectModification state from the hashtable */
429:            public boolean contains(Identity oid) {
430:                //Integer keyInteger = new Integer(System.identityHashCode(key));
431:                return mhtObjectEnvelopes.containsKey(oid);
432:            }
433:
434:            /** Reorder the objects in the table to resolve referential integrity dependencies. */
435:            private void reorder() {
436:                if (getTransaction().isOrdering() && needsCommit
437:                        && mhtObjectEnvelopes.size() > 1) {
438:                    ObjectEnvelopeOrdering ordering = new ObjectEnvelopeOrdering(
439:                            mvOrderOfIds, mhtObjectEnvelopes);
440:                    ordering.reorder();
441:                    Identity[] newOrder = ordering.getOrdering();
442:
443:                    mvOrderOfIds.clear();
444:                    for (int i = 0; i < newOrder.length; i++) {
445:                        mvOrderOfIds.add(newOrder[i]);
446:                    }
447:                }
448:            }
449:
450:            void cascadingDependents() {
451:                Iterator it = mhtObjectEnvelopes.values().iterator();
452:                ObjectEnvelope mod;
453:                // first we search for all deleted/insert objects
454:                while (it.hasNext()) {
455:                    mod = (ObjectEnvelope) it.next();
456:                    if (mod.needsDelete()) {
457:                        addForDeletionDependent(mod);
458:                    } else if (mod.needsInsert()) {
459:                        addForInsertDependent(mod);
460:                    }
461:                }
462:                /*
463:                Now start cascade insert/delete work. The order of first delete
464:                then insert is mandatory, because the user could move unmaterialized
465:                collection proxy objects from one existing, which was deleted, to a new object. In this case
466:                the proxy was materialized on deletion of the main object, but on performing
467:                the cascading insert the collection objects will be found and assigned to the new object.
468:                 */
469:                cascadeMarkedForDeletion();
470:                cascadeMarkedForInsert();
471:            }
472:
473:            void addNewAssociatedIdentity(Identity oid) {
474:                newAssociatedIdentites.add(oid);
475:            }
476:
477:            boolean isNewAssociatedObject(Identity oid) {
478:                return newAssociatedIdentites.contains(oid);
479:            }
480:
481:            void addForInsertDependent(ObjectEnvelope mod) {
482:                markedForInsertList.add(mod);
483:            }
484:
485:            /** Starts recursive insert on all insert objects object graph */
486:            private void cascadeMarkedForInsert() {
487:                // This list was used to avoid endless recursion on circular references
488:                List alreadyPrepared = new ArrayList();
489:                for (int i = 0; i < markedForInsertList.size(); i++) {
490:                    ObjectEnvelope mod = (ObjectEnvelope) markedForInsertList
491:                            .get(i);
492:                    // only if a new object was found we cascade to register the dependent objects
493:                    if (mod.needsInsert()) {
494:                        cascadeInsertFor(mod, alreadyPrepared);
495:                        alreadyPrepared.clear();
496:                    }
497:                }
498:                markedForInsertList.clear();
499:            }
500:
501:            /**
502:             * Walk through the object graph of the specified insert object. Was used for
503:             * recursive object graph walk.
504:             */
505:            private void cascadeInsertFor(ObjectEnvelope mod,
506:                    List alreadyPrepared) {
507:                // avoid endless recursion, so use List for registration
508:                if (alreadyPrepared.contains(mod.getIdentity()))
509:                    return;
510:                alreadyPrepared.add(mod.getIdentity());
511:
512:                ClassDescriptor cld = getTransaction().getBroker()
513:                        .getClassDescriptor(mod.getObject().getClass());
514:
515:                List refs = cld.getObjectReferenceDescriptors(true);
516:                cascadeInsertSingleReferences(mod, refs, alreadyPrepared);
517:
518:                List colls = cld.getCollectionDescriptors(true);
519:                cascadeInsertCollectionReferences(mod, colls, alreadyPrepared);
520:            }
521:
522:            private void cascadeInsertSingleReferences(ObjectEnvelope source,
523:                    List descriptor, List alreadyPrepared) {
524:                for (int i = 0; i < descriptor.size(); i++) {
525:                    ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) descriptor
526:                            .get(i);
527:                    Object depObj = ord.getPersistentField().get(
528:                            source.getObject());
529:
530:                    if (depObj != null) {
531:                        // in any case we have to link the source object when the object needs insert
532:                        source.addLinkOneToOne(ord, false);
533:
534:                        IndirectionHandler handler = ProxyHelper
535:                                .getIndirectionHandler(depObj);
536:                        // if the object is not materialized, nothing has changed
537:                        if (handler == null || handler.alreadyMaterialized()) {
538:                            RuntimeObject rt;
539:                            // if materialized
540:                            if (handler != null) {
541:                                rt = new RuntimeObject(
542:                                        handler.getRealSubject(),
543:                                        getTransaction(), false);
544:                            } else {
545:                                rt = new RuntimeObject(depObj, getTransaction());
546:                            }
547:                            Identity oid = rt.getIdentity();
548:                            if (!alreadyPrepared.contains(oid)) {
549:                                ObjectEnvelope depMod = getByIdentity(oid);
550:                                // if the object isn't registered and is a new object, register it
551:                                // else we have nothing to do
552:                                if (depMod == null && rt.isNew()) {
553:                                    getTransaction().lockAndRegister(
554:                                            rt,
555:                                            Transaction.WRITE,
556:                                            false,
557:                                            getTransaction()
558:                                                    .getRegistrationList());
559:                                    depMod = getByIdentity(oid);
560:                                    cascadeInsertFor(depMod, alreadyPrepared);
561:                                }
562:                            }
563:                        }
564:                    }
565:                }
566:            }
567:
568:            private void cascadeInsertCollectionReferences(
569:                    ObjectEnvelope source, List descriptor, List alreadyPrepared) {
570:                // PersistenceBroker pb = getTransaction().getBroker();
571:                for (int i = 0; i < descriptor.size(); i++) {
572:                    CollectionDescriptor col = (CollectionDescriptor) descriptor
573:                            .get(i);
574:                    Object collOrArray = col.getPersistentField().get(
575:                            source.getObject());
576:                    CollectionProxy proxy = ProxyHelper
577:                            .getCollectionProxy(collOrArray);
578:                    /*
579:                    on insert we perform only materialized collection objects. This should be
580:                    sufficient, because in method #cascadingDependents() we make sure that on
581:                    move of unmaterialized collection objects the proxy was materialized if needed.
582:                     */
583:                    if (proxy == null && collOrArray != null) {
584:                        Iterator it = BrokerHelper
585:                                .getCollectionIterator(collOrArray);
586:                        while (it.hasNext()) {
587:                            Object colObj = it.next();
588:                            if (colObj != null) {
589:                                RuntimeObject rt = new RuntimeObject(colObj,
590:                                        getTransaction());
591:                                Identity oid = rt.getIdentity();
592:                                /*
593:                                arminw:
594:                                only when the main object need insert we start with FK assignment
595:                                of the 1:n and m:n relations. If the main objects need update (was already persisted)
596:                                it should be handled by the object state detection in ObjectEnvelope
597:                                 */
598:                                if (source.needsInsert()) {
599:                                    /*
600:                                    arminw:
601:                                    TODO: what is the valid way to go, when the collection object itself is
602:                                    a unmaterialized proxy object? Think in this case we should materialize the
603:                                    object when the main object needs insert, because we have to assign the FK values
604:                                    to the main object
605:                                     */
606:                                    colObj = ProxyHelper.getRealObject(colObj);
607:                                    ObjectEnvelope oe = getByIdentity(oid);
608:                                    if (oe == null) {
609:                                        getTransaction().lockAndRegister(
610:                                                rt,
611:                                                Transaction.WRITE,
612:                                                false,
613:                                                getTransaction()
614:                                                        .getRegistrationList());
615:                                        oe = getByIdentity(oid);
616:                                    }
617:                                    if (col.isMtoNRelation()) {
618:                                        // the main objects needs insert, thus add new m:n link
619:                                        addM2NLinkEntry(col,
620:                                                source.getObject(), colObj);
621:                                    } else {
622:                                        // we mark collection reference for linking
623:                                        oe.addLinkOneToN(col, source
624:                                                .getObject(), false);
625:                                        /*
626:                                        arminw: The referenced object could be already persisted, so we have
627:                                        to dirty it to guarantee the setting of the FK (linking)
628:                                         */
629:                                        oe.setModificationState(oe
630:                                                .getModificationState()
631:                                                .markDirty());
632:                                    }
633:                                    cascadeInsertFor(oe, alreadyPrepared);
634:                                }
635:                            }
636:                        }
637:                    }
638:                }
639:            }
640:
641:            void addForDeletionDependent(ObjectEnvelope mod) {
642:                markedForDeletionList.add(mod);
643:            }
644:
645:            /** Starts recursive delete on all delete objects object graph */
646:            private void cascadeMarkedForDeletion() {
647:                List alreadyPrepared = new ArrayList();
648:                for (int i = 0; i < markedForDeletionList.size(); i++) {
649:                    ObjectEnvelope mod = (ObjectEnvelope) markedForDeletionList
650:                            .get(i);
651:                    // if the object wasn't associated with another object, start cascade delete
652:                    if (!isNewAssociatedObject(mod.getIdentity())) {
653:                        cascadeDeleteFor(mod, alreadyPrepared);
654:                        alreadyPrepared.clear();
655:                    }
656:                }
657:                markedForDeletionList.clear();
658:            }
659:
660:            /**
661:             * Walk through the object graph of the specified delete object. Was used for
662:             * recursive object graph walk.
663:             */
664:            private void cascadeDeleteFor(ObjectEnvelope mod,
665:                    List alreadyPrepared) {
666:                // avoid endless recursion
667:                if (alreadyPrepared.contains(mod.getIdentity()))
668:                    return;
669:
670:                alreadyPrepared.add(mod.getIdentity());
671:
672:                ClassDescriptor cld = getTransaction().getBroker()
673:                        .getClassDescriptor(mod.getObject().getClass());
674:
675:                List refs = cld.getObjectReferenceDescriptors(true);
676:                cascadeDeleteSingleReferences(mod, refs, alreadyPrepared);
677:
678:                List colls = cld.getCollectionDescriptors(true);
679:                cascadeDeleteCollectionReferences(mod, colls, alreadyPrepared);
680:            }
681:
682:            private void cascadeDeleteSingleReferences(ObjectEnvelope source,
683:                    List descriptor, List alreadyPrepared) {
684:                for (int i = 0; i < descriptor.size(); i++) {
685:                    ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) descriptor
686:                            .get(i);
687:                    if (getTransaction().cascadeDeleteFor(ord)) {
688:                        Object depObj = ord.getPersistentField().get(
689:                                source.getObject());
690:                        if (depObj != null) {
691:                            Identity oid = getTransaction().getBroker()
692:                                    .serviceIdentity().buildIdentity(depObj);
693:                            // if(!isNewAssociatedObject(oid) && !alreadyPrepared.contains(oid))
694:                            // if the object has a new association with a different object, don't delete it
695:                            if (!isNewAssociatedObject(oid)) {
696:                                ObjectEnvelope depMod = get(oid, depObj, false);
697:                                depMod.setModificationState(depMod
698:                                        .getModificationState().markDelete());
699:                                cascadeDeleteFor(depMod, alreadyPrepared);
700:                            }
701:                        }
702:                    }
703:                }
704:            }
705:
706:            private void cascadeDeleteCollectionReferences(
707:                    ObjectEnvelope source, List descriptor, List alreadyPrepared) {
708:                PersistenceBroker pb = getTransaction().getBroker();
709:                for (int i = 0; i < descriptor.size(); i++) {
710:                    CollectionDescriptor col = (CollectionDescriptor) descriptor
711:                            .get(i);
712:                    boolean cascadeDelete = getTransaction().cascadeDeleteFor(
713:                            col);
714:                    Object collOrArray = col.getPersistentField().get(
715:                            source.getObject());
716:                    // TODO: remove cast
717:                    CollectionProxyDefaultImpl proxy = (CollectionProxyDefaultImpl) ProxyHelper
718:                            .getCollectionProxy(collOrArray);
719:                    // on delete we have to materialize dependent objects
720:                    if (proxy != null) {
721:                        collOrArray = proxy.getData();
722:                    }
723:                    if (collOrArray != null) {
724:                        Iterator it = BrokerHelper
725:                                .getCollectionIterator(collOrArray);
726:                        while (it.hasNext()) {
727:                            Object colObj = ProxyHelper
728:                                    .getRealObject(it.next());
729:                            Identity oid = pb.serviceIdentity().buildIdentity(
730:                                    colObj);
731:                            ObjectEnvelope colMod = get(oid, colObj, false);
732:                            if (cascadeDelete) {
733:                                colMod.setModificationState(colMod
734:                                        .getModificationState().markDelete());
735:                                cascadeDeleteFor(colMod, alreadyPrepared);
736:                            } else {
737:                                if (!col.isMtoNRelation()) {
738:                                    colMod.addLinkOneToN(col, source
739:                                            .getObject(), true);
740:                                    colMod
741:                                            .setModificationState(colMod
742:                                                    .getModificationState()
743:                                                    .markDirty());
744:                                }
745:                            }
746:                            if (col.isMtoNRelation()) {
747:                                addM2NUnlinkEntry(col, source.getObject(),
748:                                        colObj);
749:                            }
750:                        }
751:                    }
752:                }
753:            }
754:
755:            void addM2NLinkEntry(CollectionDescriptor cod, Object leftSource,
756:                    Object rightSource) {
757:                if (!cod.isMtoNRelation())
758:                    throw new OJBRuntimeException(
759:                            "Expect a m:n releation, but specified a 1:n");
760:                m2nLinkList.add(new LinkEntryMtoN(leftSource, cod, rightSource,
761:                        false));
762:            }
763:
764:            void performM2NLinkEntries() {
765:                PersistenceBroker broker = getTransaction().getBroker();
766:                LinkEntry entry;
767:                for (int i = 0; i < m2nLinkList.size(); i++) {
768:                    entry = (LinkEntry) m2nLinkList.get(i);
769:                    entry.execute(broker);
770:                }
771:            }
772:
773:            void addM2NUnlinkEntry(CollectionDescriptor cod, Object leftSource,
774:                    Object rightSource) {
775:                if (!cod.isMtoNRelation())
776:                    throw new OJBRuntimeException(
777:                            "Expect a m:n releation, but specified a 1:n");
778:                m2nUnlinkList.add(new LinkEntryMtoN(leftSource, cod,
779:                        rightSource, true));
780:            }
781:
782:            void performM2NUnlinkEntries() {
783:                PersistenceBroker broker = getTransaction().getBroker();
784:                LinkEntry entry;
785:                for (int i = 0; i < m2nUnlinkList.size(); i++) {
786:                    entry = (LinkEntry) m2nUnlinkList.get(i);
787:                    entry.execute(broker);
788:                }
789:            }
790:
791:            /**
792:             * Replace the {@link org.apache.ojb.broker.Identity}
793:             * of a registered {@link ObjectEnvelope} object.
794:             *
795:             * @param newOid
796:             * @param oldOid
797:             * @return Returns <em>true</em> if successful.
798:             */
799:            boolean replaceRegisteredIdentity(Identity newOid, Identity oldOid) {
800:                /*
801:                TODO: Find a better solution
802:                 */
803:                boolean result = false;
804:                Object oe = mhtObjectEnvelopes.remove(oldOid);
805:                if (oe != null) {
806:                    mhtObjectEnvelopes.put(newOid, oe);
807:                    int index = mvOrderOfIds.indexOf(oldOid);
808:                    mvOrderOfIds.remove(index);
809:                    mvOrderOfIds.add(index, newOid);
810:                    result = true;
811:                    if (log.isDebugEnabled())
812:                        log.debug("Replace identity: " + oldOid
813:                                + " --replaced-by--> " + newOid);
814:                } else {
815:                    log.warn("Can't replace unregistered object identity ("
816:                            + oldOid + ") with new identity (" + newOid + ")");
817:                }
818:                return result;
819:            }
820:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.