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

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


0001:        package org.apache.ojb.otm.core;
0002:
0003:        /* Copyright 2003-2005 The Apache Software Foundation
0004:         *
0005:         * Licensed under the Apache License, Version 2.0 (the "License");
0006:         * you may not use this file except in compliance with the License.
0007:         * You may obtain a copy of the License at
0008:         *
0009:         *     http://www.apache.org/licenses/LICENSE-2.0
0010:         *
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         */
0017:
0018:        import java.lang.reflect.Array;
0019:        import java.math.BigDecimal;
0020:        import java.util.ArrayList;
0021:        import java.util.Arrays;
0022:        import java.util.Collection;
0023:        import java.util.Comparator;
0024:        import java.util.Iterator;
0025:        import java.util.HashMap;
0026:        import java.util.HashSet;
0027:        import java.util.Date;
0028:        import java.util.List;
0029:        import java.util.Set;
0030:        import java.util.Stack;
0031:
0032:        import org.apache.commons.collections.iterators.ArrayIterator;
0033:        import org.apache.ojb.broker.Identity;
0034:        import org.apache.ojb.broker.OJBRuntimeException;
0035:        import org.apache.ojb.broker.PBKey;
0036:        import org.apache.ojb.broker.PersistenceBroker;
0037:        import org.apache.ojb.broker.accesslayer.ConnectionManagerIF;
0038:        import org.apache.ojb.broker.cache.ObjectCache;
0039:        import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl;
0040:        import org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl;
0041:        import org.apache.ojb.broker.core.proxy.SetProxyDefaultImpl;
0042:        import org.apache.ojb.broker.core.proxy.CollectionProxyListener;
0043:        import org.apache.ojb.broker.core.proxy.IndirectionHandler;
0044:        import org.apache.ojb.broker.core.proxy.MaterializationListener;
0045:        import org.apache.ojb.broker.core.proxy.ProxyHelper;
0046:        import org.apache.ojb.broker.metadata.ClassDescriptor;
0047:        import org.apache.ojb.broker.metadata.CollectionDescriptor;
0048:        import org.apache.ojb.broker.metadata.FieldDescriptor;
0049:        import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
0050:        import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
0051:
0052:        import org.apache.ojb.otm.EditingContext;
0053:        import org.apache.ojb.otm.OTMKit;
0054:        import org.apache.ojb.otm.copy.ObjectCopyStrategy;
0055:        import org.apache.ojb.otm.lock.LockManager;
0056:        import org.apache.ojb.otm.lock.LockType;
0057:        import org.apache.ojb.otm.lock.LockingException;
0058:        import org.apache.ojb.otm.states.State;
0059:        import org.apache.ojb.otm.swizzle.Swizzling;
0060:
0061:        /**
0062:         *
0063:         * Concrete implementation of EditingContext.
0064:         *
0065:         * @author  <a href="mailto:rraghuram@hotmail.com">Raghu Rajah</a>
0066:         * @see     org.apache.ojb.otm.EditingContext
0067:         *
0068:         */
0069:        public class ConcreteEditingContext implements  EditingContext,
0070:                MaterializationListener, ObjectCache {
0071:            // for hasBidirectionalAssociation method
0072:            // Maps PBKeys to the sets of classes with/without
0073:            // bidirectional associations
0074:            private static HashMap _withBidirAsscMap = new HashMap();
0075:            private static HashMap _withoutBidirAsscMap = new HashMap();
0076:
0077:            private HashSet _withBidirAssc;
0078:            private HashSet _withoutBidirAssc;
0079:
0080:            private HashMap _objects;
0081:            private ArrayList _order;
0082:            private Transaction _tx;
0083:            private PersistenceBroker _pb;
0084:            private HashMap _original;
0085:            private HashMap _checkpointed;
0086:            private HashMap _colProxyListeners;
0087:
0088:            //////////////////////////////////////////
0089:            // Constructor
0090:            //////////////////////////////////////////
0091:
0092:            public ConcreteEditingContext(Transaction tx, PersistenceBroker pb) {
0093:                PBKey pbkey;
0094:
0095:                _tx = tx;
0096:                _pb = pb;
0097:                _objects = new HashMap();
0098:                _order = new ArrayList();
0099:                _original = new HashMap();
0100:                _checkpointed = _original;
0101:                pbkey = _pb.getPBKey();
0102:                _withoutBidirAssc = (HashSet) _withoutBidirAsscMap.get(pbkey);
0103:                if (_withoutBidirAssc != null) {
0104:                    _withBidirAssc = (HashSet) _withBidirAsscMap.get(pbkey);
0105:                } else {
0106:                    _withoutBidirAssc = new HashSet();
0107:                    _withoutBidirAsscMap.put(pbkey, _withoutBidirAssc);
0108:                    _withBidirAssc = new HashSet();
0109:                    _withBidirAsscMap.put(pbkey, _withBidirAssc);
0110:                }
0111:            }
0112:
0113:            //////////////////////////////////////////
0114:            // EditingContext operations
0115:            //////////////////////////////////////////
0116:
0117:            /**
0118:             * @see org.apache.ojb.otm.EditingContext#insert(Identity, Object, int)
0119:             */
0120:            public void insert(Identity oid, Object userObject, int lock)
0121:                    throws LockingException {
0122:                ContextEntry entry;
0123:
0124:                entry = insertInternal(oid, userObject, lock, true, null,
0125:                        new Stack());
0126:                if ((entry != null) && entry.state.needsDelete()) {
0127:                    // Undelete it
0128:                    entry.state = State.PERSISTENT_CLEAN;
0129:                }
0130:            }
0131:
0132:            private ContextEntry insertInternal(Identity oid,
0133:                    Object userObject, int lock, boolean canCreate,
0134:                    Identity insertBeforeThis, Stack stack)
0135:                    throws LockingException {
0136:                ContextEntry entry;
0137:                LockManager lockManager;
0138:                Swizzling swizzlingStrategy;
0139:                IndirectionHandler handler = null;
0140:                OTMKit kit = _tx.getKit();
0141:                // Are we building object's relations for the userObject in the transaction?
0142:                // Otherwise we just get data from the "userObject" and put it into
0143:                // the previously loaded/created object in the transaction
0144:                boolean buildingObject = false;
0145:                boolean lazySwizzle = false;
0146:
0147:                if (lock == LockType.NO_LOCK) {
0148:                    return null;
0149:                }
0150:
0151:                entry = (ContextEntry) _objects.get(oid);
0152:
0153:                if (userObject == null) {
0154:                    // invalidating object...
0155:                    _original.remove(oid);
0156:                    _checkpointed.remove(oid);
0157:                    if (entry != null) {
0158:                        entry.userObject = null;
0159:                        entry.cacheObject = null;
0160:                    }
0161:                    return entry;
0162:                }
0163:
0164:                lockManager = LockManager.getInstance();
0165:                swizzlingStrategy = kit.getSwizzlingStrategy();
0166:
0167:                handler = ProxyHelper.getIndirectionHandler(userObject);
0168:                if ((handler != null) && handler.alreadyMaterialized()) {
0169:                    userObject = handler.getRealSubject();
0170:                    handler = null;
0171:                }
0172:
0173:                if ((entry == null) || (entry.userObject == null)) {
0174:                    // first insertion of the userObject into editing context
0175:                    Object swizzledObject = swizzlingStrategy.swizzle(
0176:                            userObject, null, _pb, this );
0177:                    entry = new ContextEntry(swizzledObject);
0178:                    if (entry.handler != null) {
0179:                        ObjectCopyStrategy copyStrategy = _tx.getKit()
0180:                                .getCopyStrategy(oid);
0181:                        entry.cacheObject = copyStrategy.copy(userObject, _pb);
0182:                        // Assume that object exists, otherwise were the proxy came from?
0183:                        _objects.put(oid, entry);
0184:                        lockManager.ensureLock(oid, _tx, lock, _pb); // lock after _objects.put to avoid hanged locks
0185:                        entry.handler.addListener(this );
0186:                    } else {
0187:                        Object origCacheObj = _pb.getObjectByIdentity(oid);
0188:
0189:                        if ((origCacheObj == null) && !canCreate) {
0190:                            // we don't create the objects by reachability
0191:                            throw new IllegalStateException(
0192:                                    "Related object is neither persistent, nor otm-depentent: "
0193:                                            + oid);
0194:                        }
0195:                        if (origCacheObj != null) {
0196:                            entry.cacheObject = origCacheObj;
0197:                        }
0198:                        buildingObject = true;
0199:                        _objects.put(oid, entry);
0200:                        lockManager.ensureLock(oid, _tx, lock, _pb); // lock after _objects.put to avoid hanged locks
0201:
0202:                        if (userObject != null) {
0203:                            if ((origCacheObj == null) && canCreate) {
0204:                                ObjectCopyStrategy copyStrategy = _tx.getKit()
0205:                                        .getCopyStrategy(oid);
0206:                                entry.cacheObject = copyStrategy.copy(
0207:                                        userObject, _pb);
0208:                                entry.state = State.PERSISTENT_NEW;
0209:                                if (kit.isEagerInsert(userObject)
0210:                                        || hasBidirectionalAssociation(userObject
0211:                                                .getClass())) {
0212:                                    _pb.store(entry.cacheObject, entry.state);
0213:                                    entry.state = State.PERSISTENT_CLEAN;
0214:                                    origCacheObj = entry.cacheObject;
0215:                                }
0216:                            }
0217:
0218:                            if (origCacheObj != null) {
0219:                                _original.put(oid, getFields(userObject, false,
0220:                                        true));
0221:                            }
0222:                        }
0223:                    }
0224:                    if (insertBeforeThis != null) {
0225:                        int insertIndex = _order.indexOf(insertBeforeThis);
0226:                        _order.add(insertIndex, oid);
0227:                    } else {
0228:                        _order.add(oid);
0229:                    }
0230:                } else {
0231:                    // The object in context is the same object attempted an insert on
0232:                    // Ensure we have the correct lock level
0233:                    lockManager.ensureLock(oid, _tx, lock, _pb);
0234:
0235:                    if (handler == null) {
0236:                        if (!swizzlingStrategy.isSameInstance(entry.userObject,
0237:                                userObject)) {
0238:                            // the new object contains data to deal with
0239:                            if (entry.handler != null) {
0240:                                // materialize old object even if it is not
0241:                                // materialized yet, because we need a place
0242:                                // to copy the data from the new object
0243:                                entry.userObject = entry.handler
0244:                                        .getRealSubject();
0245:                                entry.handler = null;
0246:                            }
0247:                            // swizzle after lockReachableObjects(), when all related objects
0248:                            // will be in the editing context
0249:                            lazySwizzle = true;
0250:                        }
0251:                    }
0252:                }
0253:
0254:                // perform automatic read lock for all reachable objects
0255:                // if the inserted object is materialized
0256:                if ((handler == null) && !stack.contains(userObject)) {
0257:                    stack.push(userObject);
0258:                    lockReachableObjects(oid, userObject, entry.cacheObject,
0259:                            lock, stack, buildingObject);
0260:                    stack.pop();
0261:                    if (lazySwizzle) {
0262:                        entry.userObject = swizzlingStrategy.swizzle(
0263:                                userObject, entry.userObject, _pb, this );
0264:                    }
0265:                }
0266:
0267:                return entry;
0268:            }
0269:
0270:            /**
0271:             * Lock all objects reachable via 1:N and N:1 relations,
0272:             * @param lock The lock type to use
0273:             */
0274:            private void lockReachableObjects(Identity oid, Object userObject,
0275:                    Object cacheObject, int lock, Stack stack,
0276:                    boolean buildingObject) throws LockingException {
0277:                ContextEntry entry;
0278:                boolean onlyDependants = !_tx.getKit().isImplicitLockingUsed();
0279:                ClassDescriptor mif = _pb.getClassDescriptor(userObject
0280:                        .getClass());
0281:
0282:                // N:1 relations
0283:                Iterator iter = mif.getObjectReferenceDescriptors().iterator();
0284:                ObjectReferenceDescriptor rds = null;
0285:                PersistentField f;
0286:                Object relUserObj;
0287:                Identity relOid;
0288:                boolean isDependent;
0289:
0290:                while (iter.hasNext()) {
0291:                    rds = (ObjectReferenceDescriptor) iter.next();
0292:                    isDependent = rds.getOtmDependent();
0293:                    if (onlyDependants && !isDependent) {
0294:                        continue;
0295:                    }
0296:                    f = rds.getPersistentField();
0297:                    relUserObj = f.get(userObject);
0298:                    if (relUserObj != null) {
0299:                        relOid = new Identity(relUserObj, _pb);
0300:                        entry = (ContextEntry) _objects.get(relOid);
0301:                        if ((entry == null) || (entry.userObject != relUserObj)) {
0302:                            entry = insertInternal(relOid, relUserObj, lock,
0303:                                    isDependent, oid, stack);
0304:                            if (buildingObject && (entry != null)) {
0305:                                f.set(userObject, entry.userObject);
0306:                                f.set(cacheObject, entry.cacheObject);
0307:                            }
0308:                        }
0309:                    }
0310:                }
0311:
0312:                // 1:N relations
0313:                Iterator collections = mif.getCollectionDescriptors()
0314:                        .iterator();
0315:                CollectionDescriptor cds;
0316:                Object userCol;
0317:                Iterator userColIterator;
0318:                Class type;
0319:                ArrayList newUserCol = null;
0320:                ArrayList newCacheCol = null;
0321:
0322:                while (collections.hasNext()) {
0323:                    cds = (CollectionDescriptor) collections.next();
0324:                    f = cds.getPersistentField();
0325:                    type = f.getType();
0326:                    isDependent = cds.getOtmDependent();
0327:                    if (onlyDependants && !isDependent) {
0328:                        continue;
0329:                    }
0330:                    userCol = f.get(userObject);
0331:                    if (userCol != null) {
0332:                        if ((userCol instanceof  CollectionProxyDefaultImpl)
0333:                                && !((CollectionProxyDefaultImpl) userCol)
0334:                                        .isLoaded()) {
0335:                            continue;
0336:                        }
0337:
0338:                        if (buildingObject) {
0339:                            newUserCol = new ArrayList();
0340:                            newCacheCol = new ArrayList();
0341:                        }
0342:
0343:                        if (Collection.class.isAssignableFrom(type)) {
0344:                            userColIterator = ((Collection) userCol).iterator();
0345:                        } else if (type.isArray()) {
0346:                            userColIterator = new ArrayIterator(userCol);
0347:                        } else {
0348:                            throw new OJBRuntimeException(
0349:                                    userCol.getClass()
0350:                                            + " can not be managed by OJB OTM, use Array or Collection instead !");
0351:                        }
0352:
0353:                        while (userColIterator.hasNext()) {
0354:                            relUserObj = userColIterator.next();
0355:                            relOid = new Identity(relUserObj, _pb);
0356:                            entry = (ContextEntry) _objects.get(relOid);
0357:                            if ((entry == null)
0358:                                    || (entry.userObject != relUserObj)) {
0359:                                entry = insertInternal(relOid, relUserObj,
0360:                                        lock, isDependent, null, stack);
0361:                            }
0362:                            if (buildingObject && (entry != null)) {
0363:                                newUserCol.add(entry.userObject);
0364:                                newCacheCol.add(entry.cacheObject);
0365:                            }
0366:                        }
0367:                        if (buildingObject) {
0368:                            setCollectionField(userObject, f, newUserCol);
0369:                            setCollectionField(cacheObject, f, newCacheCol);
0370:                        }
0371:                    }
0372:                }
0373:            }
0374:
0375:            /**
0376:             * @see org.apache.ojb.otm.EditingContext#remove(Identity)
0377:             */
0378:            public void remove(Identity oid) {
0379:                _objects.remove(oid);
0380:                _order.remove(oid);
0381:                LockManager.getInstance().releaseLock(oid, _tx);
0382:            }
0383:
0384:            public void deletePersistent(Identity oid, Object userObject)
0385:                    throws LockingException {
0386:                ContextEntry entry;
0387:
0388:                entry = insertInternal(oid, userObject, LockType.WRITE_LOCK,
0389:                        true, null, new Stack());
0390:                if (entry != null) {
0391:                    entry.state = entry.state.deletePersistent();
0392:                }
0393:                _order.remove(oid);
0394:                _order.add(oid);
0395:            }
0396:
0397:            /**
0398:             * @see org.apache.ojb.otm.EditingContext#lookup(Identity)
0399:             */
0400:            public Object lookup(Identity oid) {
0401:                ContextEntry entry = (ContextEntry) _objects.get(oid);
0402:                return (entry == null ? null : entry.userObject);
0403:            }
0404:
0405:            public boolean contains(Identity oid) {
0406:                return lookup(oid) != null;
0407:            }
0408:
0409:            /**
0410:             * @see org.apache.ojb.otm.EditingContext#lookupState(Identity)
0411:             */
0412:            public State lookupState(Identity oid) throws LockingException {
0413:                State retval = null;
0414:                ContextEntry entry = (ContextEntry) _objects.get(oid);
0415:                if (entry != null) {
0416:                    /**
0417:                     * possibly return a clone so we don't allow people to tweak states.
0418:                     */
0419:                    retval = entry.state;
0420:                }
0421:                return retval;
0422:            }
0423:
0424:            /**
0425:             * @see org.apache.ojb.otm.EditingContext#setState(Identity, State)
0426:             */
0427:            public void setState(Identity oid, State state) {
0428:                ContextEntry entry = (ContextEntry) _objects.get(oid);
0429:                entry.state = state;
0430:            }
0431:
0432:            public Collection getAllObjectsInContext() {
0433:                return _objects.values();
0434:            }
0435:
0436:            //////////////////////////////////////////
0437:            // MaterializationListener interface
0438:            //////////////////////////////////////////
0439:
0440:            public void beforeMaterialization(IndirectionHandler handler,
0441:                    Identity oid) {
0442:                //noop
0443:            }
0444:
0445:            public void afterMaterialization(IndirectionHandler handler,
0446:                    Object cacheObject) {
0447:                Identity oid = handler.getIdentity();
0448:                ContextEntry entry = (ContextEntry) _objects.get(oid);
0449:
0450:                if (entry == null) {
0451:                    return;
0452:                }
0453:
0454:                int lock = LockManager.getInstance().getLockHeld(oid, _tx);
0455:                ObjectCopyStrategy copyStrategy = _tx.getKit().getCopyStrategy(
0456:                        oid);
0457:                Object userObject = copyStrategy.copy(cacheObject, _pb);
0458:                handler.setRealSubject(userObject);
0459:                _original.put(oid, getFields(userObject, false, true));
0460:
0461:                // replace the proxy object with the real one
0462:                entry.userObject = userObject;
0463:                entry.cacheObject = cacheObject;
0464:                entry.handler.removeListener(this );
0465:                entry.handler = null;
0466:
0467:                // perform automatic lock for all reachable objects
0468:                // if the inserted object is materialized
0469:                try {
0470:                    lockReachableObjects(oid, userObject, cacheObject, lock,
0471:                            new Stack(), true);
0472:                } catch (LockingException ex) {
0473:                    throw new LockingPassthruException(ex);
0474:                }
0475:            }
0476:
0477:            //////////////////////////////////////////
0478:            // Other operations
0479:            //////////////////////////////////////////
0480:
0481:            /**
0482:             *
0483:             *  Commit this context into the persistent store.
0484:             *  The EditingContext is not usable after a commit.
0485:             *
0486:             */
0487:            public void commit() throws TransactionAbortedException {
0488:                checkpointInternal(true);
0489:                releaseLocksAndClear();
0490:            }
0491:
0492:            private void releaseLocksAndClear() {
0493:                releaseLocks();
0494:                removeMaterializationListener();
0495:                _objects.clear();
0496:                _order.clear();
0497:                _original.clear();
0498:                if (_checkpointed != _original) {
0499:                    _checkpointed.clear();
0500:                }
0501:            }
0502:
0503:            /**
0504:             *
0505:             *  Writes all changes in this context into the persistent store.
0506:             *
0507:             */
0508:            public void checkpoint() throws TransactionAbortedException {
0509:                checkpointInternal(false);
0510:                _checkpointed = new HashMap();
0511:                for (Iterator iterator = _order.iterator(); iterator.hasNext();) {
0512:                    Identity oid = (Identity) iterator.next();
0513:                    ContextEntry entry = (ContextEntry) _objects.get(oid);
0514:                    if (entry.handler == null) {
0515:                        _checkpointed.put(oid, getFields(entry.userObject,
0516:                                false, true));
0517:                    }
0518:                }
0519:            }
0520:
0521:            /**
0522:             *
0523:             *  Writes all changes in this context into the persistent store.
0524:             *
0525:             */
0526:            private void checkpointInternal(boolean isCommit)
0527:                    throws TransactionAbortedException {
0528:                if (_order.size() == 0) {
0529:                    return;
0530:                }
0531:
0532:                removeCollectionProxyListeners();
0533:
0534:                ConnectionManagerIF connMan = _pb.serviceConnectionManager();
0535:                boolean saveBatchMode = connMan.isBatchMode();
0536:                Swizzling swizzlingStrategy = _tx.getKit()
0537:                        .getSwizzlingStrategy();
0538:                LockManager lockManager = LockManager.getInstance();
0539:                Identity[] lockOrder = (Identity[]) _order
0540:                        .toArray(new Identity[_order.size()]);
0541:                ObjectCache cache = _pb.serviceObjectCache();
0542:                boolean isInsertVerified = _tx.getKit().isInsertVerified();
0543:                ArrayList changedCollections = new ArrayList();
0544:
0545:                // sort objects in the order of oid.hashCode to avoid deadlocks
0546:                Arrays.sort(lockOrder, new Comparator() {
0547:                    public int compare(Object o1, Object o2) {
0548:                        return o1.hashCode() - o2.hashCode();
0549:                    }
0550:
0551:                    public boolean equals(Object obj) {
0552:                        return false;
0553:                    }
0554:                });
0555:
0556:                try {
0557:                    // mark dirty objects and lock them for write
0558:                    // also handle dependent objects and if there were inserted once,
0559:                    // repeat this process for their dependants ("cascade create")
0560:                    ArrayList newObjects = new ArrayList();
0561:                    int countNewObjects;
0562:                    do {
0563:                        newObjects.clear();
0564:                        countNewObjects = 0;
0565:                        for (int i = 0; i < lockOrder.length; i++) {
0566:                            Identity oid = lockOrder[i];
0567:                            ContextEntry entry = (ContextEntry) _objects
0568:                                    .get(oid);
0569:                            State state = entry.state;
0570:
0571:                            if (entry.userObject == null) // invalidated
0572:                            {
0573:                                continue;
0574:                            }
0575:
0576:                            if (entry.handler == null) // materialized
0577:                            {
0578:                                if (!state.isDeleted()) {
0579:                                    Object[][] origFields = (Object[][]) _checkpointed
0580:                                            .get(oid);
0581:                                    Object[][] newFields = getFields(
0582:                                            entry.userObject, true, !isCommit);
0583:
0584:                                    if (origFields == null) {
0585:                                        entry.needsCacheSwizzle = true;
0586:                                        newObjects
0587:                                                .addAll(handleDependentReferences(
0588:                                                        oid, entry.userObject,
0589:                                                        null, newFields[0],
0590:                                                        newFields[2]));
0591:                                        newObjects
0592:                                                .addAll(handleDependentCollections(
0593:                                                        oid, entry.userObject,
0594:                                                        null, newFields[1],
0595:                                                        newFields[3]));
0596:                                    } else {
0597:                                        if (isModified(origFields[0],
0598:                                                newFields[0])) {
0599:                                            entry.state = state.markDirty();
0600:                                            entry.needsCacheSwizzle = true;
0601:                                            lockManager.ensureLock(oid, _tx,
0602:                                                    LockType.WRITE_LOCK, _pb);
0603:                                            newObjects
0604:                                                    .addAll(handleDependentReferences(
0605:                                                            oid,
0606:                                                            entry.userObject,
0607:                                                            origFields[0],
0608:                                                            newFields[0],
0609:                                                            newFields[2]));
0610:                                        }
0611:
0612:                                        if (isModified(origFields[1],
0613:                                                newFields[1])) {
0614:                                            // there are modified collections,
0615:                                            // so we need to lock the object and to swizzle it to cache
0616:                                            entry.needsCacheSwizzle = true;
0617:                                            lockManager.ensureLock(oid, _tx,
0618:                                                    LockType.WRITE_LOCK, _pb);
0619:                                            newObjects
0620:                                                    .addAll(handleDependentCollections(
0621:                                                            oid,
0622:                                                            entry.userObject,
0623:                                                            origFields[1],
0624:                                                            newFields[1],
0625:                                                            newFields[3]));
0626:                                            changedCollections.add(oid);
0627:                                        }
0628:                                    }
0629:                                }
0630:                            }
0631:                        }
0632:                        countNewObjects = newObjects.size();
0633:                        if (countNewObjects > 0) {
0634:                            // new objects are not locked, so we don't need to ensure the order
0635:                            lockOrder = (Identity[]) newObjects
0636:                                    .toArray(new Identity[countNewObjects]);
0637:                        }
0638:                    } while (countNewObjects > 0);
0639:
0640:                    // Swizzle the context objects and the cache objects
0641:                    for (Iterator it = _order.iterator(); it.hasNext();) {
0642:                        Identity oid = (Identity) it.next();
0643:                        ContextEntry entry = (ContextEntry) _objects.get(oid);
0644:
0645:                        if (entry.needsCacheSwizzle) {
0646:                            entry.userObject = swizzlingStrategy
0647:                                    .getRealTarget(entry.userObject);
0648:                            entry.cacheObject = swizzlingStrategy.swizzle(
0649:                                    // we create the special ObjectCache implememntation
0650:                                    // that returns cacheObject, not userObject
0651:                                    entry.userObject, entry.cacheObject, _pb,
0652:                                    new ObjectCache() {
0653:                                        public Object lookup(Identity anOid) {
0654:                                            ContextEntry ent = (ContextEntry) _objects
0655:                                                    .get(anOid);
0656:                                            return (ent == null ? null
0657:                                                    : ent.cacheObject);
0658:                                        }
0659:
0660:                                        public boolean contains(Identity oid) {
0661:                                            return lookup(oid) != null;
0662:                                        }
0663:
0664:                                        public void cache(Identity anOid,
0665:                                                Object obj) {
0666:                                            // do nothing
0667:                                        }
0668:
0669:                                        public boolean cacheIfNew(Identity oid,
0670:                                                Object obj) {
0671:                                            return false;
0672:                                        }
0673:
0674:                                        public void clear() {
0675:                                            // do nothing
0676:                                        }
0677:
0678:                                        public void remove(Identity anOid) {
0679:                                            // do nothing
0680:                                        }
0681:                                    });
0682:                        }
0683:                    }
0684:
0685:                    // Cascade delete for dependent objects
0686:                    int countCascadeDeleted;
0687:                    do {
0688:                        countCascadeDeleted = 0;
0689:                        // Use intermediate new ArrayList(_order) because _order
0690:                        // may be changed during cascade delete
0691:                        for (Iterator it = (new ArrayList(_order)).iterator(); it
0692:                                .hasNext();) {
0693:                            Identity oid = (Identity) it.next();
0694:                            ContextEntry entry = (ContextEntry) _objects
0695:                                    .get(oid);
0696:
0697:                            if (entry.state.isDeleted()) {
0698:                                countCascadeDeleted += doCascadeDelete(oid,
0699:                                        entry.userObject);
0700:                            }
0701:                        }
0702:                    } while (countCascadeDeleted > 0);
0703:
0704:                    // perform database operations
0705:                    connMan.setBatchMode(true);
0706:                    try {
0707:                        for (Iterator it = _order.iterator(); it.hasNext();) {
0708:                            Identity oid = (Identity) it.next();
0709:                            ContextEntry entry = (ContextEntry) _objects
0710:                                    .get(oid);
0711:                            State state = entry.state;
0712:
0713:                            if (!state.needsInsert() && !state.needsUpdate()
0714:                                    && !state.needsDelete()) {
0715:                                if (changedCollections.contains(oid)) {
0716:                                    _pb.store(entry.cacheObject, state);
0717:                                }
0718:                                continue;
0719:                            }
0720:
0721:                            if (state.needsInsert()) {
0722:                                if (isInsertVerified) {
0723:                                    // PB verifies object existence by default
0724:                                    _pb.store(entry.cacheObject);
0725:                                } else {
0726:                                    // PB migth already created the object by auto-update
0727:                                    if (cache.lookup(oid) == null) {
0728:                                        _pb.store(entry.cacheObject, state);
0729:                                    }
0730:                                }
0731:
0732:                            } else if (state.needsUpdate()) {
0733:                                _pb.store(entry.cacheObject, state);
0734:                            } else if (state.needsDelete()) {
0735:                                _pb.delete(entry.cacheObject);
0736:                            }
0737:                            entry.state = state.commit();
0738:                        }
0739:                        connMan.executeBatch();
0740:                    } finally {
0741:                        connMan.setBatchMode(saveBatchMode);
0742:                    }
0743:                } catch (Throwable ex) {
0744:                    ex.printStackTrace();
0745:                    throw new TransactionAbortedException(ex);
0746:                }
0747:            }
0748:
0749:            /**
0750:             *
0751:             *  Rollback all changes made during this transaction. The EditingContext is not usable after
0752:             *  a rollback.
0753:             *
0754:             */
0755:            public void rollback() {
0756:                for (Iterator iterator = _order.iterator(); iterator.hasNext();) {
0757:                    Identity oid = (Identity) iterator.next();
0758:                    ContextEntry entry = (ContextEntry) _objects.get(oid);
0759:                    entry.state = entry.state.rollback();
0760:                    Object[][] origFields = (Object[][]) _original.get(oid);
0761:                    if (origFields != null) {
0762:                        setFields(entry.userObject, origFields);
0763:                        setFields(entry.cacheObject, origFields);
0764:                    }
0765:                }
0766:                releaseLocksAndClear();
0767:            }
0768:
0769:            /**
0770:             *
0771:             *  Rollback all changes made during this transaction to the given object.
0772:             *
0773:             */
0774:            public void refresh(Identity oid, Object object) {
0775:                ContextEntry entry = (ContextEntry) _objects.get(oid);
0776:                Object[][] origFields = (Object[][]) _original.get(oid);
0777:                if (origFields != null) {
0778:                    setFields(entry.userObject, origFields);
0779:                    if (object != entry.userObject) {
0780:                        setFields(object, origFields);
0781:                    }
0782:                }
0783:                entry.state = entry.state.refresh();
0784:            }
0785:
0786:            private void removeMaterializationListener() {
0787:                for (Iterator it = _order.iterator(); it.hasNext();) {
0788:                    Identity oid = (Identity) it.next();
0789:                    ContextEntry entry = (ContextEntry) _objects.get(oid);
0790:                    if (entry.handler != null) {
0791:                        entry.handler.removeListener(this );
0792:                    }
0793:                }
0794:            }
0795:
0796:            private void removeCollectionProxyListeners() {
0797:                if (_colProxyListeners != null) {
0798:                    for (Iterator it = _colProxyListeners.keySet().iterator(); it
0799:                            .hasNext();) {
0800:                        CollectionProxyListener listener = (CollectionProxyListener) it
0801:                                .next();
0802:                        CollectionProxyDefaultImpl colProxy = (CollectionProxyDefaultImpl) _colProxyListeners
0803:                                .get(listener);
0804:                        colProxy.removeListener(listener);
0805:                    }
0806:                    _colProxyListeners.clear();
0807:                }
0808:            }
0809:
0810:            private void releaseLocks() {
0811:                LockManager lockManager = LockManager.getInstance();
0812:
0813:                for (Iterator it = _objects.keySet().iterator(); it.hasNext();) {
0814:                    Identity oid = (Identity) it.next();
0815:                    lockManager.releaseLock(oid, _tx);
0816:                }
0817:                _tx.getKit().getLockMap().gc();
0818:            }
0819:
0820:            /**
0821:             * This method compared simple field values:
0822:             * there are some tricks...
0823:             */
0824:            private boolean isEqual(Object fld1, Object fld2) {
0825:                if (fld1 == null || fld2 == null) {
0826:                    return (fld1 == fld2);
0827:                } else if ((fld1 instanceof  BigDecimal)
0828:                        && (fld2 instanceof  BigDecimal)) {
0829:                    return (((BigDecimal) fld1).compareTo((BigDecimal) fld2) == 0);
0830:                } else if ((fld1 instanceof  Date) && (fld2 instanceof  Date)) {
0831:                    return (((Date) fld1).getTime() == ((Date) fld2).getTime());
0832:                } else {
0833:                    return fld1.equals(fld2);
0834:                }
0835:            }
0836:
0837:            private boolean isModified(Object[] newFields, Object[] oldFields) {
0838:                if (newFields.length != oldFields.length) {
0839:                    return true;
0840:                }
0841:
0842:                for (int i = 0; i < newFields.length; i++) {
0843:                    if (!isEqual(newFields[i], oldFields[i])) {
0844:                        return true;
0845:                    }
0846:                }
0847:
0848:                return false;
0849:            }
0850:
0851:            /**
0852:             * @param addListeners Whether to add CollectionProxy listeners
0853:             * @return four arrays of field values:
0854:             * 1) The class, simple fields, identities of references
0855:             * 2) collections of identities
0856:             * 3) references (parallel to identities of references in 1)
0857:             * 4) collections of objects (parallel to collections of identities in 2)
0858:             * if "withObjects" parameter is "false", then returns nulls
0859:             * in places of 3) and 4)
0860:             */
0861:            private Object[][] getFields(Object obj, boolean withObjects,
0862:                    boolean addListeners) {
0863:                ClassDescriptor mif = _pb.getClassDescriptor(obj.getClass());
0864:                FieldDescriptor[] fieldDescs = mif.getFieldDescriptions();
0865:                Collection refDescs = mif.getObjectReferenceDescriptors();
0866:                Collection colDescs = mif.getCollectionDescriptors();
0867:                int count = 0;
0868:                Object[] fields = new Object[1 + fieldDescs.length
0869:                        + refDescs.size()];
0870:                ArrayList[] collections = new ArrayList[colDescs.size()];
0871:                Object[] references = null;
0872:                ArrayList[] collectionsOfObjects = null;
0873:                int lockForListeners = LockType.NO_LOCK;
0874:
0875:                if (withObjects) {
0876:                    references = new Object[refDescs.size()];
0877:                    collectionsOfObjects = new ArrayList[colDescs.size()];
0878:                }
0879:
0880:                if (addListeners) {
0881:                    lockForListeners = LockManager.getInstance().getLockHeld(
0882:                            new Identity(obj, _pb), _tx);
0883:                }
0884:
0885:                fields[0] = obj.getClass(); // we must notice if the object class changes
0886:                count++;
0887:
0888:                for (int i = 0; i < fieldDescs.length; i++) {
0889:                    FieldDescriptor fd = fieldDescs[i];
0890:                    PersistentField f = fd.getPersistentField();
0891:                    fields[count] = f.get(obj);
0892:                    count++;
0893:                }
0894:
0895:                int countRefs = 0;
0896:                for (Iterator it = refDescs.iterator(); it.hasNext(); count++, countRefs++) {
0897:                    ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) it
0898:                            .next();
0899:                    PersistentField f = rds.getPersistentField();
0900:                    Object relObj = f.get(obj);
0901:                    if (relObj != null) {
0902:                        fields[count] = new Identity(relObj, _pb);
0903:                        if (withObjects) {
0904:                            references[countRefs] = relObj;
0905:                        }
0906:                    }
0907:                }
0908:
0909:                count = 0;
0910:                for (Iterator it = colDescs.iterator(); it.hasNext(); count++) {
0911:                    CollectionDescriptor cds = (CollectionDescriptor) it.next();
0912:                    PersistentField f = cds.getPersistentField();
0913:                    Class type = f.getType();
0914:                    Object col = f.get(obj);
0915:
0916:                    if ((col != null)
0917:                            && (col instanceof  CollectionProxyDefaultImpl)
0918:                            && !((CollectionProxyDefaultImpl) col).isLoaded()) {
0919:                        if (addListeners) {
0920:                            OTMCollectionProxyListener listener = new OTMCollectionProxyListener(
0921:                                    cds, collections, count, lockForListeners);
0922:
0923:                            ((CollectionProxyDefaultImpl) col)
0924:                                    .addListener(listener);
0925:                            if (_colProxyListeners == null) {
0926:                                _colProxyListeners = new HashMap();
0927:                            }
0928:                            _colProxyListeners.put(listener, col);
0929:                        }
0930:                        continue;
0931:                    }
0932:
0933:                    if (col != null) {
0934:                        ArrayList list = new ArrayList();
0935:                        ArrayList listOfObjects = null;
0936:                        Iterator colIterator;
0937:
0938:                        collections[count] = list;
0939:                        if (withObjects) {
0940:                            listOfObjects = new ArrayList();
0941:                            collectionsOfObjects[count] = listOfObjects;
0942:                        }
0943:
0944:                        if (Collection.class.isAssignableFrom(type)) {
0945:                            colIterator = ((Collection) col).iterator();
0946:                        } else if (type.isArray()) {
0947:                            colIterator = new ArrayIterator(col);
0948:                        } else {
0949:                            continue;
0950:                        }
0951:
0952:                        while (colIterator.hasNext()) {
0953:                            Object relObj = colIterator.next();
0954:                            list.add(new Identity(relObj, _pb));
0955:                            if (withObjects) {
0956:                                listOfObjects.add(relObj);
0957:                            }
0958:                        }
0959:                    }
0960:                }
0961:
0962:                return new Object[][] { fields, collections, references,
0963:                        collectionsOfObjects };
0964:            }
0965:
0966:            private void setFields(Object obj, Object[][] fieldsAndCollections) {
0967:                ClassDescriptor mif = _pb.getClassDescriptor(obj.getClass());
0968:                FieldDescriptor[] fieldDescs = mif.getFieldDescriptions();
0969:                Collection refDescs = mif.getObjectReferenceDescriptors();
0970:                Collection colDescs = mif.getCollectionDescriptors();
0971:                Object[] fields = fieldsAndCollections[0];
0972:                ArrayList[] collections = (ArrayList[]) fieldsAndCollections[1];
0973:                int count = 0;
0974:
0975:                if (!fields[0].equals(obj.getClass())) {
0976:                    System.err
0977:                            .println("Can't restore the object fields "
0978:                                    + "since its class changed during transaction from "
0979:                                    + fields[0] + " to " + obj.getClass());
0980:                    return;
0981:                }
0982:                count++;
0983:
0984:                for (int i = 0; i < fieldDescs.length; i++) {
0985:                    FieldDescriptor fd = fieldDescs[i];
0986:                    PersistentField f = fd.getPersistentField();
0987:                    f.set(obj, fields[count]);
0988:                    count++;
0989:                }
0990:
0991:                for (Iterator it = refDescs.iterator(); it.hasNext(); count++) {
0992:                    ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) it
0993:                            .next();
0994:                    PersistentField f = rds.getPersistentField();
0995:                    Identity oid = (Identity) fields[count];
0996:                    Object relObj;
0997:                    if (oid == null) {
0998:                        relObj = null;
0999:                    } else {
1000:                        relObj = _pb.getObjectByIdentity(oid);
1001:                    }
1002:                    f.set(obj, relObj);
1003:                }
1004:
1005:                count = 0;
1006:                for (Iterator it = colDescs.iterator(); it.hasNext(); count++) {
1007:                    CollectionDescriptor cds = (CollectionDescriptor) it.next();
1008:                    PersistentField f = cds.getPersistentField();
1009:                    ArrayList list = collections[count];
1010:                    ArrayList newCol;
1011:
1012:                    if (list == null) {
1013:                        f.set(obj, null);
1014:                    } else {
1015:                        newCol = new ArrayList();
1016:                        for (Iterator it2 = list.iterator(); it2.hasNext();) {
1017:                            Identity relOid = (Identity) it2.next();
1018:                            Object relObj = _pb.getObjectByIdentity(relOid);
1019:
1020:                            if (relObj != null) {
1021:                                newCol.add(relObj);
1022:                            }
1023:                        }
1024:                        setCollectionField(obj, f, newCol);
1025:                    }
1026:                }
1027:            }
1028:
1029:            private void setCollectionField(Object obj, PersistentField f,
1030:                    List newCol) {
1031:                Class type = f.getType();
1032:
1033:                if (Collection.class.isAssignableFrom(type)) {
1034:                    Collection col = (Collection) f.get(obj);
1035:
1036:                    if (col == null) {
1037:                        if (type == List.class || type == Collection.class) {
1038:                            col = new ArrayList();
1039:                        } else if (type == Set.class) {
1040:                            col = new HashSet();
1041:                        } else {
1042:                            try {
1043:                                col = (Collection) type.newInstance();
1044:                            } catch (Throwable ex) {
1045:                                System.err
1046:                                        .println("Cannot instantiate collection field: "
1047:                                                + f);
1048:                                ex.printStackTrace();
1049:                                return;
1050:                            }
1051:                        }
1052:                    } else {
1053:                        if (col instanceof  CollectionProxyDefaultImpl) {
1054:                            CollectionProxyDefaultImpl cp = (CollectionProxyDefaultImpl) col;
1055:                            if (col instanceof  List) {
1056:                                col = new ListProxyDefaultImpl(_pb.getPBKey(),
1057:                                        cp.getData().getClass(), null);
1058:                            } else if (col instanceof  Set) {
1059:                                col = new SetProxyDefaultImpl(_pb.getPBKey(),
1060:                                        cp.getData().getClass(), null);
1061:                            } else {
1062:                                col = new CollectionProxyDefaultImpl(_pb
1063:                                        .getPBKey(), cp.getData().getClass(),
1064:                                        null);
1065:                            }
1066:                            col.clear();
1067:                        } else {
1068:                            try {
1069:                                col = (Collection) col.getClass().newInstance();
1070:                            } catch (Exception ex) {
1071:                                System.err
1072:                                        .println("Cannot instantiate collection field: "
1073:                                                + f);
1074:                                ex.printStackTrace();
1075:                                return;
1076:                            }
1077:                        }
1078:                    }
1079:                    col.addAll(newCol);
1080:                    f.set(obj, col);
1081:                } else if (type.isArray()) {
1082:                    int length = newCol.size();
1083:                    Object array = Array.newInstance(type.getComponentType(),
1084:                            length);
1085:
1086:                    for (int i = 0; i < length; i++) {
1087:                        Array.set(array, i, newCol.get(i));
1088:                    }
1089:                    f.set(obj, array);
1090:                }
1091:            }
1092:
1093:            /**
1094:             * Does the given class has bidirectional assiciation
1095:             * with some other class?
1096:             */
1097:            private boolean hasBidirectionalAssociation(Class clazz) {
1098:                ClassDescriptor cdesc;
1099:                Collection refs;
1100:                boolean hasBidirAssc;
1101:
1102:                if (_withoutBidirAssc.contains(clazz)) {
1103:                    return false;
1104:                }
1105:
1106:                if (_withBidirAssc.contains(clazz)) {
1107:                    return true;
1108:                }
1109:
1110:                // first time we meet this class, let's look at metadata
1111:                cdesc = _pb.getClassDescriptor(clazz);
1112:                refs = cdesc.getObjectReferenceDescriptors();
1113:                hasBidirAssc = false;
1114:                REFS_CYCLE: for (Iterator it = refs.iterator(); it.hasNext();) {
1115:                    ObjectReferenceDescriptor ord;
1116:                    ClassDescriptor relCDesc;
1117:                    Collection relRefs;
1118:
1119:                    ord = (ObjectReferenceDescriptor) it.next();
1120:                    relCDesc = _pb.getClassDescriptor(ord.getItemClass());
1121:                    relRefs = relCDesc.getObjectReferenceDescriptors();
1122:                    for (Iterator relIt = relRefs.iterator(); relIt.hasNext();) {
1123:                        ObjectReferenceDescriptor relOrd;
1124:
1125:                        relOrd = (ObjectReferenceDescriptor) relIt.next();
1126:                        if (relOrd.getItemClass().equals(clazz)) {
1127:                            hasBidirAssc = true;
1128:                            break REFS_CYCLE;
1129:                        }
1130:                    }
1131:                }
1132:                if (hasBidirAssc) {
1133:                    _withBidirAssc.add(clazz);
1134:                } else {
1135:                    _withoutBidirAssc.add(clazz);
1136:                }
1137:
1138:                return hasBidirAssc;
1139:            }
1140:
1141:            /**
1142:             * @return number of deleted objects: 1 or 0 (if the object is already deleted)
1143:             */
1144:            private int markDelete(Identity oid, Identity mainOid,
1145:                    boolean isCollection) {
1146:                ContextEntry entry = (ContextEntry) _objects.get(oid);
1147:
1148:                if (entry == null) {
1149:                    throw new IllegalStateException(
1150:                            "markDelete failed: the dependent object " + oid
1151:                                    + " is not in the editing context");
1152:                }
1153:
1154:                if (entry.state.isDeleted()) {
1155:                    return 0;
1156:                } else {
1157:                    entry.state = entry.state.deletePersistent();
1158:                    if (mainOid != null) {
1159:                        int dependentIndex = _order.indexOf(oid);
1160:                        int mainIndex = _order.indexOf(mainOid);
1161:
1162:                        if (isCollection) // remove collection item before main obj
1163:                        {
1164:                            if (dependentIndex > mainIndex) {
1165:                                _order.remove(dependentIndex);
1166:                                _order.add(mainIndex, oid);
1167:                            }
1168:                        } else // remove reference after main obj
1169:                        {
1170:                            if (dependentIndex < mainIndex) {
1171:                                _order.remove(dependentIndex); // this causes mainIndex--
1172:                                _order.add(mainIndex, oid);
1173:                            }
1174:                        }
1175:
1176:                    }
1177:                    return 1;
1178:                }
1179:            }
1180:
1181:            /**
1182:             * Mark for creation all newly introduced dependent references.
1183:             * Mark for deletion all nullified dependent references.
1184:             * @return the list of created objects
1185:             */
1186:            private ArrayList handleDependentReferences(Identity oid,
1187:                    Object userObject, Object[] origFields, Object[] newFields,
1188:                    Object[] newRefs) throws LockingException {
1189:                ClassDescriptor mif = _pb.getClassDescriptor(userObject
1190:                        .getClass());
1191:                FieldDescriptor[] fieldDescs = mif.getFieldDescriptions();
1192:                Collection refDescs = mif.getObjectReferenceDescriptors();
1193:                int count = 1 + fieldDescs.length;
1194:                ArrayList newObjects = new ArrayList();
1195:                int countRefs = 0;
1196:
1197:                for (Iterator it = refDescs.iterator(); it.hasNext(); count++, countRefs++) {
1198:                    ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) it
1199:                            .next();
1200:                    Identity origOid = (origFields == null ? null
1201:                            : (Identity) origFields[count]);
1202:                    Identity newOid = (Identity) newFields[count];
1203:
1204:                    if (rds.getOtmDependent()) {
1205:                        if ((origOid == null) && (newOid != null)) {
1206:                            ContextEntry entry = (ContextEntry) _objects
1207:                                    .get(newOid);
1208:
1209:                            if (entry == null) {
1210:                                Object relObj = newRefs[countRefs];
1211:                                insertInternal(newOid, relObj,
1212:                                        LockType.WRITE_LOCK, true, oid,
1213:                                        new Stack());
1214:                                newObjects.add(newOid);
1215:                            }
1216:                        } else if ((origOid != null)
1217:                                && ((newOid == null) || !newOid.equals(origOid))) {
1218:                            markDelete(origOid, oid, false);
1219:                        }
1220:                    }
1221:                }
1222:
1223:                return newObjects;
1224:            }
1225:
1226:            /**
1227:             * Mark for creation all objects that were included into dependent collections.
1228:             * Mark for deletion all objects that were excluded from dependent collections.
1229:             */
1230:            private ArrayList handleDependentCollections(Identity oid,
1231:                    Object obj, Object[] origCollections,
1232:                    Object[] newCollections, Object[] newCollectionsOfObjects)
1233:                    throws LockingException {
1234:                ClassDescriptor mif = _pb.getClassDescriptor(obj.getClass());
1235:                Collection colDescs = mif.getCollectionDescriptors();
1236:                ArrayList newObjects = new ArrayList();
1237:                int count = 0;
1238:
1239:                for (Iterator it = colDescs.iterator(); it.hasNext(); count++) {
1240:                    CollectionDescriptor cds = (CollectionDescriptor) it.next();
1241:
1242:                    if (cds.getOtmDependent()) {
1243:                        ArrayList origList = (origCollections == null ? null
1244:                                : (ArrayList) origCollections[count]);
1245:                        ArrayList newList = (ArrayList) newCollections[count];
1246:
1247:                        if (origList != null) {
1248:                            for (Iterator it2 = origList.iterator(); it2
1249:                                    .hasNext();) {
1250:                                Identity origOid = (Identity) it2.next();
1251:
1252:                                if ((newList == null)
1253:                                        || !newList.contains(origOid)) {
1254:                                    markDelete(origOid, oid, true);
1255:                                }
1256:                            }
1257:                        }
1258:
1259:                        if (newList != null) {
1260:                            int countElem = 0;
1261:                            for (Iterator it2 = newList.iterator(); it2
1262:                                    .hasNext(); countElem++) {
1263:                                Identity newOid = (Identity) it2.next();
1264:
1265:                                if ((origList == null)
1266:                                        || !origList.contains(newOid)) {
1267:                                    ContextEntry entry = (ContextEntry) _objects
1268:                                            .get(newOid);
1269:
1270:                                    if (entry == null) {
1271:                                        ArrayList relCol = (ArrayList) newCollectionsOfObjects[count];
1272:                                        Object relObj = relCol.get(countElem);
1273:                                        insertInternal(newOid, relObj,
1274:                                                LockType.WRITE_LOCK, true,
1275:                                                null, new Stack());
1276:                                        newObjects.add(newOid);
1277:                                    }
1278:                                }
1279:                            }
1280:                        }
1281:                    }
1282:                }
1283:
1284:                return newObjects;
1285:            }
1286:
1287:            /**
1288:             * Mark for deletion all dependent objects (via references and collections).
1289:             * @return the number of deleted objects
1290:             */
1291:            private int doCascadeDelete(Identity oid, Object obj) {
1292:                ClassDescriptor mif = _pb.getClassDescriptor(ProxyHelper
1293:                        .getRealClass(obj));
1294:                Collection refDescs = mif.getObjectReferenceDescriptors();
1295:                Collection colDescs = mif.getCollectionDescriptors();
1296:                int countCascadeDeleted = 0;
1297:
1298:                for (Iterator it = refDescs.iterator(); it.hasNext();) {
1299:                    ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) it
1300:                            .next();
1301:
1302:                    if (rds.getOtmDependent()) {
1303:                        PersistentField f = rds.getPersistentField();
1304:                        Object relObj = f.get(obj);
1305:
1306:                        if (relObj != null) {
1307:                            countCascadeDeleted += markDelete(new Identity(
1308:                                    relObj, _pb), oid, false);
1309:                        }
1310:                    }
1311:                }
1312:
1313:                for (Iterator it = colDescs.iterator(); it.hasNext();) {
1314:                    CollectionDescriptor cds = (CollectionDescriptor) it.next();
1315:
1316:                    if (cds.getOtmDependent()) {
1317:                        PersistentField f = cds.getPersistentField();
1318:                        Class type = f.getType();
1319:                        Object col = f.get(obj);
1320:
1321:                        if (col != null) {
1322:                            Iterator colIterator;
1323:
1324:                            if (Collection.class.isAssignableFrom(type)) {
1325:                                colIterator = ((Collection) col).iterator();
1326:                            } else if (type.isArray()) {
1327:                                colIterator = new ArrayIterator(col);
1328:                            } else {
1329:                                continue;
1330:                            }
1331:
1332:                            while (colIterator.hasNext()) {
1333:
1334:                                countCascadeDeleted += markDelete(new Identity(
1335:                                        colIterator.next(), _pb), oid, true);
1336:                            }
1337:                        }
1338:                    }
1339:                }
1340:
1341:                return countCascadeDeleted;
1342:            }
1343:
1344:            /*
1345:             * The rest of ObjectCache implementation for swizling
1346:             * All methods except lookup() are never used by swizzling,
1347:             * remove() appeared to already exist in this class
1348:             * with the same signature as in ObjectCache interface,
1349:             * other methods are unsupported.
1350:             */
1351:            public void cache(Identity oid, Object obj) {
1352:                throw new UnsupportedOperationException();
1353:            }
1354:
1355:            public boolean cacheIfNew(Identity oid, Object obj) {
1356:                // not implemented
1357:                throw new UnsupportedOperationException("Not implemented");
1358:            }
1359:
1360:            public void clear() {
1361:                throw new UnsupportedOperationException();
1362:            }
1363:
1364:            //////////////////////////////////////////
1365:            // Inner classes
1366:            //////////////////////////////////////////
1367:
1368:            private static class ContextEntry {
1369:                Object userObject;
1370:                Object cacheObject;
1371:                State state = State.PERSISTENT_CLEAN;
1372:
1373:                /**
1374:                 * Handler the proxy object, null if the object is real
1375:                 */
1376:                IndirectionHandler handler;
1377:
1378:                /**
1379:                 * This flag is used during commit/checkpoint
1380:                 */
1381:                boolean needsCacheSwizzle;
1382:
1383:                ContextEntry(Object theUserObject) {
1384:                    userObject = theUserObject;
1385:                    if (userObject != null) {
1386:                        handler = ProxyHelper.getIndirectionHandler(userObject);
1387:                        if ((handler != null) && handler.alreadyMaterialized()) {
1388:                            userObject = handler.getRealSubject();
1389:                            handler = null;
1390:                        }
1391:                    }
1392:                }
1393:            }
1394:
1395:            private class OTMCollectionProxyListener implements 
1396:                    CollectionProxyListener {
1397:                private final CollectionDescriptor _cds;
1398:                private final ArrayList[] _collections;
1399:                private final int _index;
1400:                private final int _lock;
1401:
1402:                OTMCollectionProxyListener(CollectionDescriptor cds,
1403:                        ArrayList[] collections, int index, int lock) {
1404:                    _cds = cds;
1405:                    _collections = collections;
1406:                    _index = index;
1407:                    _lock = lock;
1408:                }
1409:
1410:                public void beforeLoading(CollectionProxyDefaultImpl colProxy) {
1411:                    // do nothing
1412:                }
1413:
1414:                /**
1415:                 * The collection proxy contains PB cache objects. We have to replace it
1416:                 * with a collection of user objects.
1417:                 */
1418:                public void afterLoading(CollectionProxyDefaultImpl colProxy) {
1419:                    ArrayList list = new ArrayList();
1420:                    ArrayList newUserCol = new ArrayList();
1421:                    LockManager lockManager = LockManager.getInstance();
1422:                    _collections[_index] = list;
1423:
1424:                    for (Iterator it = colProxy.iterator(); it.hasNext();) {
1425:                        Object relUserObj;
1426:                        Object relCacheObj = it.next();
1427:                        Identity relOid = new Identity(relCacheObj, _pb);
1428:                        ContextEntry entry;
1429:
1430:                        list.add(relOid);
1431:                        entry = (ContextEntry) _objects.get(relOid);
1432:                        if (entry != null) {
1433:                            relUserObj = entry.userObject;
1434:                        } else {
1435:                            ObjectCopyStrategy copyStrategy;
1436:
1437:                            copyStrategy = _tx.getKit().getCopyStrategy(relOid);
1438:                            relUserObj = copyStrategy.copy(relCacheObj, _pb);
1439:                            try {
1440:                                entry = insertInternal(relOid, relUserObj,
1441:                                        _lock, _cds.getOtmDependent(), null,
1442:                                        new Stack());
1443:                                if (entry != null) {
1444:                                    relUserObj = entry.userObject;
1445:                                }
1446:                            } catch (LockingException ex) {
1447:                                throw new LockingPassthruException(ex);
1448:                            }
1449:                        }
1450:                        newUserCol.add(relUserObj);
1451:                    }
1452:                    colProxy.clear();
1453:                    colProxy.addAll(newUserCol);
1454:                }
1455:            }
1456:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.