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


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one
0003:         * or more contributor license agreements.  See the NOTICE file
0004:         * distributed with this work for additional information
0005:         * regarding copyright ownership.  The ASF licenses this file
0006:         * to you under the Apache License, Version 2.0 (the
0007:         * "License"); you may not use this file except in compliance
0008:         * with the License.  You may obtain a copy of the License at
0009:         *
0010:         * http://www.apache.org/licenses/LICENSE-2.0
0011:         *
0012:         * Unless required by applicable law or agreed to in writing,
0013:         * software distributed under the License is distributed on an
0014:         * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015:         * KIND, either express or implied.  See the License for the
0016:         * specific language governing permissions and limitations
0017:         * under the License.    
0018:         */
0019:        package org.apache.openjpa.kernel;
0020:
0021:        import java.io.IOException;
0022:        import java.io.ObjectInputStream;
0023:        import java.io.ObjectOutputStream;
0024:        import java.io.Serializable;
0025:        import java.lang.reflect.Modifier;
0026:        import java.security.AccessController;
0027:        import java.util.AbstractCollection;
0028:        import java.util.ArrayList;
0029:        import java.util.BitSet;
0030:        import java.util.Collection;
0031:        import java.util.Collections;
0032:        import java.util.HashMap;
0033:        import java.util.HashSet;
0034:        import java.util.Iterator;
0035:        import java.util.LinkedList;
0036:        import java.util.List;
0037:        import java.util.Map;
0038:        import java.util.Set;
0039:        import javax.transaction.Status;
0040:        import javax.transaction.Synchronization;
0041:
0042:        import org.apache.commons.collections.iterators.IteratorChain;
0043:        import org.apache.commons.collections.map.IdentityMap;
0044:        import org.apache.commons.collections.map.LinkedMap;
0045:        import org.apache.commons.collections.set.MapBackedSet;
0046:        import org.apache.openjpa.conf.Compatibility;
0047:        import org.apache.openjpa.conf.OpenJPAConfiguration;
0048:        import org.apache.openjpa.datacache.DataCache;
0049:        import org.apache.openjpa.ee.ManagedRuntime;
0050:        import org.apache.openjpa.enhance.PCRegistry;
0051:        import org.apache.openjpa.enhance.PersistenceCapable;
0052:        import org.apache.openjpa.event.LifecycleEvent;
0053:        import org.apache.openjpa.event.LifecycleEventManager;
0054:        import org.apache.openjpa.event.RemoteCommitEventManager;
0055:        import org.apache.openjpa.event.TransactionEvent;
0056:        import org.apache.openjpa.event.TransactionEventManager;
0057:        import org.apache.openjpa.kernel.exps.ExpressionParser;
0058:        import org.apache.openjpa.lib.log.Log;
0059:        import org.apache.openjpa.lib.util.J2DoPrivHelper;
0060:        import org.apache.openjpa.lib.util.Localizer;
0061:        import org.apache.openjpa.lib.util.ReferenceHashMap;
0062:        import org.apache.openjpa.lib.util.ReferenceHashSet;
0063:        import org.apache.openjpa.lib.util.ReferenceMap;
0064:        import org.apache.openjpa.lib.util.concurrent.ReentrantLock;
0065:        import org.apache.openjpa.meta.ClassMetaData;
0066:        import org.apache.openjpa.meta.FieldMetaData;
0067:        import org.apache.openjpa.meta.MetaDataRepository;
0068:        import org.apache.openjpa.meta.SequenceMetaData;
0069:        import org.apache.openjpa.meta.ValueMetaData;
0070:        import org.apache.openjpa.meta.ValueStrategies;
0071:        import org.apache.openjpa.util.ApplicationIds;
0072:        import org.apache.openjpa.util.CallbackException;
0073:        import org.apache.openjpa.util.Exceptions;
0074:        import org.apache.openjpa.util.GeneralException;
0075:        import org.apache.openjpa.util.ImplHelper;
0076:        import org.apache.openjpa.util.InternalException;
0077:        import org.apache.openjpa.util.InvalidStateException;
0078:        import org.apache.openjpa.util.NoTransactionException;
0079:        import org.apache.openjpa.util.ObjectExistsException;
0080:        import org.apache.openjpa.util.ObjectId;
0081:        import org.apache.openjpa.util.ObjectNotFoundException;
0082:        import org.apache.openjpa.util.OpenJPAException;
0083:        import org.apache.openjpa.util.OptimisticException;
0084:        import org.apache.openjpa.util.RuntimeExceptionTranslator;
0085:        import org.apache.openjpa.util.StoreException;
0086:        import org.apache.openjpa.util.UnsupportedException;
0087:        import org.apache.openjpa.util.UserException;
0088:
0089:        /**
0090:         * Concrete {@link Broker}. The broker handles object-level behavior,
0091:         * but leaves all interaction with the data store to a {@link StoreManager}
0092:         * that must be supplied at initialization.
0093:         *
0094:         * @author Abe White
0095:         */
0096:        public class BrokerImpl implements  Broker, FindCallbacks, Cloneable,
0097:                Serializable {
0098:
0099:            /**
0100:             * Incremental flush.
0101:             */
0102:            protected static final int FLUSH_INC = 0;
0103:
0104:            /**
0105:             * Flush in preparation of commit.
0106:             */
0107:            protected static final int FLUSH_COMMIT = 1;
0108:
0109:            /**
0110:             * Flush to check consistency of cache, then immediately rollback changes.
0111:             */
0112:            protected static final int FLUSH_ROLLBACK = 2;
0113:
0114:            /**
0115:             * Run persistence-by-reachability and other flush-time operations without
0116:             * accessing the database.
0117:             */
0118:            protected static final int FLUSH_LOGICAL = 3;
0119:
0120:            static final int STATUS_INIT = 0;
0121:            static final int STATUS_TRANSIENT = 1;
0122:            static final int STATUS_OID_ASSIGN = 2;
0123:            static final int STATUS_COMMIT_NEW = 3;
0124:
0125:            private static final int FLAG_ACTIVE = 2 << 0;
0126:            private static final int FLAG_STORE_ACTIVE = 2 << 1;
0127:            private static final int FLAG_CLOSE_INVOKED = 2 << 2;
0128:            private static final int FLAG_PRESTORING = 2 << 3;
0129:            private static final int FLAG_DEREFDELETING = 2 << 4;
0130:            private static final int FLAG_FLUSHING = 2 << 5;
0131:            private static final int FLAG_STORE_FLUSHING = 2 << 6;
0132:            private static final int FLAG_FLUSHED = 2 << 7;
0133:            private static final int FLAG_FLUSH_REQUIRED = 2 << 8;
0134:            private static final int FLAG_REMOTE_LISTENER = 2 << 9;
0135:            private static final int FLAG_RETAINED_CONN = 2 << 10;
0136:            private static final int FLAG_TRANS_ENDING = 2 << 11;
0137:
0138:            private static final Object[] EMPTY_OBJECTS = new Object[0];
0139:
0140:            private static final Localizer _loc = Localizer
0141:                    .forPackage(BrokerImpl.class);
0142:
0143:            //	the store manager in use; this may be a decorator such as a
0144:            //	data cache store manager around the native store manager
0145:            private transient DelegatingStoreManager _store = null;
0146:
0147:            private FetchConfiguration _fc = null;
0148:            private String _user = null;
0149:            private String _pass = null;
0150:
0151:            // these must be rebuilt by the facade layer during its deserialization
0152:            private transient Log _log = null;
0153:            private transient Compatibility _compat = null;
0154:            private transient ManagedRuntime _runtime = null;
0155:            private transient LockManager _lm = null;
0156:            private transient InverseManager _im = null;
0157:            private transient ReentrantLock _lock = null;
0158:            private transient OpCallbacks _call = null;
0159:            private transient RuntimeExceptionTranslator _extrans = null;
0160:
0161:            // ref to producing factory and configuration
0162:            private transient AbstractBrokerFactory _factory = null;
0163:            private transient OpenJPAConfiguration _conf = null;
0164:
0165:            // cache class loader associated with the broker
0166:            private transient ClassLoader _loader = null;
0167:
0168:            // user state
0169:            private Synchronization _sync = null;
0170:            private Map _userObjects = null;
0171:
0172:            // managed object caches
0173:            private ManagedCache _cache = null;
0174:            private TransactionalCache _transCache = null;
0175:            private Set _transAdditions = null;
0176:            private Set _derefCache = null;
0177:            private Set _derefAdditions = null;
0178:
0179:            // these are used for method-internal state only
0180:            private transient Map _loading = null;
0181:            private transient Set _operating = null;
0182:
0183:            private Set _persistedClss = null;
0184:            private Set _updatedClss = null;
0185:            private Set _deletedClss = null;
0186:            private Set _pending = null;
0187:            private int findAllDepth = 0;
0188:
0189:            // track instances that become transactional after the first savepoint
0190:            // (the first uses the transactional cache)
0191:            private Set _savepointCache = null;
0192:            private LinkedMap _savepoints = null;
0193:            private transient SavepointManager _spm = null;
0194:
0195:            // track open queries and extents so we can free their resources on close
0196:            private transient ReferenceHashSet _queries = null;
0197:            private transient ReferenceHashSet _extents = null;
0198:
0199:            // track operation stack depth. Transient because operations cannot
0200:            // span serialization.
0201:            private transient int _operationCount = 0;
0202:
0203:            // options
0204:            private boolean _nontransRead = false;
0205:            private boolean _nontransWrite = false;
0206:            private boolean _retainState = false;
0207:            private int _autoClear = CLEAR_DATASTORE;
0208:            private int _restoreState = RESTORE_IMMUTABLE;
0209:            private boolean _optimistic = false;
0210:            private boolean _ignoreChanges = false;
0211:            private boolean _multithreaded = false;
0212:            private boolean _managed = false;
0213:            private boolean _syncManaged = false;
0214:            private int _connRetainMode = CONN_RETAIN_DEMAND;
0215:            private boolean _evictDataCache = false;
0216:            private boolean _populateDataCache = true;
0217:            private boolean _largeTransaction = false;
0218:            private int _autoDetach = 0;
0219:            private int _detachState = DETACH_LOADED;
0220:            private boolean _detachedNew = true;
0221:            private boolean _orderDirty = false;
0222:
0223:            // status
0224:            private int _flags = 0;
0225:
0226:            // this is not in status because it should not be serialized
0227:            private transient boolean _isSerializing = false;
0228:
0229:            // transient because closed brokers can't be serialized
0230:            private transient boolean _closed = false;
0231:            private transient RuntimeException _closedException = null;
0232:
0233:            // event managers
0234:            private TransactionEventManager _transEventManager = null;
0235:            private int _transCallbackMode = 0;
0236:            private LifecycleEventManager _lifeEventManager = null;
0237:            private int _lifeCallbackMode = 0;
0238:
0239:            private transient boolean _initializeWasInvoked = false;
0240:
0241:            /**
0242:             * Set the persistence manager's authentication. This is the first
0243:             * method called after construction.
0244:             *
0245:             * @param user the username this broker represents; used when pooling
0246:             * brokers to make sure that a request to the factory for
0247:             * a connection with an explicit user is delegated to a suitable broker
0248:             * @param pass the password for the above user
0249:             */
0250:            public void setAuthentication(String user, String pass) {
0251:                _user = user;
0252:                _pass = pass;
0253:            }
0254:
0255:            /**
0256:             * Initialize the persistence manager. This method is called
0257:             * automatically by the factory before use.
0258:             *
0259:             * @param factory the factory used to create this broker
0260:             * @param sm a concrete StoreManager implementation to
0261:             * handle interaction with the data store
0262:             * @param managed the transaction mode
0263:             * @param connMode the connection retain mode
0264:             * @param fromDeserialization whether this call happened because of a
0265:             * deserialization or creation of a new BrokerImpl.
0266:             */
0267:            public void initialize(AbstractBrokerFactory factory,
0268:                    DelegatingStoreManager sm, boolean managed, int connMode,
0269:                    boolean fromDeserialization) {
0270:                _initializeWasInvoked = true;
0271:                _loader = (ClassLoader) AccessController
0272:                        .doPrivileged(J2DoPrivHelper
0273:                                .getContextClassLoaderAction());
0274:                if (!fromDeserialization)
0275:                    _conf = factory.getConfiguration();
0276:                _compat = _conf.getCompatibilityInstance();
0277:                _factory = factory;
0278:                _log = _conf.getLog(OpenJPAConfiguration.LOG_RUNTIME);
0279:                if (!fromDeserialization)
0280:                    _cache = new ManagedCache(this );
0281:                initializeOperatingSet();
0282:                _connRetainMode = connMode;
0283:                _managed = managed;
0284:                if (managed)
0285:                    _runtime = _conf.getManagedRuntimeInstance();
0286:                else
0287:                    _runtime = new LocalManagedRuntime(this );
0288:
0289:                if (!fromDeserialization) {
0290:                    _lifeEventManager = new LifecycleEventManager();
0291:                    _transEventManager = new TransactionEventManager();
0292:                    int cmode = _conf.getMetaDataRepositoryInstance()
0293:                            .getMetaDataFactory().getDefaults()
0294:                            .getCallbackMode();
0295:                    setLifecycleListenerCallbackMode(cmode);
0296:                    setTransactionListenerCallbackMode(cmode);
0297:
0298:                    // setup default options
0299:                    _factory.configureBroker(this );
0300:                }
0301:
0302:                // make sure to do this after configuring broker so that store manager
0303:                // can look to broker configuration; we set both store and lock managers
0304:                // before initializing them because they may each try to access the
0305:                // other in thier initialization
0306:                _store = sm;
0307:                _lm = _conf.newLockManagerInstance();
0308:                _im = _conf.newInverseManagerInstance();
0309:                _spm = _conf.getSavepointManagerInstance();
0310:                _store.setContext(this );
0311:                _lm.setContext(this );
0312:
0313:                if (_connRetainMode == CONN_RETAIN_ALWAYS)
0314:                    retainConnection();
0315:                if (!fromDeserialization) {
0316:                    _fc = _store.newFetchConfiguration();
0317:                    _fc.setContext(this );
0318:                }
0319:
0320:                // synch with the global transaction in progress, if any
0321:                if (_factory.syncWithManagedTransaction(this , false))
0322:                    beginInternal();
0323:            }
0324:
0325:            private void initializeOperatingSet() {
0326:                _operating = MapBackedSet.decorate(new IdentityMap());
0327:            }
0328:
0329:            /**
0330:             * Gets the unmodifiable set of instances being operated.
0331:             */
0332:            protected Set getOperatingSet() {
0333:                return Collections.unmodifiableSet(_operating);
0334:            }
0335:
0336:            public Object clone() throws CloneNotSupportedException {
0337:                if (_initializeWasInvoked)
0338:                    throw new CloneNotSupportedException();
0339:                else {
0340:                    return super .clone();
0341:                }
0342:            }
0343:
0344:            /**
0345:             * Create a {@link Map} to be used for the primary managed object cache.
0346:             * Maps oids to state managers. By default, this creates a
0347:             * {@link ReferenceMap} with soft values.
0348:             */
0349:            protected Map newManagedObjectCache() {
0350:                return new ReferenceHashMap(ReferenceMap.HARD,
0351:                        ReferenceMap.SOFT);
0352:            }
0353:
0354:            //////////////////////////////////
0355:            // Implementation of StoreContext
0356:            //////////////////////////////////
0357:
0358:            public Broker getBroker() {
0359:                return this ;
0360:            }
0361:
0362:            //////////////
0363:            // Properties
0364:            //////////////
0365:
0366:            public void setImplicitBehavior(OpCallbacks call,
0367:                    RuntimeExceptionTranslator ex) {
0368:                if (_call == null)
0369:                    _call = call;
0370:                if (_extrans == null)
0371:                    _extrans = ex;
0372:            }
0373:
0374:            RuntimeExceptionTranslator getInstanceExceptionTranslator() {
0375:                return (_operationCount == 0) ? _extrans : null;
0376:            }
0377:
0378:            public BrokerFactory getBrokerFactory() {
0379:                return _factory;
0380:            }
0381:
0382:            public OpenJPAConfiguration getConfiguration() {
0383:                return _conf;
0384:            }
0385:
0386:            public FetchConfiguration getFetchConfiguration() {
0387:                return _fc;
0388:            }
0389:
0390:            public int getConnectionRetainMode() {
0391:                return _connRetainMode;
0392:            }
0393:
0394:            public boolean isManaged() {
0395:                return _managed;
0396:            }
0397:
0398:            public ManagedRuntime getManagedRuntime() {
0399:                return _runtime;
0400:            }
0401:
0402:            public ClassLoader getClassLoader() {
0403:                return _loader;
0404:            }
0405:
0406:            public DelegatingStoreManager getStoreManager() {
0407:                return _store;
0408:            }
0409:
0410:            public LockManager getLockManager() {
0411:                return _lm;
0412:            }
0413:
0414:            public InverseManager getInverseManager() {
0415:                return _im;
0416:            }
0417:
0418:            public String getConnectionUserName() {
0419:                return _user;
0420:            }
0421:
0422:            public String getConnectionPassword() {
0423:                return _pass;
0424:            }
0425:
0426:            public boolean getMultithreaded() {
0427:                return _multithreaded;
0428:            }
0429:
0430:            public void setMultithreaded(boolean multithreaded) {
0431:                assertOpen();
0432:                _multithreaded = multithreaded;
0433:                if (multithreaded && _lock == null)
0434:                    _lock = new ReentrantLock();
0435:                else if (!multithreaded)
0436:                    _lock = null;
0437:            }
0438:
0439:            public boolean getIgnoreChanges() {
0440:                return _ignoreChanges;
0441:            }
0442:
0443:            public void setIgnoreChanges(boolean val) {
0444:                assertOpen();
0445:                _ignoreChanges = val;
0446:            }
0447:
0448:            public boolean getNontransactionalRead() {
0449:                return _nontransRead;
0450:            }
0451:
0452:            public void setNontransactionalRead(boolean val) {
0453:                assertOpen();
0454:                if ((_flags & FLAG_PRESTORING) != 0)
0455:                    throw new UserException(_loc.get("illegal-op-in-prestore"));
0456:
0457:                // make sure the runtime supports it
0458:                if (val
0459:                        && !_conf.supportedOptions().contains(
0460:                                _conf.OPTION_NONTRANS_READ))
0461:                    throw new UnsupportedException(_loc
0462:                            .get("nontrans-read-not-supported"));
0463:
0464:                _nontransRead = val;
0465:            }
0466:
0467:            public boolean getNontransactionalWrite() {
0468:                return _nontransWrite;
0469:            }
0470:
0471:            public void setNontransactionalWrite(boolean val) {
0472:                assertOpen();
0473:                if ((_flags & FLAG_PRESTORING) != 0)
0474:                    throw new UserException(_loc.get("illegal-op-in-prestore"));
0475:
0476:                _nontransWrite = val;
0477:            }
0478:
0479:            public boolean getOptimistic() {
0480:                return _optimistic;
0481:            }
0482:
0483:            public void setOptimistic(boolean val) {
0484:                assertOpen();
0485:                if ((_flags & FLAG_ACTIVE) != 0)
0486:                    throw new InvalidStateException(_loc.get("trans-active",
0487:                            "Optimistic"));
0488:
0489:                // make sure the runtime supports it
0490:                if (val
0491:                        && !_conf.supportedOptions().contains(
0492:                                _conf.OPTION_OPTIMISTIC))
0493:                    throw new UnsupportedException(_loc
0494:                            .get("optimistic-not-supported"));
0495:
0496:                _optimistic = val;
0497:            }
0498:
0499:            public int getRestoreState() {
0500:                return _restoreState;
0501:            }
0502:
0503:            public void setRestoreState(int val) {
0504:                assertOpen();
0505:                if ((_flags & FLAG_ACTIVE) != 0)
0506:                    throw new InvalidStateException(_loc.get("trans-active",
0507:                            "Restore"));
0508:
0509:                _restoreState = val;
0510:            }
0511:
0512:            public boolean getRetainState() {
0513:                return _retainState;
0514:            }
0515:
0516:            public void setRetainState(boolean val) {
0517:                assertOpen();
0518:                if ((_flags & FLAG_PRESTORING) != 0)
0519:                    throw new UserException(_loc.get("illegal-op-in-prestore"));
0520:                _retainState = val;
0521:            }
0522:
0523:            public int getAutoClear() {
0524:                return _autoClear;
0525:            }
0526:
0527:            public void setAutoClear(int val) {
0528:                assertOpen();
0529:                _autoClear = val;
0530:            }
0531:
0532:            public int getAutoDetach() {
0533:                return _autoDetach;
0534:            }
0535:
0536:            public void setAutoDetach(int detachFlags) {
0537:                assertOpen();
0538:                _autoDetach = detachFlags;
0539:            }
0540:
0541:            public void setAutoDetach(int detachFlag, boolean on) {
0542:                assertOpen();
0543:                if (on)
0544:                    _autoDetach |= detachFlag;
0545:                else
0546:                    _autoDetach &= ~detachFlag;
0547:            }
0548:
0549:            public int getDetachState() {
0550:                return _detachState;
0551:            }
0552:
0553:            public void setDetachState(int mode) {
0554:                assertOpen();
0555:                _detachState = mode;
0556:            }
0557:
0558:            public boolean isDetachedNew() {
0559:                return _detachedNew;
0560:            }
0561:
0562:            public void setDetachedNew(boolean isNew) {
0563:                assertOpen();
0564:                _detachedNew = isNew;
0565:            }
0566:
0567:            public boolean getSyncWithManagedTransactions() {
0568:                return _syncManaged;
0569:            }
0570:
0571:            public void setSyncWithManagedTransactions(boolean sync) {
0572:                assertOpen();
0573:                _syncManaged = sync;
0574:            }
0575:
0576:            public boolean getEvictFromDataCache() {
0577:                return _evictDataCache;
0578:            }
0579:
0580:            public void setEvictFromDataCache(boolean evict) {
0581:                assertOpen();
0582:                _evictDataCache = evict;
0583:            }
0584:
0585:            public boolean getPopulateDataCache() {
0586:                return _populateDataCache;
0587:            }
0588:
0589:            public void setPopulateDataCache(boolean cache) {
0590:                assertOpen();
0591:                _populateDataCache = cache;
0592:            }
0593:
0594:            public boolean isTrackChangesByType() {
0595:                return _largeTransaction;
0596:            }
0597:
0598:            public void setTrackChangesByType(boolean largeTransaction) {
0599:                assertOpen();
0600:                _largeTransaction = largeTransaction;
0601:            }
0602:
0603:            public Object getUserObject(Object key) {
0604:                beginOperation(false);
0605:                try {
0606:                    return (_userObjects == null) ? null : _userObjects
0607:                            .get(key);
0608:                } finally {
0609:                    endOperation();
0610:                }
0611:            }
0612:
0613:            public Object putUserObject(Object key, Object val) {
0614:                beginOperation(false);
0615:                try {
0616:                    if (val == null)
0617:                        return (_userObjects == null) ? null : _userObjects
0618:                                .remove(key);
0619:
0620:                    if (_userObjects == null)
0621:                        _userObjects = new HashMap();
0622:                    return _userObjects.put(key, val);
0623:                } finally {
0624:                    endOperation();
0625:                }
0626:            }
0627:
0628:            //////////
0629:            // Events
0630:            //////////
0631:
0632:            public void addLifecycleListener(Object listener, Class[] classes) {
0633:                beginOperation(false);
0634:                try {
0635:                    _lifeEventManager.addListener(listener, classes);
0636:                } finally {
0637:                    endOperation();
0638:                }
0639:            }
0640:
0641:            public void removeLifecycleListener(Object listener) {
0642:                beginOperation(false);
0643:                try {
0644:                    _lifeEventManager.removeListener(listener);
0645:                } finally {
0646:                    endOperation();
0647:                }
0648:            }
0649:
0650:            public int getLifecycleListenerCallbackMode() {
0651:                return _lifeCallbackMode;
0652:            }
0653:
0654:            public void setLifecycleListenerCallbackMode(int mode) {
0655:                beginOperation(false);
0656:                try {
0657:                    _lifeCallbackMode = mode;
0658:                    _lifeEventManager
0659:                            .setFailFast((mode & CALLBACK_FAIL_FAST) != 0);
0660:                } finally {
0661:                    endOperation();
0662:                }
0663:            }
0664:
0665:            /**
0666:             * Give state managers access to the lifecycle event manager.
0667:             */
0668:            public LifecycleEventManager getLifecycleEventManager() {
0669:                return _lifeEventManager;
0670:            }
0671:
0672:            /**
0673:             * Fire given lifecycle event, handling any exceptions appropriately.
0674:             *
0675:             * @return whether events are being processed at this time
0676:             */
0677:            boolean fireLifecycleEvent(Object src, Object related,
0678:                    ClassMetaData meta, int eventType) {
0679:                if (_lifeEventManager == null)
0680:                    return false;
0681:                handleCallbackExceptions(_lifeEventManager.fireEvent(src,
0682:                        related, meta, eventType), _lifeCallbackMode);
0683:                return true;
0684:            }
0685:
0686:            /**
0687:             * Take actions on callback exceptions depending on callback mode.
0688:             */
0689:            private void handleCallbackExceptions(Exception[] exceps, int mode) {
0690:                if (exceps.length == 0 || (mode & CALLBACK_IGNORE) != 0)
0691:                    return;
0692:
0693:                OpenJPAException ce;
0694:                if (exceps.length == 1)
0695:                    ce = new CallbackException(exceps[0]);
0696:                else
0697:                    ce = new CallbackException(_loc.get("callback-err"))
0698:                            .setNestedThrowables(exceps);
0699:                if ((mode & CALLBACK_ROLLBACK) != 0
0700:                        && (_flags & FLAG_ACTIVE) != 0) {
0701:                    ce.setFatal(true);
0702:                    setRollbackOnlyInternal(ce);
0703:                }
0704:                if ((mode & CALLBACK_LOG) != 0 && _log.isWarnEnabled())
0705:                    _log.warn(ce);
0706:                if ((mode & CALLBACK_RETHROW) != 0)
0707:                    throw ce;
0708:            }
0709:
0710:            public void addTransactionListener(Object tl) {
0711:                beginOperation(false);
0712:                try {
0713:                    _transEventManager.addListener(tl);
0714:                    if (tl instanceof  RemoteCommitEventManager)
0715:                        _flags |= FLAG_REMOTE_LISTENER;
0716:                } finally {
0717:                    endOperation();
0718:                }
0719:            }
0720:
0721:            public void removeTransactionListener(Object tl) {
0722:                beginOperation(false);
0723:                try {
0724:                    if (_transEventManager.removeListener(tl)
0725:                            && (tl instanceof  RemoteCommitEventManager))
0726:                        _flags &= ~FLAG_REMOTE_LISTENER;
0727:                } finally {
0728:                    endOperation();
0729:                }
0730:            }
0731:
0732:            public int getTransactionListenerCallbackMode() {
0733:                return _transCallbackMode;
0734:            }
0735:
0736:            public void setTransactionListenerCallbackMode(int mode) {
0737:                beginOperation(false);
0738:                try {
0739:                    _transCallbackMode = mode;
0740:                    _transEventManager
0741:                            .setFailFast((mode & CALLBACK_FAIL_FAST) != 0);
0742:                } finally {
0743:                    endOperation();
0744:                }
0745:            }
0746:
0747:            /**
0748:             * Fire given transaction event, handling any exceptions appropriately.
0749:             */
0750:            private void fireTransactionEvent(TransactionEvent trans) {
0751:                if (_transEventManager != null)
0752:                    handleCallbackExceptions(_transEventManager
0753:                            .fireEvent(trans), _transCallbackMode);
0754:            }
0755:
0756:            ///////////
0757:            // Lookups
0758:            ///////////
0759:
0760:            public Object find(Object oid, boolean validate, FindCallbacks call) {
0761:                int flags = OID_COPY | OID_ALLOW_NEW | OID_NODELETED;
0762:                if (!validate)
0763:                    flags |= OID_NOVALIDATE;
0764:                return find(oid, _fc, null, null, flags, call);
0765:            }
0766:
0767:            public Object find(Object oid, FetchConfiguration fetch,
0768:                    BitSet exclude, Object edata, int flags) {
0769:                return find(oid, fetch, exclude, edata, flags, null);
0770:            }
0771:
0772:            /**
0773:             * Internal finder.
0774:             */
0775:            protected Object find(Object oid, FetchConfiguration fetch,
0776:                    BitSet exclude, Object edata, int flags, FindCallbacks call) {
0777:                if (call == null)
0778:                    call = this ;
0779:                oid = call.processArgument(oid);
0780:                if (oid == null) {
0781:                    if ((flags & OID_NOVALIDATE) == 0)
0782:                        throw new ObjectNotFoundException(_loc.get("null-oid"));
0783:                    return call.processReturn(oid, null);
0784:                }
0785:                if (fetch == null)
0786:                    fetch = _fc;
0787:
0788:                beginOperation(true);
0789:                try {
0790:                    assertNontransactionalRead();
0791:
0792:                    // cached instance?
0793:                    StateManagerImpl sm = getStateManagerImplById(oid,
0794:                            (flags & OID_ALLOW_NEW) != 0 || hasFlushed());
0795:                    if (sm != null) {
0796:                        if (!requiresLoad(sm, true, fetch, edata, flags))
0797:                            return call.processReturn(oid, sm);
0798:
0799:                        if (!sm.isLoading()) {
0800:                            // make sure all the configured fields are loaded; do this
0801:                            // after making instance transactional for locking
0802:                            if (!sm.isTransactional()
0803:                                    && useTransactionalState(fetch))
0804:                                sm.transactional();
0805:                            boolean loaded;
0806:                            try {
0807:                                loaded = sm.load(fetch,
0808:                                        StateManagerImpl.LOAD_FGS, exclude,
0809:                                        edata, false);
0810:                            } catch (ObjectNotFoundException onfe) {
0811:                                if ((flags & OID_NODELETED) != 0
0812:                                        || (flags & OID_NOVALIDATE) != 0)
0813:                                    throw onfe;
0814:                                return call.processReturn(oid, null);
0815:                            }
0816:
0817:                            // if no data needed to be loaded and the user wants to
0818:                            // validate, just make sure the object exists
0819:                            if (!loaded && (flags & OID_NOVALIDATE) == 0
0820:                                    && _compat.getValidateTrueChecksStore()
0821:                                    && !sm.isTransactional()
0822:                                    && !_store.exists(sm, edata)) {
0823:                                if ((flags & OID_NODELETED) == 0)
0824:                                    return call.processReturn(oid, null);
0825:                                throw new ObjectNotFoundException(_loc.get(
0826:                                        "del-instance",
0827:                                        sm.getManagedInstance(), oid))
0828:                                        .setFailedObject(sm
0829:                                                .getManagedInstance());
0830:                            }
0831:                        }
0832:
0833:                        // since the object was cached, we may need to upgrade lock
0834:                        // if current level is higher than level of initial load
0835:                        if ((_flags & FLAG_ACTIVE) != 0) {
0836:                            int level = fetch.getReadLockLevel();
0837:                            _lm.lock(sm, level, fetch.getLockTimeout(), edata);
0838:                            sm.readLocked(level, fetch.getWriteLockLevel());
0839:                        }
0840:                        return call.processReturn(oid, sm);
0841:                    }
0842:
0843:                    // if there's no cached sm for a new/transient id type, we
0844:                    // it definitely doesn't exist
0845:                    if (oid instanceof  StateManagerId)
0846:                        return call.processReturn(oid, null);
0847:
0848:                    // initialize a new state manager for the datastore instance
0849:                    sm = newStateManagerImpl(oid, (flags & OID_COPY) != 0);
0850:                    boolean load = requiresLoad(sm, false, fetch, edata, flags);
0851:                    sm = initialize(sm, load, fetch, edata);
0852:                    if (sm == null) {
0853:                        if ((flags & OID_NOVALIDATE) != 0)
0854:                            throw new ObjectNotFoundException(oid);
0855:                        return call.processReturn(oid, null);
0856:                    }
0857:
0858:                    // make sure all configured fields were loaded
0859:                    if (load) {
0860:                        try {
0861:                            sm.load(fetch, StateManagerImpl.LOAD_FGS, exclude,
0862:                                    edata, false);
0863:                        } catch (ObjectNotFoundException onfe) {
0864:                            if ((flags & OID_NODELETED) != 0
0865:                                    || (flags & OID_NOVALIDATE) != 0)
0866:                                throw onfe;
0867:                            return call.processReturn(oid, null);
0868:                        }
0869:                    }
0870:                    return call.processReturn(oid, sm);
0871:                } catch (OpenJPAException ke) {
0872:                    throw ke;
0873:                } catch (RuntimeException re) {
0874:                    throw new GeneralException(re);
0875:                } finally {
0876:                    endOperation();
0877:                }
0878:            }
0879:
0880:            /**
0881:             * Initialize a newly-constructed state manager.
0882:             */
0883:            protected StateManagerImpl initialize(StateManagerImpl sm,
0884:                    boolean load, FetchConfiguration fetch, Object edata) {
0885:                if (!load) {
0886:                    sm.initialize(sm.getMetaData().getDescribedType(),
0887:                            PCState.HOLLOW);
0888:                } else {
0889:                    PCState state = (useTransactionalState(fetch)) ? PCState.PCLEAN
0890:                            : PCState.PNONTRANS;
0891:                    sm.setLoading(true);
0892:                    try {
0893:                        if (!_store.initialize(sm, state, fetch, edata))
0894:                            return null;
0895:                    } finally {
0896:                        sm.setLoading(false);
0897:                    }
0898:                }
0899:                return sm;
0900:            }
0901:
0902:            public Object[] findAll(Collection oids, boolean validate,
0903:                    FindCallbacks call) {
0904:                int flags = OID_COPY | OID_ALLOW_NEW | OID_NODELETED;
0905:                if (!validate)
0906:                    flags |= OID_NOVALIDATE;
0907:                return findAll(oids, _fc, null, null, flags, call);
0908:            }
0909:
0910:            public Object[] findAll(Collection oids, FetchConfiguration fetch,
0911:                    BitSet exclude, Object edata, int flags) {
0912:                return findAll(oids, fetch, exclude, edata, flags, null);
0913:            }
0914:
0915:            /**
0916:             * Internal finder.
0917:             */
0918:            protected Object[] findAll(Collection oids,
0919:                    FetchConfiguration fetch, BitSet exclude, Object edata,
0920:                    int flags, FindCallbacks call) {
0921:                findAllDepth++;
0922:
0923:                // throw any exceptions for null oids up immediately
0924:                if (oids == null)
0925:                    throw new NullPointerException("oids == null");
0926:                if ((flags & OID_NOVALIDATE) != 0 && oids.contains(null))
0927:                    throw new UserException(_loc.get("null-oids"));
0928:
0929:                // we have to use a map of oid->sm rather than a simple
0930:                // array, so that we make sure not to create multiple sms for equivalent
0931:                // oids if the user has duplicates in the given array
0932:                if (_loading == null)
0933:                    _loading = new HashMap((int) (oids.size() * 1.33 + 1));
0934:
0935:                if (call == null)
0936:                    call = this ;
0937:                if (fetch == null)
0938:                    fetch = _fc;
0939:
0940:                beginOperation(true);
0941:                try {
0942:                    assertNontransactionalRead();
0943:
0944:                    // collection of state managers to pass to store manager
0945:                    List load = null;
0946:                    StateManagerImpl sm;
0947:                    boolean initialized;
0948:                    boolean transState = useTransactionalState(fetch);
0949:                    Object obj, oid;
0950:                    int idx = 0;
0951:                    for (Iterator itr = oids.iterator(); itr.hasNext(); idx++) {
0952:                        // if we've already seen this oid, skip repeats
0953:                        obj = itr.next();
0954:                        oid = call.processArgument(obj);
0955:                        if (oid == null || _loading.containsKey(obj))
0956:                            continue;
0957:
0958:                        // if we don't have a cached instance or it is not transactional
0959:                        // and is hollow or we need to validate, load it
0960:                        sm = getStateManagerImplById(oid,
0961:                                (flags & OID_ALLOW_NEW) != 0 || hasFlushed());
0962:                        initialized = sm != null;
0963:                        if (!initialized)
0964:                            sm = newStateManagerImpl(oid,
0965:                                    (flags & OID_COPY) != 0);
0966:
0967:                        _loading.put(obj, sm);
0968:                        if (requiresLoad(sm, initialized, fetch, edata, flags)) {
0969:                            transState = transState
0970:                                    || useTransactionalState(fetch);
0971:                            if (initialized && !sm.isTransactional()
0972:                                    && transState)
0973:                                sm.transactional();
0974:                            if (load == null)
0975:                                load = new ArrayList(oids.size() - idx);
0976:                            load.add(sm);
0977:                        } else if (!initialized)
0978:                            sm.initialize(sm.getMetaData().getDescribedType(),
0979:                                    PCState.HOLLOW);
0980:                    }
0981:
0982:                    // pass all state managers in need of loading or validation to the
0983:                    // store manager
0984:                    if (load != null) {
0985:                        PCState state = (transState) ? PCState.PCLEAN
0986:                                : PCState.PNONTRANS;
0987:                        Collection failed = _store.loadAll(load, state,
0988:                                StoreManager.FORCE_LOAD_NONE, fetch, edata);
0989:
0990:                        // set failed instances to null
0991:                        if (failed != null && !failed.isEmpty()) {
0992:                            if ((flags & OID_NOVALIDATE) != 0)
0993:                                throw newObjectNotFoundException(failed);
0994:                            for (Iterator itr = failed.iterator(); itr
0995:                                    .hasNext();)
0996:                                _loading.put(itr.next(), null);
0997:                        }
0998:                    }
0999:
1000:                    // create results array; make sure all configured fields are
1001:                    // loaded in each instance
1002:                    Object[] results = new Object[oids.size()];
1003:                    boolean active = (_flags & FLAG_ACTIVE) != 0;
1004:                    int level = fetch.getReadLockLevel();
1005:                    idx = 0;
1006:                    for (Iterator itr = oids.iterator(); itr.hasNext(); idx++) {
1007:                        oid = itr.next();
1008:                        sm = (StateManagerImpl) _loading.get(oid);
1009:                        if (sm != null
1010:                                && requiresLoad(sm, true, fetch, edata, flags)) {
1011:                            try {
1012:                                sm.load(fetch, StateManagerImpl.LOAD_FGS,
1013:                                        exclude, edata, false);
1014:                                if (active) {
1015:                                    _lm.lock(sm, level, fetch.getLockTimeout(),
1016:                                            edata);
1017:                                    sm.readLocked(level, fetch
1018:                                            .getWriteLockLevel());
1019:                                }
1020:                            } catch (ObjectNotFoundException onfe) {
1021:                                if ((flags & OID_NODELETED) != 0
1022:                                        || (flags & OID_NOVALIDATE) != 0)
1023:                                    throw onfe;
1024:                                sm = null;
1025:                            }
1026:                        }
1027:                        results[idx] = call.processReturn(oid, sm);
1028:                    }
1029:                    return results;
1030:                } catch (OpenJPAException ke) {
1031:                    throw ke;
1032:                } catch (RuntimeException re) {
1033:                    throw new GeneralException(re);
1034:                } finally {
1035:                    findAllDepth--;
1036:                    if (findAllDepth == 0)
1037:                        _loading = null;
1038:                    endOperation();
1039:                }
1040:            }
1041:
1042:            private boolean hasFlushed() {
1043:                return (_flags & FLAG_FLUSHED) != 0;
1044:            }
1045:
1046:            /**
1047:             * Return whether the given instance needs loading before being returned
1048:             * to the user.
1049:             */
1050:            private boolean requiresLoad(OpenJPAStateManager sm,
1051:                    boolean initialized, FetchConfiguration fetch,
1052:                    Object edata, int flags) {
1053:                if (!fetch.requiresLoad())
1054:                    return false;
1055:                if ((flags & OID_NOVALIDATE) == 0)
1056:                    return true;
1057:                if (edata != null) // take advantage of existing result
1058:                    return true;
1059:                if (initialized && sm.getPCState() != PCState.HOLLOW)
1060:                    return false;
1061:                if (!initialized
1062:                        && sm.getMetaData().getPCSubclasses().length > 0)
1063:                    return true;
1064:                return !_compat.getValidateFalseReturnsHollow();
1065:            }
1066:
1067:            /**
1068:             * Return whether to use a transactional state.
1069:             */
1070:            private boolean useTransactionalState(FetchConfiguration fetch) {
1071:                return (_flags & FLAG_ACTIVE) != 0
1072:                        && (!_optimistic || _autoClear == CLEAR_ALL || fetch
1073:                                .getReadLockLevel() != LOCK_NONE);
1074:            }
1075:
1076:            public Object findCached(Object oid, FindCallbacks call) {
1077:                if (call == null)
1078:                    call = this ;
1079:                oid = call.processArgument(oid);
1080:                if (oid == null)
1081:                    return call.processReturn(oid, null);
1082:
1083:                beginOperation(true);
1084:                try {
1085:                    StateManagerImpl sm = getStateManagerImplById(oid, true);
1086:                    return call.processReturn(oid, sm);
1087:                } finally {
1088:                    endOperation();
1089:                }
1090:            }
1091:
1092:            public Class getObjectIdType(Class cls) {
1093:                if (cls == null)
1094:                    return null;
1095:
1096:                beginOperation(false);
1097:                try {
1098:                    ClassMetaData meta = _conf.getMetaDataRepositoryInstance()
1099:                            .getMetaData(cls, _loader, false);
1100:                    if (meta == null
1101:                            || meta.getIdentityType() == ClassMetaData.ID_UNKNOWN)
1102:                        return null;
1103:                    if (meta.getIdentityType() == ClassMetaData.ID_APPLICATION)
1104:                        return meta.getObjectIdType();
1105:
1106:                    return _store.getDataStoreIdType(meta);
1107:                } catch (OpenJPAException ke) {
1108:                    throw ke;
1109:                } catch (RuntimeException re) {
1110:                    throw new GeneralException(re);
1111:                } finally {
1112:                    endOperation();
1113:                }
1114:            }
1115:
1116:            public Object newObjectId(Class cls, Object val) {
1117:                if (val == null)
1118:                    return null;
1119:
1120:                beginOperation(false);
1121:                try {
1122:                    ClassMetaData meta = _conf.getMetaDataRepositoryInstance()
1123:                            .getMetaData(cls, _loader, true);
1124:                    switch (meta.getIdentityType()) {
1125:                    case ClassMetaData.ID_DATASTORE:
1126:                        // delegate to store manager for datastore ids
1127:                        if (val instanceof  String
1128:                                && ((String) val)
1129:                                        .startsWith(StateManagerId.STRING_PREFIX))
1130:                            return new StateManagerId((String) val);
1131:                        return _store.newDataStoreId(val, meta);
1132:                    case ClassMetaData.ID_APPLICATION:
1133:                        if (ImplHelper.isAssignable(meta.getObjectIdType(), val
1134:                                .getClass())) {
1135:                            if (!meta.isOpenJPAIdentity()
1136:                                    && meta.isObjectIdTypeShared())
1137:                                return new ObjectId(cls, val);
1138:                            return val;
1139:                        }
1140:
1141:                        // stringified app id?
1142:                        if (val instanceof  String
1143:                                && !_conf.getCompatibilityInstance()
1144:                                        .getStrictIdentityValues()
1145:                                && !Modifier.isAbstract(cls.getModifiers()))
1146:                            return PCRegistry.newObjectId(cls, (String) val);
1147:
1148:                        Object[] arr = (val instanceof  Object[]) ? (Object[]) val
1149:                                : new Object[] { val };
1150:                        return ApplicationIds.fromPKValues(arr, meta);
1151:                    default:
1152:                        throw new UserException(_loc.get("meta-unknownid", cls));
1153:                    }
1154:                } catch (OpenJPAException ke) {
1155:                    throw ke;
1156:                } catch (ClassCastException cce) {
1157:                    throw new UserException(_loc.get("bad-id-value", val, val
1158:                            .getClass().getName(), cls)).setCause(cce);
1159:                } catch (RuntimeException re) {
1160:                    throw new GeneralException(re);
1161:                } finally {
1162:                    endOperation();
1163:                }
1164:            }
1165:
1166:            /**
1167:             * Create a new state manager for the given oid.
1168:             */
1169:            private StateManagerImpl newStateManagerImpl(Object oid,
1170:                    boolean copy) {
1171:                // see if we're in the process of loading this oid in a loadAll call
1172:                StateManagerImpl sm;
1173:                if (_loading != null) {
1174:                    sm = (StateManagerImpl) _loading.get(oid);
1175:                    if (sm != null && sm.getPersistenceCapable() == null)
1176:                        return sm;
1177:                }
1178:
1179:                // find metadata for the oid
1180:                Class pcType = _store.getManagedType(oid);
1181:                MetaDataRepository repos = _conf
1182:                        .getMetaDataRepositoryInstance();
1183:                ClassMetaData meta;
1184:                if (pcType != null)
1185:                    meta = repos.getMetaData(pcType, _loader, true);
1186:                else
1187:                    meta = repos.getMetaData(oid, _loader, true);
1188:
1189:                // copy the oid if needed
1190:                if (copy && _compat.getCopyObjectIds()) {
1191:                    if (meta.getIdentityType() == ClassMetaData.ID_APPLICATION)
1192:                        oid = ApplicationIds.copy(oid, meta);
1193:                    else if (meta.getIdentityType() == ClassMetaData.ID_UNKNOWN)
1194:                        throw new UserException(_loc
1195:                                .get("meta-unknownid", meta));
1196:                    else
1197:                        oid = _store.copyDataStoreId(oid, meta);
1198:                }
1199:
1200:                sm = newStateManagerImpl(oid, meta);
1201:                sm.setObjectId(oid);
1202:                return sm;
1203:            }
1204:
1205:            /**
1206:             * Create a state manager for the given oid and metadata.
1207:             */
1208:            protected StateManagerImpl newStateManagerImpl(Object oid,
1209:                    ClassMetaData meta) {
1210:                return new StateManagerImpl(oid, meta, this );
1211:            }
1212:
1213:            ///////////////
1214:            // Transaction
1215:            ///////////////
1216:
1217:            public void begin() {
1218:                beginOperation(true);
1219:                try {
1220:                    if ((_flags & FLAG_ACTIVE) != 0)
1221:                        throw new InvalidStateException(_loc.get("active"));
1222:                    _factory.syncWithManagedTransaction(this , true);
1223:                    beginInternal();
1224:                } finally {
1225:                    endOperation();
1226:                }
1227:            }
1228:
1229:            /**
1230:             * Notify the store manager of a transaction.
1231:             */
1232:            private void beginInternal() {
1233:                try {
1234:                    beginStoreManagerTransaction(_optimistic);
1235:                    _flags |= FLAG_ACTIVE;
1236:
1237:                    // start locking
1238:                    if (!_optimistic) {
1239:                        _fc.setReadLockLevel(_conf.getReadLockLevelConstant());
1240:                        _fc
1241:                                .setWriteLockLevel(_conf
1242:                                        .getWriteLockLevelConstant());
1243:                        _fc.setLockTimeout(_conf.getLockTimeout());
1244:                    }
1245:                    _lm.beginTransaction();
1246:
1247:                    if (_transEventManager.hasBeginListeners())
1248:                        fireTransactionEvent(new TransactionEvent(this ,
1249:                                TransactionEvent.AFTER_BEGIN, null, null, null,
1250:                                null));
1251:                } catch (OpenJPAException ke) {
1252:                    // if we already started the transaction, don't let it commit
1253:                    if ((_flags & FLAG_ACTIVE) != 0)
1254:                        setRollbackOnlyInternal(ke);
1255:                    throw ke.setFatal(true);
1256:                } catch (RuntimeException re) {
1257:                    // if we already started the transaction, don't let it commit
1258:                    if ((_flags & FLAG_ACTIVE) != 0)
1259:                        setRollbackOnlyInternal(re);
1260:                    throw new StoreException(re).setFatal(true);
1261:                }
1262:
1263:                if (_pending != null) {
1264:                    StateManagerImpl sm;
1265:                    for (Iterator it = _pending.iterator(); it.hasNext();) {
1266:                        sm = (StateManagerImpl) it.next();
1267:                        sm.transactional();
1268:                        if (sm.isDirty())
1269:                            setDirty(sm, true);
1270:                    }
1271:                    _pending = null;
1272:                }
1273:            }
1274:
1275:            public void beginStore() {
1276:                beginOperation(true);
1277:                try {
1278:                    assertTransactionOperation();
1279:                    if ((_flags & FLAG_STORE_ACTIVE) == 0)
1280:                        beginStoreManagerTransaction(false);
1281:                } catch (OpenJPAException ke) {
1282:                    throw ke;
1283:                } catch (RuntimeException re) {
1284:                    throw new StoreException(re);
1285:                } finally {
1286:                    endOperation();
1287:                }
1288:            }
1289:
1290:            /**
1291:             * Begin a store manager transaction.
1292:             */
1293:            private void beginStoreManagerTransaction(boolean optimistic) {
1294:                if (!optimistic) {
1295:                    retainConnection();
1296:                    _store.begin();
1297:                    _flags |= FLAG_STORE_ACTIVE;
1298:                } else {
1299:                    if (_connRetainMode == CONN_RETAIN_TRANS)
1300:                        retainConnection();
1301:                    _store.beginOptimistic();
1302:                }
1303:            }
1304:
1305:            /**
1306:             * End the current store manager transaction. Throws an
1307:             * exception to signal a forced rollback after failed commit, otherwise
1308:             * returns any exception encountered during the end process.
1309:             */
1310:            private RuntimeException endStoreManagerTransaction(boolean rollback) {
1311:                boolean forcedRollback = false;
1312:                boolean releaseConn = false;
1313:                RuntimeException err = null;
1314:                try {
1315:                    if ((_flags & FLAG_STORE_ACTIVE) != 0) {
1316:                        releaseConn = _connRetainMode != CONN_RETAIN_ALWAYS;
1317:                        if (rollback)
1318:                            _store.rollback();
1319:                        else
1320:                            _store.commit();
1321:                    } else {
1322:                        releaseConn = _connRetainMode == CONN_RETAIN_TRANS;
1323:                        _store.rollbackOptimistic();
1324:                    }
1325:                } catch (RuntimeException re) {
1326:                    if (!rollback) {
1327:                        forcedRollback = true;
1328:                        try {
1329:                            _store.rollback();
1330:                        } catch (RuntimeException re2) {
1331:                        }
1332:                    }
1333:                    err = re;
1334:                } finally {
1335:                    _flags &= ~FLAG_STORE_ACTIVE;
1336:                }
1337:
1338:                if (releaseConn) {
1339:                    try {
1340:                        releaseConnection();
1341:                    } catch (RuntimeException re) {
1342:                        if (err == null)
1343:                            err = re;
1344:                    }
1345:                }
1346:
1347:                if (forcedRollback)
1348:                    throw err;
1349:                return err;
1350:            }
1351:
1352:            public void commit() {
1353:                beginOperation(false);
1354:                try {
1355:                    assertTransactionOperation();
1356:
1357:                    javax.transaction.Transaction trans = _runtime
1358:                            .getTransactionManager().getTransaction();
1359:                    if (trans == null)
1360:                        throw new InvalidStateException(_loc.get("null-trans"));
1361:
1362:                    // this commit on the transaction will cause our
1363:                    // beforeCompletion method to be invoked
1364:                    trans.commit();
1365:                } catch (OpenJPAException ke) {
1366:                    if (_log.isTraceEnabled())
1367:                        _log.trace(_loc.get("end-trans-error"), ke);
1368:                    throw ke;
1369:                } catch (Exception e) {
1370:                    if (_log.isTraceEnabled())
1371:                        _log.trace(_loc.get("end-trans-error"), e);
1372:                    throw new StoreException(e);
1373:                } finally {
1374:                    endOperation();
1375:                }
1376:            }
1377:
1378:            public void rollback() {
1379:                beginOperation(false);
1380:                try {
1381:                    assertTransactionOperation();
1382:
1383:                    javax.transaction.Transaction trans = _runtime
1384:                            .getTransactionManager().getTransaction();
1385:                    if (trans != null)
1386:                        trans.rollback();
1387:                } catch (OpenJPAException ke) {
1388:                    if (_log.isTraceEnabled())
1389:                        _log.trace(_loc.get("end-trans-error"), ke);
1390:                    throw ke;
1391:                } catch (Exception e) {
1392:                    if (_log.isTraceEnabled())
1393:                        _log.trace(_loc.get("end-trans-error"), e);
1394:                    throw new StoreException(e);
1395:                } finally {
1396:                    endOperation();
1397:                }
1398:            }
1399:
1400:            public boolean syncWithManagedTransaction() {
1401:                assertOpen();
1402:                lock();
1403:                try {
1404:                    if ((_flags & FLAG_ACTIVE) != 0)
1405:                        return true;
1406:                    if (!_managed)
1407:                        throw new InvalidStateException(_loc
1408:                                .get("trans-not-managed"));
1409:                    if (_factory.syncWithManagedTransaction(this , false)) {
1410:                        beginInternal();
1411:                        return true;
1412:                    }
1413:                    return false;
1414:                } finally {
1415:                    unlock();
1416:                }
1417:            }
1418:
1419:            public void commitAndResume() {
1420:                endAndResume(true);
1421:            }
1422:
1423:            public void rollbackAndResume() {
1424:                endAndResume(false);
1425:            }
1426:
1427:            private void endAndResume(boolean commit) {
1428:                beginOperation(false);
1429:                try {
1430:                    if (commit)
1431:                        commit();
1432:                    else
1433:                        rollback();
1434:                    begin();
1435:                } finally {
1436:                    endOperation();
1437:                }
1438:            }
1439:
1440:            public boolean getRollbackOnly() {
1441:                beginOperation(true);
1442:                try {
1443:                    if ((_flags & FLAG_ACTIVE) == 0)
1444:                        return false;
1445:
1446:                    javax.transaction.Transaction trans = _runtime
1447:                            .getTransactionManager().getTransaction();
1448:                    if (trans == null)
1449:                        return false;
1450:                    return trans.getStatus() == Status.STATUS_MARKED_ROLLBACK;
1451:                } catch (OpenJPAException ke) {
1452:                    throw ke;
1453:                } catch (Exception e) {
1454:                    throw new GeneralException(e);
1455:                } finally {
1456:                    endOperation();
1457:                }
1458:            }
1459:
1460:            public Throwable getRollbackCause() {
1461:                beginOperation(true);
1462:                try {
1463:                    if ((_flags & FLAG_ACTIVE) == 0)
1464:                        return null;
1465:
1466:                    javax.transaction.Transaction trans = _runtime
1467:                            .getTransactionManager().getTransaction();
1468:                    if (trans == null)
1469:                        return null;
1470:                    if (trans.getStatus() == Status.STATUS_MARKED_ROLLBACK)
1471:                        return _runtime.getRollbackCause();
1472:
1473:                    return null;
1474:                } catch (OpenJPAException ke) {
1475:                    throw ke;
1476:                } catch (Exception e) {
1477:                    throw new GeneralException(e);
1478:                } finally {
1479:                    endOperation();
1480:                }
1481:            }
1482:
1483:            public void setRollbackOnly() {
1484:                setRollbackOnly(new UserException());
1485:            }
1486:
1487:            public void setRollbackOnly(Throwable cause) {
1488:                beginOperation(true);
1489:                try {
1490:                    assertTransactionOperation();
1491:                    setRollbackOnlyInternal(cause);
1492:                } finally {
1493:                    endOperation();
1494:                }
1495:            }
1496:
1497:            /**
1498:             * Mark the current transaction as rollback-only.
1499:             */
1500:            private void setRollbackOnlyInternal(Throwable cause) {
1501:                try {
1502:                    javax.transaction.Transaction trans = _runtime
1503:                            .getTransactionManager().getTransaction();
1504:                    if (trans == null)
1505:                        throw new InvalidStateException(_loc.get("null-trans"));
1506:                    // ensure tran is in a valid state to accept the setRollbackOnly
1507:                    int tranStatus = trans.getStatus();
1508:                    if ((tranStatus != Status.STATUS_NO_TRANSACTION)
1509:                            && (tranStatus != Status.STATUS_ROLLEDBACK)
1510:                            && (tranStatus != Status.STATUS_COMMITTED))
1511:                        _runtime.setRollbackOnly(cause);
1512:                    else if (_log.isTraceEnabled())
1513:                        _log.trace(_loc.get("invalid-tran-status", new Integer(
1514:                                tranStatus), "setRollbackOnly"));
1515:                } catch (OpenJPAException ke) {
1516:                    throw ke;
1517:                } catch (Exception e) {
1518:                    throw new GeneralException(e);
1519:                }
1520:            }
1521:
1522:            public void setSavepoint(String name) {
1523:                beginOperation(true);
1524:                try {
1525:                    assertActiveTransaction();
1526:                    if (_savepoints != null && _savepoints.containsKey(name))
1527:                        throw new UserException(_loc.get("savepoint-exists",
1528:                                name));
1529:
1530:                    if (hasFlushed() && !_spm.supportsIncrementalFlush())
1531:                        throw new UnsupportedException(_loc
1532:                                .get("savepoint-flush-not-supported"));
1533:
1534:                    OpenJPASavepoint save = _spm.newSavepoint(name, this );
1535:                    if (_savepoints == null || _savepoints.isEmpty()) {
1536:                        save.save(getTransactionalStates());
1537:                        _savepoints = new LinkedMap();
1538:                    } else {
1539:                        if (_savepointCache == null)
1540:                            save.save(Collections.EMPTY_LIST);
1541:                        else {
1542:                            save.save(_savepointCache);
1543:                            _savepointCache.clear();
1544:                        }
1545:                    }
1546:                    _savepoints.put(name, save);
1547:                } catch (OpenJPAException ke) {
1548:                    throw ke;
1549:                } catch (Exception e) {
1550:                    throw new GeneralException(e);
1551:                } finally {
1552:                    endOperation();
1553:                }
1554:            }
1555:
1556:            public void releaseSavepoint() {
1557:                beginOperation(false);
1558:                try {
1559:                    if (_savepoints == null || _savepoints.isEmpty())
1560:                        throw new UserException(_loc.get("no-lastsavepoint"));
1561:                    releaseSavepoint((String) _savepoints.get(_savepoints
1562:                            .size() - 1));
1563:                } finally {
1564:                    endOperation();
1565:                }
1566:            }
1567:
1568:            public void releaseSavepoint(String savepoint) {
1569:                beginOperation(false);
1570:                try {
1571:                    assertActiveTransaction();
1572:
1573:                    int index = (_savepoints == null) ? -1 : _savepoints
1574:                            .indexOf(savepoint);
1575:                    if (index < 0)
1576:                        throw new UserException(_loc.get("no-savepoint",
1577:                                savepoint));
1578:
1579:                    // clear old in reverse
1580:                    OpenJPASavepoint save;
1581:                    while (_savepoints.size() > index + 1) {
1582:                        save = (OpenJPASavepoint) _savepoints
1583:                                .remove(_savepoints.size() - 1);
1584:                        save.release(false);
1585:                    }
1586:
1587:                    save = (OpenJPASavepoint) _savepoints.remove(index);
1588:                    save.release(true);
1589:                    if (_savepointCache != null)
1590:                        _savepointCache.clear();
1591:                } catch (OpenJPAException ke) {
1592:                    throw ke;
1593:                } catch (Exception e) {
1594:                    throw new GeneralException(e);
1595:                } finally {
1596:                    endOperation();
1597:                }
1598:            }
1599:
1600:            public void rollbackToSavepoint() {
1601:                beginOperation(false);
1602:                try {
1603:                    if (_savepoints == null || _savepoints.isEmpty())
1604:                        throw new UserException(_loc.get("no-lastsavepoint"));
1605:                    rollbackToSavepoint((String) _savepoints.get(_savepoints
1606:                            .size() - 1));
1607:                } finally {
1608:                    endOperation();
1609:                }
1610:            }
1611:
1612:            public void rollbackToSavepoint(String savepoint) {
1613:                beginOperation(false);
1614:                try {
1615:                    assertActiveTransaction();
1616:
1617:                    int index = (_savepoints == null) ? -1 : _savepoints
1618:                            .indexOf(savepoint);
1619:                    if (index < 0)
1620:                        throw new UserException(_loc.get("no-savepoint",
1621:                                savepoint));
1622:
1623:                    // clear old in reverse
1624:                    OpenJPASavepoint save;
1625:                    while (_savepoints.size() > index + 1) {
1626:                        save = (OpenJPASavepoint) _savepoints
1627:                                .remove(_savepoints.size() - 1);
1628:                        save.release(false);
1629:                    }
1630:
1631:                    save = (OpenJPASavepoint) _savepoints.remove(index);
1632:                    Collection saved = save.rollback(_savepoints.values());
1633:                    if (_savepointCache != null)
1634:                        _savepointCache.clear();
1635:                    if (hasTransactionalObjects()) {
1636:                        // build up a new collection of states
1637:                        TransactionalCache oldTransCache = _transCache;
1638:                        TransactionalCache newTransCache = new TransactionalCache(
1639:                                _orderDirty);
1640:                        _transCache = null;
1641:
1642:                        // currently there is the assumption that incremental
1643:                        // flush is either a) not allowed, or b) required
1644:                        // pre-savepoint.  this solves a number of issues including
1645:                        // storing flushed states as well as OID handling.
1646:                        // if future plugins do not follow this, we need to cache
1647:                        // more info per state
1648:                        SavepointFieldManager fm;
1649:                        StateManagerImpl sm;
1650:                        for (Iterator itr = saved.iterator(); itr.hasNext();) {
1651:                            fm = (SavepointFieldManager) itr.next();
1652:                            sm = fm.getStateManager();
1653:                            sm.rollbackToSavepoint(fm);
1654:                            oldTransCache.remove(sm);
1655:                            if (sm.isDirty())
1656:                                newTransCache.addDirty(sm);
1657:                            else
1658:                                newTransCache.addClean(sm);
1659:                        }
1660:                        for (Iterator itr = oldTransCache.iterator(); itr
1661:                                .hasNext();) {
1662:                            sm = (StateManagerImpl) itr.next();
1663:                            sm.rollback();
1664:                            removeFromTransaction(sm);
1665:                        }
1666:                        _transCache = newTransCache;
1667:                    }
1668:                } catch (OpenJPAException ke) {
1669:                    throw ke;
1670:                } catch (Exception e) {
1671:                    throw new GeneralException(e);
1672:                } finally {
1673:                    endOperation();
1674:                }
1675:            }
1676:
1677:            public void flush() {
1678:                beginOperation(true);
1679:                try {
1680:                    // return silently if no trans is active, or if this is a reentrant
1681:                    // call, which can happen if the store manager tries to get an
1682:                    // auto-inc oid during flush
1683:                    if ((_flags & FLAG_ACTIVE) == 0
1684:                            || (_flags & FLAG_STORE_FLUSHING) != 0)
1685:                        return;
1686:
1687:                    // make sure the runtime supports it
1688:                    if (!_conf.supportedOptions().contains(
1689:                            _conf.OPTION_INC_FLUSH))
1690:                        throw new UnsupportedException(_loc
1691:                                .get("incremental-flush-not-supported"));
1692:                    if (_savepoints != null && !_savepoints.isEmpty()
1693:                            && !_spm.supportsIncrementalFlush())
1694:                        throw new UnsupportedException(_loc
1695:                                .get("savepoint-flush-not-supported"));
1696:
1697:                    try {
1698:                        flushSafe(FLUSH_INC);
1699:                        _flags |= FLAG_FLUSHED;
1700:                    } catch (OpenJPAException ke) {
1701:                        // rollback on flush error; objects may be in inconsistent state
1702:                        setRollbackOnly(ke);
1703:                        throw ke.setFatal(true);
1704:                    } catch (RuntimeException re) {
1705:                        // rollback on flush error; objects may be in inconsistent state
1706:                        setRollbackOnly(re);
1707:                        throw new StoreException(re).setFatal(true);
1708:                    }
1709:                } finally {
1710:                    endOperation();
1711:                }
1712:            }
1713:
1714:            public void preFlush() {
1715:                beginOperation(true);
1716:                try {
1717:                    if ((_flags & FLAG_ACTIVE) != 0)
1718:                        flushSafe(FLUSH_LOGICAL);
1719:                } finally {
1720:                    endOperation();
1721:                }
1722:            }
1723:
1724:            public void validateChanges() {
1725:                beginOperation(true);
1726:                try {
1727:                    // if no trans, just return; if active datastore trans, flush
1728:                    if ((_flags & FLAG_ACTIVE) == 0)
1729:                        return;
1730:                    if ((_flags & FLAG_STORE_ACTIVE) != 0) {
1731:                        flush();
1732:                        return;
1733:                    }
1734:
1735:                    // make sure the runtime supports inc flush
1736:                    if (!_conf.supportedOptions().contains(
1737:                            _conf.OPTION_INC_FLUSH))
1738:                        throw new UnsupportedException(_loc
1739:                                .get("incremental-flush-not-supported"));
1740:
1741:                    try {
1742:                        flushSafe(FLUSH_ROLLBACK);
1743:                    } catch (OpenJPAException ke) {
1744:                        throw ke;
1745:                    } catch (RuntimeException re) {
1746:                        throw new StoreException(re);
1747:                    }
1748:                } finally {
1749:                    endOperation();
1750:                }
1751:            }
1752:
1753:            public boolean isActive() {
1754:                beginOperation(true);
1755:                try {
1756:                    return (_flags & FLAG_ACTIVE) != 0;
1757:                } finally {
1758:                    endOperation();
1759:                }
1760:            }
1761:
1762:            public boolean isStoreActive() {
1763:                // we need to lock here, because we might be in the middle of an
1764:                // atomic transaction process (e.g., commitAndResume)
1765:                beginOperation(true);
1766:                try {
1767:                    return (_flags & FLAG_STORE_ACTIVE) != 0;
1768:                } finally {
1769:                    endOperation();
1770:                }
1771:            }
1772:
1773:            /**
1774:             * Return whether the current transaction is ending, i.e. in the 2nd phase
1775:             * of a commit or rollback
1776:             */
1777:            boolean isTransactionEnding() {
1778:                return (_flags & FLAG_TRANS_ENDING) != 0;
1779:            }
1780:
1781:            public boolean beginOperation(boolean syncTrans) {
1782:                lock();
1783:                try {
1784:                    assertOpen();
1785:
1786:                    if (syncTrans && _operationCount == 0 && _syncManaged
1787:                            && (_flags & FLAG_ACTIVE) == 0)
1788:                        syncWithManagedTransaction();
1789:                    return _operationCount++ == 1;
1790:                } catch (OpenJPAException ke) {
1791:                    unlock();
1792:                    throw ke;
1793:                } catch (RuntimeException re) {
1794:                    unlock();
1795:                    throw new GeneralException(re);
1796:                }
1797:            }
1798:
1799:            /**
1800:             * Mark the operation over. If outermost caller of stack, returns true
1801:             * and will detach managed instances if necessary.
1802:             */
1803:            public boolean endOperation() {
1804:                try {
1805:                    if (_operationCount == 1
1806:                            && (_autoDetach & DETACH_NONTXREAD) != 0
1807:                            && (_flags & FLAG_ACTIVE) == 0) {
1808:                        detachAllInternal(null);
1809:                    }
1810:                    if (_operationCount < 1)
1811:                        throw new InternalException(_loc
1812:                                .get("multi-threaded-access"));
1813:                    return _operationCount == 1;
1814:                } catch (OpenJPAException ke) {
1815:                    throw ke;
1816:                } catch (RuntimeException re) {
1817:                    throw new GeneralException(re);
1818:                } finally {
1819:                    _operationCount--;
1820:                    if (_operationCount == 0)
1821:                        initializeOperatingSet();
1822:                    unlock();
1823:                }
1824:            }
1825:
1826:            public Synchronization getSynchronization() {
1827:                return _sync;
1828:            }
1829:
1830:            public void setSynchronization(Synchronization sync) {
1831:                assertOpen();
1832:                _sync = sync;
1833:            }
1834:
1835:            ///////////////////////////////////////////////
1836:            // Implementation of Synchronization interface
1837:            ///////////////////////////////////////////////
1838:
1839:            public void beforeCompletion() {
1840:                beginOperation(false);
1841:                try {
1842:                    // user-supplied synchronization
1843:                    if (_sync != null)
1844:                        _sync.beforeCompletion();
1845:
1846:                    flushSafe(FLUSH_COMMIT);
1847:                } catch (OpenJPAException ke) {
1848:                    if (_log.isTraceEnabled())
1849:                        _log.trace(_loc.get("end-trans-error"), ke);
1850:                    throw translateManagedCompletionException(ke);
1851:                } catch (RuntimeException re) {
1852:                    if (_log.isTraceEnabled())
1853:                        _log.trace(_loc.get("end-trans-error"), re);
1854:                    throw translateManagedCompletionException(new StoreException(
1855:                            re));
1856:                } finally {
1857:                    endOperation();
1858:                }
1859:            }
1860:
1861:            public void afterCompletion(int status) {
1862:                beginOperation(false);
1863:                try {
1864:                    assertActiveTransaction();
1865:
1866:                    _flags |= FLAG_TRANS_ENDING;
1867:                    endTransaction(status);
1868:                    if (_sync != null)
1869:                        _sync.afterCompletion(status);
1870:
1871:                    if ((_autoDetach & DETACH_COMMIT) != 0)
1872:                        detachAllInternal(null);
1873:                    else if (status == Status.STATUS_ROLLEDBACK
1874:                            && (_autoDetach & DETACH_ROLLBACK) != 0) {
1875:                        detachAllInternal(null);
1876:                    }
1877:
1878:                    // in an ee context, it's possible that the user tried to close
1879:                    // us but we didn't actually close because we were waiting on this
1880:                    // transaction; if that's true, then close now
1881:                    if ((_flags & FLAG_CLOSE_INVOKED) != 0
1882:                            && _compat.getCloseOnManagedCommit())
1883:                        free();
1884:                } catch (OpenJPAException ke) {
1885:                    if (_log.isTraceEnabled())
1886:                        _log.trace(_loc.get("end-trans-error"), ke);
1887:                    throw translateManagedCompletionException(ke);
1888:                } catch (RuntimeException re) {
1889:                    if (_log.isTraceEnabled())
1890:                        _log.trace(_loc.get("end-trans-error"), re);
1891:                    throw translateManagedCompletionException(new StoreException(
1892:                            re));
1893:                } finally {
1894:                    _flags &= ~FLAG_ACTIVE;
1895:                    _flags &= ~FLAG_FLUSHED;
1896:                    _flags &= ~FLAG_TRANS_ENDING;
1897:
1898:                    // event manager nulled if freed broker
1899:                    if (_transEventManager != null
1900:                            && _transEventManager.hasEndListeners()) {
1901:                        fireTransactionEvent(new TransactionEvent(
1902:                                this ,
1903:                                status == Status.STATUS_COMMITTED ? TransactionEvent.AFTER_COMMIT_COMPLETE
1904:                                        : TransactionEvent.AFTER_ROLLBACK_COMPLETE,
1905:                                null, null, null, null));
1906:                    }
1907:
1908:                    endOperation();
1909:                }
1910:            }
1911:
1912:            /**
1913:             * If we're in a managed transaction, use our implicit behavior exception
1914:             * translator to translate before/afterCompletion callback errors.
1915:             */
1916:            private RuntimeException translateManagedCompletionException(
1917:                    RuntimeException re) {
1918:                return (!_managed || _extrans == null) ? re : _extrans
1919:                        .translate(re);
1920:            }
1921:
1922:            /**
1923:             * Flush safely, catching reentrant calls.
1924:             */
1925:            private void flushSafe(int reason) {
1926:                if ((_flags & FLAG_FLUSHING) != 0)
1927:                    throw new InvalidStateException(_loc.get("reentrant-flush"));
1928:
1929:                _flags |= FLAG_FLUSHING;
1930:                try {
1931:                    flush(reason);
1932:                } finally {
1933:                    _flags &= ~FLAG_FLUSHING;
1934:                }
1935:            }
1936:
1937:            /**
1938:             * Flush the transactional state to the data store. Subclasses that
1939:             * customize commit behavior should override this method. The method
1940:             * assumes that the persistence manager is locked, is not closed,
1941:             * and has an active transaction.
1942:             *
1943:             * @param reason one of {@link #FLUSH_INC}, {@link #FLUSH_COMMIT},
1944:             * {@link #FLUSH_ROLLBACK}, or {@link #FLUSH_LOGICAL}
1945:             * @since 0.2.5
1946:             */
1947:            protected void flush(int reason) {
1948:                // this will enlist proxied states as necessary so we know whether we
1949:                // have anything to flush
1950:                Collection transactional = getTransactionalStates();
1951:
1952:                // do we actually have to flush?  only if our flags say so, or if
1953:                // we have transaction listeners that need to be invoked for commit
1954:                // (no need to invoke them on inc flush if nothing is dirty).  we
1955:                // special case the remote commit listener used by the datacache cause
1956:                // we know it doesn't require the commit event when nothing changes
1957:                boolean flush = (_flags & FLAG_FLUSH_REQUIRED) != 0;
1958:                boolean listeners = (_transEventManager.hasFlushListeners() || _transEventManager
1959:                        .hasEndListeners())
1960:                        && ((_flags & FLAG_REMOTE_LISTENER) == 0 || _transEventManager
1961:                                .getListeners().size() > 1);
1962:                if (!flush && (reason != FLUSH_COMMIT || !listeners))
1963:                    return;
1964:
1965:                Collection mobjs = null;
1966:                _flags |= FLAG_PRESTORING;
1967:                try {
1968:                    if (flush) {
1969:                        // call pre store on all currently transactional objs
1970:                        for (Iterator itr = transactional.iterator(); itr
1971:                                .hasNext();)
1972:                            ((StateManagerImpl) itr.next()).beforeFlush(reason,
1973:                                    _call);
1974:                        flushAdditions(transactional, reason);
1975:                    }
1976:
1977:                    // hopefully now all dependent instances that are going to end
1978:                    // up referenced have been marked as such; delete unrefed
1979:                    // dependents
1980:                    _flags |= FLAG_DEREFDELETING;
1981:                    if (flush && _derefCache != null && !_derefCache.isEmpty()) {
1982:                        for (Iterator itr = _derefCache.iterator(); itr
1983:                                .hasNext();)
1984:                            deleteDeref((StateManagerImpl) itr.next());
1985:                        flushAdditions(transactional, reason);
1986:                    }
1987:
1988:                    if (reason != FLUSH_LOGICAL) {
1989:                        // if no datastore transaction, start one; even if we don't
1990:                        // think we'll need to flush at this point, our transaction
1991:                        // listeners might introduce some dirty objects or interact
1992:                        // directly with the database
1993:                        if ((_flags & FLAG_STORE_ACTIVE) == 0)
1994:                            beginStoreManagerTransaction(false);
1995:
1996:                        if ((_transEventManager.hasFlushListeners() || _transEventManager
1997:                                .hasEndListeners())
1998:                                && (flush || reason == FLUSH_COMMIT)) {
1999:                            // fire events
2000:                            mobjs = new ManagedObjectCollection(transactional);
2001:                            if (reason == FLUSH_COMMIT
2002:                                    && _transEventManager.hasEndListeners()) {
2003:                                fireTransactionEvent(new TransactionEvent(this ,
2004:                                        TransactionEvent.BEFORE_COMMIT, mobjs,
2005:                                        _persistedClss, _updatedClss,
2006:                                        _deletedClss));
2007:
2008:                                flushAdditions(transactional, reason);
2009:                                flush = (_flags & FLAG_FLUSH_REQUIRED) != 0;
2010:                            }
2011:
2012:                            if (flush && _transEventManager.hasFlushListeners()) {
2013:                                fireTransactionEvent(new TransactionEvent(this ,
2014:                                        TransactionEvent.BEFORE_FLUSH, mobjs,
2015:                                        _persistedClss, _updatedClss,
2016:                                        _deletedClss));
2017:                                flushAdditions(transactional, reason);
2018:                            }
2019:                        }
2020:                    }
2021:                } finally {
2022:                    _flags &= ~FLAG_PRESTORING;
2023:                    _flags &= ~FLAG_DEREFDELETING;
2024:                    _transAdditions = null;
2025:                    _derefAdditions = null;
2026:
2027:                    // also clear derefed set; the deletes have been recorded
2028:                    if (_derefCache != null)
2029:                        _derefCache = null;
2030:                }
2031:
2032:                // flush to store manager
2033:                List exceps = null;
2034:                try {
2035:                    if (flush && reason != FLUSH_LOGICAL) {
2036:                        _flags |= FLAG_STORE_FLUSHING;
2037:                        exceps = add(exceps, newFlushException(_store
2038:                                .flush(transactional)));
2039:                    }
2040:                } finally {
2041:                    _flags &= ~FLAG_STORE_FLUSHING;
2042:
2043:                    if (reason == FLUSH_ROLLBACK)
2044:                        exceps = add(exceps, endStoreManagerTransaction(true));
2045:                    else if (reason != FLUSH_LOGICAL)
2046:                        _flags &= ~FLAG_FLUSH_REQUIRED;
2047:
2048:                    // mark states as flushed
2049:                    if (flush) {
2050:                        StateManagerImpl sm;
2051:                        for (Iterator itr = transactional.iterator(); itr
2052:                                .hasNext();) {
2053:                            sm = (StateManagerImpl) itr.next();
2054:                            try {
2055:                                // the state may have become transient, such as if
2056:                                // it is embedded and the owner has been deleted during
2057:                                // this flush process; bug #1100
2058:                                if (sm.getPCState() == PCState.TRANSIENT)
2059:                                    continue;
2060:
2061:                                sm.afterFlush(reason);
2062:                                if (reason == FLUSH_INC) {
2063:                                    // if not about to clear trans cache for commit 
2064:                                    // anyway, re-cache dirty objects with default soft
2065:                                    // refs; we don't need hard refs now that the 
2066:                                    // changes have been flushed
2067:                                    sm.proxyFields(true, false);
2068:                                    _transCache.flushed(sm);
2069:                                }
2070:                            } catch (Exception e) {
2071:                                exceps = add(exceps, e);
2072:                            }
2073:                        }
2074:                    }
2075:                }
2076:
2077:                // throw any exceptions to shortcut listeners on fail
2078:                throwNestedExceptions(exceps, true);
2079:
2080:                if (flush && reason != FLUSH_ROLLBACK
2081:                        && reason != FLUSH_LOGICAL
2082:                        && _transEventManager.hasFlushListeners()) {
2083:                    fireTransactionEvent(new TransactionEvent(this ,
2084:                            TransactionEvent.AFTER_FLUSH, mobjs,
2085:                            _persistedClss, _updatedClss, _deletedClss));
2086:                }
2087:            }
2088:
2089:            /**
2090:             * Flush newly-transactional objects.
2091:             */
2092:            private void flushAdditions(Collection transactional, int reason) {
2093:                boolean loop;
2094:                do {
2095:                    // flush new transactional instances; note logical or
2096:                    loop = flushTransAdditions(transactional, reason)
2097:                            | deleteDerefAdditions(_derefCache);
2098:                } while (loop);
2099:            }
2100:
2101:            /**
2102:             * Flush transactional additions.
2103:             */
2104:            private boolean flushTransAdditions(Collection transactional,
2105:                    int reason) {
2106:                if (_transAdditions == null || _transAdditions.isEmpty())
2107:                    return false;
2108:
2109:                // keep local transactional list copy up to date
2110:                transactional.addAll(_transAdditions);
2111:
2112:                // copy the change set, then clear it for the next iteration
2113:                StateManagerImpl[] states = (StateManagerImpl[]) _transAdditions
2114:                        .toArray(new StateManagerImpl[_transAdditions.size()]);
2115:                _transAdditions = null;
2116:
2117:                for (int i = 0; i < states.length; i++)
2118:                    states[i].beforeFlush(reason, _call);
2119:                return true;
2120:            }
2121:
2122:            /**
2123:             * Delete new dereferenced objects.
2124:             */
2125:            private boolean deleteDerefAdditions(Collection derefs) {
2126:                if (_derefAdditions == null || _derefAdditions.isEmpty())
2127:                    return false;
2128:
2129:                // remember these additions in case one becomes derefed again later
2130:                derefs.addAll(_derefAdditions);
2131:
2132:                StateManagerImpl[] states = (StateManagerImpl[]) _derefAdditions
2133:                        .toArray(new StateManagerImpl[_derefAdditions.size()]);
2134:                _derefAdditions = null;
2135:
2136:                for (int i = 0; i < states.length; i++)
2137:                    deleteDeref(states[i]);
2138:                return true;
2139:            }
2140:
2141:            /**
2142:             * Delete a dereferenced dependent.
2143:             */
2144:            private void deleteDeref(StateManagerImpl sm) {
2145:                int action = processArgument(OpCallbacks.OP_DELETE, sm
2146:                        .getManagedInstance(), sm, null);
2147:                if ((action & OpCallbacks.ACT_RUN) != 0)
2148:                    sm.delete();
2149:                if ((action & OpCallbacks.ACT_CASCADE) != 0)
2150:                    sm.cascadeDelete(_call);
2151:            }
2152:
2153:            /**
2154:             * Determine the action to take based on the user's given callbacks and
2155:             * our implicit behavior.
2156:             */
2157:            private int processArgument(int op, Object obj,
2158:                    OpenJPAStateManager sm, OpCallbacks call) {
2159:                if (call != null)
2160:                    return call.processArgument(op, obj, sm);
2161:                if (_call != null)
2162:                    return _call.processArgument(op, obj, sm);
2163:                return OpCallbacks.ACT_RUN | OpCallbacks.ACT_CASCADE;
2164:            }
2165:
2166:            /**
2167:             * Throw the proper exception based on the given set of flush errors, or
2168:             * do nothing if no errors occurred.
2169:             */
2170:            private OpenJPAException newFlushException(Collection exceps) {
2171:                if (exceps == null || exceps.isEmpty())
2172:                    return null;
2173:
2174:                Throwable[] t = (Throwable[]) exceps
2175:                        .toArray(new Throwable[exceps.size()]);
2176:                List failed = new ArrayList(t.length);
2177:
2178:                // create fatal exception with nested exceptions for all the failed
2179:                // objects; if all OL exceptions, throw a top-level OL exception
2180:                boolean opt = true;
2181:                for (int i = 0; opt && i < t.length; i++) {
2182:                    opt = t[i] instanceof  OptimisticException;
2183:                    if (opt) {
2184:                        Object f = ((OptimisticException) t[i])
2185:                                .getFailedObject();
2186:                        if (f != null)
2187:                            failed.add(f);
2188:                    }
2189:                }
2190:                if (opt && !failed.isEmpty())
2191:                    return new OptimisticException(failed, t);
2192:                if (opt)
2193:                    return new OptimisticException(t);
2194:                return new StoreException(_loc.get("rolled-back"))
2195:                        .setNestedThrowables(t).setFatal(true);
2196:            }
2197:
2198:            /**
2199:             * End the current transaction, making appropriate state transitions.
2200:             */
2201:            protected void endTransaction(int status) {
2202:                // if a data store transaction was in progress, do the
2203:                // appropriate transaction change
2204:                boolean rollback = status != Status.STATUS_COMMITTED;
2205:                List exceps = null;
2206:
2207:                try {
2208:                    exceps = add(exceps, endStoreManagerTransaction(rollback));
2209:                } catch (RuntimeException re) {
2210:                    rollback = true;
2211:                    exceps = add(exceps, re);
2212:                }
2213:
2214:                // go back to default none lock level
2215:                _fc.setReadLockLevel(LOCK_NONE);
2216:                _fc.setWriteLockLevel(LOCK_NONE);
2217:                _fc.setLockTimeout(-1);
2218:
2219:                Collection transStates;
2220:                if (hasTransactionalObjects())
2221:                    transStates = _transCache;
2222:                else
2223:                    transStates = Collections.EMPTY_LIST;
2224:
2225:                // fire after rollback/commit event
2226:                Collection mobjs = null;
2227:                if (_transEventManager.hasEndListeners()) {
2228:                    mobjs = new ManagedObjectCollection(transStates);
2229:                    int eventType = (rollback) ? TransactionEvent.AFTER_ROLLBACK
2230:                            : TransactionEvent.AFTER_COMMIT;
2231:                    fireTransactionEvent(new TransactionEvent(this , eventType,
2232:                            mobjs, _persistedClss, _updatedClss, _deletedClss));
2233:                }
2234:
2235:                // null transactional caches now so that all the removeFromTransaction
2236:                // calls as we transition each object don't have to do any work; don't
2237:                // clear trans cache object because we still need the transStates
2238:                // reference to it below
2239:                _transCache = null;
2240:                if (_persistedClss != null)
2241:                    _persistedClss = null;
2242:                if (_updatedClss != null)
2243:                    _updatedClss = null;
2244:                if (_deletedClss != null)
2245:                    _deletedClss = null;
2246:
2247:                // new cache would get cleared anyway during transitions, but doing so
2248:                // immediately saves us some lookups
2249:                _cache.clearNew();
2250:
2251:                // tell all derefed instances they're no longer derefed; we can't
2252:                // rely on rollback and commit calls below cause some instances might
2253:                // not be transactional
2254:                if (_derefCache != null && !_derefCache.isEmpty()) {
2255:                    for (Iterator itr = _derefCache.iterator(); itr.hasNext();)
2256:                        ((StateManagerImpl) itr.next())
2257:                                .setDereferencedDependent(false, false);
2258:                    _derefCache = null;
2259:                }
2260:
2261:                // peform commit or rollback state transitions on each instance
2262:                StateManagerImpl sm;
2263:                for (Iterator itr = transStates.iterator(); itr.hasNext();) {
2264:                    sm = (StateManagerImpl) itr.next();
2265:                    try {
2266:                        if (rollback) {
2267:                            // tell objects that may have been derefed then flushed
2268:                            // (and therefore deleted) to un-deref
2269:                            sm.setDereferencedDependent(false, false);
2270:                            sm.rollback();
2271:                        } else
2272:                            sm.commit();
2273:                    } catch (RuntimeException re) {
2274:                        exceps = add(exceps, re);
2275:                    }
2276:                }
2277:
2278:                // notify the lock manager to clean up and release remaining locks
2279:                _lm.endTransaction();
2280:
2281:                // clear old savepoints in reverse
2282:                OpenJPASavepoint save;
2283:                while (_savepoints != null && _savepoints.size() > 0) {
2284:                    save = (OpenJPASavepoint) _savepoints.remove(_savepoints
2285:                            .size() - 1);
2286:                    save.release(false);
2287:                }
2288:                _savepoints = null;
2289:                _savepointCache = null;
2290:
2291:                // fire after state change event
2292:                if (_transEventManager.hasEndListeners())
2293:                    fireTransactionEvent(new TransactionEvent(this ,
2294:                            TransactionEvent.AFTER_STATE_TRANSITIONS, mobjs,
2295:                            null, null, null));
2296:
2297:                // now clear trans cache; keep cleared version rather than
2298:                // null to avoid having to re-create the set later; more efficient
2299:                if (transStates != Collections.EMPTY_LIST) {
2300:                    _transCache = (TransactionalCache) transStates;
2301:                    _transCache.clear();
2302:                }
2303:
2304:                throwNestedExceptions(exceps, true);
2305:            }
2306:
2307:            ////////////////////
2308:            // Object lifecycle
2309:            ////////////////////
2310:
2311:            public void persist(Object obj, OpCallbacks call) {
2312:                persist(obj, null, true, call);
2313:            }
2314:
2315:            public OpenJPAStateManager persist(Object obj, Object id,
2316:                    OpCallbacks call) {
2317:                return persist(obj, id, true, call);
2318:            }
2319:
2320:            public void persistAll(Collection objs, OpCallbacks call) {
2321:                persistAll(objs, true, call);
2322:            }
2323:
2324:            /**
2325:             * Persist the given objects.  Indicate whether this was an explicit persist
2326:             * (PNEW) or a provisonal persist (PNEWPROVISIONAL).
2327:             */
2328:            public void persistAll(Collection objs, boolean explicit,
2329:                    OpCallbacks call) {
2330:                if (objs.isEmpty())
2331:                    return;
2332:
2333:                beginOperation(true);
2334:                List exceps = null;
2335:                try {
2336:                    assertWriteOperation();
2337:
2338:                    for (Iterator itr = objs.iterator(); itr.hasNext();) {
2339:                        try {
2340:                            persist(itr.next(), explicit, call);
2341:                        } catch (UserException ue) {
2342:                            exceps = add(exceps, ue);
2343:                        }
2344:                    }
2345:                } finally {
2346:                    endOperation();
2347:                }
2348:                throwNestedExceptions(exceps, false);
2349:            }
2350:
2351:            /**
2352:             * If the given element is not null, add it to the given list,
2353:             * creating the list if necessary.
2354:             */
2355:            private List add(List l, Object o) {
2356:                if (o == null)
2357:                    return l;
2358:                if (l == null)
2359:                    l = new LinkedList();
2360:                l.add(o);
2361:                return l;
2362:            }
2363:
2364:            /**
2365:             * Throw an exception wrapping the given nested exceptions.
2366:             */
2367:            private void throwNestedExceptions(List exceps, boolean datastore) {
2368:                if (exceps == null || exceps.isEmpty())
2369:                    return;
2370:                if (datastore && exceps.size() == 1)
2371:                    throw (RuntimeException) exceps.get(0);
2372:
2373:                boolean fatal = false;
2374:                Throwable[] t = (Throwable[]) exceps
2375:                        .toArray(new Throwable[exceps.size()]);
2376:                for (int i = 0; i < t.length; i++) {
2377:                    if (t[i] instanceof  OpenJPAException
2378:                            && ((OpenJPAException) t[i]).isFatal())
2379:                        fatal = true;
2380:                }
2381:                OpenJPAException err;
2382:                if (datastore)
2383:                    err = new StoreException(_loc.get("nested-exceps"));
2384:                else
2385:                    err = new UserException(_loc.get("nested-exceps"));
2386:                throw err.setNestedThrowables(t).setFatal(fatal);
2387:            }
2388:
2389:            /**
2390:             * Persist the given object.  Indicate whether this was an explicit persist
2391:             * (PNEW) or a provisonal persist (PNEWPROVISIONAL)
2392:             */
2393:            public void persist(Object obj, boolean explicit, OpCallbacks call) {
2394:                persist(obj, null, explicit, call);
2395:            }
2396:
2397:            /**
2398:             * Persist the given object.  Indicate whether this was an explicit persist
2399:             * (PNEW) or a provisonal persist (PNEWPROVISIONAL).
2400:             * See {@link Broker} for details on this method.
2401:             */
2402:            public OpenJPAStateManager persist(Object obj, Object id,
2403:                    boolean explicit, OpCallbacks call) {
2404:                if (obj == null)
2405:                    return null;
2406:
2407:                beginOperation(true);
2408:                try {
2409:                    assertWriteOperation();
2410:
2411:                    StateManagerImpl sm = getStateManagerImpl(obj, true);
2412:                    if (!_operating.add(obj))
2413:                        return sm;
2414:
2415:                    int action = processArgument(OpCallbacks.OP_PERSIST, obj,
2416:                            sm, call);
2417:                    if (action == OpCallbacks.ACT_NONE)
2418:                        return sm;
2419:
2420:                    // ACT_CASCADE
2421:                    if ((action & OpCallbacks.ACT_RUN) == 0) {
2422:                        if (sm != null)
2423:                            sm.cascadePersist(call);
2424:                        else
2425:                            cascadeTransient(OpCallbacks.OP_PERSIST, obj, call,
2426:                                    "persist");
2427:                        return sm;
2428:                    }
2429:
2430:                    // ACT_RUN
2431:                    PersistenceCapable pc;
2432:                    if (sm != null) {
2433:                        if (sm.isDetached())
2434:                            throw new ObjectExistsException(_loc.get(
2435:                                    "persist-detached", Exceptions
2436:                                            .toString(obj)))
2437:                                    .setFailedObject(obj);
2438:
2439:                        if (!sm.isEmbedded()) {
2440:                            sm.persist();
2441:                            _cache.persist(sm);
2442:                            if ((action & OpCallbacks.ACT_CASCADE) != 0)
2443:                                sm.cascadePersist(call);
2444:                            return sm;
2445:                        }
2446:
2447:                        // an embedded field; notify the owner that the value has
2448:                        // changed by becoming independently persistent
2449:                        sm.getOwner().dirty(sm.getOwnerIndex());
2450:                        _cache.persist(sm);
2451:                        pc = sm.getPersistenceCapable();
2452:                    } else {
2453:                        pc = assertPersistenceCapable(obj);
2454:                        if (pc.pcIsDetached() == Boolean.TRUE)
2455:                            throw new ObjectExistsException(_loc.get(
2456:                                    "persist-detached", Exceptions
2457:                                            .toString(obj)))
2458:                                    .setFailedObject(obj);
2459:                    }
2460:
2461:                    ClassMetaData meta = _conf.getMetaDataRepositoryInstance()
2462:                            .getMetaData(obj.getClass(), _loader, true);
2463:                    fireLifecycleEvent(obj, null, meta,
2464:                            LifecycleEvent.BEFORE_PERSIST);
2465:
2466:                    // create id for instance
2467:                    if (id == null) {
2468:                        if (meta.getIdentityType() == ClassMetaData.ID_APPLICATION)
2469:                            id = ApplicationIds.create(pc, meta);
2470:                        else if (meta.getIdentityType() == ClassMetaData.ID_UNKNOWN)
2471:                            throw new UserException(_loc.get("meta-unknownid",
2472:                                    meta));
2473:                        else
2474:                            id = StateManagerId.newInstance(this );
2475:                    }
2476:
2477:                    // make sure we don't already have the instance cached
2478:                    checkForDuplicateId(id, obj);
2479:
2480:                    // if had embedded sm, null it
2481:                    if (sm != null)
2482:                        pc.pcReplaceStateManager(null);
2483:
2484:                    // create new sm
2485:                    sm = new StateManagerImpl(id, meta, this );
2486:                    if ((_flags & FLAG_ACTIVE) != 0) {
2487:                        if (explicit)
2488:                            sm.initialize(pc, PCState.PNEW);
2489:                        else
2490:                            sm.initialize(pc, PCState.PNEWPROVISIONAL);
2491:                    } else
2492:                        sm.initialize(pc, PCState.PNONTRANSNEW);
2493:                    if ((action & OpCallbacks.ACT_CASCADE) != 0)
2494:                        sm.cascadePersist(call);
2495:                    return sm;
2496:                } catch (OpenJPAException ke) {
2497:                    throw ke;
2498:                } catch (RuntimeException re) {
2499:                    throw new GeneralException(re);
2500:                } finally {
2501:                    endOperation();
2502:                }
2503:            }
2504:
2505:            /**
2506:             * Temporarily manage the given instance in order to cascade the given
2507:             * operation through it.
2508:             */
2509:            private void cascadeTransient(int op, Object obj, OpCallbacks call,
2510:                    String errOp) {
2511:                PersistenceCapable pc = assertPersistenceCapable(obj);
2512:
2513:                // if using detached state manager, don't replace
2514:                if (pc.pcGetStateManager() != null)
2515:                    throw newDetachedException(obj, errOp);
2516:
2517:                ClassMetaData meta = _conf.getMetaDataRepositoryInstance()
2518:                        .getMetaData(obj.getClass(), _loader, true);
2519:                StateManagerImpl sm = new StateManagerImpl(StateManagerId
2520:                        .newInstance(this ), meta, this );
2521:                sm.initialize(pc, PCState.TLOADED);
2522:                try {
2523:                    switch (op) {
2524:                    case OpCallbacks.OP_PERSIST:
2525:                        sm.cascadePersist(call);
2526:                        break;
2527:                    case OpCallbacks.OP_DELETE:
2528:                        sm.cascadeDelete(call);
2529:                        break;
2530:                    case OpCallbacks.OP_REFRESH:
2531:                        sm.gatherCascadeRefresh(call);
2532:                        break;
2533:                    default:
2534:                        throw new InternalException(String.valueOf(op));
2535:                    }
2536:                } finally {
2537:                    sm.release(true);
2538:                }
2539:            }
2540:
2541:            public void deleteAll(Collection objs, OpCallbacks call) {
2542:                beginOperation(true);
2543:                try {
2544:                    assertWriteOperation();
2545:
2546:                    List exceps = null;
2547:                    Object obj;
2548:                    for (Iterator itr = objs.iterator(); itr.hasNext();) {
2549:                        try {
2550:                            obj = itr.next();
2551:                            if (obj != null)
2552:                                delete(obj, getStateManagerImpl(obj, true),
2553:                                        call);
2554:                        } catch (UserException ue) {
2555:                            exceps = add(exceps, ue);
2556:                        }
2557:                    }
2558:                    throwNestedExceptions(exceps, false);
2559:                } finally {
2560:                    endOperation();
2561:                }
2562:            }
2563:
2564:            public void delete(Object obj, OpCallbacks call) {
2565:                if (obj == null)
2566:                    return;
2567:
2568:                beginOperation(true);
2569:                try {
2570:                    assertWriteOperation();
2571:                    delete(obj, getStateManagerImpl(obj, true), call);
2572:                } catch (OpenJPAException ke) {
2573:                    throw ke;
2574:                } catch (RuntimeException re) {
2575:                    throw new GeneralException(re);
2576:                } finally {
2577:                    endOperation();
2578:                }
2579:            }
2580:
2581:            /**
2582:             * Internal delete.
2583:             */
2584:            void delete(Object obj, StateManagerImpl sm, OpCallbacks call) {
2585:                if (!_operating.add(obj))
2586:                    return;
2587:
2588:                int action = processArgument(OpCallbacks.OP_DELETE, obj, sm,
2589:                        call);
2590:                if (action == OpCallbacks.ACT_NONE)
2591:                    return;
2592:
2593:                // ACT_CASCADE
2594:                if ((action & OpCallbacks.ACT_RUN) == 0) {
2595:                    if (sm != null)
2596:                        sm.cascadeDelete(call);
2597:                    else
2598:                        cascadeTransient(OpCallbacks.OP_DELETE, obj, call,
2599:                                "delete");
2600:                    return;
2601:                }
2602:
2603:                // ACT_RUN
2604:                if (sm != null) {
2605:                    if (sm.isDetached())
2606:                        throw newDetachedException(obj, "delete");
2607:                    if ((action & OpCallbacks.ACT_CASCADE) != 0)
2608:                        sm.cascadeDelete(call);
2609:                    sm.delete();
2610:                } else if (assertPersistenceCapable(obj).pcIsDetached() == Boolean.TRUE)
2611:                    throw newDetachedException(obj, "delete");
2612:            }
2613:
2614:            /**
2615:             * Throw an exception indicating that the current action can't be
2616:             * performed on a detached object.
2617:             */
2618:            private OpenJPAException newDetachedException(Object obj,
2619:                    String operation) {
2620:                throw new UserException(_loc.get("bad-detached-op", operation,
2621:                        Exceptions.toString(obj))).setFailedObject(obj);
2622:            }
2623:
2624:            public void releaseAll(Collection objs, OpCallbacks call) {
2625:                beginOperation(false);
2626:                try {
2627:                    List exceps = null;
2628:                    for (Iterator itr = objs.iterator(); itr.hasNext();) {
2629:                        try {
2630:                            release(itr.next(), call);
2631:                        } catch (UserException ue) {
2632:                            exceps = add(exceps, ue);
2633:                        }
2634:                    }
2635:                    throwNestedExceptions(exceps, false);
2636:                } finally {
2637:                    endOperation();
2638:                }
2639:            }
2640:
2641:            public void release(Object obj, OpCallbacks call) {
2642:                if (obj == null)
2643:                    return;
2644:
2645:                beginOperation(false);
2646:                try {
2647:                    StateManagerImpl sm = getStateManagerImpl(obj, true);
2648:                    int action = processArgument(OpCallbacks.OP_RELEASE, obj,
2649:                            sm, call);
2650:
2651:                    if (sm == null)
2652:                        return;
2653:                    if ((action & OpCallbacks.ACT_RUN) != 0
2654:                            && sm.isPersistent()) {
2655:                        boolean pending = sm.isPendingTransactional();
2656:                        sm.release(true);
2657:                        if (pending)
2658:                            removeFromPendingTransaction(sm);
2659:                    }
2660:                } catch (OpenJPAException ke) {
2661:                    throw ke;
2662:                } catch (RuntimeException re) {
2663:                    throw new GeneralException(re);
2664:                } finally {
2665:                    endOperation();
2666:                }
2667:            }
2668:
2669:            public OpenJPAStateManager embed(Object obj, Object id,
2670:                    OpenJPAStateManager owner, ValueMetaData ownerMeta) {
2671:                beginOperation(true);
2672:                try {
2673:                    StateManagerImpl orig = getStateManagerImpl(obj, true);
2674:                    if (orig != null) {
2675:                        // if already embedded, nothing to do
2676:                        if (orig.getOwner() == owner
2677:                                && orig.getMetaData().getEmbeddingMetaData() == ownerMeta)
2678:                            return orig;
2679:
2680:                        // otherwise make sure pc is fully loaded for when we copy its
2681:                        // data below
2682:                        orig.load(_fc, StateManagerImpl.LOAD_ALL, null, null,
2683:                                false);
2684:                    }
2685:
2686:                    // create new state manager with embedded metadata
2687:                    ClassMetaData meta = ownerMeta.getEmbeddedMetaData();
2688:                    if (meta == null)
2689:                        throw new InternalException(_loc.get("bad-embed",
2690:                                ownerMeta));
2691:
2692:                    if (id == null)
2693:                        id = StateManagerId.newInstance(this );
2694:
2695:                    StateManagerImpl sm = new StateManagerImpl(id, meta, this );
2696:                    sm.setOwner((StateManagerImpl) owner, ownerMeta);
2697:
2698:                    PersistenceCapable copy;
2699:                    PCState state;
2700:                    Class type = meta.getDescribedType();
2701:                    if (obj != null) {
2702:                        // give copy and the original instance the same state manager
2703:                        // so that we can copy fields from one to the other
2704:                        StateManagerImpl copySM;
2705:                        PersistenceCapable pc;
2706:                        if (orig == null) {
2707:                            copySM = sm;
2708:                            pc = assertPersistenceCapable(obj);
2709:                            pc.pcReplaceStateManager(sm);
2710:                        } else {
2711:                            copySM = orig;
2712:                            pc = orig.getPersistenceCapable();
2713:                        }
2714:
2715:                        try {
2716:                            // copy the instance.  we do this even if it doesn't already
2717:                            // have a state manager in case it is later assigned to a
2718:                            // PC field; at that point it's too late to copy
2719:                            copy = PCRegistry.newInstance(type, copySM, false);
2720:                            int[] fields = new int[meta.getFields().length];
2721:                            for (int i = 0; i < fields.length; i++)
2722:                                fields[i] = i;
2723:                            copy.pcCopyFields(pc, fields);
2724:                            state = PCState.ECOPY;
2725:                            copy.pcReplaceStateManager(null);
2726:                        } finally {
2727:                            // if the instance didn't have a state manager to start,
2728:                            // revert it to being transient
2729:                            if (orig == null)
2730:                                pc.pcReplaceStateManager(null);
2731:                        }
2732:                    } else {
2733:                        copy = PCRegistry.newInstance(type, sm, false);
2734:                        if ((_flags & FLAG_ACTIVE) != 0 && !_optimistic)
2735:                            state = PCState.ECLEAN;
2736:                        else
2737:                            state = PCState.ENONTRANS;
2738:                    }
2739:
2740:                    sm.initialize(copy, state);
2741:                    return sm;
2742:                } catch (OpenJPAException ke) {
2743:                    throw ke;
2744:                } catch (RuntimeException re) {
2745:                    throw new GeneralException(re);
2746:                } finally {
2747:                    endOperation();
2748:                }
2749:            }
2750:
2751:            /**
2752:             * If not already cached, create an empty copy of the given state
2753:             * manager in the given state.
2754:             */
2755:            OpenJPAStateManager copy(OpenJPAStateManager copy, PCState state) {
2756:                beginOperation(true);
2757:                try {
2758:                    assertOpen();
2759:                    Object oid = copy.fetchObjectId();
2760:                    Class type = copy.getManagedInstance().getClass();
2761:                    if (oid == null)
2762:                        throw new InternalException();
2763:                    // cached instance?
2764:                    StateManagerImpl sm = null;
2765:                    if (!copy.isEmbedded())
2766:                        sm = getStateManagerImplById(oid, true);
2767:                    if (sm == null) {
2768:                        MetaDataRepository repos = _conf
2769:                                .getMetaDataRepositoryInstance();
2770:                        ClassMetaData meta = repos.getMetaData(type, _loader,
2771:                                true);
2772:                        // construct a new state manager with all info known
2773:                        sm = new StateManagerImpl(oid, meta, this );
2774:                        sm.setObjectId(oid);
2775:                        sm.initialize(sm.getMetaData().getDescribedType(),
2776:                                state);
2777:                    }
2778:                    return sm;
2779:                } finally {
2780:                    endOperation();
2781:                }
2782:            }
2783:
2784:            public void refreshAll(Collection objs, OpCallbacks call) {
2785:                if (objs.isEmpty())
2786:                    return;
2787:
2788:                beginOperation(true);
2789:                try {
2790:                    assertNontransactionalRead();
2791:
2792:                    for (Iterator itr = objs.iterator(); itr.hasNext();)
2793:                        gatherCascadeRefresh(itr.next(), call);
2794:                    if (_operating.isEmpty())
2795:                        return;
2796:                    if (_operating.size() == 1)
2797:                        refreshInternal(_operating.iterator().next(), call);
2798:                    else
2799:                        refreshInternal(_operating, call);
2800:                } finally {
2801:                    endOperation();
2802:                }
2803:            }
2804:
2805:            public void refresh(Object obj, OpCallbacks call) {
2806:                if (obj == null)
2807:                    return;
2808:
2809:                beginOperation(true);
2810:                try {
2811:                    assertNontransactionalRead();
2812:
2813:                    gatherCascadeRefresh(obj, call);
2814:                    if (_operating.isEmpty())
2815:                        return;
2816:                    if (_operating.size() == 1)
2817:                        refreshInternal(_operating.iterator().next(), call);
2818:                    else
2819:                        refreshInternal(_operating, call);
2820:                } finally {
2821:                    endOperation();
2822:                }
2823:            }
2824:
2825:            /**
2826:             * Gathers all objects reachable through cascade-refresh relations
2827:             * into the operating set.
2828:             */
2829:            void gatherCascadeRefresh(Object obj, OpCallbacks call) {
2830:                if (obj == null)
2831:                    return;
2832:                if (!_operating.add(obj))
2833:                    return;
2834:
2835:                StateManagerImpl sm = getStateManagerImpl(obj, false);
2836:                int action = processArgument(OpCallbacks.OP_REFRESH, obj, sm,
2837:                        call);
2838:                if ((action & OpCallbacks.ACT_CASCADE) == 0)
2839:                    return;
2840:
2841:                if (sm != null)
2842:                    sm.gatherCascadeRefresh(call);
2843:                else
2844:                    cascadeTransient(OpCallbacks.OP_REFRESH, obj, call,
2845:                            "refresh");
2846:            }
2847:
2848:            /**
2849:             * This method is called with the full set of objects reachable via
2850:             * cascade-refresh relations from the user-given instances.
2851:             */
2852:            protected void refreshInternal(Collection objs, OpCallbacks call) {
2853:                List exceps = null;
2854:                try {
2855:                    // collect instances that need a refresh
2856:                    Collection load = null;
2857:                    StateManagerImpl sm;
2858:                    Object obj;
2859:                    for (Iterator itr = objs.iterator(); itr.hasNext();) {
2860:                        obj = itr.next();
2861:                        if (obj == null)
2862:                            continue;
2863:
2864:                        try {
2865:                            sm = getStateManagerImpl(obj, true);
2866:                            if ((processArgument(OpCallbacks.OP_REFRESH, obj,
2867:                                    sm, call) & OpCallbacks.ACT_RUN) == 0)
2868:                                continue;
2869:
2870:                            if (sm != null) {
2871:                                if (sm.isDetached())
2872:                                    throw newDetachedException(obj, "refresh");
2873:                                else if (sm.beforeRefresh(true)) {
2874:                                    if (load == null)
2875:                                        load = new ArrayList(objs.size());
2876:                                    load.add(sm);
2877:                                }
2878:                            } else if (assertPersistenceCapable(obj)
2879:                                    .pcIsDetached() == Boolean.TRUE)
2880:                                throw newDetachedException(obj, "refresh");
2881:                        } catch (OpenJPAException ke) {
2882:                            exceps = add(exceps, ke);
2883:                        }
2884:                    }
2885:
2886:                    // refresh all
2887:                    if (load != null) {
2888:                        Collection failed = _store.loadAll(load, null,
2889:                                StoreManager.FORCE_LOAD_REFRESH, _fc, null);
2890:                        if (failed != null && !failed.isEmpty())
2891:                            exceps = add(exceps,
2892:                                    newObjectNotFoundException(failed));
2893:
2894:                        // perform post-refresh transitions and make sure all fetch
2895:                        // group fields are loaded
2896:                        for (Iterator itr = load.iterator(); itr.hasNext();) {
2897:                            sm = (StateManagerImpl) itr.next();
2898:                            if (failed != null && failed.contains(sm.getId()))
2899:                                continue;
2900:
2901:                            try {
2902:                                sm.afterRefresh();
2903:                                sm.load(_fc, StateManagerImpl.LOAD_FGS, null,
2904:                                        null, false);
2905:                            } catch (OpenJPAException ke) {
2906:                                exceps = add(exceps, ke);
2907:                            }
2908:                        }
2909:                    }
2910:
2911:                    // now invoke postRefresh on all the instances
2912:                    for (Iterator itr = objs.iterator(); itr.hasNext();) {
2913:                        try {
2914:                            sm = getStateManagerImpl(itr.next(), true);
2915:                            if (sm != null && !sm.isDetached())
2916:                                fireLifecycleEvent(sm.getManagedInstance(),
2917:                                        null, sm.getMetaData(),
2918:                                        LifecycleEvent.AFTER_REFRESH);
2919:                        } catch (OpenJPAException ke) {
2920:                            exceps = add(exceps, ke);
2921:                        }
2922:                    }
2923:                } catch (OpenJPAException ke) {
2924:                    throw ke;
2925:                } catch (RuntimeException re) {
2926:                    throw new GeneralException(re);
2927:                }
2928:                throwNestedExceptions(exceps, false);
2929:            }
2930:
2931:            /**
2932:             * Optimization for single-object refresh.
2933:             */
2934:            protected void refreshInternal(Object obj, OpCallbacks call) {
2935:                try {
2936:                    StateManagerImpl sm = getStateManagerImpl(obj, true);
2937:                    if ((processArgument(OpCallbacks.OP_REFRESH, obj, sm, call) & OpCallbacks.ACT_RUN) == 0)
2938:                        return;
2939:
2940:                    if (sm != null) {
2941:                        if (sm.isDetached())
2942:                            throw newDetachedException(obj, "refresh");
2943:                        else if (sm.beforeRefresh(false)) {
2944:                            sm.load(_fc, StateManagerImpl.LOAD_FGS, null, null,
2945:                                    false);
2946:                            sm.afterRefresh();
2947:                        }
2948:                        fireLifecycleEvent(sm.getManagedInstance(), null, sm
2949:                                .getMetaData(), LifecycleEvent.AFTER_REFRESH);
2950:                    } else if (assertPersistenceCapable(obj).pcIsDetached() == Boolean.TRUE)
2951:                        throw newDetachedException(obj, "refresh");
2952:                } catch (OpenJPAException ke) {
2953:                    throw ke;
2954:                } catch (RuntimeException re) {
2955:                    throw new GeneralException(re);
2956:                }
2957:            }
2958:
2959:            public void retrieveAll(Collection objs, boolean dfgOnly,
2960:                    OpCallbacks call) {
2961:                if (objs.isEmpty())
2962:                    return;
2963:                if (objs.size() == 1) {
2964:                    retrieve(objs.iterator().next(), dfgOnly, call);
2965:                    return;
2966:                }
2967:
2968:                List exceps = null;
2969:                beginOperation(true);
2970:                try {
2971:                    assertOpen();
2972:                    assertNontransactionalRead();
2973:
2974:                    // collect all hollow instances for load
2975:                    Object obj;
2976:                    Collection load = null;
2977:                    StateManagerImpl sm;
2978:                    Collection sms = new ArrayList(objs.size());
2979:                    for (Iterator itr = objs.iterator(); itr.hasNext();) {
2980:                        obj = itr.next();
2981:                        if (obj == null)
2982:                            continue;
2983:
2984:                        try {
2985:                            sm = getStateManagerImpl(obj, true);
2986:                            if ((processArgument(OpCallbacks.OP_RETRIEVE, obj,
2987:                                    sm, call) & OpCallbacks.ACT_RUN) == 0)
2988:                                continue;
2989:
2990:                            if (sm != null) {
2991:                                if (sm.isDetached())
2992:                                    throw newDetachedException(obj, "retrieve");
2993:                                if (sm.isPersistent()) {
2994:                                    sms.add(sm);
2995:                                    if (sm.getPCState() == PCState.HOLLOW) {
2996:                                        if (load == null)
2997:                                            load = new ArrayList();
2998:                                        load.add(sm);
2999:                                    }
3000:                                }
3001:                            } else if (assertPersistenceCapable(obj)
3002:                                    .pcIsDetached() == Boolean.TRUE)
3003:                                throw newDetachedException(obj, "retrieve");
3004:                        } catch (UserException ue) {
3005:                            exceps = add(exceps, ue);
3006:                        }
3007:                    }
3008:
3009:                    // load all hollow instances
3010:                    Collection failed = null;
3011:                    if (load != null) {
3012:                        int mode = (dfgOnly) ? _store.FORCE_LOAD_DFG
3013:                                : _store.FORCE_LOAD_ALL;
3014:                        failed = _store.loadAll(load, null, mode, _fc, null);
3015:                        if (failed != null && !failed.isEmpty())
3016:                            exceps = add(exceps,
3017:                                    newObjectNotFoundException(failed));
3018:                    }
3019:
3020:                    // retrieve all non-failed instances
3021:                    for (Iterator itr = sms.iterator(); itr.hasNext();) {
3022:                        sm = (StateManagerImpl) itr.next();
3023:                        if (failed != null && failed.contains(sm.getId()))
3024:                            continue;
3025:
3026:                        int mode = (dfgOnly) ? StateManagerImpl.LOAD_FGS
3027:                                : StateManagerImpl.LOAD_ALL;
3028:                        try {
3029:                            sm.beforeRead(-1);
3030:                            sm.load(_fc, mode, null, null, false);
3031:                        } catch (OpenJPAException ke) {
3032:                            exceps = add(exceps, ke);
3033:                        }
3034:                    }
3035:                } catch (OpenJPAException ke) {
3036:                    throw ke;
3037:                } catch (RuntimeException re) {
3038:                    throw new GeneralException(re);
3039:                } finally {
3040:                    endOperation();
3041:                }
3042:                throwNestedExceptions(exceps, false);
3043:            }
3044:
3045:            public void retrieve(Object obj, boolean dfgOnly, OpCallbacks call) {
3046:                if (obj == null)
3047:                    return;
3048:
3049:                beginOperation(true);
3050:                try {
3051:                    assertOpen();
3052:                    assertNontransactionalRead();
3053:
3054:                    StateManagerImpl sm = getStateManagerImpl(obj, true);
3055:                    if ((processArgument(OpCallbacks.OP_RETRIEVE, obj, sm, call) & OpCallbacks.ACT_RUN) == 0)
3056:                        return;
3057:
3058:                    if (sm != null) {
3059:                        if (sm.isDetached())
3060:                            throw newDetachedException(obj, "retrieve");
3061:                        if (sm.isPersistent()) {
3062:                            int mode = (dfgOnly) ? StateManagerImpl.LOAD_FGS
3063:                                    : StateManagerImpl.LOAD_ALL;
3064:                            sm.beforeRead(-1);
3065:                            sm.load(_fc, mode, null, null, false);
3066:                        }
3067:                    } else if (assertPersistenceCapable(obj).pcIsDetached() == Boolean.TRUE)
3068:                        throw newDetachedException(obj, "retrieve");
3069:                } catch (OpenJPAException ke) {
3070:                    throw ke;
3071:                } catch (RuntimeException re) {
3072:                    throw new GeneralException(re);
3073:                } finally {
3074:                    endOperation();
3075:                }
3076:            }
3077:
3078:            public void evictAll(OpCallbacks call) {
3079:                beginOperation(false);
3080:                try {
3081:                    // evict all PClean and PNonTrans objects
3082:                    Collection c = getManagedStates();
3083:                    StateManagerImpl sm;
3084:                    for (Iterator itr = c.iterator(); itr.hasNext();) {
3085:                        sm = (StateManagerImpl) itr.next();
3086:                        if (sm.isPersistent() && !sm.isDirty())
3087:                            evict(sm.getManagedInstance(), call);
3088:                    }
3089:                } finally {
3090:                    endOperation();
3091:                }
3092:            }
3093:
3094:            public void evictAll(Collection objs, OpCallbacks call) {
3095:                List exceps = null;
3096:                beginOperation(false);
3097:                try {
3098:                    for (Iterator itr = objs.iterator(); itr.hasNext();) {
3099:                        try {
3100:                            evict(itr.next(), call);
3101:                        } catch (UserException ue) {
3102:                            exceps = add(exceps, ue);
3103:                        }
3104:                    }
3105:                } finally {
3106:                    endOperation();
3107:                }
3108:                throwNestedExceptions(exceps, false);
3109:            }
3110:
3111:            public void evictAll(Extent extent, OpCallbacks call) {
3112:                if (extent == null)
3113:                    return;
3114:
3115:                beginOperation(false);
3116:                try {
3117:                    // evict all PClean and PNonTrans objects in extent
3118:                    Collection c = getManagedStates();
3119:                    StateManagerImpl sm;
3120:                    Class cls;
3121:                    for (Iterator itr = c.iterator(); itr.hasNext();) {
3122:                        sm = (StateManagerImpl) itr.next();
3123:                        if (sm.isPersistent() && !sm.isDirty()) {
3124:                            cls = sm.getMetaData().getDescribedType();
3125:                            if (cls == extent.getElementType()
3126:                                    || (extent.hasSubclasses() && extent
3127:                                            .getElementType().isAssignableFrom(
3128:                                                    cls)))
3129:                                evict(sm.getManagedInstance(), call);
3130:                        }
3131:                    }
3132:                } finally {
3133:                    endOperation();
3134:                }
3135:            }
3136:
3137:            public void evict(Object obj, OpCallbacks call) {
3138:                if (obj == null)
3139:                    return;
3140:
3141:                beginOperation(false);
3142:                try {
3143:                    StateManagerImpl sm = getStateManagerImpl(obj, true);
3144:                    if ((processArgument(OpCallbacks.OP_EVICT, obj, sm, call) & OpCallbacks.ACT_RUN) == 0)
3145:                        return;
3146:                    if (sm == null)
3147:                        return;
3148:
3149:                    sm.evict();
3150:                    if (_evictDataCache && sm.getObjectId() != null) {
3151:                        DataCache cache = sm.getMetaData().getDataCache();
3152:                        if (cache != null)
3153:                            cache.remove(sm.getObjectId());
3154:                    }
3155:                } catch (OpenJPAException ke) {
3156:                    throw ke;
3157:                } catch (RuntimeException re) {
3158:                    throw new GeneralException(re);
3159:                } finally {
3160:                    endOperation();
3161:                }
3162:            }
3163:
3164:            public Object detach(Object obj, OpCallbacks call) {
3165:                if (obj == null)
3166:                    return null;
3167:                if (call == null)
3168:                    call = _call;
3169:
3170:                beginOperation(true);
3171:                try {
3172:                    return new DetachManager(this , false, call).detach(obj);
3173:                } catch (OpenJPAException ke) {
3174:                    throw ke;
3175:                } catch (RuntimeException re) {
3176:                    throw new GeneralException(re);
3177:                } finally {
3178:                    endOperation();
3179:                }
3180:            }
3181:
3182:            public Object[] detachAll(Collection objs, OpCallbacks call) {
3183:                if (objs == null)
3184:                    return null;
3185:                if (objs.isEmpty())
3186:                    return EMPTY_OBJECTS;
3187:                if (call == null)
3188:                    call = _call;
3189:
3190:                beginOperation(true);
3191:                try {
3192:                    return new DetachManager(this , false, call).detachAll(objs);
3193:                } catch (OpenJPAException ke) {
3194:                    throw ke;
3195:                } catch (RuntimeException re) {
3196:                    throw new GeneralException(re);
3197:                } finally {
3198:                    endOperation();
3199:                }
3200:            }
3201:
3202:            public void detachAll(OpCallbacks call) {
3203:                detachAll(call, true);
3204:            }
3205:
3206:            public void detachAll(OpCallbacks call, boolean flush) {
3207:                beginOperation(true);
3208:                try {
3209:                    // If a flush is desired (based on input parm), then check if the
3210:                    //   "dirty" flag is set before calling flush().
3211:                    if ((flush) && ((_flags & FLAG_FLUSH_REQUIRED) != 0))
3212:                        flush();
3213:                    detachAllInternal(call);
3214:                } catch (OpenJPAException ke) {
3215:                    throw ke;
3216:                } catch (RuntimeException re) {
3217:                    throw new GeneralException(re);
3218:                } finally {
3219:                    endOperation();
3220:                }
3221:            }
3222:
3223:            private void detachAllInternal(OpCallbacks call) {
3224:                Collection states = getManagedStates();
3225:                StateManagerImpl sm;
3226:                for (Iterator itr = states.iterator(); itr.hasNext();) {
3227:                    sm = (StateManagerImpl) itr.next();
3228:                    if (!sm.isPersistent())
3229:                        itr.remove();
3230:                    else if (!sm.getMetaData().isDetachable()) {
3231:                        sm.release(true);
3232:                        itr.remove();
3233:                    }
3234:                }
3235:                if (states.isEmpty())
3236:                    return;
3237:
3238:                if (call == null)
3239:                    call = _call;
3240:                new DetachManager(this , true, call)
3241:                        .detachAll(new ManagedObjectCollection(states));
3242:            }
3243:
3244:            public Object attach(Object obj, boolean copyNew, OpCallbacks call) {
3245:                if (obj == null)
3246:                    return null;
3247:
3248:                beginOperation(true);
3249:                try {
3250:                    // make sure not to try to set rollback only if this fails
3251:                    assertWriteOperation();
3252:                    try {
3253:                        return new AttachManager(this , copyNew, call)
3254:                                .attach(obj);
3255:                    } catch (OptimisticException oe) {
3256:                        setRollbackOnly(oe);
3257:                        throw oe.setFatal(true);
3258:                    } catch (OpenJPAException ke) {
3259:                        throw ke;
3260:                    } catch (RuntimeException re) {
3261:                        throw new GeneralException(re);
3262:                    }
3263:                } finally {
3264:                    endOperation();
3265:                }
3266:            }
3267:
3268:            public Object[] attachAll(Collection objs, boolean copyNew,
3269:                    OpCallbacks call) {
3270:                if (objs == null)
3271:                    return null;
3272:                if (objs.isEmpty())
3273:                    return EMPTY_OBJECTS;
3274:
3275:                beginOperation(true);
3276:                try {
3277:                    // make sure not to try to set rollback only if this fails
3278:                    assertWriteOperation();
3279:                    try {
3280:                        return new AttachManager(this , copyNew, call)
3281:                                .attachAll(objs);
3282:                    } catch (OptimisticException oe) {
3283:                        setRollbackOnly(oe);
3284:                        throw oe.setFatal(true);
3285:                    } catch (OpenJPAException ke) {
3286:                        throw ke;
3287:                    } catch (RuntimeException re) {
3288:                        throw new GeneralException(re);
3289:                    }
3290:                } finally {
3291:                    endOperation();
3292:                }
3293:            }
3294:
3295:            public void nontransactionalAll(Collection objs, OpCallbacks call) {
3296:                beginOperation(true);
3297:                try {
3298:                    List exceps = null;
3299:                    for (Iterator itr = objs.iterator(); itr.hasNext();) {
3300:                        try {
3301:                            nontransactional(itr.next(), call);
3302:                        } catch (UserException ue) {
3303:                            exceps = add(exceps, ue);
3304:                        }
3305:                    }
3306:                    throwNestedExceptions(exceps, false);
3307:                } finally {
3308:                    endOperation();
3309:                }
3310:            }
3311:
3312:            public void nontransactional(Object obj, OpCallbacks call) {
3313:                if (obj == null)
3314:                    return;
3315:
3316:                beginOperation(true);
3317:                try {
3318:                    StateManagerImpl sm = getStateManagerImpl(obj, true);
3319:                    if ((processArgument(OpCallbacks.OP_NONTRANSACTIONAL, obj,
3320:                            sm, call) & OpCallbacks.ACT_RUN) == 0)
3321:                        return;
3322:                    if (sm != null)
3323:                        sm.nontransactional();
3324:                } catch (OpenJPAException ke) {
3325:                    throw ke;
3326:                } catch (RuntimeException re) {
3327:                    throw new GeneralException(re);
3328:                } finally {
3329:                    endOperation();
3330:                }
3331:            }
3332:
3333:            /**
3334:             * Make the given instances transactional.
3335:             */
3336:            public void transactionalAll(Collection objs,
3337:                    boolean updateVersion, OpCallbacks call) {
3338:                if (objs.isEmpty())
3339:                    return;
3340:                if (objs.size() == 1) {
3341:                    transactional(objs.iterator().next(), updateVersion, call);
3342:                    return;
3343:                }
3344:
3345:                beginOperation(true);
3346:                try {
3347:                    // collect all hollow instances for load, and make unmananged
3348:                    // instances transient-transactional
3349:                    Collection load = null;
3350:                    Object obj;
3351:                    StateManagerImpl sm;
3352:                    ClassMetaData meta;
3353:                    Collection sms = new ArrayList(objs.size());
3354:                    List exceps = null;
3355:                    for (Iterator itr = objs.iterator(); itr.hasNext();) {
3356:                        obj = itr.next();
3357:                        if (obj == null)
3358:                            continue;
3359:
3360:                        try {
3361:                            sm = getStateManagerImpl(obj, true);
3362:                            if ((processArgument(OpCallbacks.OP_TRANSACTIONAL,
3363:                                    obj, sm, call) & OpCallbacks.ACT_RUN) == 0)
3364:                                continue;
3365:
3366:                            if (sm == null) {
3367:                                // manage transient instance
3368:                                meta = _conf.getMetaDataRepositoryInstance()
3369:                                        .getMetaData(obj.getClass(), _loader,
3370:                                                true);
3371:
3372:                                sm = new StateManagerImpl(StateManagerId
3373:                                        .newInstance(this ), meta, this );
3374:                                sm.initialize(assertPersistenceCapable(obj),
3375:                                        PCState.TCLEAN);
3376:                            } else if (sm.isPersistent()) {
3377:                                assertActiveTransaction();
3378:                                sms.add(sm);
3379:                                if (sm.getPCState() == PCState.HOLLOW) {
3380:                                    if (load == null)
3381:                                        load = new ArrayList();
3382:                                    load.add(sm);
3383:                                }
3384:
3385:                                sm.setCheckVersion(true);
3386:                                if (updateVersion)
3387:                                    sm.setUpdateVersion(true);
3388:                                _flags |= FLAG_FLUSH_REQUIRED; // version check/up
3389:                            }
3390:                        } catch (UserException ue) {
3391:                            exceps = add(exceps, ue);
3392:                        }
3393:                    }
3394:
3395:                    // load all hollow instances
3396:                    Collection failed = null;
3397:                    if (load != null) {
3398:                        failed = _store.loadAll(load, null,
3399:                                _store.FORCE_LOAD_NONE, _fc, null);
3400:                        if (failed != null && !failed.isEmpty())
3401:                            exceps = add(exceps,
3402:                                    newObjectNotFoundException(failed));
3403:                    }
3404:
3405:                    transactionalStatesAll(sms, failed, exceps);
3406:                } catch (OpenJPAException ke) {
3407:                    throw ke;
3408:                } catch (RuntimeException re) {
3409:                    throw new GeneralException(re);
3410:                } finally {
3411:                    endOperation();
3412:                }
3413:            }
3414:
3415:            /**
3416:             * Make the given instances transactional.
3417:             */
3418:            public void transactional(Object obj, boolean updateVersion,
3419:                    OpCallbacks call) {
3420:                if (obj == null)
3421:                    return;
3422:
3423:                beginOperation(true);
3424:                try {
3425:                    StateManagerImpl sm = getStateManagerImpl(obj, true);
3426:                    if ((processArgument(OpCallbacks.OP_TRANSACTIONAL, obj, sm,
3427:                            call) & OpCallbacks.ACT_RUN) == 0)
3428:                        return;
3429:
3430:                    if (sm != null && sm.isPersistent()) {
3431:                        assertActiveTransaction();
3432:                        sm.transactional();
3433:                        sm.load(_fc, StateManagerImpl.LOAD_FGS, null, null,
3434:                                false);
3435:                        sm.setCheckVersion(true);
3436:                        if (updateVersion)
3437:                            sm.setUpdateVersion(true);
3438:                        _flags |= FLAG_FLUSH_REQUIRED; // version check/up
3439:                    } else if (sm == null) {
3440:                        // manage transient instance
3441:                        ClassMetaData meta = _conf
3442:                                .getMetaDataRepositoryInstance().getMetaData(
3443:                                        obj.getClass(), _loader, true);
3444:                        Object id = StateManagerId.newInstance(this );
3445:                        sm = new StateManagerImpl(id, meta, this );
3446:                        sm.initialize(assertPersistenceCapable(obj),
3447:                                PCState.TCLEAN);
3448:                    }
3449:                } catch (OpenJPAException ke) {
3450:                    throw ke;
3451:                } catch (RuntimeException re) {
3452:                    throw new GeneralException(re);
3453:                } finally {
3454:                    endOperation();
3455:                }
3456:            }
3457:
3458:            /**
3459:             * Transition the given state managers to transactional.
3460:             */
3461:            private void transactionalStatesAll(Collection sms,
3462:                    Collection failed, List exceps) {
3463:                // make instances transactional and make sure they are loaded
3464:                StateManagerImpl sm;
3465:                for (Iterator itr = sms.iterator(); itr.hasNext();) {
3466:                    sm = (StateManagerImpl) itr.next();
3467:                    if (failed != null && failed.contains(sm.getId()))
3468:                        continue;
3469:
3470:                    try {
3471:                        sm.transactional();
3472:                        sm.load(_fc, StateManagerImpl.LOAD_FGS, null, null,
3473:                                false);
3474:                    } catch (OpenJPAException ke) {
3475:                        exceps = add(exceps, ke);
3476:                    }
3477:                }
3478:                throwNestedExceptions(exceps, false);
3479:            }
3480:
3481:            /////////////////
3482:            // Extent, Query
3483:            /////////////////
3484:
3485:            public Extent newExtent(Class type, boolean subclasses) {
3486:                return newExtent(type, subclasses, null);
3487:            }
3488:
3489:            private Extent newExtent(Class type, boolean subclasses,
3490:                    FetchConfiguration fetch) {
3491:                beginOperation(true);
3492:                try {
3493:                    ExtentImpl extent = new ExtentImpl(this , type, subclasses,
3494:                            fetch);
3495:                    if (_extents == null)
3496:                        _extents = new ReferenceHashSet(ReferenceHashSet.WEAK);
3497:                    _extents.add(extent);
3498:
3499:                    return extent;
3500:                } catch (OpenJPAException ke) {
3501:                    throw ke;
3502:                } catch (RuntimeException re) {
3503:                    throw new GeneralException(re);
3504:                } finally {
3505:                    endOperation();
3506:                }
3507:            }
3508:
3509:            public Iterator extentIterator(Class type, boolean subclasses,
3510:                    FetchConfiguration fetch, boolean ignoreChanges) {
3511:                Extent extent = newExtent(type, subclasses, fetch);
3512:                extent.setIgnoreChanges(ignoreChanges);
3513:                return extent.iterator();
3514:            }
3515:
3516:            public Query newQuery(String lang, Class cls, Object query) {
3517:                Query q = newQuery(lang, query);
3518:                q.setCandidateType(cls, true);
3519:                return q;
3520:            }
3521:
3522:            public Query newQuery(String lang, Object query) {
3523:                // common mistakes
3524:                if (query instanceof  Extent || query instanceof  Class)
3525:                    throw new UserException(_loc.get("bad-new-query"));
3526:
3527:                beginOperation(false);
3528:                try {
3529:                    StoreQuery sq = _store.newQuery(lang);
3530:                    if (sq == null) {
3531:                        ExpressionParser ep = QueryLanguages
3532:                                .parserForLanguage(lang);
3533:                        if (ep != null)
3534:                            sq = new ExpressionStoreQuery(ep);
3535:                        else if (QueryLanguages.LANG_METHODQL.equals(lang))
3536:                            sq = new MethodStoreQuery();
3537:                        else
3538:                            throw new UnsupportedException(lang);
3539:                    }
3540:
3541:                    Query q = newQueryImpl(lang, sq);
3542:                    q.setIgnoreChanges(_ignoreChanges);
3543:                    if (query != null)
3544:                        q.setQuery(query);
3545:
3546:                    // track queries
3547:                    if (_queries == null)
3548:                        _queries = new ReferenceHashSet(ReferenceHashSet.WEAK);
3549:                    _queries.add(q);
3550:                    return q;
3551:                } catch (OpenJPAException ke) {
3552:                    throw ke;
3553:                } catch (RuntimeException re) {
3554:                    throw new GeneralException(re);
3555:                } finally {
3556:                    endOperation();
3557:                }
3558:            }
3559:
3560:            /**
3561:             * Create a new query.
3562:             */
3563:            protected QueryImpl newQueryImpl(String lang, StoreQuery sq) {
3564:                return new QueryImpl(this , lang, sq);
3565:            }
3566:
3567:            public Seq getIdentitySequence(ClassMetaData meta) {
3568:                if (meta == null)
3569:                    return null;
3570:                return getSequence(meta, null);
3571:            }
3572:
3573:            public Seq getValueSequence(FieldMetaData fmd) {
3574:                if (fmd == null)
3575:                    return null;
3576:                return getSequence(fmd.getDefiningMetaData(), fmd);
3577:            }
3578:
3579:            /**
3580:             * Return a sequence for the given class and optional field.
3581:             */
3582:            private Seq getSequence(ClassMetaData meta, FieldMetaData fmd) {
3583:                // get sequence strategy from metadata
3584:                int strategy;
3585:                if (fmd == null)
3586:                    strategy = meta.getIdentityStrategy();
3587:                else
3588:                    strategy = fmd.getValueStrategy();
3589:
3590:                // we can handle non-native strategies without the store manager
3591:                switch (strategy) {
3592:                case ValueStrategies.UUID_HEX:
3593:                    return UUIDHexSeq.getInstance();
3594:                case ValueStrategies.UUID_STRING:
3595:                    return UUIDStringSeq.getInstance();
3596:                case ValueStrategies.SEQUENCE:
3597:                    SequenceMetaData smd = (fmd == null) ? meta
3598:                            .getIdentitySequenceMetaData() : fmd
3599:                            .getValueSequenceMetaData();
3600:                    return smd.getInstance(_loader);
3601:                default:
3602:                    // use store manager for native sequence
3603:                    if (fmd == null) {
3604:                        // this will return a sequence even for app id classes,
3605:                        // which is what we want for backwards-compatibility
3606:                        return _store.getDataStoreIdSequence(meta);
3607:                    }
3608:                    return _store.getValueSequence(fmd);
3609:                }
3610:            }
3611:
3612:            ///////////
3613:            // Locking
3614:            ///////////
3615:
3616:            public void lock(Object obj, OpCallbacks call) {
3617:                if (obj == null)
3618:                    return;
3619:
3620:                beginOperation(true); // have to sync or lock level always NONE
3621:                try {
3622:                    lock(obj, _fc.getWriteLockLevel(), _fc.getLockTimeout(),
3623:                            call);
3624:                } finally {
3625:                    endOperation();
3626:                }
3627:            }
3628:
3629:            public void lock(Object obj, int level, int timeout,
3630:                    OpCallbacks call) {
3631:                if (obj == null)
3632:                    return;
3633:
3634:                beginOperation(true);
3635:                try {
3636:                    assertActiveTransaction();
3637:
3638:                    StateManagerImpl sm = getStateManagerImpl(obj, true);
3639:                    if ((processArgument(OpCallbacks.OP_LOCK, obj, sm, call) & OpCallbacks.ACT_RUN) == 0)
3640:                        return;
3641:                    if (sm == null || !sm.isPersistent())
3642:                        return;
3643:
3644:                    _lm.lock(sm, level, timeout, null);
3645:                    sm.readLocked(level, level); // use same level for future write
3646:                } catch (OpenJPAException ke) {
3647:                    throw ke;
3648:                } catch (RuntimeException re) {
3649:                    throw new GeneralException(re);
3650:                } finally {
3651:                    endOperation();
3652:                }
3653:            }
3654:
3655:            public void lockAll(Collection objs, OpCallbacks call) {
3656:                if (objs.isEmpty())
3657:                    return;
3658:
3659:                beginOperation(true); // have to sync or lock level always NONE
3660:                try {
3661:                    lockAll(objs, _fc.getWriteLockLevel(),
3662:                            _fc.getLockTimeout(), call);
3663:                } finally {
3664:                    endOperation();
3665:                }
3666:            }
3667:
3668:            public void lockAll(Collection objs, int level, int timeout,
3669:                    OpCallbacks call) {
3670:                if (objs.isEmpty())
3671:                    return;
3672:                if (objs.size() == 1) {
3673:                    lock(objs.iterator().next(), level, timeout, call);
3674:                    return;
3675:                }
3676:
3677:                beginOperation(true);
3678:                try {
3679:                    assertActiveTransaction();
3680:
3681:                    Collection sms = new ArrayList(objs.size());
3682:                    Object obj;
3683:                    StateManagerImpl sm;
3684:                    for (Iterator itr = objs.iterator(); itr.hasNext();) {
3685:                        obj = itr.next();
3686:                        if (obj == null)
3687:                            continue;
3688:
3689:                        sm = getStateManagerImpl(obj, true);
3690:                        if ((processArgument(OpCallbacks.OP_LOCK, obj, sm, call) & OpCallbacks.ACT_RUN) == 0)
3691:                            continue;
3692:                        if (sm != null && sm.isPersistent())
3693:                            sms.add(sm);
3694:                    }
3695:
3696:                    _lm.lockAll(sms, level, timeout, null);
3697:                    for (Iterator itr = sms.iterator(); itr.hasNext();)
3698:                        ((StateManagerImpl) itr.next())
3699:                                .readLocked(level, level);
3700:                } catch (OpenJPAException ke) {
3701:                    throw ke;
3702:                } catch (RuntimeException re) {
3703:                    throw new GeneralException(re);
3704:                } finally {
3705:                    endOperation();
3706:                }
3707:            }
3708:
3709:            //////////////
3710:            // Connection
3711:            //////////////
3712:
3713:            public boolean cancelAll() {
3714:                // this method does not lock, since we want to allow a different
3715:                // thread to be able to cancel on a locked-up persistence manager
3716:
3717:                assertOpen();
3718:                try {
3719:                    // if we're flushing, have to set rollback only -- do this before we
3720:                    // attempt to cancel, because otherwise the cancel might case the
3721:                    // transaction to complete before we have a chance to set the
3722:                    // rollback only flag
3723:                    if ((_flags & FLAG_STORE_FLUSHING) != 0)
3724:                        setRollbackOnlyInternal(new UserException());
3725:                    return _store.cancelAll();
3726:                } catch (OpenJPAException ke) {
3727:                    throw ke;
3728:                } catch (RuntimeException re) {
3729:                    throw new StoreException(re);
3730:                }
3731:            }
3732:
3733:            public Object getConnection() {
3734:                assertOpen();
3735:                if (!_conf.supportedOptions().contains(
3736:                        _conf.OPTION_DATASTORE_CONNECTION))
3737:                    throw new UnsupportedException(_loc
3738:                            .get("conn-not-supported"));
3739:
3740:                return _store.getClientConnection();
3741:            }
3742:
3743:            public boolean hasConnection() {
3744:                assertOpen();
3745:                return (_flags & FLAG_RETAINED_CONN) != 0;
3746:            }
3747:
3748:            /**
3749:             * Tell store to retain connection if we haven't already.
3750:             */
3751:            private void retainConnection() {
3752:                if ((_flags & FLAG_RETAINED_CONN) == 0) {
3753:                    _store.retainConnection();
3754:                    _flags |= FLAG_RETAINED_CONN;
3755:                }
3756:            }
3757:
3758:            /**
3759:             * Tell store to release connection if we have retained one.
3760:             */
3761:            private void releaseConnection() {
3762:                if ((_flags & FLAG_RETAINED_CONN) != 0) {
3763:                    _store.releaseConnection();
3764:                    _flags &= ~FLAG_RETAINED_CONN;
3765:                }
3766:            }
3767:
3768:            /////////
3769:            // Cache
3770:            /////////
3771:
3772:            public Collection getManagedObjects() {
3773:                beginOperation(false);
3774:                try {
3775:                    return new ManagedObjectCollection(getManagedStates());
3776:                } finally {
3777:                    endOperation();
3778:                }
3779:            }
3780:
3781:            public Collection getTransactionalObjects() {
3782:                beginOperation(false);
3783:                try {
3784:                    return new ManagedObjectCollection(getTransactionalStates());
3785:                } finally {
3786:                    endOperation();
3787:                }
3788:            }
3789:
3790:            public Collection getPendingTransactionalObjects() {
3791:                beginOperation(false);
3792:                try {
3793:                    return new ManagedObjectCollection(
3794:                            getPendingTransactionalStates());
3795:                } finally {
3796:                    endOperation();
3797:                }
3798:            }
3799:
3800:            public Collection getDirtyObjects() {
3801:                beginOperation(false);
3802:                try {
3803:                    return new ManagedObjectCollection(getDirtyStates());
3804:                } finally {
3805:                    endOperation();
3806:                }
3807:            }
3808:
3809:            public boolean getOrderDirtyObjects() {
3810:                return _orderDirty;
3811:            }
3812:
3813:            public void setOrderDirtyObjects(boolean order) {
3814:                _orderDirty = order;
3815:            }
3816:
3817:            /**
3818:             * Return a copy of all managed state managers.
3819:             */
3820:            protected Collection getManagedStates() {
3821:                return _cache.copy();
3822:            }
3823:
3824:            /**
3825:             * Return a copy of all transactional state managers.
3826:             */
3827:            protected Collection getTransactionalStates() {
3828:                if (!hasTransactionalObjects())
3829:                    return Collections.EMPTY_LIST;
3830:                return _transCache.copy();
3831:            }
3832:
3833:            /**
3834:             * Whether or not there are any transactional objects in the current
3835:             * persistence context. If there are any instances with untracked state,
3836:             * this method will cause those instances to be scanned.
3837:             */
3838:            private boolean hasTransactionalObjects() {
3839:                _cache.dirtyCheck();
3840:                return _transCache != null;
3841:            }
3842:
3843:            /**
3844:             * Return a copy of all dirty state managers.
3845:             */
3846:            protected Collection getDirtyStates() {
3847:                if (!hasTransactionalObjects())
3848:                    return Collections.EMPTY_LIST;
3849:
3850:                return _transCache.copyDirty();
3851:            }
3852:
3853:            /**
3854:             * Return a copy of all state managers which will become
3855:             * transactional upon the next transaction.
3856:             */
3857:            protected Collection getPendingTransactionalStates() {
3858:                if (_pending == null)
3859:                    return Collections.EMPTY_LIST;
3860:                return new ArrayList(_pending);
3861:            }
3862:
3863:            /**
3864:             * Set the cached StateManager for the instance that had the given oid.
3865:             * This method must not be called multiple times for new instances.
3866:             *
3867:             * @param id the id previously used by the instance
3868:             * @param sm the state manager for the instance; if the state
3869:             * manager is transient, we'll stop managing the instance;
3870:             * if it has updated its oid, we'll re-cache under the new oid
3871:             * @param status one of our STATUS constants describing why we're
3872:             * setting the state manager
3873:             */
3874:            void setStateManager(Object id, StateManagerImpl sm, int status) {
3875:                lock();
3876:                try {
3877:                    switch (status) {
3878:                    case STATUS_INIT:
3879:                        _cache.add(sm);
3880:                        break;
3881:                    case STATUS_TRANSIENT:
3882:                        _cache.remove(id, sm);
3883:                        break;
3884:                    case STATUS_OID_ASSIGN:
3885:                        assignObjectId(_cache, id, sm);
3886:                        break;
3887:                    case STATUS_COMMIT_NEW:
3888:                        _cache.commitNew(id, sm);
3889:                        break;
3890:                    default:
3891:                        throw new InternalException();
3892:                    }
3893:                } finally {
3894:                    unlock();
3895:                }
3896:            }
3897:
3898:            /**
3899:             * Notify the broker that the given state manager should
3900:             * be added to the set of instances involved in the current transaction.
3901:             */
3902:            void addToTransaction(StateManagerImpl sm) {
3903:                // we only add clean instances now; dirty instances are added in
3904:                // the setDirty callback
3905:                if (sm.isDirty())
3906:                    return;
3907:
3908:                lock();
3909:                try {
3910:                    if (!hasTransactionalObjects())
3911:                        _transCache = new TransactionalCache(_orderDirty);
3912:                    _transCache.addClean(sm);
3913:                } finally {
3914:                    unlock();
3915:                }
3916:            }
3917:
3918:            /**
3919:             * Notify the persistence manager that the given state manager should
3920:             * be removed from the set of instances involved in the current transaction.
3921:             */
3922:            void removeFromTransaction(StateManagerImpl sm) {
3923:                lock();
3924:                try {
3925:                    if (_transCache != null)
3926:                        // intentional direct access; we don't want to recompute
3927:                        // dirtiness while removing instances from the transaction
3928:                        _transCache.remove(sm);
3929:                    if (_derefCache != null && !sm.isPersistent())
3930:                        _derefCache.remove(sm);
3931:                } finally {
3932:                    unlock();
3933:                }
3934:            }
3935:
3936:            /**
3937:             * Notification that the given instance has been dirtied. This
3938:             * notification is given when an object first transitions to a dirty state,
3939:             * and every time the object is modified by the user thereafter.
3940:             */
3941:            void setDirty(StateManagerImpl sm, boolean firstDirty) {
3942:                if (sm.isPersistent())
3943:                    _flags |= FLAG_FLUSH_REQUIRED;
3944:
3945:                if (_savepoints != null && !_savepoints.isEmpty()) {
3946:                    if (_savepointCache == null)
3947:                        _savepointCache = new HashSet();
3948:                    _savepointCache.add(sm);
3949:                }
3950:
3951:                if (firstDirty && sm.isTransactional()) {
3952:                    lock();
3953:                    try {
3954:                        // cache dirty instance
3955:                        if (!hasTransactionalObjects())
3956:                            _transCache = new TransactionalCache(_orderDirty);
3957:                        _transCache.addDirty(sm);
3958:
3959:                        // also record that the class is dirty
3960:                        if (sm.isNew()) {
3961:                            if (_persistedClss == null)
3962:                                _persistedClss = new HashSet();
3963:                            _persistedClss.add(sm.getMetaData()
3964:                                    .getDescribedType());
3965:                        } else if (sm.isDeleted()) {
3966:                            if (_deletedClss == null)
3967:                                _deletedClss = new HashSet();
3968:                            _deletedClss.add(sm.getMetaData()
3969:                                    .getDescribedType());
3970:                        } else {
3971:                            if (_updatedClss == null)
3972:                                _updatedClss = new HashSet();
3973:                            _updatedClss.add(sm.getMetaData()
3974:                                    .getDescribedType());
3975:                        }
3976:
3977:                        // if tracking changes and this instance wasn't already dirty,
3978:                        // add to changed set; we use this for detecting instances that
3979:                        // enter the transaction during pre store
3980:                        if ((_flags & FLAG_PRESTORING) != 0) {
3981:                            if (_transAdditions == null)
3982:                                _transAdditions = new HashSet();
3983:                            _transAdditions.add(sm);
3984:                        }
3985:                    } finally {
3986:                        unlock();
3987:                    }
3988:                }
3989:            }
3990:
3991:            /**
3992:             * Notify the broker that the given state manager should
3993:             * be added to the set of instances that will become transactional
3994:             * on the next transaction
3995:             */
3996:            void addToPendingTransaction(StateManagerImpl sm) {
3997:                lock();
3998:                try {
3999:                    if (_pending == null)
4000:                        _pending = new HashSet();
4001:                    _pending.add(sm);
4002:                } finally {
4003:                    unlock();
4004:                }
4005:            }
4006:
4007:            /**
4008:             * Notify the persistence manager that the given state manager should
4009:             * be removed from the set of instances involved in the next transaction.
4010:             */
4011:            void removeFromPendingTransaction(StateManagerImpl sm) {
4012:                lock();
4013:                try {
4014:                    if (_pending != null)
4015:                        _pending.remove(sm);
4016:                    if (_derefCache != null && !sm.isPersistent())
4017:                        _derefCache.remove(sm);
4018:                } finally {
4019:                    unlock();
4020:                }
4021:            }
4022:
4023:            /**
4024:             * Add a dereferenced dependent object to the persistence manager's cache.
4025:             * On flush, these objects will be deleted.
4026:             */
4027:            void addDereferencedDependent(StateManagerImpl sm) {
4028:                lock();
4029:                try {
4030:                    // if we're in the middle of flush and introducing more derefs
4031:                    // via instance callbacks, add them to the special additions set
4032:                    if ((_flags & FLAG_DEREFDELETING) != 0) {
4033:                        if (_derefAdditions == null)
4034:                            _derefAdditions = new HashSet();
4035:                        _derefAdditions.add(sm);
4036:                    } else {
4037:                        if (_derefCache == null)
4038:                            _derefCache = new HashSet();
4039:                        _derefCache.add(sm);
4040:                    }
4041:                } finally {
4042:                    unlock();
4043:                }
4044:            }
4045:
4046:            /**
4047:             * Remove the given previously dereferenced dependent object from the
4048:             * cache. It is now referenced.
4049:             */
4050:            void removeDereferencedDependent(StateManagerImpl sm) {
4051:                lock();
4052:                try {
4053:                    boolean removed = false;
4054:                    if (_derefAdditions != null)
4055:                        removed = _derefAdditions.remove(sm);
4056:                    if (!removed
4057:                            && (_derefCache == null || !_derefCache.remove(sm)))
4058:                        throw new InvalidStateException(_loc.get("not-derefed",
4059:                                Exceptions.toString(sm.getManagedInstance())))
4060:                                .setFailedObject(sm.getManagedInstance())
4061:                                .setFatal(true);
4062:                } finally {
4063:                    unlock();
4064:                }
4065:            }
4066:
4067:            public void dirtyType(Class cls) {
4068:                if (cls == null)
4069:                    return;
4070:
4071:                beginOperation(false);
4072:                try {
4073:                    if (_updatedClss == null)
4074:                        _updatedClss = new HashSet();
4075:                    _updatedClss.add(cls);
4076:                } finally {
4077:                    endOperation();
4078:                }
4079:            }
4080:
4081:            public Collection getPersistedTypes() {
4082:                if (_persistedClss == null || _persistedClss.isEmpty())
4083:                    return Collections.EMPTY_LIST;
4084:                return Collections.unmodifiableCollection(_persistedClss);
4085:            }
4086:
4087:            public Collection getUpdatedTypes() {
4088:                if (_updatedClss == null || _updatedClss.isEmpty())
4089:                    return Collections.EMPTY_LIST;
4090:                return Collections.unmodifiableCollection(_updatedClss);
4091:            }
4092:
4093:            public Collection getDeletedTypes() {
4094:                if (_deletedClss == null || _deletedClss.isEmpty())
4095:                    return Collections.EMPTY_LIST;
4096:                return Collections.unmodifiableCollection(_deletedClss);
4097:            }
4098:
4099:            ///////////
4100:            // Closing
4101:            ///////////
4102:
4103:            public boolean isClosed() {
4104:                return _closed;
4105:            }
4106:
4107:            public boolean isCloseInvoked() {
4108:                return _closed || (_flags & FLAG_CLOSE_INVOKED) != 0;
4109:            }
4110:
4111:            public void close() {
4112:                beginOperation(false);
4113:                try {
4114:                    // throw an exception if closing in an active local trans
4115:                    if (!_managed && (_flags & FLAG_ACTIVE) != 0)
4116:                        throw new InvalidStateException(_loc.get("active"));
4117:
4118:                    // only close if not active; if active managed trans wait
4119:                    // for completion
4120:                    _flags |= FLAG_CLOSE_INVOKED;
4121:
4122:                    if ((_flags & FLAG_ACTIVE) == 0)
4123:                        free();
4124:                } finally {
4125:                    endOperation();
4126:                }
4127:            }
4128:
4129:            /**
4130:             * Free the resources used by this persistence manager.
4131:             */
4132:            protected void free() {
4133:                RuntimeException err = null;
4134:                if ((_autoDetach & DETACH_CLOSE) != 0) {
4135:                    try {
4136:                        detachAllInternal(_call);
4137:                    } catch (RuntimeException re) {
4138:                        err = re;
4139:                    }
4140:                }
4141:
4142:                _sync = null;
4143:                _userObjects = null;
4144:                _cache.clear();
4145:                _transCache = null;
4146:                _persistedClss = null;
4147:                _updatedClss = null;
4148:                _deletedClss = null;
4149:                _derefCache = null;
4150:                _pending = null;
4151:                _loader = null;
4152:                _transEventManager = null;
4153:                _lifeEventManager = null;
4154:
4155:                OpenJPASavepoint save;
4156:                while (_savepoints != null && !_savepoints.isEmpty()) {
4157:                    save = (OpenJPASavepoint) _savepoints.remove(_savepoints
4158:                            .size() - 1);
4159:                    save.release(false);
4160:                }
4161:                _savepoints = null;
4162:                _savepointCache = null;
4163:
4164:                if (_queries != null) {
4165:                    for (Iterator itr = _queries.iterator(); itr.hasNext();) {
4166:                        try {
4167:                            ((Query) itr.next()).closeResources();
4168:                        } catch (RuntimeException re) {
4169:                        }
4170:                    }
4171:                    _queries = null;
4172:                }
4173:
4174:                if (_extents != null) {
4175:                    Extent e;
4176:                    for (Iterator itr = _extents.iterator(); itr.hasNext();) {
4177:                        e = (Extent) itr.next();
4178:                        try {
4179:                            e.closeAll();
4180:                        } catch (RuntimeException re) {
4181:                        }
4182:                    }
4183:                    _extents = null;
4184:                }
4185:
4186:                try {
4187:                    releaseConnection();
4188:                } catch (RuntimeException re) {
4189:                }
4190:
4191:                _lm.close();
4192:                _store.close();
4193:                _flags = 0;
4194:                _closed = true;
4195:                if (_log.isTraceEnabled())
4196:                    _closedException = new IllegalStateException();
4197:
4198:                if (err != null)
4199:                    throw err;
4200:            }
4201:
4202:            ///////////////////
4203:            // Synchronization
4204:            ///////////////////
4205:
4206:            public void lock() {
4207:                if (_lock != null)
4208:                    _lock.lock();
4209:            }
4210:
4211:            public void unlock() {
4212:                if (_lock != null)
4213:                    _lock.unlock();
4214:            }
4215:
4216:            ////////////////////
4217:            // State management
4218:            ////////////////////
4219:
4220:            public Object newInstance(Class cls) {
4221:                assertOpen();
4222:
4223:                if (!cls.isInterface()
4224:                        && Modifier.isAbstract(cls.getModifiers()))
4225:                    throw new UnsupportedOperationException(_loc.get(
4226:                            "new-abstract", cls).getMessage());
4227:
4228:                // 1.5 doesn't initialize classes without a true Class.forName
4229:                if (!PCRegistry.isRegistered(cls)) {
4230:                    try {
4231:                        Class.forName(cls.getName(), true,
4232:                                (ClassLoader) AccessController
4233:                                        .doPrivileged(J2DoPrivHelper
4234:                                                .getClassLoaderAction(cls)));
4235:                    } catch (Throwable t) {
4236:                    }
4237:                }
4238:
4239:                if (_conf.getMetaDataRepositoryInstance().getMetaData(cls,
4240:                        getClassLoader(), false) == null)
4241:                    throw new IllegalArgumentException(_loc.get(
4242:                            "no-interface-metadata", cls.getName())
4243:                            .getMessage());
4244:
4245:                try {
4246:                    return PCRegistry.newInstance(cls, null, false);
4247:                } catch (IllegalStateException ise) {
4248:                    IllegalArgumentException iae = new IllegalArgumentException(
4249:                            ise.getMessage());
4250:                    iae.setStackTrace(ise.getStackTrace());
4251:                    throw iae;
4252:                }
4253:            }
4254:
4255:            public Object getObjectId(Object obj) {
4256:                assertOpen();
4257:                if (ImplHelper.isManageable(obj))
4258:                    return (ImplHelper.toPersistenceCapable(obj, _conf))
4259:                            .pcFetchObjectId();
4260:                return null;
4261:            }
4262:
4263:            public int getLockLevel(Object o) {
4264:                assertOpen();
4265:                if (o == null)
4266:                    return LockLevels.LOCK_NONE;
4267:
4268:                OpenJPAStateManager sm = getStateManager(o);
4269:                if (sm == null)
4270:                    return LockLevels.LOCK_NONE;
4271:                return getLockManager().getLockLevel(sm);
4272:            }
4273:
4274:            public Object getVersion(Object obj) {
4275:                assertOpen();
4276:                if (ImplHelper.isManageable(obj))
4277:                    return (ImplHelper.toPersistenceCapable(obj, _conf))
4278:                            .pcGetVersion();
4279:                return null;
4280:            }
4281:
4282:            public boolean isDirty(Object obj) {
4283:                assertOpen();
4284:                if (ImplHelper.isManageable(obj)) {
4285:                    PersistenceCapable pc = ImplHelper.toPersistenceCapable(
4286:                            obj, _conf);
4287:                    return pc.pcIsDirty();
4288:                }
4289:                return false;
4290:            }
4291:
4292:            public boolean isTransactional(Object obj) {
4293:                assertOpen();
4294:                if (ImplHelper.isManageable(obj))
4295:                    return (ImplHelper.toPersistenceCapable(obj, _conf))
4296:                            .pcIsTransactional();
4297:                return false;
4298:            }
4299:
4300:            public boolean isPersistent(Object obj) {
4301:                assertOpen();
4302:                if (ImplHelper.isManageable(obj))
4303:                    return (ImplHelper.toPersistenceCapable(obj, _conf))
4304:                            .pcIsPersistent();
4305:                return false;
4306:            }
4307:
4308:            public boolean isNew(Object obj) {
4309:                assertOpen();
4310:                if (ImplHelper.isManageable(obj))
4311:                    return (ImplHelper.toPersistenceCapable(obj, _conf))
4312:                            .pcIsNew();
4313:                return false;
4314:            }
4315:
4316:            public boolean isDeleted(Object obj) {
4317:                assertOpen();
4318:                if (ImplHelper.isManageable(obj))
4319:                    return (ImplHelper.toPersistenceCapable(obj, _conf))
4320:                            .pcIsDeleted();
4321:                return false;
4322:            }
4323:
4324:            public boolean isDetached(Object obj) {
4325:                if (!(ImplHelper.isManageable(obj)))
4326:                    return false;
4327:
4328:                PersistenceCapable pc = ImplHelper.toPersistenceCapable(obj,
4329:                        _conf);
4330:                Boolean detached = pc.pcIsDetached();
4331:                if (detached != null)
4332:                    return detached.booleanValue();
4333:
4334:                // last resort: instance is detached if it has a store record
4335:                ClassMetaData meta = _conf.getMetaDataRepositoryInstance()
4336:                        .getMetaData(
4337:                                ImplHelper.getManagedInstance(pc).getClass(),
4338:                                _loader, true);
4339:                Object oid = ApplicationIds.create(pc, meta);
4340:                if (oid == null)
4341:                    return false;
4342:                return find(oid, null, EXCLUDE_ALL, null, 0) != null;
4343:            }
4344:
4345:            public OpenJPAStateManager getStateManager(Object obj) {
4346:                assertOpen();
4347:                return getStateManagerImpl(obj, false);
4348:            }
4349:
4350:            /**
4351:             * Return the state manager for the given instance, or null.
4352:             *
4353:             * @param assertThisContext if true, thow an exception if the given
4354:             * object is managed by another broker
4355:             */
4356:            protected StateManagerImpl getStateManagerImpl(Object obj,
4357:                    boolean assertThisContext) {
4358:                if (ImplHelper.isManageable(obj)) {
4359:                    PersistenceCapable pc = ImplHelper.toPersistenceCapable(
4360:                            obj, _conf);
4361:                    if (pc.pcGetGenericContext() == this )
4362:                        return (StateManagerImpl) pc.pcGetStateManager();
4363:                    if (assertThisContext && pc.pcGetGenericContext() != null)
4364:                        throw new UserException(_loc.get("not-managed",
4365:                                Exceptions.toString(obj))).setFailedObject(obj);
4366:                }
4367:                return null;
4368:            }
4369:
4370:            /**
4371:             * Return the state manager for the given oid.
4372:             *
4373:             * @param allowNew if true, objects made persistent in the current
4374:             * transaction will be included in the search; if
4375:             * multiple new objects match the given oid, it is
4376:             * undefined which will be returned
4377:             */
4378:            protected StateManagerImpl getStateManagerImplById(Object oid,
4379:                    boolean allowNew) {
4380:                return _cache.getById(oid, allowNew);
4381:            }
4382:
4383:            /**
4384:             * Return the given instance as a {@link PersistenceCapable}.
4385:             * If the instance is not manageable throw the proper exception.
4386:             */
4387:            protected PersistenceCapable assertPersistenceCapable(Object obj) {
4388:                if (obj == null)
4389:                    return null;
4390:                if (ImplHelper.isManageable(obj))
4391:                    return ImplHelper.toPersistenceCapable(obj, _conf);
4392:
4393:                // check for different instances of the PersistenceCapable interface
4394:                // and throw a better error that mentions the class loaders
4395:                Class[] intfs = obj.getClass().getInterfaces();
4396:                for (int i = 0; intfs != null && i < intfs.length; i++) {
4397:                    if (intfs[i].getName().equals(
4398:                            PersistenceCapable.class.getName())) {
4399:                        throw new UserException(
4400:                                _loc
4401:                                        .get(
4402:                                                "pc-loader-different",
4403:                                                Exceptions.toString(obj),
4404:                                                (ClassLoader) AccessController
4405:                                                        .doPrivileged(J2DoPrivHelper
4406:                                                                .getClassLoaderAction(PersistenceCapable.class)),
4407:                                                (ClassLoader) AccessController
4408:                                                        .doPrivileged(J2DoPrivHelper
4409:                                                                .getClassLoaderAction(intfs[i]))))
4410:                                .setFailedObject(obj);
4411:                    }
4412:                }
4413:
4414:                // not enhanced
4415:                throw new UserException(_loc.get("pc-cast", Exceptions
4416:                        .toString(obj))).setFailedObject(obj);
4417:            }
4418:
4419:            /////////
4420:            // Utils
4421:            /////////
4422:            /**
4423:             * Throw an exception if the context is closed.  The exact message and
4424:             * content of the exception varies whether TRACE is enabled or not.
4425:             */
4426:            public void assertOpen() {
4427:                if (_closed) {
4428:                    if (_closedException == null) // TRACE not enabled
4429:                        throw new InvalidStateException(_loc
4430:                                .get("closed-notrace")).setFatal(true);
4431:                    else {
4432:                        OpenJPAException e = new InvalidStateException(_loc
4433:                                .get("closed"), _closedException)
4434:                                .setFatal(true);
4435:                        e.setCause(_closedException);
4436:                        throw e;
4437:                    }
4438:                }
4439:            }
4440:
4441:            public void assertActiveTransaction() {
4442:                if ((_flags & FLAG_ACTIVE) == 0)
4443:                    throw new NoTransactionException(_loc.get("not-active"));
4444:            }
4445:
4446:            /**
4447:             * Throw exception if a transaction-related operation is attempted and
4448:             * no transaction is active.
4449:             */
4450:            private void assertTransactionOperation() {
4451:                if ((_flags & FLAG_ACTIVE) == 0)
4452:                    throw new InvalidStateException(_loc.get("not-active"));
4453:            }
4454:
4455:            public void assertNontransactionalRead() {
4456:                if ((_flags & FLAG_ACTIVE) == 0 && !_nontransRead)
4457:                    throw new InvalidStateException(_loc.get("non-trans-read"));
4458:            }
4459:
4460:            public void assertWriteOperation() {
4461:                if ((_flags & FLAG_ACTIVE) == 0
4462:                        && (!_nontransWrite || (_autoDetach & DETACH_NONTXREAD) != 0))
4463:                    throw new NoTransactionException(_loc
4464:                            .get("write-operation"));
4465:            }
4466:
4467:            /**
4468:             * Return an object not found exception containing nested exceptions
4469:             * for all of the given failed objects.
4470:             */
4471:            private static ObjectNotFoundException newObjectNotFoundException(
4472:                    Collection failed) {
4473:                Throwable[] t = new Throwable[failed.size()];
4474:                int idx = 0;
4475:                for (Iterator itr = failed.iterator(); itr.hasNext(); idx++)
4476:                    t[idx] = new ObjectNotFoundException(itr.next());
4477:                return new ObjectNotFoundException(failed, t);
4478:            }
4479:
4480:            ////////////////////////////////
4481:            // FindCallbacks implementation
4482:            ////////////////////////////////
4483:
4484:            public Object processArgument(Object oid) {
4485:                return oid;
4486:            }
4487:
4488:            public Object processReturn(Object oid, OpenJPAStateManager sm) {
4489:                return (sm == null) ? null : sm.getManagedInstance();
4490:            }
4491:
4492:            private void writeObject(ObjectOutputStream out) throws IOException {
4493:                assertOpen();
4494:                lock();
4495:                try {
4496:                    if (isActive()) {
4497:                        if (!getOptimistic())
4498:                            throw new InvalidStateException(_loc
4499:                                    .get("cant-serialize-pessimistic-broker"));
4500:                        if (hasFlushed())
4501:                            throw new InvalidStateException(_loc
4502:                                    .get("cant-serialize-flushed-broker"));
4503:                        if (hasConnection())
4504:                            throw new InvalidStateException(_loc
4505:                                    .get("cant-serialize-connected-broker"));
4506:                    }
4507:
4508:                    try {
4509:                        _isSerializing = true;
4510:                        out.writeObject(_factory.getPoolKey());
4511:                        out.defaultWriteObject();
4512:                    } finally {
4513:                        _isSerializing = false;
4514:                    }
4515:                } finally {
4516:                    unlock();
4517:                }
4518:            }
4519:
4520:            private void readObject(ObjectInputStream in)
4521:                    throws ClassNotFoundException, IOException {
4522:                Object factoryKey = in.readObject();
4523:                AbstractBrokerFactory factory = AbstractBrokerFactory
4524:                        .getPooledFactoryForKey(factoryKey);
4525:
4526:                // this needs to happen before defaultReadObject so that it's
4527:                // available for calls to broker.getConfiguration() during
4528:                // StateManager deserialization
4529:                _conf = factory.getConfiguration();
4530:
4531:                in.defaultReadObject();
4532:                factory.initializeBroker(_managed, _connRetainMode, this , true);
4533:
4534:                // re-initialize the lock if needed.
4535:                setMultithreaded(_multithreaded);
4536:
4537:                if (isActive() && _runtime instanceof  LocalManagedRuntime)
4538:                    ((LocalManagedRuntime) _runtime).begin();
4539:            }
4540:
4541:            /**
4542:             * Whether or not this broker is in the midst of being serialized.
4543:             *
4544:             * @since 1.1.0 
4545:             */
4546:            boolean isSerializing() {
4547:                return _isSerializing;
4548:            }
4549:
4550:            /**
4551:             * Transactional cache that holds soft refs to clean instances.
4552:             */
4553:            static class TransactionalCache implements  Set, Serializable {
4554:
4555:                private final boolean _orderDirty;
4556:                private Set _dirty = null;
4557:                private Set _clean = null;
4558:
4559:                public TransactionalCache(boolean orderDirty) {
4560:                    _orderDirty = orderDirty;
4561:                }
4562:
4563:                /**
4564:                 * Return a copy of all transactional state managers.
4565:                 */
4566:                public Collection copy() {
4567:                    if (isEmpty())
4568:                        return Collections.EMPTY_LIST;
4569:
4570:                    // size may not be entirely accurate due to refs expiring, so
4571:                    // manually copy each object; doesn't matter this way if size too
4572:                    // big by some
4573:                    List copy = new ArrayList(size());
4574:                    if (_dirty != null)
4575:                        for (Iterator itr = _dirty.iterator(); itr.hasNext();)
4576:                            copy.add(itr.next());
4577:                    if (_clean != null)
4578:                        for (Iterator itr = _clean.iterator(); itr.hasNext();)
4579:                            copy.add(itr.next());
4580:                    return copy;
4581:                }
4582:
4583:                /**
4584:                 * Return a copy of all dirty state managers.
4585:                 */
4586:                public Collection copyDirty() {
4587:                    if (_dirty == null || _dirty.isEmpty())
4588:                        return Collections.EMPTY_LIST;
4589:                    return new ArrayList(_dirty);
4590:                }
4591:
4592:                /**
4593:                 * Transfer the given instance from the dirty cache to the clean cache.
4594:                 */
4595:                public void flushed(StateManagerImpl sm) {
4596:                    if (sm.isDirty() && _dirty != null && _dirty.remove(sm))
4597:                        addCleanInternal(sm);
4598:                }
4599:
4600:                /**
4601:                 * Add the given instance to the clean cache.
4602:                 */
4603:                public void addClean(StateManagerImpl sm) {
4604:                    if (addCleanInternal(sm) && _dirty != null)
4605:                        _dirty.remove(sm);
4606:                }
4607:
4608:                private boolean addCleanInternal(StateManagerImpl sm) {
4609:                    if (_clean == null)
4610:                        _clean = new ReferenceHashSet(ReferenceHashSet.SOFT);
4611:                    return _clean.add(sm);
4612:                }
4613:
4614:                /**
4615:                 * Add the given instance to the dirty cache.
4616:                 */
4617:                public void addDirty(StateManagerImpl sm) {
4618:                    if (_dirty == null) {
4619:                        if (_orderDirty)
4620:                            _dirty = MapBackedSet.decorate(new LinkedMap());
4621:                        else
4622:                            _dirty = new HashSet();
4623:                    }
4624:                    if (_dirty.add(sm))
4625:                        removeCleanInternal(sm);
4626:                }
4627:
4628:                /**
4629:                 * Remove the given instance from the cache.
4630:                 */
4631:                public boolean remove(StateManagerImpl sm) {
4632:                    return removeCleanInternal(sm)
4633:                            || (_dirty != null && _dirty.remove(sm));
4634:                }
4635:
4636:                private boolean removeCleanInternal(StateManagerImpl sm) {
4637:                    return _clean != null && _clean.remove(sm);
4638:                }
4639:
4640:                public Iterator iterator() {
4641:                    IteratorChain chain = new IteratorChain();
4642:                    if (_dirty != null && !_dirty.isEmpty())
4643:                        chain.addIterator(_dirty.iterator());
4644:                    if (_clean != null && !_clean.isEmpty())
4645:                        chain.addIterator(_clean.iterator());
4646:                    return chain;
4647:                }
4648:
4649:                public boolean contains(Object obj) {
4650:                    return (_dirty != null && _dirty.contains(obj))
4651:                            || (_clean != null && _clean.contains(obj));
4652:                }
4653:
4654:                public boolean containsAll(Collection coll) {
4655:                    for (Iterator itr = coll.iterator(); itr.hasNext();)
4656:                        if (!contains(itr.next()))
4657:                            return false;
4658:                    return true;
4659:                }
4660:
4661:                public void clear() {
4662:                    if (_dirty != null)
4663:                        _dirty = null;
4664:                    if (_clean != null)
4665:                        _clean = null;
4666:                }
4667:
4668:                public boolean isEmpty() {
4669:                    return (_dirty == null || _dirty.isEmpty())
4670:                            && (_clean == null || _clean.isEmpty());
4671:                }
4672:
4673:                public int size() {
4674:                    int size = 0;
4675:                    if (_dirty != null)
4676:                        size += _dirty.size();
4677:                    if (_clean != null)
4678:                        size += _clean.size();
4679:                    return size;
4680:                }
4681:
4682:                public boolean add(Object obj) {
4683:                    throw new UnsupportedOperationException();
4684:                }
4685:
4686:                public boolean addAll(Collection coll) {
4687:                    throw new UnsupportedOperationException();
4688:                }
4689:
4690:                public boolean remove(Object obj) {
4691:                    throw new UnsupportedOperationException();
4692:                }
4693:
4694:                public boolean removeAll(Collection coll) {
4695:                    throw new UnsupportedOperationException();
4696:                }
4697:
4698:                public boolean retainAll(Collection c) {
4699:                    throw new UnsupportedOperationException();
4700:                }
4701:
4702:                public Object[] toArray() {
4703:                    throw new UnsupportedOperationException();
4704:                }
4705:
4706:                public Object[] toArray(Object[] arr) {
4707:                    throw new UnsupportedOperationException();
4708:                }
4709:            }
4710:
4711:            /**
4712:             * Unique id for state managers of new datastore instances without assigned
4713:             * object ids.
4714:             */
4715:            private static class StateManagerId implements  Serializable {
4716:
4717:                public static final String STRING_PREFIX = "openjpasm:";
4718:
4719:                private static long _generator = 0;
4720:
4721:                private final int _bhash;
4722:                private final long _id;
4723:
4724:                public static StateManagerId newInstance(Broker b) {
4725:                    return new StateManagerId(System.identityHashCode(b),
4726:                            _generator++);
4727:                }
4728:
4729:                private StateManagerId(int bhash, long id) {
4730:                    _bhash = bhash;
4731:                    _id = id;
4732:                }
4733:
4734:                public StateManagerId(String str) {
4735:                    str = str.substring(STRING_PREFIX.length());
4736:                    int idx = str.indexOf(':');
4737:                    _bhash = Integer.parseInt(str.substring(0, idx));
4738:                    _id = Long.parseLong(str.substring(idx + 1));
4739:                }
4740:
4741:                public boolean equals(Object other) {
4742:                    if (other == this )
4743:                        return true;
4744:                    if (!(other instanceof  StateManagerId))
4745:                        return false;
4746:                    StateManagerId sid = (StateManagerId) other;
4747:                    return _bhash == sid._bhash && _id == sid._id;
4748:                }
4749:
4750:                public int hashCode() {
4751:                    return (int) (_id ^ (_id >>> 32));
4752:                }
4753:
4754:                public String toString() {
4755:                    return STRING_PREFIX + _bhash + ":" + _id;
4756:                }
4757:            }
4758:
4759:            /**
4760:             * Collection type that holds state managers but whose interface deals
4761:             * with the corresponding managed objects.
4762:             */
4763:            private static class ManagedObjectCollection extends
4764:                    AbstractCollection {
4765:
4766:                private final Collection _states;
4767:
4768:                public ManagedObjectCollection(Collection states) {
4769:                    _states = states;
4770:                }
4771:
4772:                public Collection getStateManagers() {
4773:                    return _states;
4774:                }
4775:
4776:                public int size() {
4777:                    return _states.size();
4778:                }
4779:
4780:                public Iterator iterator() {
4781:                    return new Iterator() {
4782:                        private final Iterator _itr = _states.iterator();
4783:
4784:                        public boolean hasNext() {
4785:                            return _itr.hasNext();
4786:                        }
4787:
4788:                        public Object next() {
4789:                            return ((OpenJPAStateManager) _itr.next())
4790:                                    .getManagedInstance();
4791:                        }
4792:
4793:                        public void remove() {
4794:                            throw new UnsupportedException();
4795:                        }
4796:                    };
4797:                }
4798:            }
4799:
4800:            /**
4801:             * Assign the object id to the cache. Exception will be
4802:             * thrown if the id already exists in the cache. 
4803:             */
4804:            protected void assignObjectId(Object cache, Object id,
4805:                    StateManagerImpl sm) {
4806:                ((ManagedCache) cache).assignObjectId(id, sm);
4807:            }
4808:
4809:            /** 
4810:             * This method makes sure we don't already have the instance cached
4811:             */
4812:            protected void checkForDuplicateId(Object id, Object obj) {
4813:                StateManagerImpl other = getStateManagerImplById(id, false);
4814:                if (other != null && !other.isDeleted() && !other.isNew())
4815:                    throw new ObjectExistsException(_loc.get("cache-exists",
4816:                            obj.getClass().getName(), id)).setFailedObject(obj);
4817:            }
4818:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.