Source Code Cross Referenced for StateManagerImpl.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.NotSerializableException;
0023:        import java.io.ObjectInputStream;
0024:        import java.io.ObjectOutput;
0025:        import java.io.ObjectOutputStream;
0026:        import java.io.Serializable;
0027:        import java.lang.reflect.Modifier;
0028:        import java.util.ArrayList;
0029:        import java.util.Arrays;
0030:        import java.util.BitSet;
0031:        import java.util.Calendar;
0032:        import java.util.Comparator;
0033:        import java.util.Date;
0034:        import java.util.HashMap;
0035:        import java.util.Iterator;
0036:        import java.util.TimeZone;
0037:
0038:        import org.apache.commons.lang.StringUtils;
0039:        import org.apache.openjpa.conf.OpenJPAConfiguration;
0040:        import org.apache.openjpa.enhance.DynamicPersistenceCapable;
0041:        import org.apache.openjpa.enhance.FieldManager;
0042:        import org.apache.openjpa.enhance.ManagedInstanceProvider;
0043:        import org.apache.openjpa.enhance.PCRegistry;
0044:        import org.apache.openjpa.enhance.PersistenceCapable;
0045:        import org.apache.openjpa.enhance.RedefinitionHelper;
0046:        import org.apache.openjpa.enhance.StateManager;
0047:        import org.apache.openjpa.event.LifecycleEvent;
0048:        import org.apache.openjpa.event.LifecycleEventManager;
0049:        import org.apache.openjpa.lib.util.Localizer;
0050:        import org.apache.openjpa.meta.ClassMetaData;
0051:        import org.apache.openjpa.meta.FetchGroup;
0052:        import org.apache.openjpa.meta.FieldMetaData;
0053:        import org.apache.openjpa.meta.JavaTypes;
0054:        import org.apache.openjpa.meta.UpdateStrategies;
0055:        import org.apache.openjpa.meta.ValueMetaData;
0056:        import org.apache.openjpa.meta.ValueStrategies;
0057:        import org.apache.openjpa.util.ApplicationIds;
0058:        import org.apache.openjpa.util.Exceptions;
0059:        import org.apache.openjpa.util.ImplHelper;
0060:        import org.apache.openjpa.util.InternalException;
0061:        import org.apache.openjpa.util.InvalidStateException;
0062:        import org.apache.openjpa.util.ObjectNotFoundException;
0063:        import org.apache.openjpa.util.OpenJPAId;
0064:        import org.apache.openjpa.util.ProxyManager;
0065:        import org.apache.openjpa.util.RuntimeExceptionTranslator;
0066:        import org.apache.openjpa.util.UserException;
0067:        import serp.util.Numbers;
0068:
0069:        /**
0070:         * Implementation of the {@link OpenJPAStateManager} interface for use
0071:         * with this runtime. Each state manager manages the state of a single
0072:         * persistence capable instance. The state manager is also responsible for
0073:         * all communications about the instance to the {@link StoreManager}.
0074:         *  The state manager uses the State pattern in both its interaction with
0075:         * the governed instance and its interaction with the broker.
0076:         * In its interactions with the persistence capable instance, it uses the
0077:         * {@link FieldManager} interface. Similarly, when interacting with the
0078:         * broker, it uses the {@link PCState} singleton that represents
0079:         * the current lifecycle state of the instance.
0080:         *
0081:         * @author Abe White
0082:         */
0083:        public class StateManagerImpl implements  OpenJPAStateManager,
0084:                Serializable {
0085:
0086:            public static final int LOAD_FGS = 0;
0087:            public static final int LOAD_ALL = 1;
0088:            public static final int LOAD_SERIALIZE = 2;
0089:
0090:            private static final int FLAG_SAVE = 2 << 0;
0091:            private static final int FLAG_DEREF = 2 << 1;
0092:            private static final int FLAG_LOADED = 2 << 2;
0093:            private static final int FLAG_READ_LOCKED = 2 << 3;
0094:            private static final int FLAG_WRITE_LOCKED = 2 << 4;
0095:            private static final int FLAG_OID_ASSIGNED = 2 << 5;
0096:            private static final int FLAG_LOADING = 2 << 6;
0097:            private static final int FLAG_PRE_DELETING = 2 << 7;
0098:            private static final int FLAG_FLUSHED = 2 << 8;
0099:            private static final int FLAG_PRE_FLUSHED = 2 << 9;
0100:            private static final int FLAG_FLUSHED_DIRTY = 2 << 10;
0101:            private static final int FLAG_IMPL_CACHE = 2 << 11;
0102:            private static final int FLAG_INVERSES = 2 << 12;
0103:            private static final int FLAG_NO_UNPROXY = 2 << 13;
0104:            private static final int FLAG_VERSION_CHECK = 2 << 14;
0105:            private static final int FLAG_VERSION_UPDATE = 2 << 15;
0106:            private static final int FLAG_DETACHING = 2 << 16;
0107:
0108:            private static final Localizer _loc = Localizer
0109:                    .forPackage(StateManagerImpl.class);
0110:
0111:            // information about the instance
0112:            private transient PersistenceCapable _pc = null;
0113:            private transient ClassMetaData _meta = null;
0114:            private BitSet _loaded = null;
0115:            private BitSet _dirty = null;
0116:            private BitSet _flush = null;
0117:            private int _flags = 0;
0118:
0119:            // id is the state manager identity; oid is the persistent identity.  oid
0120:            // may be null for embedded and transient-transactional objects or new
0121:            // instances that haven't been assigned an oid.  id is reassigned to oid
0122:            // on successful oid assignment (or flush completion if assignment is
0123:            // during flush)
0124:            private Object _id = null;
0125:            private Object _oid = null;
0126:
0127:            // the managing persistence manager and lifecycle state
0128:            private transient BrokerImpl _broker; // this is serialized specially
0129:            private PCState _state = PCState.TRANSIENT;
0130:
0131:            // the current and last loaded version indicators, and the lock object
0132:            private Object _version = null;
0133:            private Object _loadVersion = null;
0134:            private Object _lock = null;
0135:            private int _readLockLevel = -1;
0136:            private int _writeLockLevel = -1;
0137:
0138:            // delegates when providing/replacing instance data
0139:            private SingleFieldManager _single = null;
0140:            private SaveFieldManager _saved = null;
0141:            private FieldManager _fm = null;
0142:
0143:            // impldata; field impldata and intermediate data share the same array
0144:            private Object _impl = null;
0145:            private Object[] _fieldImpl = null;
0146:
0147:            // information about the owner of this instance, if it is embedded
0148:            private StateManagerImpl _owner = null;
0149:            private int _ownerIndex = -1;
0150:
0151:            /**
0152:             * Constructor; supply id, type metadata, and owning persistence manager.
0153:             */
0154:            protected StateManagerImpl(Object id, ClassMetaData meta,
0155:                    BrokerImpl broker) {
0156:                _id = id;
0157:                _meta = meta;
0158:                _broker = broker;
0159:                _single = new SingleFieldManager(this , broker);
0160:
0161:                if (_meta.getIdentityType() == ClassMetaData.ID_UNKNOWN)
0162:                    throw new UserException(_loc.get("meta-unknownid", _meta));
0163:            }
0164:
0165:            /**
0166:             * Set the owning state and field if this is an embedded instance.
0167:             */
0168:            void setOwner(StateManagerImpl owner, ValueMetaData ownerMeta) {
0169:                _owner = owner;
0170:                _ownerIndex = ownerMeta.getFieldMetaData().getIndex();
0171:            }
0172:
0173:            /**
0174:             * Whether this state manager is in the middle of a load.
0175:             */
0176:            boolean isLoading() {
0177:                return (_flags & FLAG_LOADING) > 0;
0178:            }
0179:
0180:            /**
0181:             * Whether this state manager is in the middle of a load initiated
0182:             * by outside code; for any internal methods that cause loading, the
0183:             * loading flag is set automatically.
0184:             */
0185:            void setLoading(boolean loading) {
0186:                if (loading)
0187:                    _flags |= FLAG_LOADING;
0188:                else
0189:                    _flags &= ~FLAG_LOADING;
0190:            }
0191:
0192:            /**
0193:             * Set or reset the lifecycle state of the managed instance. If the
0194:             * transactional state of the instance changes, it will be enlisted/
0195:             * delisted from the current transaction as necessary. The given
0196:             * state will be initialized after being set. If the given state
0197:             * is the same as the current state, this method will have no effect.
0198:             */
0199:            private void setPCState(PCState state) {
0200:                if (_state == state)
0201:                    return;
0202:
0203:                lock();
0204:                try {
0205:                    // notify the store manager that we're changing states; can veto
0206:                    _broker.getStoreManager().beforeStateChange(this , _state,
0207:                            state);
0208:
0209:                    // replace state
0210:                    boolean wasDeleted = _state.isDeleted();
0211:                    boolean wasDirty = _state.isDirty();
0212:                    boolean wasPending = _state.isPendingTransactional();
0213:                    _state = state;
0214:
0215:                    // enlist/delist from transaction
0216:                    if (_state.isTransactional()) {
0217:                        _broker.addToTransaction(this );
0218:                        if (_state.isDeleted() != wasDeleted)
0219:                            _broker.setDirty(this , !wasDirty || isFlushed());
0220:                        else if (_state.isDirty() && !wasDirty)
0221:                            _broker.setDirty(this , true);
0222:                    } else if (!wasPending && _state.isPendingTransactional())
0223:                        _broker.addToPendingTransaction(this );
0224:                    else if (wasPending && !_state.isPendingTransactional())
0225:                        _broker.removeFromPendingTransaction(this );
0226:                    else
0227:                        _broker.removeFromTransaction(this );
0228:
0229:                    // initialize
0230:                    _state.initialize(this );
0231:                    if (_state.isDeleted() && !wasDeleted)
0232:                        fireLifecycleEvent(LifecycleEvent.AFTER_DELETE);
0233:                } finally {
0234:                    unlock();
0235:                }
0236:            }
0237:
0238:            //////////////////////////////////////
0239:            // OpenJPAStateManager implementation
0240:            //////////////////////////////////////
0241:
0242:            public void initialize(Class cls, PCState state) {
0243:                // check to see if our current object id instance is the
0244:                // correct id type for the specified class; this is for cases
0245:                // when we have an application id hierarchy and we had set the
0246:                // metadata to a superclass id -- the subclass' id may be a
0247:                // different class, so we need to reset it
0248:                if (_meta.getDescribedType() != cls) {
0249:                    ClassMetaData sub = _meta.getRepository().getMetaData(cls,
0250:                            _broker.getClassLoader(), true);
0251:                    if (_oid != null) {
0252:                        if (_meta.getIdentityType() == ClassMetaData.ID_DATASTORE)
0253:                            _oid = _broker.getStoreManager().copyDataStoreId(
0254:                                    _oid, sub);
0255:                        else if (_meta.isOpenJPAIdentity())
0256:                            _oid = ApplicationIds.copy(_oid, sub);
0257:                        else if (sub.getObjectIdType() != _meta
0258:                                .getObjectIdType()) {
0259:                            Object[] pkFields = ApplicationIds.toPKValues(_oid,
0260:                                    _meta);
0261:                            _oid = ApplicationIds.fromPKValues(pkFields, sub);
0262:                        }
0263:                    }
0264:                    _meta = sub;
0265:                }
0266:
0267:                PersistenceCapable inst = PCRegistry.newInstance(cls, this ,
0268:                        _oid, true);
0269:                if (inst == null) {
0270:                    // the instance was null: check to see if the instance is
0271:                    // abstract (as can sometimes be the case when the
0272:                    // class discriminator strategy is not configured correctly)
0273:                    if (Modifier.isAbstract(cls.getModifiers()))
0274:                        throw new UserException(_loc.get(
0275:                                "instantiate-abstract", cls.getName(), _oid));
0276:                    throw new InternalException();
0277:                }
0278:
0279:                initialize(inst, state);
0280:            }
0281:
0282:            /**
0283:             * Initialize with the given instance and state.
0284:             */
0285:            protected void initialize(PersistenceCapable pc, PCState state) {
0286:                if (pc == null)
0287:                    throw new UserException(_loc.get("init-null-pc", _meta));
0288:                if (pc.pcGetStateManager() != null
0289:                        && pc.pcGetStateManager() != this )
0290:                    throw new UserException(_loc.get("init-sm-pc", Exceptions
0291:                            .toString(pc))).setFailedObject(pc);
0292:                pc.pcReplaceStateManager(this );
0293:
0294:                FieldMetaData[] fmds = _meta.getFields();
0295:                _loaded = new BitSet(fmds.length);
0296:                _flush = new BitSet(fmds.length);
0297:                _dirty = new BitSet(fmds.length);
0298:
0299:                for (int i = 0; i < fmds.length; i++) {
0300:                    // mark primary key and non-persistent fields as loaded
0301:                    if (fmds[i].isPrimaryKey()
0302:                            || fmds[i].getManagement() != fmds[i].MANAGE_PERSISTENT)
0303:                        _loaded.set(i);
0304:
0305:                    // record whether there are any managed inverse fields
0306:                    if (_broker.getInverseManager() != null
0307:                            && fmds[i].getInverseMetaDatas().length > 0)
0308:                        _flags |= FLAG_INVERSES;
0309:                }
0310:
0311:                pc.pcSetDetachedState(null);
0312:                _pc = pc;
0313:
0314:                if (_oid instanceof  OpenJPAId)
0315:                    ((OpenJPAId) _oid).setManagedInstanceType(_meta
0316:                            .getDescribedType());
0317:
0318:                // initialize our state and add ourselves to the broker's cache
0319:                setPCState(state);
0320:                _broker.setStateManager(_id, this , BrokerImpl.STATUS_INIT);
0321:                if (state == PCState.PNEW)
0322:                    fireLifecycleEvent(LifecycleEvent.AFTER_PERSIST);
0323:
0324:                // if this is a non-tracking PC, add a hard ref to the appropriate data
0325:                // sets and give it an opportunity to make a state snapshot.
0326:                if (!isIntercepting()) {
0327:                    saveFields(true);
0328:                    if (!isNew())
0329:                        RedefinitionHelper.assignLazyLoadProxies(this );
0330:                }
0331:            }
0332:
0333:            /**
0334:             * Whether or not data access in this instance is intercepted. This differs
0335:             * from {@link ClassMetaData#isIntercepting()} in that it checks for
0336:             * property access + subclassing in addition to the redefinition /
0337:             * enhancement checks.
0338:             *
0339:             * @since 1.0.0
0340:             */
0341:            public boolean isIntercepting() {
0342:                if (getMetaData().isIntercepting())
0343:                    return true;
0344:                if (getMetaData().getAccessType() != ClassMetaData.ACCESS_FIELD
0345:                        && _pc instanceof  DynamicPersistenceCapable)
0346:                    return true;
0347:
0348:                return false;
0349:            }
0350:
0351:            /**
0352:             * Fire the given lifecycle event to all listeners.
0353:             */
0354:            private boolean fireLifecycleEvent(int type) {
0355:                return _broker.fireLifecycleEvent(getManagedInstance(), null,
0356:                        _meta, type);
0357:            }
0358:
0359:            public void load(FetchConfiguration fetch) {
0360:                load(fetch, LOAD_FGS, null, null, false);
0361:            }
0362:
0363:            /**
0364:             * Load the state of this instance based on the given fetch configuration
0365:             * and load mode. Return true if any data was loaded, false otherwise.
0366:             */
0367:            protected boolean load(FetchConfiguration fetch, int loadMode,
0368:                    BitSet exclude, Object sdata, boolean forWrite) {
0369:                if (!forWrite && (!isPersistent() || isNew() || isDeleted()))
0370:                    return false;
0371:
0372:                // if any fields being loaded, do state transitions for read
0373:                BitSet fields = getUnloadedInternal(fetch, loadMode, exclude);
0374:                boolean active = _broker.isActive();
0375:                if (!forWrite && fields != null)
0376:                    beforeRead(-1);
0377:
0378:                // call load even if no fields are being loaded, because it takes
0379:                // care of checking if the DFG is loaded, making sure version info
0380:                // is loaded, etc
0381:                int lockLevel = calculateLockLevel(active, forWrite, fetch);
0382:                boolean ret = loadFields(fields, fetch, lockLevel, sdata);
0383:                obtainLocks(active, forWrite, lockLevel, fetch, sdata);
0384:                return ret;
0385:            }
0386:
0387:            public Object getManagedInstance() {
0388:                if (_pc instanceof  ManagedInstanceProvider)
0389:                    return ((ManagedInstanceProvider) _pc).getManagedInstance();
0390:                else
0391:                    return _pc;
0392:            }
0393:
0394:            public PersistenceCapable getPersistenceCapable() {
0395:                return _pc;
0396:            }
0397:
0398:            public ClassMetaData getMetaData() {
0399:                return _meta;
0400:            }
0401:
0402:            public OpenJPAStateManager getOwner() {
0403:                return _owner;
0404:            }
0405:
0406:            public int getOwnerIndex() {
0407:                return _ownerIndex;
0408:            }
0409:
0410:            public boolean isEmbedded() {
0411:                return _owner != null;
0412:            }
0413:
0414:            public boolean isFlushed() {
0415:                return (_flags & FLAG_FLUSHED) > 0;
0416:            }
0417:
0418:            public boolean isFlushedDirty() {
0419:                return (_flags & FLAG_FLUSHED_DIRTY) > 0;
0420:            }
0421:
0422:            public BitSet getLoaded() {
0423:                return _loaded;
0424:            }
0425:
0426:            public BitSet getFlushed() {
0427:                return _flush;
0428:            }
0429:
0430:            public BitSet getDirty() {
0431:                return _dirty;
0432:            }
0433:
0434:            public BitSet getUnloaded(FetchConfiguration fetch) {
0435:                // collect fields to load from data store based on fetch configuration
0436:                BitSet fields = getUnloadedInternal(fetch, LOAD_FGS, null);
0437:                return (fields == null) ? new BitSet(0) : fields;
0438:            }
0439:
0440:            /**
0441:             * Internal version of {@link OpenJPAStateManager#getUnloaded} that avoids
0442:             * creating an empty bit set by returning null when there are no unloaded
0443:             * fields.
0444:             */
0445:            private BitSet getUnloadedInternal(FetchConfiguration fetch,
0446:                    int mode, BitSet exclude) {
0447:                if (exclude == StoreContext.EXCLUDE_ALL)
0448:                    return null;
0449:
0450:                BitSet fields = null;
0451:                FieldMetaData[] fmds = _meta.getFields();
0452:                boolean load;
0453:                for (int i = 0; i < fmds.length; i++) {
0454:                    if (_loaded.get(i) || (exclude != null && exclude.get(i)))
0455:                        continue;
0456:
0457:                    switch (mode) {
0458:                    case LOAD_SERIALIZE:
0459:                        load = !fmds[i].isTransient();
0460:                        break;
0461:                    case LOAD_FGS:
0462:                        load = fetch == null
0463:                                || fetch.requiresFetch(fmds[i]) != FetchConfiguration.FETCH_NONE;
0464:                        break;
0465:                    default: // LOAD_ALL
0466:                        load = true;
0467:                    }
0468:
0469:                    if (load) {
0470:                        if (fields == null)
0471:                            fields = new BitSet(fmds.length);
0472:                        fields.set(i);
0473:                    }
0474:                }
0475:                return fields;
0476:            }
0477:
0478:            public StoreContext getContext() {
0479:                return _broker;
0480:            }
0481:
0482:            /**
0483:             * Managing broker.
0484:             */
0485:            BrokerImpl getBroker() {
0486:                return _broker;
0487:            }
0488:
0489:            public Object getId() {
0490:                return _id;
0491:            }
0492:
0493:            public Object getObjectId() {
0494:                StateManagerImpl sm = this ;
0495:                while (sm.getOwner() != null)
0496:                    sm = (StateManagerImpl) sm.getOwner();
0497:                return sm._oid;
0498:            }
0499:
0500:            public void setObjectId(Object oid) {
0501:                _oid = oid;
0502:                if (_pc != null && oid instanceof  OpenJPAId)
0503:                    ((OpenJPAId) oid).setManagedInstanceType(_meta
0504:                            .getDescribedType());
0505:            }
0506:
0507:            public boolean assignObjectId(boolean flush) {
0508:                lock();
0509:                try {
0510:                    return assignObjectId(flush, false);
0511:                } finally {
0512:                    unlock();
0513:                }
0514:            }
0515:
0516:            /**
0517:             * Ask store manager to assign our oid, optionally flushing and
0518:             * optionally recaching on the new oid.
0519:             */
0520:            private boolean assignObjectId(boolean flush, boolean preFlushing) {
0521:                if (_oid != null || isEmbedded() || !isPersistent())
0522:                    return true;
0523:
0524:                if (_broker.getStoreManager().assignObjectId(this , preFlushing)) {
0525:                    if (!preFlushing)
0526:                        assertObjectIdAssigned(true);
0527:                } else if (flush)
0528:                    _broker.flush();
0529:                else
0530:                    return false;
0531:                return true;
0532:            }
0533:
0534:            /**
0535:             * Make sure we were assigned an oid, and perform actions to make it
0536:             * permanent.
0537:             *
0538:             * @param recache whether to recache ourself on the new oid
0539:             */
0540:            private void assertObjectIdAssigned(boolean recache) {
0541:                if (!isNew() || isDeleted() || isProvisional()
0542:                        || (_flags & FLAG_OID_ASSIGNED) != 0)
0543:                    return;
0544:                if (_oid == null) {
0545:                    if (_meta.getIdentityType() == ClassMetaData.ID_DATASTORE)
0546:                        throw new InternalException(Exceptions
0547:                                .toString(getManagedInstance()));
0548:                    _oid = ApplicationIds.create(_pc, _meta);
0549:                }
0550:
0551:                Object orig = _id;
0552:                _id = _oid;
0553:                if (recache) {
0554:                    try {
0555:                        _broker.setStateManager(orig, this ,
0556:                                BrokerImpl.STATUS_OID_ASSIGN);
0557:                    } catch (RuntimeException re) {
0558:                        _id = orig;
0559:                        _oid = null;
0560:                        throw re;
0561:                    }
0562:                }
0563:                _flags |= FLAG_OID_ASSIGNED;
0564:            }
0565:
0566:            /**
0567:             * Assign the proper generated value to the given field based on its
0568:             * value-strategy.
0569:             */
0570:            private boolean assignField(int field, boolean preFlushing) {
0571:                OpenJPAStateManager sm = this ;
0572:                while (sm.isEmbedded())
0573:                    sm = sm.getOwner();
0574:                if (!sm.isNew() || sm.isFlushed() || sm.isDeleted())
0575:                    return false;
0576:
0577:                // special-case oid fields, which require us to look inside the oid
0578:                // object
0579:                FieldMetaData fmd = _meta.getField(field);
0580:                if (fmd.getDeclaredTypeCode() == JavaTypes.OID) {
0581:                    // try to shortcut if possible
0582:                    if (_oid != null || isEmbedded() || !isPersistent())
0583:                        return true;
0584:
0585:                    // check embedded fields of oid for value strategy + default value
0586:                    FieldMetaData[] pks = fmd.getEmbeddedMetaData().getFields();
0587:                    OpenJPAStateManager oidsm = null;
0588:                    boolean assign = false;
0589:                    for (int i = 0; !assign && i < pks.length; i++) {
0590:                        if (pks[i].getValueStrategy() == ValueStrategies.NONE)
0591:                            continue;
0592:                        if (oidsm == null)
0593:                            oidsm = new ObjectIdStateManager(
0594:                                    fetchObjectField(field), this , fmd);
0595:                        assign = oidsm.isDefaultValue(i);
0596:                    }
0597:                    return assign && assignObjectId(!preFlushing, preFlushing);
0598:                }
0599:
0600:                // Just return if there's no value generation strategy
0601:                if (fmd.getValueStrategy() == ValueStrategies.NONE)
0602:                    return false;
0603:
0604:                // Throw exception if field already has a value assigned.
0605:                // @GeneratedValue overrides POJO initial values and setter methods
0606:                if (!fmd.isValueGenerated() && !isDefaultValue(field))
0607:                    throw new InvalidStateException(_loc.get(
0608:                            "existing-value-override-excep", fmd
0609:                                    .getFullName(false)));
0610:
0611:                // for primary key fields, assign the object id and recache so that
0612:                // to the user, so it looks like the oid always matches the pk fields
0613:                if (fmd.isPrimaryKey() && !isEmbedded())
0614:                    return assignObjectId(!preFlushing, preFlushing);
0615:
0616:                // for other fields just assign the field or flush if needed
0617:                if (_broker.getStoreManager().assignField(this , field,
0618:                        preFlushing)) {
0619:                    fmd.setValueGenerated(true);
0620:                    return true;
0621:                }
0622:                if (!preFlushing)
0623:                    _broker.flush();
0624:                return !preFlushing;
0625:            }
0626:
0627:            public Object getLock() {
0628:                return _lock;
0629:            }
0630:
0631:            public void setLock(Object lock) {
0632:                _lock = lock;
0633:            }
0634:
0635:            public Object getVersion() {
0636:                return _version;
0637:            }
0638:
0639:            public void setVersion(Object version) {
0640:                _loadVersion = version;
0641:                assignVersionField(version);
0642:            }
0643:
0644:            Object getLoadVersion() {
0645:                return _loadVersion;
0646:            }
0647:
0648:            public void setNextVersion(Object version) {
0649:                assignVersionField(version);
0650:            }
0651:
0652:            private void assignVersionField(Object version) {
0653:                _version = version;
0654:                FieldMetaData vfield = _meta.getVersionField();
0655:                if (vfield != null)
0656:                    store(vfield.getIndex(), JavaTypes.convert(version, vfield
0657:                            .getTypeCode()));
0658:            }
0659:
0660:            public PCState getPCState() {
0661:                return _state;
0662:            }
0663:
0664:            public synchronized Object getImplData() {
0665:                return _impl;
0666:            }
0667:
0668:            public synchronized Object setImplData(Object data,
0669:                    boolean cacheable) {
0670:                Object old = _impl;
0671:                _impl = data;
0672:                if (cacheable && data != null)
0673:                    _flags |= FLAG_IMPL_CACHE;
0674:                else
0675:                    _flags &= ~FLAG_IMPL_CACHE;
0676:                return old;
0677:            }
0678:
0679:            public boolean isImplDataCacheable() {
0680:                return (_flags & FLAG_IMPL_CACHE) != 0;
0681:            }
0682:
0683:            public Object getImplData(int field) {
0684:                return getExtraFieldData(field, true);
0685:            }
0686:
0687:            public Object setImplData(int field, Object data) {
0688:                return setExtraFieldData(field, data, true);
0689:            }
0690:
0691:            public synchronized boolean isImplDataCacheable(int field) {
0692:                if (_fieldImpl == null || !_loaded.get(field))
0693:                    return false;
0694:                if (_meta.getField(field).usesImplData() != null)
0695:                    return false;
0696:                int idx = _meta.getExtraFieldDataIndex(field);
0697:                return idx != -1 && _fieldImpl[idx] != null;
0698:            }
0699:
0700:            public Object getIntermediate(int field) {
0701:                return getExtraFieldData(field, false);
0702:            }
0703:
0704:            public void setIntermediate(int field, Object data) {
0705:                setExtraFieldData(field, data, false);
0706:            }
0707:
0708:            /**
0709:             * Return the data from the proper index of the extra field data array.
0710:             */
0711:            private synchronized Object getExtraFieldData(int field,
0712:                    boolean isLoaded) {
0713:                // only return the field data if the field is in the right loaded
0714:                // state; otherwise we might return intermediate for impl data or
0715:                // vice versa
0716:                if (_fieldImpl == null || _loaded.get(field) != isLoaded)
0717:                    return null;
0718:                int idx = _meta.getExtraFieldDataIndex(field);
0719:                return (idx == -1) ? null : _fieldImpl[idx];
0720:            }
0721:
0722:            /**
0723:             * Set the data from to proper index of the extra field data array.
0724:             */
0725:            private synchronized Object setExtraFieldData(int field,
0726:                    Object data, boolean loaded) {
0727:                int idx = _meta.getExtraFieldDataIndex(field);
0728:                if (idx == -1)
0729:                    throw new InternalException(String.valueOf(_meta
0730:                            .getField(field)));
0731:
0732:                Object old = (_fieldImpl == null) ? null : _fieldImpl[idx];
0733:                if (data != null) {
0734:                    // cannot set if field in wrong loaded state
0735:                    if (_loaded.get(field) != loaded)
0736:                        throw new InternalException(String.valueOf(_meta
0737:                                .getField(field)));
0738:
0739:                    // set data
0740:                    if (_fieldImpl == null)
0741:                        _fieldImpl = new Object[_meta.getExtraFieldDataLength()];
0742:                    _fieldImpl[idx] = data;
0743:                } else if (_fieldImpl != null && _loaded.get(field) == loaded)
0744:                    _fieldImpl[idx] = null;
0745:                return old;
0746:            }
0747:
0748:            public Object fetch(int field) {
0749:                Object val = fetchField(field, false);
0750:                return _meta.getField(field).getExternalValue(val, _broker);
0751:            }
0752:
0753:            public Object fetchField(int field, boolean transitions) {
0754:                FieldMetaData fmd = _meta.getField(field);
0755:                if (fmd == null)
0756:                    throw new UserException(_loc.get("no-field", String
0757:                            .valueOf(field), getManagedInstance().getClass()))
0758:                            .setFailedObject(getManagedInstance());
0759:
0760:                // do normal state transitions
0761:                if (!fmd.isPrimaryKey() && transitions)
0762:                    accessingField(field);
0763:
0764:                switch (fmd.getDeclaredTypeCode()) {
0765:                case JavaTypes.STRING:
0766:                    return fetchStringField(field);
0767:                case JavaTypes.OBJECT:
0768:                    return fetchObjectField(field);
0769:                case JavaTypes.BOOLEAN:
0770:                    return (fetchBooleanField(field)) ? Boolean.TRUE
0771:                            : Boolean.FALSE;
0772:                case JavaTypes.BYTE:
0773:                    return new Byte(fetchByteField(field));
0774:                case JavaTypes.CHAR:
0775:                    return new Character(fetchCharField(field));
0776:                case JavaTypes.DOUBLE:
0777:                    return new Double(fetchDoubleField(field));
0778:                case JavaTypes.FLOAT:
0779:                    return new Float(fetchFloatField(field));
0780:                case JavaTypes.INT:
0781:                    return Numbers.valueOf(fetchIntField(field));
0782:                case JavaTypes.LONG:
0783:                    return Numbers.valueOf(fetchLongField(field));
0784:                case JavaTypes.SHORT:
0785:                    return new Short(fetchShortField(field));
0786:                default:
0787:                    return fetchObjectField(field);
0788:                }
0789:            }
0790:
0791:            public void store(int field, Object val) {
0792:                val = _meta.getField(field).getFieldValue(val, _broker);
0793:                storeField(field, val);
0794:            }
0795:
0796:            public void storeField(int field, Object val) {
0797:                storeField(field, val, this );
0798:            }
0799:
0800:            /**
0801:             * <p>Checks whether or not <code>_pc</code> is dirty. In the cases where
0802:             * field tracking is not happening (see below), this method will do a
0803:             * state comparison to find whether <code>_pc</code> is dirty, and will
0804:             * update this instance with this information. In the cases where field
0805:             * tracking is happening, this method is a no-op.</p>
0806:             *
0807:             * <p>Fields are tracked for all classes that are run through the OpenJPA
0808:             * enhancer prior to or during deployment, and all classes (enhanced or
0809:             * unenhanced) in a Java 6 environment or newer.</p>
0810:             *
0811:             * <p>In a Java 5 VM or older:
0812:             * <br>- instances of unenhanced classes that use
0813:             * property access and obey the property access limitations are tracked
0814:             * when the instances are loaded from the database by OpenJPA, and are
0815:             * not tracked when the instances are created by application code.
0816:             * <br>- instances of unenhanced classes that use field access are
0817:             * never tracked.</p>
0818:             *
0819:             * @since 1.0.0
0820:             */
0821:            public void dirtyCheck() {
0822:                if (!needsDirtyCheck())
0823:                    return;
0824:
0825:                SaveFieldManager saved = getSaveFieldManager();
0826:                if (saved == null)
0827:                    throw new InternalException(_loc.get("no-saved-fields",
0828:                            getMetaData().getDescribedType().getName()));
0829:
0830:                FieldMetaData[] fmds = getMetaData().getFields();
0831:                for (int i = 0; i < fmds.length; i++) {
0832:                    // pk and version fields cannot be mutated; don't mark them
0833:                    // as such. ##### validate?
0834:                    if (!fmds[i].isPrimaryKey() && !fmds[i].isVersion()
0835:                            && _loaded.get(i)) {
0836:                        if (!saved.isFieldEqual(i, fetch(i))) {
0837:                            dirty(i);
0838:                        }
0839:                    }
0840:                }
0841:            }
0842:
0843:            private boolean needsDirtyCheck() {
0844:                if (isIntercepting())
0845:                    return false;
0846:                if (isDeleted())
0847:                    return false;
0848:                if (isNew() && !isFlushed())
0849:                    return false;
0850:                return true;
0851:            }
0852:
0853:            public Object fetchInitialField(int field) {
0854:                FieldMetaData fmd = _meta.getField(field);
0855:                if (_broker.getRestoreState() == RestoreState.RESTORE_NONE
0856:                        && ((_flags & FLAG_INVERSES) == 0 || fmd
0857:                                .getInverseMetaDatas().length == 0))
0858:                    throw new InvalidStateException(_loc.get("restore-unset"));
0859:
0860:                switch (fmd.getDeclaredTypeCode()) {
0861:                case JavaTypes.DATE:
0862:                case JavaTypes.CALENDAR:
0863:                case JavaTypes.ARRAY:
0864:                case JavaTypes.COLLECTION:
0865:                case JavaTypes.MAP:
0866:                case JavaTypes.OBJECT:
0867:                    // if we're not saving mutable types, throw an exception
0868:                    if (_broker.getRestoreState() != RestoreState.RESTORE_ALL
0869:                            && ((_flags & FLAG_INVERSES) == 0 || fmd
0870:                                    .getInverseMetaDatas().length == 0))
0871:                        throw new InvalidStateException(_loc
0872:                                .get("mutable-restore-unset"));
0873:                }
0874:
0875:                lock();
0876:                try {
0877:                    if (_saved == null || !_loaded.get(field)
0878:                            || !_dirty.get(field))
0879:                        return fetchField(field, false);
0880:
0881:                    // if the field is dirty but we never loaded it, we can't restore it
0882:                    if (_saved.getUnloaded().get(field))
0883:                        throw new InvalidStateException(_loc.get(
0884:                                "initial-unloaded", fmd));
0885:
0886:                    provideField(_saved.getState(), _single, field);
0887:                    return fetchField(_single, fmd);
0888:                } finally {
0889:                    unlock();
0890:                }
0891:            }
0892:
0893:            /**
0894:             * Fetch the specified field from the specified field manager, wrapping it
0895:             * in an object if it's a primitive. A field should be provided to the
0896:             * field manager before this call is made.
0897:             */
0898:            private static Object fetchField(FieldManager fm, FieldMetaData fmd) {
0899:                int field = fmd.getIndex();
0900:                switch (fmd.getDeclaredTypeCode()) {
0901:                case JavaTypes.BOOLEAN:
0902:                    return (fm.fetchBooleanField(field)) ? Boolean.TRUE
0903:                            : Boolean.FALSE;
0904:                case JavaTypes.BYTE:
0905:                    return new Byte(fm.fetchByteField(field));
0906:                case JavaTypes.CHAR:
0907:                    return new Character(fm.fetchCharField(field));
0908:                case JavaTypes.DOUBLE:
0909:                    return new Double(fm.fetchDoubleField(field));
0910:                case JavaTypes.FLOAT:
0911:                    return new Float(fm.fetchFloatField(field));
0912:                case JavaTypes.INT:
0913:                    return Numbers.valueOf(fm.fetchIntField(field));
0914:                case JavaTypes.LONG:
0915:                    return Numbers.valueOf(fm.fetchLongField(field));
0916:                case JavaTypes.SHORT:
0917:                    return new Short(fm.fetchShortField(field));
0918:                case JavaTypes.STRING:
0919:                    return fm.fetchStringField(field);
0920:                default:
0921:                    return fm.fetchObjectField(field);
0922:                }
0923:            }
0924:
0925:            public void setRemote(int field, Object value) {
0926:                lock();
0927:                try {
0928:                    Boolean stat = dirty(field, Boolean.FALSE, false);
0929:                    storeField(field, value, _single);
0930:                    replaceField(_pc, _single, field);
0931:                    postDirty(stat);
0932:                } finally {
0933:                    unlock();
0934:                }
0935:            }
0936:
0937:            ////////////////////////
0938:            // Lifecycle operations
0939:            ////////////////////////
0940:
0941:            /**
0942:             * Notification that the object is about to be accessed.
0943:             *
0944:             * @param field the field number being read, or -1 if not a single
0945:             * field read
0946:             */
0947:            void beforeRead(int field) {
0948:                // allow unmediated reads of primary key fields
0949:                if (field != -1 && _meta.getField(field).isPrimaryKey())
0950:                    return;
0951:
0952:                if (_broker.isActive() && !_broker.isTransactionEnding()) {
0953:                    if (_broker.getOptimistic())
0954:                        setPCState(_state.beforeOptimisticRead(this , field));
0955:                    else
0956:                        setPCState(_state.beforeRead(this , field));
0957:                } else if (_broker.getNontransactionalRead())
0958:                    setPCState(_state.beforeNontransactionalRead(this , field));
0959:                else
0960:                    throw new InvalidStateException(_loc.get("non-trans-read"))
0961:                            .setFailedObject(getManagedInstance());
0962:            }
0963:
0964:            /**
0965:             * Delegates to the current state.
0966:             *
0967:             * @see PCState#beforeFlush
0968:             */
0969:            void beforeFlush(int reason, OpCallbacks call) {
0970:                _state.beforeFlush(this , reason == BrokerImpl.FLUSH_LOGICAL,
0971:                        call);
0972:            }
0973:
0974:            /**
0975:             * Delegates to the current state.
0976:             *
0977:             * @see PCState#flush
0978:             */
0979:            void afterFlush(int reason) {
0980:                // nothing happens when we flush non-persistent states
0981:                if (!isPersistent())
0982:                    return;
0983:
0984:                if (reason != BrokerImpl.FLUSH_ROLLBACK
0985:                        && reason != BrokerImpl.FLUSH_LOGICAL) {
0986:                    // analyze previous state for later
0987:                    boolean wasNew = isNew();
0988:                    boolean wasFlushed = isFlushed();
0989:                    boolean wasDeleted = isDeleted();
0990:
0991:                    // all dirty fields were flushed
0992:                    _flush.or(_dirty);
0993:
0994:                    // important to set flushed bit after calling _state.flush so
0995:                    // that the state can tell whether this is the first flush
0996:                    setPCState(_state.flush(this ));
0997:                    _flags |= FLAG_FLUSHED;
0998:                    _flags &= ~FLAG_FLUSHED_DIRTY;
0999:
1000:                    _flags &= ~FLAG_VERSION_CHECK;
1001:                    _flags &= ~FLAG_VERSION_UPDATE;
1002:
1003:                    // if this was an inc flush during which we had our identity
1004:                    // assigned, tell the broker to cache us under our final oid
1005:                    if (reason == BrokerImpl.FLUSH_INC)
1006:                        assertObjectIdAssigned(true);
1007:
1008:                    // if this object was stored with preFlush, do post-store callback
1009:                    if ((_flags & FLAG_PRE_FLUSHED) > 0)
1010:                        fireLifecycleEvent(LifecycleEvent.AFTER_STORE);
1011:
1012:                    // do post-update as needed
1013:                    if (wasNew && !wasFlushed)
1014:                        fireLifecycleEvent(LifecycleEvent.AFTER_PERSIST_PERFORMED);
1015:                    else if (wasDeleted)
1016:                        fireLifecycleEvent(LifecycleEvent.AFTER_DELETE_PERFORMED);
1017:                    else
1018:                        // updates and new-flushed with changes
1019:                        fireLifecycleEvent(LifecycleEvent.AFTER_UPDATE_PERFORMED);
1020:                } else if (reason == BrokerImpl.FLUSH_ROLLBACK) {
1021:                    // revert to last loaded version and original oid
1022:                    assignVersionField(_loadVersion);
1023:                    if (isNew() && (_flags & FLAG_OID_ASSIGNED) == 0)
1024:                        _oid = null;
1025:                }
1026:                _flags &= ~FLAG_PRE_FLUSHED;
1027:            }
1028:
1029:            /**
1030:             * Delegates to the current state after checking the value
1031:             * of the RetainState flag.
1032:             *
1033:             * @see PCState#commit
1034:             * @see PCState#commitRetain
1035:             */
1036:            void commit() {
1037:                // release locks before oid updated
1038:                releaseLocks();
1039:
1040:                // update version and oid information
1041:                setVersion(_version);
1042:                _flags &= ~FLAG_FLUSHED;
1043:                _flags &= ~FLAG_FLUSHED_DIRTY;
1044:
1045:                Object orig = _id;
1046:                assertObjectIdAssigned(false);
1047:
1048:                boolean wasNew = isNew() && !isDeleted() && !isProvisional();
1049:                if (_broker.getRetainState())
1050:                    setPCState(_state.commitRetain(this ));
1051:                else
1052:                    setPCState(_state.commit(this ));
1053:
1054:                // ask the broker to re-cache us if we were new previously
1055:                if (wasNew)
1056:                    _broker.setStateManager(orig, this ,
1057:                            BrokerImpl.STATUS_COMMIT_NEW);
1058:            }
1059:
1060:            /**
1061:             * Delegates to the current state after checking the value
1062:             * of the RetainState flag.
1063:             *
1064:             * @see PCState#rollback
1065:             * @see PCState#rollbackRestore
1066:             */
1067:            void rollback() {
1068:                // release locks
1069:                releaseLocks();
1070:                _flags &= ~FLAG_FLUSHED;
1071:                _flags &= ~FLAG_FLUSHED_DIRTY;
1072:                afterFlush(BrokerImpl.FLUSH_ROLLBACK);
1073:
1074:                if (_broker.getRestoreState() != RestoreState.RESTORE_NONE)
1075:                    setPCState(_state.rollbackRestore(this ));
1076:                else
1077:                    setPCState(_state.rollback(this ));
1078:            }
1079:
1080:            /**
1081:             * Rollback state of the managed instance to the given savepoint.
1082:             */
1083:            void rollbackToSavepoint(SavepointFieldManager savepoint) {
1084:                _state = savepoint.getPCState();
1085:                BitSet loaded = savepoint.getLoaded();
1086:                for (int i = 0, len = loaded.length(); i < len; i++) {
1087:                    if (loaded.get(i) && savepoint.restoreField(i)) {
1088:                        provideField(savepoint.getCopy(), savepoint, i);
1089:                        replaceField(_pc, savepoint, i);
1090:                    }
1091:                }
1092:                _loaded = loaded;
1093:                _dirty = savepoint.getDirty();
1094:                _flush = savepoint.getFlushed();
1095:                _version = savepoint.getVersion();
1096:                _loadVersion = savepoint.getLoadVersion();
1097:            }
1098:
1099:            /**
1100:             * Delegates to the current state.
1101:             *
1102:             * @see PCState#persist
1103:             * @see Broker#persist
1104:             */
1105:            void persist() {
1106:                setPCState(_state.persist(this ));
1107:            }
1108:
1109:            /**
1110:             * Delegates to the current state.
1111:             *
1112:             * @see PCState#delete
1113:             * @see Broker#delete
1114:             */
1115:            void delete() {
1116:                setPCState(_state.delete(this ));
1117:            }
1118:
1119:            /**
1120:             * Delegates to the current state.
1121:             *
1122:             * @see PCState#nontransactional
1123:             * @see Broker#nontransactional
1124:             */
1125:            void nontransactional() {
1126:                setPCState(_state.nontransactional(this ));
1127:            }
1128:
1129:            /**
1130:             * Delegates to the current state.
1131:             *
1132:             * @see PCState#transactional
1133:             * @see Broker#transactional
1134:             */
1135:            void transactional() {
1136:                setPCState(_state.transactional(this ));
1137:            }
1138:
1139:            /**
1140:             * Delegates to the current state.
1141:             *
1142:             * @see PCState#nonprovisional
1143:             */
1144:            void nonprovisional(boolean logical, OpCallbacks call) {
1145:                setPCState(_state.nonprovisional(this , logical, call));
1146:            }
1147:
1148:            /**
1149:             * Delegates to the current state.
1150:             *
1151:             * @see PCState#release
1152:             * @see Broker#release
1153:             */
1154:            void release(boolean unproxy) {
1155:                release(unproxy, false);
1156:            }
1157:
1158:            void release(boolean unproxy, boolean force) {
1159:                // optimization for detach-in-place special case when fields are
1160:                // already (un)proxied correctly
1161:                if (!unproxy)
1162:                    _flags |= FLAG_NO_UNPROXY;
1163:                try {
1164:                    if (force)
1165:                        setPCState(PCState.TRANSIENT);
1166:                    else
1167:                        setPCState(_state.release(this ));
1168:                } finally {
1169:                    _flags &= ~FLAG_NO_UNPROXY;
1170:                }
1171:            }
1172:
1173:            /**
1174:             * Delegates to the current state.
1175:             *
1176:             * @see PCState#evict
1177:             * @see Broker#evict
1178:             */
1179:            void evict() {
1180:                setPCState(_state.evict(this ));
1181:            }
1182:
1183:            /**
1184:             * Gather relations reachable from values using
1185:             * {@link ValueMetaData#CASCADE_IMMEDIATE}.
1186:             */
1187:            void gatherCascadeRefresh(OpCallbacks call) {
1188:                FieldMetaData[] fmds = _meta.getFields();
1189:                for (int i = 0; i < fmds.length; i++) {
1190:                    if (!_loaded.get(i))
1191:                        continue;
1192:
1193:                    if (fmds[i].getCascadeRefresh() == ValueMetaData.CASCADE_IMMEDIATE
1194:                            || fmds[i].getKey().getCascadeRefresh() == ValueMetaData.CASCADE_IMMEDIATE
1195:                            || fmds[i].getElement().getCascadeRefresh() == ValueMetaData.CASCADE_IMMEDIATE) {
1196:                        _single.storeObjectField(i, fetchField(i, false));
1197:                        _single.gatherCascadeRefresh(call);
1198:                        _single.clear();
1199:                    }
1200:                }
1201:            }
1202:
1203:            public boolean beforeRefresh(boolean refreshAll) {
1204:                // note: all logic placed here rather than in the states for
1205:                // optimization; this method public b/c used by remote package
1206:
1207:                // nothing to do for non persistent or new unflushed instances
1208:                if (!isPersistent() || (isNew() && !isFlushed()))
1209:                    return false;
1210:
1211:                lock();
1212:                try {
1213:                    // if dirty need to clear fields
1214:                    if (isDirty()) {
1215:                        clearFields();
1216:                        return true;
1217:                    }
1218:
1219:                    // if some fields have been loaded but the instance is out of
1220:                    // date or this is part of a refreshAll() and we don't want to
1221:                    // take the extra hit to see if the instance is out of date, clear
1222:                    if (_loaded.length() > 0
1223:                            && (refreshAll || isEmbedded() || !syncVersion(null))) {
1224:                        Object version = _version;
1225:                        clearFields();
1226:
1227:                        // if syncVersion just replaced the version, reset it
1228:                        if (!refreshAll && !isEmbedded())
1229:                            setVersion(version);
1230:                        return true;
1231:                    }
1232:                    return false;
1233:                } finally {
1234:                    unlock();
1235:                }
1236:            }
1237:
1238:            /**
1239:             * Perform state transitions after refresh. This method is only
1240:             * called if {@link #beforeRefresh} returns true.
1241:             */
1242:            void afterRefresh() {
1243:                lock();
1244:                try {
1245:                    // transition to clean or nontransactional depending on trans status
1246:                    if (!_broker.isActive())
1247:                        setPCState(_state.afterNontransactionalRefresh());
1248:                    else if (_broker.getOptimistic())
1249:                        setPCState(_state.afterOptimisticRefresh());
1250:                    else
1251:                        setPCState(_state.afterRefresh());
1252:                } finally {
1253:                    unlock();
1254:                }
1255:            }
1256:
1257:            /**
1258:             * Mark this object as a dereferenced dependent object.
1259:             */
1260:            void setDereferencedDependent(boolean deref, boolean notify) {
1261:                if (!deref && (_flags & FLAG_DEREF) > 0) {
1262:                    if (notify)
1263:                        _broker.removeDereferencedDependent(this );
1264:                    _flags &= ~FLAG_DEREF;
1265:                } else if (deref && (_flags & FLAG_DEREF) == 0) {
1266:                    _flags |= FLAG_DEREF;
1267:                    if (notify)
1268:                        _broker.addDereferencedDependent(this );
1269:                }
1270:            }
1271:
1272:            ///////////
1273:            // Locking
1274:            ///////////
1275:
1276:            /**
1277:             * Notification that we've been read-locked. Pass in the level at which
1278:             * we were locked and the level at which we should write lock ourselves
1279:             * on dirty.
1280:             */
1281:            void readLocked(int readLockLevel, int writeLockLevel) {
1282:                // make sure object is added to transaction so lock will get
1283:                // cleared on commit/rollback
1284:                if (readLockLevel != LockLevels.LOCK_NONE)
1285:                    transactional();
1286:
1287:                _readLockLevel = readLockLevel;
1288:                _writeLockLevel = writeLockLevel;
1289:                _flags |= FLAG_READ_LOCKED;
1290:                _flags &= ~FLAG_WRITE_LOCKED;
1291:            }
1292:
1293:            /**
1294:             * Return the lock level to use when loading state.
1295:             */
1296:            private int calculateLockLevel(boolean active, boolean forWrite,
1297:                    FetchConfiguration fetch) {
1298:                if (!active)
1299:                    return LockLevels.LOCK_NONE;
1300:                if (fetch == null)
1301:                    fetch = _broker.getFetchConfiguration();
1302:
1303:                if (_readLockLevel == -1)
1304:                    _readLockLevel = fetch.getReadLockLevel();
1305:                if (_writeLockLevel == -1)
1306:                    _writeLockLevel = fetch.getWriteLockLevel();
1307:                return (forWrite) ? _writeLockLevel : _readLockLevel;
1308:            }
1309:
1310:            /**
1311:             * Make sure we're locked at the given level.
1312:             */
1313:            private void obtainLocks(boolean active, boolean forWrite,
1314:                    int lockLevel, FetchConfiguration fetch, Object sdata) {
1315:                if (!active)
1316:                    return;
1317:
1318:                // if we haven't been locked yet, lock now at the given level
1319:                int flag = (forWrite) ? FLAG_WRITE_LOCKED : FLAG_READ_LOCKED;
1320:                if ((_flags & flag) == 0) {
1321:                    // make sure object is added to transaction so lock will get
1322:                    // cleared on commit/rollback
1323:                    if (lockLevel != LockLevels.LOCK_NONE)
1324:                        transactional();
1325:
1326:                    if (fetch == null)
1327:                        fetch = _broker.getFetchConfiguration();
1328:                    _broker.getLockManager().lock(this , lockLevel,
1329:                            fetch.getLockTimeout(), sdata);
1330:                    _flags |= FLAG_READ_LOCKED;
1331:                    _flags |= flag;
1332:                }
1333:            }
1334:
1335:            /**
1336:             * Release locks.
1337:             */
1338:            private void releaseLocks() {
1339:                if (_lock != null)
1340:                    _broker.getLockManager().release(this );
1341:                _readLockLevel = -1;
1342:                _writeLockLevel = -1;
1343:                _flags &= ~FLAG_READ_LOCKED;
1344:                _flags &= ~FLAG_WRITE_LOCKED;
1345:            }
1346:
1347:            ////////////////////////////////////////////
1348:            // Implementation of StateManager interface
1349:            ////////////////////////////////////////////
1350:
1351:            /**
1352:             * @return whether or not unloaded fields should be closed.
1353:             */
1354:            public boolean serializing() {
1355:                // if the broker is in the midst of a serialization, then no special
1356:                // handling should be performed on the instance, and no subsequent
1357:                // load should happen
1358:                if (_broker.isSerializing())
1359:                    return false;
1360:
1361:                try {
1362:                    if (_meta.isDetachable())
1363:                        return DetachManager.preSerialize(this );
1364:
1365:                    load(_broker.getFetchConfiguration(), LOAD_SERIALIZE, null,
1366:                            null, false);
1367:                    return false;
1368:                } catch (RuntimeException re) {
1369:                    throw translate(re);
1370:                }
1371:            }
1372:
1373:            public boolean writeDetached(ObjectOutput out) throws IOException {
1374:                BitSet idxs = new BitSet(_meta.getFields().length);
1375:                lock();
1376:                try {
1377:                    boolean detsm = DetachManager.writeDetachedState(this , out,
1378:                            idxs);
1379:                    if (detsm)
1380:                        _flags |= FLAG_DETACHING;
1381:
1382:                    FieldMetaData[] fmds = _meta.getFields();
1383:                    for (int i = 0; i < fmds.length; i++) {
1384:                        if (fmds[i].isTransient())
1385:                            continue;
1386:                        provideField(_pc, _single, i);
1387:                        _single.serialize(out, !idxs.get(i));
1388:                        _single.clear();
1389:                    }
1390:                    return true;
1391:                } catch (RuntimeException re) {
1392:                    throw translate(re);
1393:                } finally {
1394:                    _flags &= ~FLAG_DETACHING;
1395:                    unlock();
1396:                }
1397:            }
1398:
1399:            public void proxyDetachedDeserialized(int idx) {
1400:                // we don't serialize state manager impls
1401:                throw new InternalException();
1402:            }
1403:
1404:            public boolean isTransactional() {
1405:                // special case for TCLEAN, which we want to appear non-trans to
1406:                // internal code, but which publicly should be transactional
1407:                return _state == PCState.TCLEAN || _state.isTransactional();
1408:            }
1409:
1410:            public boolean isPendingTransactional() {
1411:                return _state.isPendingTransactional();
1412:            }
1413:
1414:            public boolean isProvisional() {
1415:                return _state.isProvisional();
1416:            }
1417:
1418:            public boolean isPersistent() {
1419:                return _state.isPersistent();
1420:            }
1421:
1422:            public boolean isNew() {
1423:                return _state.isNew();
1424:            }
1425:
1426:            public boolean isDeleted() {
1427:                return _state.isDeleted();
1428:            }
1429:
1430:            public boolean isDirty() {
1431:                return _state.isDirty();
1432:            }
1433:
1434:            public boolean isDetached() {
1435:                return (_flags & FLAG_DETACHING) != 0;
1436:            }
1437:
1438:            public Object getGenericContext() {
1439:                return _broker;
1440:            }
1441:
1442:            public Object fetchObjectId() {
1443:                try {
1444:                    assignObjectId(true);
1445:                    if (_oid == null
1446:                            || !_broker.getConfiguration()
1447:                                    .getCompatibilityInstance()
1448:                                    .getCopyObjectIds())
1449:                        return _oid;
1450:
1451:                    if (_meta.getIdentityType() == ClassMetaData.ID_DATASTORE)
1452:                        return _broker.getStoreManager().copyDataStoreId(_oid,
1453:                                _meta);
1454:                    return ApplicationIds.copy(_oid, _meta);
1455:                } catch (RuntimeException re) {
1456:                    throw translate(re);
1457:                }
1458:            }
1459:
1460:            public Object getPCPrimaryKey(Object oid, int field) {
1461:                FieldMetaData fmd = _meta.getField(field);
1462:                Object pk = ApplicationIds.get(oid, fmd);
1463:                if (pk == null)
1464:                    return null;
1465:
1466:                ClassMetaData relmeta = fmd.getDeclaredTypeMetaData();
1467:                if (relmeta.getIdentityType() == ClassMetaData.ID_DATASTORE
1468:                        && fmd.getObjectIdFieldTypeCode() == JavaTypes.LONG)
1469:                    pk = _broker.getStoreManager().newDataStoreId(pk, relmeta);
1470:                else if (relmeta.getIdentityType() == ClassMetaData.ID_APPLICATION
1471:                        && fmd.getObjectIdFieldType() != relmeta
1472:                                .getObjectIdType())
1473:                    pk = ApplicationIds.fromPKValues(new Object[] { pk },
1474:                            relmeta);
1475:                return _broker.find(pk, false, null);
1476:            }
1477:
1478:            public byte replaceFlags() {
1479:                // we always use load required so that we can detect when objects
1480:                // are touched for locking or making transactional
1481:                return PersistenceCapable.LOAD_REQUIRED;
1482:            }
1483:
1484:            public StateManager replaceStateManager(StateManager sm) {
1485:                return sm;
1486:            }
1487:
1488:            public void accessingField(int field) {
1489:                // possibly change state
1490:                try {
1491:                    beforeRead(field);
1492:                    beforeAccessField(field);
1493:                } catch (RuntimeException re) {
1494:                    throw translate(re);
1495:                }
1496:            }
1497:
1498:            /**
1499:             * Load the given field before access.
1500:             */
1501:            protected void beforeAccessField(int field) {
1502:                lock();
1503:                try {
1504:                    boolean active = _broker.isActive();
1505:                    int lockLevel = calculateLockLevel(active, false, null);
1506:                    if (!_loaded.get(field))
1507:                        loadField(field, lockLevel, false, true);
1508:                    else
1509:                        assignField(field, false);
1510:                    obtainLocks(active, false, lockLevel, null, null);
1511:                } catch (RuntimeException re) {
1512:                    throw translate(re);
1513:                } finally {
1514:                    unlock();
1515:                }
1516:            }
1517:
1518:            public void dirty(String field) {
1519:                FieldMetaData fmd = _meta.getField(field);
1520:                if (fmd == null)
1521:                    throw translate(new UserException(_loc.get("no-field",
1522:                            field, ImplHelper.getManagedInstance(_pc)
1523:                                    .getClass()))
1524:                            .setFailedObject(getManagedInstance()));
1525:
1526:                dirty(fmd.getIndex(), null, true);
1527:            }
1528:
1529:            public void dirty(int field) {
1530:                dirty(field, null, true);
1531:            }
1532:
1533:            /**
1534:             * Make the given field dirty.
1535:             *
1536:             * @param mutate if null, may be an SCO mutation; if true, is certainly
1537:             * a mutation (or at least treat as one)
1538:             * @return {@link Boolean#FALSE} if this instance was already dirty,
1539:             * <code>null</code> if it was dirty but not since flush, and
1540:             * {@link Boolean#TRUE} if it was not dirty
1541:             */
1542:            private Boolean dirty(int field, Boolean mutate,
1543:                    boolean loadFetchGroup) {
1544:                boolean locked = false;
1545:                boolean newFlush = false;
1546:                boolean clean = false;
1547:                try {
1548:                    FieldMetaData fmd = _meta.getField(field);
1549:                    if (!isNew() || isFlushed()) {
1550:                        if (fmd.getUpdateStrategy() == UpdateStrategies.RESTRICT)
1551:                            throw new InvalidStateException(_loc.get(
1552:                                    "update-restrict", fmd));
1553:                        if (fmd.getUpdateStrategy() == UpdateStrategies.IGNORE)
1554:                            return Boolean.FALSE;
1555:                    }
1556:
1557:                    if (isEmbedded()) {
1558:                        // notify owner of change
1559:                        _owner.dirty(_ownerIndex, Boolean.TRUE, loadFetchGroup);
1560:                    }
1561:
1562:                    // is this a direct mutation of an sco field?
1563:                    if (mutate == null) {
1564:                        switch (fmd.getDeclaredTypeCode()) {
1565:                        case JavaTypes.COLLECTION:
1566:                        case JavaTypes.MAP:
1567:                        case JavaTypes.ARRAY:
1568:                        case JavaTypes.DATE:
1569:                        case JavaTypes.CALENDAR:
1570:                        case JavaTypes.OBJECT:
1571:                            mutate = Boolean.TRUE;
1572:                            break;
1573:                        case JavaTypes.PC:
1574:                            mutate = (fmd.isEmbedded()) ? Boolean.TRUE
1575:                                    : Boolean.FALSE;
1576:                            break;
1577:                        default:
1578:                            mutate = Boolean.FALSE; // not sco
1579:                        }
1580:                    }
1581:
1582:                    // possibly change state
1583:                    boolean active = _broker.isActive();
1584:                    clean = !_state.isDirty(); // intentional direct access
1585:
1586:                    // fire event fast before state change.
1587:                    if (clean)
1588:                        fireLifecycleEvent(LifecycleEvent.BEFORE_DIRTY);
1589:                    if (active) {
1590:                        if (_broker.getOptimistic())
1591:                            setPCState(_state.beforeOptimisticWrite(this ,
1592:                                    field, mutate.booleanValue()));
1593:                        else
1594:                            setPCState(_state.beforeWrite(this , field, mutate
1595:                                    .booleanValue()));
1596:                    } else if (fmd.getManagement() == FieldMetaData.MANAGE_PERSISTENT) {
1597:                        if (isPersistent()
1598:                                && !_broker.getNontransactionalWrite())
1599:                            throw new InvalidStateException(_loc
1600:                                    .get("non-trans-write"))
1601:                                    .setFailedObject(getManagedInstance());
1602:
1603:                        setPCState(_state.beforeNontransactionalWrite(this ,
1604:                                field, mutate.booleanValue()));
1605:                    }
1606:
1607:                    if ((_flags & FLAG_FLUSHED) != 0) {
1608:                        newFlush = (_flags & FLAG_FLUSHED_DIRTY) == 0;
1609:                        _flags |= FLAG_FLUSHED_DIRTY;
1610:                    }
1611:
1612:                    lock();
1613:                    locked = true;
1614:
1615:                    // note that the field is in need of flushing again, and tell the
1616:                    // broker too
1617:                    _flush.clear(field);
1618:                    _broker.setDirty(this , newFlush && !clean);
1619:
1620:                    // save the field for rollback if needed
1621:                    saveField(field);
1622:
1623:                    // dirty the field and mark loaded; load fetch group if needed
1624:                    int lockLevel = calculateLockLevel(active, true, null);
1625:                    if (!_dirty.get(field)) {
1626:                        setLoaded(field, true);
1627:                        _dirty.set(field);
1628:
1629:                        // make sure the field's fetch group is loaded
1630:                        if (loadFetchGroup && isPersistent()
1631:                                && fmd.getManagement() == fmd.MANAGE_PERSISTENT)
1632:                            loadField(field, lockLevel, true, true);
1633:                    }
1634:                    obtainLocks(active, true, lockLevel, null, null);
1635:                } catch (RuntimeException re) {
1636:                    throw translate(re);
1637:                } finally {
1638:                    if (locked)
1639:                        unlock();
1640:                }
1641:
1642:                if (clean)
1643:                    return Boolean.TRUE;
1644:                if (newFlush) {
1645:                    // this event can be fired later cause we're already dirty.
1646:                    fireLifecycleEvent(LifecycleEvent.BEFORE_DIRTY_FLUSHED);
1647:                    return null;
1648:                }
1649:                return Boolean.FALSE;
1650:            }
1651:
1652:            /**
1653:             * Fire post-dirty events after field value changes.
1654:             *
1655:             * @param status return value from {@link #dirty(int, Boolean, boolean)}
1656:             */
1657:            private void postDirty(Boolean status) {
1658:                if (Boolean.TRUE.equals(status))
1659:                    fireLifecycleEvent(LifecycleEvent.AFTER_DIRTY);
1660:                else if (status == null)
1661:                    fireLifecycleEvent(LifecycleEvent.AFTER_DIRTY_FLUSHED);
1662:            }
1663:
1664:            public void removed(int field, Object removed, boolean key) {
1665:                if (removed == null)
1666:                    return;
1667:
1668:                try {
1669:                    // dereference dependent fields, delete embedded
1670:                    FieldMetaData fmd = _meta.getField(field);
1671:                    ValueMetaData vmd = (key) ? fmd.getKey() : fmd.getElement();
1672:                    if (vmd.isEmbeddedPC())
1673:                        _single.delete(vmd, removed, null);
1674:                    else if (vmd.getCascadeDelete() == ValueMetaData.CASCADE_AUTO)
1675:                        _single.dereferenceDependent(removed);
1676:                } catch (RuntimeException re) {
1677:                    throw translate(re);
1678:                }
1679:            }
1680:
1681:            public Object newProxy(int field) {
1682:                FieldMetaData fmd = _meta.getField(field);
1683:                if (!fmd.isExternalized())
1684:                    return newFieldProxy(field);
1685:
1686:                switch (fmd.getTypeCode()) {
1687:                case JavaTypes.DATE:
1688:                    if (fmd.getDeclaredType() == java.sql.Date.class)
1689:                        return new java.sql.Date(System.currentTimeMillis());
1690:                    if (fmd.getDeclaredType() == java.sql.Timestamp.class)
1691:                        return new java.sql.Timestamp(System
1692:                                .currentTimeMillis());
1693:                    if (fmd.getDeclaredType() == java.sql.Time.class)
1694:                        return new java.sql.Time(System.currentTimeMillis());
1695:                    return new Date();
1696:                case JavaTypes.CALENDAR:
1697:                    return Calendar.getInstance();
1698:                case JavaTypes.COLLECTION:
1699:                    return new ArrayList();
1700:                case JavaTypes.MAP:
1701:                    return new HashMap();
1702:                }
1703:                return null;
1704:            }
1705:
1706:            public Object newFieldProxy(int field) {
1707:                FieldMetaData fmd = _meta.getField(field);
1708:                ProxyManager mgr = _broker.getConfiguration()
1709:                        .getProxyManagerInstance();
1710:                Object init = fmd.getInitializer();
1711:
1712:                switch (fmd.getDeclaredTypeCode()) {
1713:                case JavaTypes.DATE:
1714:                    return mgr.newDateProxy(fmd.getDeclaredType());
1715:                case JavaTypes.CALENDAR:
1716:                    return mgr.newCalendarProxy(fmd.getDeclaredType(),
1717:                            init instanceof  TimeZone ? (TimeZone) init : null);
1718:                case JavaTypes.COLLECTION:
1719:                    return mgr.newCollectionProxy(fmd.getProxyType(), fmd
1720:                            .getElement().getDeclaredType(),
1721:                            init instanceof  Comparator ? (Comparator) init
1722:                                    : null);
1723:                case JavaTypes.MAP:
1724:                    return mgr.newMapProxy(fmd.getProxyType(), fmd.getKey()
1725:                            .getDeclaredType(), fmd.getElement()
1726:                            .getDeclaredType(),
1727:                            init instanceof  Comparator ? (Comparator) init
1728:                                    : null);
1729:                }
1730:                return null;
1731:            }
1732:
1733:            public boolean isDefaultValue(int field) {
1734:                lock();
1735:                try {
1736:                    _single.clear();
1737:                    provideField(_pc, _single, field);
1738:                    boolean ret = _single.isDefaultValue();
1739:                    _single.clear();
1740:                    return ret;
1741:                } finally {
1742:                    unlock();
1743:                }
1744:            }
1745:
1746:            /////////////////////////////////////////////////////////
1747:            // Record that the field is dirty (which might load DFG)
1748:            /////////////////////////////////////////////////////////
1749:
1750:            public void settingBooleanField(PersistenceCapable pc, int field,
1751:                    boolean curVal, boolean newVal, int set) {
1752:                if (set != SET_REMOTE) {
1753:                    if (newVal == curVal && _loaded.get(field))
1754:                        return;
1755:                    assertNoPrimaryKeyChange(field);
1756:                }
1757:
1758:                lock();
1759:                try {
1760:                    Boolean stat = dirty(field, Boolean.FALSE, set == SET_USER);
1761:                    _single.storeBooleanField(field, newVal);
1762:                    replaceField(pc, _single, field);
1763:                    postDirty(stat);
1764:                } finally {
1765:                    unlock();
1766:                }
1767:            }
1768:
1769:            public void settingByteField(PersistenceCapable pc, int field,
1770:                    byte curVal, byte newVal, int set) {
1771:                if (set != SET_REMOTE) {
1772:                    if (newVal == curVal && _loaded.get(field))
1773:                        return;
1774:                    assertNoPrimaryKeyChange(field);
1775:                }
1776:
1777:                lock();
1778:                try {
1779:                    Boolean stat = dirty(field, Boolean.FALSE, set == SET_USER);
1780:                    _single.storeByteField(field, newVal);
1781:                    replaceField(pc, _single, field);
1782:                    postDirty(stat);
1783:                } finally {
1784:                    unlock();
1785:                }
1786:            }
1787:
1788:            public void settingCharField(PersistenceCapable pc, int field,
1789:                    char curVal, char newVal, int set) {
1790:                if (set != SET_REMOTE) {
1791:                    if (newVal == curVal && _loaded.get(field))
1792:                        return;
1793:                    assertNoPrimaryKeyChange(field);
1794:                }
1795:
1796:                lock();
1797:                try {
1798:                    Boolean stat = dirty(field, Boolean.FALSE, set == SET_USER);
1799:                    _single.storeCharField(field, newVal);
1800:                    replaceField(pc, _single, field);
1801:                    postDirty(stat);
1802:                } finally {
1803:                    unlock();
1804:                }
1805:            }
1806:
1807:            public void settingDoubleField(PersistenceCapable pc, int field,
1808:                    double curVal, double newVal, int set) {
1809:                if (set != SET_REMOTE) {
1810:                    if (newVal == curVal && _loaded.get(field))
1811:                        return;
1812:                    assertNoPrimaryKeyChange(field);
1813:                }
1814:
1815:                lock();
1816:                try {
1817:                    Boolean stat = dirty(field, Boolean.FALSE, set == SET_USER);
1818:                    _single.storeDoubleField(field, newVal);
1819:                    replaceField(pc, _single, field);
1820:                    postDirty(stat);
1821:                } finally {
1822:                    unlock();
1823:                }
1824:            }
1825:
1826:            public void settingFloatField(PersistenceCapable pc, int field,
1827:                    float curVal, float newVal, int set) {
1828:                if (set != SET_REMOTE) {
1829:                    if (newVal == curVal && _loaded.get(field))
1830:                        return;
1831:                    assertNoPrimaryKeyChange(field);
1832:                }
1833:
1834:                lock();
1835:                try {
1836:                    Boolean stat = dirty(field, Boolean.FALSE, set == SET_USER);
1837:                    _single.storeFloatField(field, newVal);
1838:                    replaceField(pc, _single, field);
1839:                    postDirty(stat);
1840:                } finally {
1841:                    unlock();
1842:                }
1843:            }
1844:
1845:            public void settingIntField(PersistenceCapable pc, int field,
1846:                    int curVal, int newVal, int set) {
1847:                if (set != SET_REMOTE) {
1848:                    if (newVal == curVal && _loaded.get(field))
1849:                        return;
1850:                    assertNoPrimaryKeyChange(field);
1851:                }
1852:
1853:                lock();
1854:                try {
1855:                    Boolean stat = dirty(field, Boolean.FALSE, set == SET_USER);
1856:                    _single.storeIntField(field, newVal);
1857:                    replaceField(pc, _single, field);
1858:                    postDirty(stat);
1859:                } finally {
1860:                    unlock();
1861:                }
1862:            }
1863:
1864:            public void settingLongField(PersistenceCapable pc, int field,
1865:                    long curVal, long newVal, int set) {
1866:                if (set != SET_REMOTE) {
1867:                    if (newVal == curVal && _loaded.get(field))
1868:                        return;
1869:                    assertNoPrimaryKeyChange(field);
1870:                }
1871:
1872:                lock();
1873:                try {
1874:                    Boolean stat = dirty(field, Boolean.FALSE, set == SET_USER);
1875:                    _single.storeLongField(field, newVal);
1876:                    replaceField(pc, _single, field);
1877:                    postDirty(stat);
1878:                } finally {
1879:                    unlock();
1880:                }
1881:            }
1882:
1883:            public void settingObjectField(PersistenceCapable pc, int field,
1884:                    Object curVal, Object newVal, int set) {
1885:                if (set != SET_REMOTE) {
1886:                    FieldMetaData fmd = _meta.getField(field);
1887:                    if (_loaded.get(field)) {
1888:                        if (newVal == curVal)
1889:                            return;
1890:
1891:                        // only compare new to old values if the comparison is going to
1892:                        // be cheap -- don't compare collections, maps, UDTs
1893:                        switch (fmd.getDeclaredTypeCode()) {
1894:                        case JavaTypes.ARRAY:
1895:                        case JavaTypes.COLLECTION:
1896:                        case JavaTypes.MAP:
1897:                        case JavaTypes.PC:
1898:                        case JavaTypes.PC_UNTYPED:
1899:                            break;
1900:                        default:
1901:                            if (newVal != null && newVal.equals(curVal))
1902:                                return;
1903:                        }
1904:                    } else {
1905:                        // if this is a dependent unloaded field, make sure to load
1906:                        // it now
1907:                        if (fmd.getCascadeDelete() == ValueMetaData.CASCADE_AUTO
1908:                                || fmd.getKey().getCascadeDelete() == ValueMetaData.CASCADE_AUTO
1909:                                || fmd.getElement().getCascadeDelete() == ValueMetaData.CASCADE_AUTO)
1910:                            curVal = fetchObjectField(field);
1911:                    }
1912:
1913:                    assertNoPrimaryKeyChange(field);
1914:                    if (fmd.getDeclaredTypeCode() == JavaTypes.OID)
1915:                        assertNotManagedObjectId(newVal);
1916:                }
1917:
1918:                lock();
1919:                try {
1920:                    Boolean stat = dirty(field, Boolean.FALSE, set == SET_USER);
1921:                    if (set != SET_REMOTE) {
1922:                        _single.storeObjectField(field, curVal);
1923:                        _single.unproxy();
1924:                        _single.dereferenceDependent();
1925:                        _single.clear();
1926:                    }
1927:                    _single.storeObjectField(field, newVal);
1928:                    replaceField(pc, _single, field);
1929:                    postDirty(stat);
1930:                } finally {
1931:                    unlock();
1932:                }
1933:            }
1934:
1935:            public void settingShortField(PersistenceCapable pc, int field,
1936:                    short curVal, short newVal, int set) {
1937:                if (set != SET_REMOTE) {
1938:                    if (newVal == curVal && _loaded.get(field))
1939:                        return;
1940:                    assertNoPrimaryKeyChange(field);
1941:                }
1942:
1943:                lock();
1944:                try {
1945:                    Boolean stat = dirty(field, Boolean.FALSE, set == SET_USER);
1946:                    _single.storeShortField(field, newVal);
1947:                    replaceField(pc, _single, field);
1948:                    postDirty(stat);
1949:                } finally {
1950:                    unlock();
1951:                }
1952:            }
1953:
1954:            public void settingStringField(PersistenceCapable pc, int field,
1955:                    String curVal, String newVal, int set) {
1956:                if (set != SET_REMOTE) {
1957:                    if (StringUtils.equals(newVal, curVal)
1958:                            && _loaded.get(field))
1959:                        return;
1960:                    assertNoPrimaryKeyChange(field);
1961:                }
1962:
1963:                lock();
1964:                try {
1965:                    Boolean stat = dirty(field, Boolean.FALSE, set == SET_USER);
1966:                    _single.storeStringField(field, newVal);
1967:                    replaceField(pc, _single, field);
1968:                    postDirty(stat);
1969:                } finally {
1970:                    unlock();
1971:                }
1972:            }
1973:
1974:            /**
1975:             * Disallows changing primary key fields for instances.
1976:             */
1977:            private void assertNoPrimaryKeyChange(int field) {
1978:                if (_oid != null && _meta.getField(field).isPrimaryKey())
1979:                    throw translate(new InvalidStateException(_loc
1980:                            .get("change-identity"))
1981:                            .setFailedObject(getManagedInstance()));
1982:            }
1983:
1984:            /**
1985:             * Disallows setting an object id field to a managed instance.
1986:             */
1987:            void assertNotManagedObjectId(Object val) {
1988:                if (val != null
1989:                        && (ImplHelper.toPersistenceCapable(val, getContext()
1990:                                .getConfiguration())).pcGetGenericContext() != null)
1991:                    throw translate(new InvalidStateException(_loc.get(
1992:                            "managed-oid", Exceptions.toString(val), Exceptions
1993:                                    .toString(getManagedInstance())))
1994:                            .setFailedObject(getManagedInstance()));
1995:            }
1996:
1997:            ////////////////////////////
1998:            // Delegate to FieldManager
1999:            ////////////////////////////
2000:
2001:            public void providedBooleanField(PersistenceCapable pc, int field,
2002:                    boolean curVal) {
2003:                _fm.storeBooleanField(field, curVal);
2004:            }
2005:
2006:            public void providedByteField(PersistenceCapable pc, int field,
2007:                    byte curVal) {
2008:                _fm.storeByteField(field, curVal);
2009:            }
2010:
2011:            public void providedCharField(PersistenceCapable pc, int field,
2012:                    char curVal) {
2013:                _fm.storeCharField(field, curVal);
2014:            }
2015:
2016:            public void providedDoubleField(PersistenceCapable pc, int field,
2017:                    double curVal) {
2018:                _fm.storeDoubleField(field, curVal);
2019:            }
2020:
2021:            public void providedFloatField(PersistenceCapable pc, int field,
2022:                    float curVal) {
2023:                _fm.storeFloatField(field, curVal);
2024:            }
2025:
2026:            public void providedIntField(PersistenceCapable pc, int field,
2027:                    int curVal) {
2028:                _fm.storeIntField(field, curVal);
2029:            }
2030:
2031:            public void providedLongField(PersistenceCapable pc, int field,
2032:                    long curVal) {
2033:                _fm.storeLongField(field, curVal);
2034:            }
2035:
2036:            public void providedObjectField(PersistenceCapable pc, int field,
2037:                    Object curVal) {
2038:                _fm.storeObjectField(field, curVal);
2039:            }
2040:
2041:            public void providedShortField(PersistenceCapable pc, int field,
2042:                    short curVal) {
2043:                _fm.storeShortField(field, curVal);
2044:            }
2045:
2046:            public void providedStringField(PersistenceCapable pc, int field,
2047:                    String curVal) {
2048:                _fm.storeStringField(field, curVal);
2049:            }
2050:
2051:            public boolean replaceBooleanField(PersistenceCapable pc, int field) {
2052:                return _fm.fetchBooleanField(field);
2053:            }
2054:
2055:            public byte replaceByteField(PersistenceCapable pc, int field) {
2056:                return _fm.fetchByteField(field);
2057:            }
2058:
2059:            public char replaceCharField(PersistenceCapable pc, int field) {
2060:                return _fm.fetchCharField(field);
2061:            }
2062:
2063:            public double replaceDoubleField(PersistenceCapable pc, int field) {
2064:                return _fm.fetchDoubleField(field);
2065:            }
2066:
2067:            public float replaceFloatField(PersistenceCapable pc, int field) {
2068:                return _fm.fetchFloatField(field);
2069:            }
2070:
2071:            public int replaceIntField(PersistenceCapable pc, int field) {
2072:                return _fm.fetchIntField(field);
2073:            }
2074:
2075:            public long replaceLongField(PersistenceCapable pc, int field) {
2076:                return _fm.fetchLongField(field);
2077:            }
2078:
2079:            public Object replaceObjectField(PersistenceCapable pc, int field) {
2080:                return _fm.fetchObjectField(field);
2081:            }
2082:
2083:            public short replaceShortField(PersistenceCapable pc, int field) {
2084:                return _fm.fetchShortField(field);
2085:            }
2086:
2087:            public String replaceStringField(PersistenceCapable pc, int field) {
2088:                return _fm.fetchStringField(field);
2089:            }
2090:
2091:            //////////////////////////////////
2092:            // Implementation of FieldManager
2093:            //////////////////////////////////
2094:
2095:            public boolean fetchBoolean(int field) {
2096:                FieldMetaData fmd = _meta.getField(field);
2097:                if (!fmd.isExternalized())
2098:                    return fetchBooleanField(field);
2099:
2100:                Object val = fetchField(field, false);
2101:                return ((Boolean) fmd.getExternalValue(val, _broker))
2102:                        .booleanValue();
2103:            }
2104:
2105:            public boolean fetchBooleanField(int field) {
2106:                lock();
2107:                try {
2108:                    if (!_loaded.get(field))
2109:                        loadField(field, LockLevels.LOCK_NONE, false, false);
2110:
2111:                    provideField(_pc, _single, field);
2112:                    return _single.fetchBooleanField(field);
2113:                } finally {
2114:                    unlock();
2115:                }
2116:            }
2117:
2118:            public byte fetchByte(int field) {
2119:                FieldMetaData fmd = _meta.getField(field);
2120:                if (!fmd.isExternalized())
2121:                    return fetchByteField(field);
2122:
2123:                Object val = fetchField(field, false);
2124:                return ((Number) fmd.getExternalValue(val, _broker))
2125:                        .byteValue();
2126:            }
2127:
2128:            public byte fetchByteField(int field) {
2129:                lock();
2130:                try {
2131:                    if (!_loaded.get(field))
2132:                        loadField(field, LockLevels.LOCK_NONE, false, false);
2133:
2134:                    provideField(_pc, _single, field);
2135:                    return _single.fetchByteField(field);
2136:                } finally {
2137:                    unlock();
2138:                }
2139:            }
2140:
2141:            public char fetchChar(int field) {
2142:                FieldMetaData fmd = _meta.getField(field);
2143:                if (!fmd.isExternalized())
2144:                    return fetchCharField(field);
2145:
2146:                Object val = fetchField(field, false);
2147:                return ((Character) fmd.getExternalValue(val, _broker))
2148:                        .charValue();
2149:            }
2150:
2151:            public char fetchCharField(int field) {
2152:                lock();
2153:                try {
2154:                    if (!_loaded.get(field))
2155:                        loadField(field, LockLevels.LOCK_NONE, false, false);
2156:
2157:                    provideField(_pc, _single, field);
2158:                    return _single.fetchCharField(field);
2159:                } finally {
2160:                    unlock();
2161:                }
2162:            }
2163:
2164:            public double fetchDouble(int field) {
2165:                FieldMetaData fmd = _meta.getField(field);
2166:                if (!fmd.isExternalized())
2167:                    return fetchDoubleField(field);
2168:
2169:                Object val = fetchField(field, false);
2170:                return ((Number) fmd.getExternalValue(val, _broker))
2171:                        .doubleValue();
2172:            }
2173:
2174:            public double fetchDoubleField(int field) {
2175:                lock();
2176:                try {
2177:                    if (!_loaded.get(field))
2178:                        loadField(field, LockLevels.LOCK_NONE, false, false);
2179:
2180:                    provideField(_pc, _single, field);
2181:                    return _single.fetchDoubleField(field);
2182:                } finally {
2183:                    unlock();
2184:                }
2185:            }
2186:
2187:            public float fetchFloat(int field) {
2188:                FieldMetaData fmd = _meta.getField(field);
2189:                if (!fmd.isExternalized())
2190:                    return fetchFloatField(field);
2191:
2192:                Object val = fetchField(field, false);
2193:                return ((Number) fmd.getExternalValue(val, _broker))
2194:                        .floatValue();
2195:            }
2196:
2197:            public float fetchFloatField(int field) {
2198:                lock();
2199:                try {
2200:                    if (!_loaded.get(field))
2201:                        loadField(field, LockLevels.LOCK_NONE, false, false);
2202:
2203:                    provideField(_pc, _single, field);
2204:                    return _single.fetchFloatField(field);
2205:                } finally {
2206:                    unlock();
2207:                }
2208:            }
2209:
2210:            public int fetchInt(int field) {
2211:                FieldMetaData fmd = _meta.getField(field);
2212:                if (!fmd.isExternalized())
2213:                    return fetchIntField(field);
2214:
2215:                Object val = fetchField(field, false);
2216:                return ((Number) fmd.getExternalValue(val, _broker)).intValue();
2217:            }
2218:
2219:            public int fetchIntField(int field) {
2220:                lock();
2221:                try {
2222:                    if (!_loaded.get(field))
2223:                        loadField(field, LockLevels.LOCK_NONE, false, false);
2224:
2225:                    provideField(_pc, _single, field);
2226:                    return _single.fetchIntField(field);
2227:                } finally {
2228:                    unlock();
2229:                }
2230:            }
2231:
2232:            public long fetchLong(int field) {
2233:                FieldMetaData fmd = _meta.getField(field);
2234:                if (!fmd.isExternalized())
2235:                    return fetchLongField(field);
2236:
2237:                Object val = fetchField(field, false);
2238:                return ((Number) fmd.getExternalValue(val, _broker))
2239:                        .longValue();
2240:            }
2241:
2242:            public long fetchLongField(int field) {
2243:                lock();
2244:                try {
2245:                    if (!_loaded.get(field))
2246:                        loadField(field, LockLevels.LOCK_NONE, false, false);
2247:
2248:                    provideField(_pc, _single, field);
2249:                    return _single.fetchLongField(field);
2250:                } finally {
2251:                    unlock();
2252:                }
2253:            }
2254:
2255:            public Object fetchObject(int field) {
2256:                FieldMetaData fmd = _meta.getField(field);
2257:                if (!fmd.isExternalized())
2258:                    return fetchObjectField(field);
2259:
2260:                Object val = fetchField(field, false);
2261:                return fmd.getExternalValue(val, _broker);
2262:            }
2263:
2264:            public Object fetchObjectField(int field) {
2265:                lock();
2266:                try {
2267:                    if (!_loaded.get(field))
2268:                        loadField(field, LockLevels.LOCK_NONE, false, false);
2269:
2270:                    provideField(_pc, _single, field);
2271:                    return _single.fetchObjectField(field);
2272:                } finally {
2273:                    unlock();
2274:                }
2275:            }
2276:
2277:            public short fetchShort(int field) {
2278:                FieldMetaData fmd = _meta.getField(field);
2279:                if (!fmd.isExternalized())
2280:                    return fetchShortField(field);
2281:
2282:                Object val = fetchField(field, false);
2283:                return ((Number) fmd.getExternalValue(val, _broker))
2284:                        .shortValue();
2285:            }
2286:
2287:            public short fetchShortField(int field) {
2288:                lock();
2289:                try {
2290:                    if (!_loaded.get(field))
2291:                        loadField(field, LockLevels.LOCK_NONE, false, false);
2292:
2293:                    provideField(_pc, _single, field);
2294:                    return _single.fetchShortField(field);
2295:                } finally {
2296:                    unlock();
2297:                }
2298:            }
2299:
2300:            public String fetchString(int field) {
2301:                FieldMetaData fmd = _meta.getField(field);
2302:                if (!fmd.isExternalized())
2303:                    return fetchStringField(field);
2304:
2305:                Object val = fetchField(field, false);
2306:                return (String) fmd.getExternalValue(val, _broker);
2307:            }
2308:
2309:            public String fetchStringField(int field) {
2310:                lock();
2311:                try {
2312:                    if (!_loaded.get(field))
2313:                        loadField(field, LockLevels.LOCK_NONE, false, false);
2314:
2315:                    provideField(_pc, _single, field);
2316:                    return _single.fetchStringField(field);
2317:                } finally {
2318:                    unlock();
2319:                }
2320:            }
2321:
2322:            public void storeBoolean(int field, boolean externalVal) {
2323:                FieldMetaData fmd = _meta.getField(field);
2324:                if (!fmd.isExternalized())
2325:                    storeBooleanField(field, externalVal);
2326:                else {
2327:                    Object val = (externalVal) ? Boolean.TRUE : Boolean.FALSE;
2328:                    storeField(field, fmd.getFieldValue(val, _broker));
2329:                }
2330:            }
2331:
2332:            public void storeBooleanField(int field, boolean curVal) {
2333:                lock();
2334:                try {
2335:                    _single.storeBooleanField(field, curVal);
2336:                    replaceField(_pc, _single, field);
2337:                    setLoaded(field, true);
2338:                    postLoad(field, null);
2339:                } finally {
2340:                    unlock();
2341:                }
2342:            }
2343:
2344:            public void storeByte(int field, byte externalVal) {
2345:                FieldMetaData fmd = _meta.getField(field);
2346:                if (!fmd.isExternalized())
2347:                    storeByteField(field, externalVal);
2348:                else
2349:                    storeField(field, fmd.getFieldValue(new Byte(externalVal),
2350:                            _broker));
2351:            }
2352:
2353:            public void storeByteField(int field, byte curVal) {
2354:                lock();
2355:                try {
2356:                    _single.storeByteField(field, curVal);
2357:                    replaceField(_pc, _single, field);
2358:                    setLoaded(field, true);
2359:                    postLoad(field, null);
2360:                } finally {
2361:                    unlock();
2362:                }
2363:            }
2364:
2365:            public void storeChar(int field, char externalVal) {
2366:                FieldMetaData fmd = _meta.getField(field);
2367:                if (!fmd.isExternalized())
2368:                    storeCharField(field, externalVal);
2369:                else
2370:                    storeField(field, fmd.getFieldValue(new Character(
2371:                            externalVal), _broker));
2372:            }
2373:
2374:            public void storeCharField(int field, char curVal) {
2375:                lock();
2376:                try {
2377:                    _single.storeCharField(field, curVal);
2378:                    replaceField(_pc, _single, field);
2379:                    setLoaded(field, true);
2380:                    postLoad(field, null);
2381:                } finally {
2382:                    unlock();
2383:                }
2384:            }
2385:
2386:            public void storeDouble(int field, double externalVal) {
2387:                FieldMetaData fmd = _meta.getField(field);
2388:                if (!fmd.isExternalized())
2389:                    storeDoubleField(field, externalVal);
2390:                else
2391:                    storeField(field, fmd.getFieldValue(
2392:                            new Double(externalVal), _broker));
2393:            }
2394:
2395:            public void storeDoubleField(int field, double curVal) {
2396:                lock();
2397:                try {
2398:                    _single.storeDoubleField(field, curVal);
2399:                    replaceField(_pc, _single, field);
2400:                    setLoaded(field, true);
2401:                    postLoad(field, null);
2402:                } finally {
2403:                    unlock();
2404:                }
2405:            }
2406:
2407:            public void storeFloat(int field, float externalVal) {
2408:                FieldMetaData fmd = _meta.getField(field);
2409:                if (!fmd.isExternalized())
2410:                    storeFloatField(field, externalVal);
2411:                else
2412:                    storeField(field, fmd.getFieldValue(new Float(externalVal),
2413:                            _broker));
2414:            }
2415:
2416:            public void storeFloatField(int field, float curVal) {
2417:                lock();
2418:                try {
2419:                    _single.storeFloatField(field, curVal);
2420:                    replaceField(_pc, _single, field);
2421:                    setLoaded(field, true);
2422:                    postLoad(field, null);
2423:                } finally {
2424:                    unlock();
2425:                }
2426:            }
2427:
2428:            public void storeInt(int field, int externalVal) {
2429:                FieldMetaData fmd = _meta.getField(field);
2430:                if (!fmd.isExternalized())
2431:                    storeIntField(field, externalVal);
2432:                else
2433:                    storeField(field, fmd.getFieldValue(Numbers
2434:                            .valueOf(externalVal), _broker));
2435:            }
2436:
2437:            public void storeIntField(int field, int curVal) {
2438:                lock();
2439:                try {
2440:                    _single.storeIntField(field, curVal);
2441:                    replaceField(_pc, _single, field);
2442:                    setLoaded(field, true);
2443:                    postLoad(field, null);
2444:                } finally {
2445:                    unlock();
2446:                }
2447:            }
2448:
2449:            public void storeLong(int field, long externalVal) {
2450:                FieldMetaData fmd = _meta.getField(field);
2451:                if (!fmd.isExternalized())
2452:                    storeLongField(field, externalVal);
2453:                else
2454:                    storeField(field, fmd.getFieldValue(Numbers
2455:                            .valueOf(externalVal), _broker));
2456:            }
2457:
2458:            public void storeLongField(int field, long curVal) {
2459:                lock();
2460:                try {
2461:                    _single.storeLongField(field, curVal);
2462:                    replaceField(_pc, _single, field);
2463:                    setLoaded(field, true);
2464:                    postLoad(field, null);
2465:                } finally {
2466:                    unlock();
2467:                }
2468:            }
2469:
2470:            public void storeObject(int field, Object externalVal) {
2471:                FieldMetaData fmd = _meta.getField(field);
2472:                externalVal = fmd.order(externalVal);
2473:                if (!fmd.isExternalized())
2474:                    storeObjectField(field, externalVal);
2475:                else
2476:                    storeField(field, fmd.getFieldValue(externalVal, _broker));
2477:            }
2478:
2479:            public void storeObjectField(int field, Object curVal) {
2480:                lock();
2481:                try {
2482:                    _single.storeObjectField(field, curVal);
2483:                    _single.proxy(true, false);
2484:                    replaceField(_pc, _single, field);
2485:                    setLoaded(field, true);
2486:                    postLoad(field, null);
2487:                } finally {
2488:                    unlock();
2489:                }
2490:            }
2491:
2492:            public void storeShort(int field, short externalVal) {
2493:                FieldMetaData fmd = _meta.getField(field);
2494:                if (!fmd.isExternalized())
2495:                    storeShortField(field, externalVal);
2496:                else
2497:                    storeField(field, fmd.getFieldValue(new Short(externalVal),
2498:                            _broker));
2499:            }
2500:
2501:            public void storeShortField(int field, short curVal) {
2502:                lock();
2503:                try {
2504:                    _single.storeShortField(field, curVal);
2505:                    replaceField(_pc, _single, field);
2506:                    setLoaded(field, true);
2507:                    postLoad(field, null);
2508:                } finally {
2509:                    unlock();
2510:                }
2511:            }
2512:
2513:            public void storeString(int field, String externalVal) {
2514:                FieldMetaData fmd = _meta.getField(field);
2515:                if (!fmd.isExternalized())
2516:                    storeStringField(field, externalVal);
2517:                else
2518:                    storeField(field, fmd.getFieldValue(externalVal, _broker));
2519:            }
2520:
2521:            public void storeStringField(int field, String curVal) {
2522:                lock();
2523:                try {
2524:                    _single.storeStringField(field, curVal);
2525:                    replaceField(_pc, _single, field);
2526:                    setLoaded(field, true);
2527:                    postLoad(field, null);
2528:                } finally {
2529:                    unlock();
2530:                }
2531:            }
2532:
2533:            /**
2534:             * Store the given field value into the given field manager.
2535:             */
2536:            private void storeField(int field, Object val, FieldManager fm) {
2537:                FieldMetaData fmd = _meta.getField(field);
2538:                if (fmd == null)
2539:                    throw new UserException(_loc.get("no-field-index", String
2540:                            .valueOf(field), _meta.getDescribedType()))
2541:                            .setFailedObject(getManagedInstance());
2542:
2543:                switch (fmd.getDeclaredTypeCode()) {
2544:                case JavaTypes.BOOLEAN:
2545:                    boolean bool = val != null
2546:                            && ((Boolean) val).booleanValue();
2547:                    fm.storeBooleanField(field, bool);
2548:                    break;
2549:                case JavaTypes.BYTE:
2550:                    byte b = (val == null) ? 0 : ((Number) val).byteValue();
2551:                    fm.storeByteField(field, b);
2552:                    break;
2553:                case JavaTypes.CHAR:
2554:                    char c = (val == null) ? 0 : ((Character) val).charValue();
2555:                    fm.storeCharField(field, c);
2556:                    break;
2557:                case JavaTypes.DOUBLE:
2558:                    double d = (val == null) ? 0 : ((Number) val).doubleValue();
2559:                    fm.storeDoubleField(field, d);
2560:                    break;
2561:                case JavaTypes.FLOAT:
2562:                    float f = (val == null) ? 0 : ((Number) val).floatValue();
2563:                    fm.storeFloatField(field, f);
2564:                    break;
2565:                case JavaTypes.INT:
2566:                    int i = (val == null) ? 0 : ((Number) val).intValue();
2567:                    fm.storeIntField(field, i);
2568:                    break;
2569:                case JavaTypes.LONG:
2570:                    long l = (val == null) ? 0 : ((Number) val).longValue();
2571:                    fm.storeLongField(field, l);
2572:                    break;
2573:                case JavaTypes.SHORT:
2574:                    short s = (val == null) ? 0 : ((Number) val).shortValue();
2575:                    fm.storeShortField(field, s);
2576:                    break;
2577:                case JavaTypes.STRING:
2578:                    fm.storeStringField(field, (String) val);
2579:                    break;
2580:                default:
2581:                    fm.storeObjectField(field, val);
2582:                }
2583:            }
2584:
2585:            /////////////
2586:            // Utilities
2587:            /////////////
2588:
2589:            /**
2590:             * Erase the fact that this instance has been flushed.
2591:             */
2592:            void eraseFlush() {
2593:                _flags &= ~FLAG_FLUSHED;
2594:                _flags &= ~FLAG_FLUSHED_DIRTY;
2595:
2596:                int fmds = _meta.getFields().length;
2597:                for (int i = 0; i < fmds; i++)
2598:                    _flush.clear(i);
2599:            }
2600:
2601:            /**
2602:             * Records that all instance fields are/are not loaded.
2603:             * Primary key and non-persistent fields are not affected.
2604:             */
2605:            void setLoaded(boolean val) {
2606:                FieldMetaData[] fmds = _meta.getFields();
2607:                for (int i = 0; i < fmds.length; i++) {
2608:                    if (!fmds[i].isPrimaryKey()
2609:                            && fmds[i].getManagement() == fmds[i].MANAGE_PERSISTENT)
2610:                        setLoaded(i, val);
2611:                }
2612:                if (!val) {
2613:                    _flags &= ~FLAG_LOADED;
2614:                    setDirty(false);
2615:                } else
2616:                    _flags |= FLAG_LOADED;
2617:            }
2618:
2619:            /**
2620:             * Records that all instance fields are/are not dirty,
2621:             * and changes the flags of the instance accordingly.
2622:             */
2623:            void setDirty(boolean val) {
2624:                FieldMetaData[] fmds = _meta.getFields();
2625:                boolean update = !isNew() || isFlushed();
2626:                for (int i = 0; i < fmds.length; i++) {
2627:                    if (val
2628:                            && (!update || fmds[i].getUpdateStrategy() != UpdateStrategies.IGNORE))
2629:                        _dirty.set(i);
2630:                    else if (!val) {
2631:                        // we never consider clean fields flushed; this also takes
2632:                        // care of clearing the flushed fields on commit/rollback
2633:                        _flush.clear(i);
2634:                        _dirty.clear(i);
2635:                    }
2636:                }
2637:
2638:                if (val)
2639:                    _flags |= FLAG_LOADED;
2640:            }
2641:
2642:            /**
2643:             * Executes pre-clear callbacks, clears all managed fields, and calls the
2644:             * {@link #setLoaded} method with a value of false. Primary key fields
2645:             * are not cleared.
2646:             */
2647:            void clearFields() {
2648:                if (!isIntercepting())
2649:                    return;
2650:
2651:                fireLifecycleEvent(LifecycleEvent.BEFORE_CLEAR);
2652:
2653:                // unproxy all fields
2654:                unproxyFields();
2655:
2656:                lock();
2657:                try {
2658:                    // clear non-pk fields
2659:                    FieldMetaData[] fmds = _meta.getFields();
2660:                    for (int i = 0; i < fmds.length; i++) {
2661:                        if (!fmds[i].isPrimaryKey()
2662:                                && fmds[i].getManagement() == FieldMetaData.MANAGE_PERSISTENT)
2663:                            replaceField(_pc, ClearFieldManager.getInstance(),
2664:                                    i);
2665:                    }
2666:
2667:                    // forget version info and impl data so we re-read next time
2668:                    setLoaded(false);
2669:                    _version = null;
2670:                    _loadVersion = null;
2671:                    if (_fieldImpl != null)
2672:                        Arrays.fill(_fieldImpl, null);
2673:                } finally {
2674:                    unlock();
2675:                }
2676:
2677:                fireLifecycleEvent(LifecycleEvent.AFTER_CLEAR);
2678:            }
2679:
2680:            /**
2681:             * Record that we should save any fields that change from this point
2682:             * forward.
2683:             */
2684:            void saveFields(boolean immediate) {
2685:                if (_broker.getRestoreState() == RestoreState.RESTORE_NONE
2686:                        && (_flags & FLAG_INVERSES) == 0)
2687:                    return;
2688:
2689:                _flags |= FLAG_SAVE;
2690:                if (immediate) {
2691:                    for (int i = 0, len = _loaded.length(); i < len; i++)
2692:                        saveField(i);
2693:                    _flags &= ~FLAG_SAVE;
2694:                }
2695:            }
2696:
2697:            /**
2698:             * If the field isn't already saved, saves the currently loaded field
2699:             * state of the instance. The saved values can all be restored via
2700:             * {@link #restoreFields}.
2701:             */
2702:            private void saveField(int field) {
2703:                if ((_flags & FLAG_SAVE) == 0)
2704:                    return;
2705:
2706:                // if this is a managed inverse field, load it so we're sure to have
2707:                // the original value
2708:                if (!_loaded.get(field)
2709:                        && ((_flags & FLAG_INVERSES) != 0 && _meta.getField(
2710:                                field).getInverseMetaDatas().length > 0))
2711:                    loadField(field, LockLevels.LOCK_NONE, false, false);
2712:
2713:                // don't bother creating the save field manager if we're not going to
2714:                // save the old field value anyway
2715:                if (_saved == null) {
2716:                    if (_loaded.get(field))
2717:                        _saved = new SaveFieldManager(this , null, _dirty);
2718:                    else
2719:                        return;
2720:                }
2721:
2722:                // copy the field to save field manager; if the field is not directly
2723:                // copyable, immediately provide and replace it via the save field
2724:                // manager, which will copy the mutable value to prevent by-ref mods
2725:                if (_saved.saveField(field)) {
2726:                    provideField(_pc, _saved, field);
2727:                    replaceField(_saved.getState(), _saved, field);
2728:                }
2729:            }
2730:
2731:            /**
2732:             * Notification that the state will not need to be rolled back
2733:             * to that of the last call to {@link #saveFields}.
2734:             */
2735:            void clearSavedFields() {
2736:                if (isIntercepting()) {
2737:                    _flags &= ~FLAG_SAVE;
2738:                    _saved = null;
2739:                }
2740:            }
2741:
2742:            public SaveFieldManager getSaveFieldManager() {
2743:                return _saved;
2744:            }
2745:
2746:            /**
2747:             * Rollback the state of the instance to the saved state from the
2748:             * last call to {@link #saveFields}, or to default values if never saved.
2749:             */
2750:            void restoreFields() {
2751:                lock();
2752:                try {
2753:                    if (_saved == null) {
2754:                        if ((_flags & FLAG_SAVE) == 0)
2755:                            clearFields();
2756:                        else
2757:                            // only unloaded fields were dirtied
2758:                            _loaded.andNot(_loaded);
2759:                    }
2760:                    // we direct state transitions based on our own getRestoreState
2761:                    // method, but to decide whether to actually rollback field
2762:                    // values, we consult the broker for the user's setting
2763:                    else if (_broker.getRestoreState() != RestoreState.RESTORE_NONE) {
2764:                        // rollback all currently-loaded fields
2765:                        for (int i = 0, len = _loaded.length(); i < len; i++)
2766:                            if (_loaded.get(i) && _saved.restoreField(i))
2767:                                replaceField(_pc, _saved, i);
2768:
2769:                        // rollback loaded set
2770:                        _loaded.andNot(_saved.getUnloaded());
2771:                    }
2772:                } finally {
2773:                    unlock();
2774:                }
2775:            }
2776:
2777:            /**
2778:             * Replaces all second class object fields with fresh proxied instances
2779:             * containing the same information as the originals.
2780:             */
2781:            void proxyFields(boolean reset, boolean replaceNull) {
2782:                // we only replace nulls if the runtime can't differentiate between
2783:                // null and empty containers.  we replace nulls in this case to
2784:                // maintain consistency whether values are being retained or not
2785:                if (replaceNull)
2786:                    replaceNull = !_broker.getConfiguration()
2787:                            .supportedOptions().contains(
2788:                                    OpenJPAConfiguration.OPTION_NULL_CONTAINER);
2789:
2790:                lock();
2791:                try {
2792:                    for (int i = 0, len = _loaded.length(); i < len; i++) {
2793:                        if (_loaded.get(i)) {
2794:                            provideField(_pc, _single, i);
2795:                            if (_single.proxy(reset, replaceNull))
2796:                                replaceField(_pc, _single, i);
2797:                            else
2798:                                _single.clear();
2799:                        }
2800:                    }
2801:                } finally {
2802:                    unlock();
2803:                }
2804:            }
2805:
2806:            /**
2807:             * Unproxy all fields.
2808:             */
2809:            void unproxyFields() {
2810:                if ((_flags & FLAG_NO_UNPROXY) != 0)
2811:                    return;
2812:
2813:                lock();
2814:                try {
2815:                    for (int i = 0, len = _loaded.length(); i < len; i++) {
2816:                        provideField(_pc, _single, i);
2817:                        _single.unproxy();
2818:                        _single.releaseEmbedded();
2819:                        _single.clear();
2820:                    }
2821:                } finally {
2822:                    unlock();
2823:                }
2824:            }
2825:
2826:            /**
2827:             * Get ready for a flush. Persists all persistence-capable object fields,
2828:             * and checks for illegal null values. Also assigns oids and field values
2829:             * for all strategies that don't require flushing.
2830:             */
2831:            void preFlush(boolean logical, OpCallbacks call) {
2832:                if ((_flags & FLAG_PRE_FLUSHED) != 0)
2833:                    return;
2834:
2835:                if (isPersistent()) {
2836:                    fireLifecycleEvent(LifecycleEvent.BEFORE_STORE);
2837:                    // BEFORE_PERSIST is handled during Broker.persist and Broker.attach
2838:                    if (isDeleted())
2839:                        fireLifecycleEvent(LifecycleEvent.BEFORE_DELETE);
2840:                    else if (!(isNew() && !isFlushed()))
2841:                        fireLifecycleEvent(LifecycleEvent.BEFORE_UPDATE);
2842:                    _flags |= FLAG_PRE_FLUSHED;
2843:                }
2844:
2845:                lock();
2846:                try {
2847:                    if (!logical)
2848:                        assignObjectId(false, true);
2849:                    for (int i = 0, len = _meta.getFields().length; i < len; i++) {
2850:                        if ((logical || !assignField(i, true))
2851:                                && !_flush.get(i) && _dirty.get(i)) {
2852:                            provideField(_pc, _single, i);
2853:                            if (_single.preFlush(logical, call))
2854:                                replaceField(_pc, _single, i);
2855:                            else
2856:                                _single.clear();
2857:                        }
2858:                    }
2859:
2860:                    dirtyCheck();
2861:                } finally {
2862:                    unlock();
2863:                }
2864:            }
2865:
2866:            /**
2867:             * Make callbacks for deletion.
2868:             */
2869:            void preDelete() {
2870:                // set a flag while call pre delete callback so that user can't
2871:                // get into infinite recursion by calling delete(this)
2872:                // within his callback method
2873:                if ((_flags & FLAG_PRE_DELETING) == 0) {
2874:                    _flags |= FLAG_PRE_DELETING;
2875:                    try {
2876:                        fireLifecycleEvent(LifecycleEvent.BEFORE_DELETE);
2877:                    } finally {
2878:                        _flags &= ~FLAG_PRE_DELETING;
2879:                    }
2880:                }
2881:            }
2882:
2883:            /**
2884:             * Cascade deletes and dereference dependent fields.
2885:             */
2886:            void cascadeDelete(OpCallbacks call) {
2887:                FieldMetaData[] fmds = _meta.getFields();
2888:                for (int i = 0; i < fmds.length; i++) {
2889:                    if (fmds[i].getCascadeDelete() != ValueMetaData.CASCADE_NONE
2890:                            || fmds[i].getKey().getCascadeDelete() != ValueMetaData.CASCADE_NONE
2891:                            || fmds[i].getElement().getCascadeDelete() != ValueMetaData.CASCADE_NONE) {
2892:                        _single.storeObjectField(i, fetchField(i, false));
2893:                        _single.delete(call);
2894:                        _single.clear();
2895:                    }
2896:                }
2897:            }
2898:
2899:            /**
2900:             * Called after an instance is persisted by a user through the broker.
2901:             * Cascades the persist operation to fields marked
2902:             * {@link ValueMetaData#CASCADE_IMMEDIATE}.
2903:             */
2904:            void cascadePersist(OpCallbacks call) {
2905:                FieldMetaData[] fmds = _meta.getFields();
2906:                for (int i = 0; i < fmds.length; i++) {
2907:                    if (!_loaded.get(i))
2908:                        continue;
2909:
2910:                    if (fmds[i].getCascadePersist() == ValueMetaData.CASCADE_IMMEDIATE
2911:                            || fmds[i].getKey().getCascadePersist() == ValueMetaData.CASCADE_IMMEDIATE
2912:                            || fmds[i].getElement().getCascadePersist() == ValueMetaData.CASCADE_IMMEDIATE) {
2913:                        _single.storeObjectField(i, fetchField(i, false));
2914:                        _single.persist(call);
2915:                        _single.clear();
2916:                    }
2917:                }
2918:            }
2919:
2920:            /**
2921:             * Load the given field set from the data store into the instance.
2922:             * Return true if any data is loaded, false otherwise.
2923:             */
2924:            boolean loadFields(BitSet fields, FetchConfiguration fetch,
2925:                    int lockLevel, Object sdata) {
2926:                // can't load version field from store
2927:                if (fields != null) {
2928:                    FieldMetaData vfield = _meta.getVersionField();
2929:                    if (vfield != null)
2930:                        fields.clear(vfield.getIndex());
2931:                }
2932:
2933:                boolean ret = false;
2934:                setLoading(true);
2935:                try {
2936:                    // if any fields given, load them
2937:                    int len = (fields == null) ? 0 : fields.length();
2938:                    if (len > 0) {
2939:                        if (fetch == null)
2940:                            fetch = _broker.getFetchConfiguration();
2941:                        if (!_broker.getStoreManager().load(this , fields,
2942:                                fetch, lockLevel, sdata)) {
2943:                            throw new ObjectNotFoundException(_loc.get(
2944:                                    "del-instance", _meta.getDescribedType(),
2945:                                    _oid))
2946:                                    .setFailedObject(getManagedInstance());
2947:                        }
2948:                        ret = true;
2949:                    }
2950:
2951:                    // make sure version information has been set; version info must
2952:                    // always be set after the first state load or set (which is why
2953:                    // we do this even if no fields were loaded -- could be that this
2954:                    // method is being called after a field is set)... some instances
2955:                    // might not have version info, in which case this gets called
2956:                    // mutiple times; that should be ok too
2957:                    if (_loadVersion == null) {
2958:                        syncVersion(sdata);
2959:                        ret = ret || _loadVersion != null;
2960:                    }
2961:                } finally {
2962:                    setLoading(false);
2963:                }
2964:
2965:                // see if the dfg is now loaded; do this regardless of whether we
2966:                // loaded any fields, cause may already have been loaded by
2967:                // StoreManager during initialization
2968:                postLoad(-1, fetch);
2969:                return ret;
2970:            }
2971:
2972:            /**
2973:             * Load the given field's fetch group; the field itself may already be
2974:             * loaded if it is being set by the user.
2975:             */
2976:            protected void loadField(int field, int lockLevel,
2977:                    boolean forWrite, boolean fgs) {
2978:                FetchConfiguration fetch = _broker.getFetchConfiguration();
2979:                FieldMetaData fmd = _meta.getField(field);
2980:                BitSet fields = null;
2981:
2982:                // if this is a dfg field or we need to load our dfg, do so
2983:                if (fgs && (_flags & FLAG_LOADED) == 0)
2984:                    fields = getUnloadedInternal(fetch, LOAD_FGS, null);
2985:
2986:                // check for load fetch group
2987:                String lfg = fmd.getLoadFetchGroup();
2988:                boolean lfgAdded = false;
2989:                if (lfg != null) {
2990:                    FieldMetaData[] fmds = _meta.getFields();
2991:                    for (int i = 0; i < fmds.length; i++) {
2992:                        if (!_loaded.get(i)
2993:                                && (i == field || fmds[i].isInFetchGroup(lfg))) {
2994:                            if (fields == null)
2995:                                fields = new BitSet(fmds.length);
2996:                            fields.set(i);
2997:                        }
2998:                    }
2999:
3000:                    // relation field is loaded with the load-fetch-group
3001:                    // but this addition must be reverted once the load is over
3002:                    if (!fetch.hasFetchGroup(lfg)) {
3003:                        fetch.addFetchGroup(lfg);
3004:                        lfgAdded = true;
3005:                    }
3006:                } else if (fmd.isInDefaultFetchGroup() && fields == null) {
3007:                    // no load group but dfg: add dfg fields if we haven't already
3008:                    fields = getUnloadedInternal(fetch, LOAD_FGS, null);
3009:                } else if (!_loaded.get(fmd.getIndex())) {
3010:                    // no load group or dfg: load individual field
3011:                    if (fields == null)
3012:                        fields = new BitSet();
3013:                    fields.set(fmd.getIndex());
3014:                }
3015:
3016:                // call this method even if there are no unloaded fields; loadFields
3017:                // takes care of things like loading version info and setting PC flags
3018:                try {
3019:                    loadFields(fields, fetch, lockLevel, null);
3020:                } finally {
3021:                    if (lfgAdded)
3022:                        fetch.removeFetchGroup(lfg);
3023:                }
3024:            }
3025:
3026:            /**
3027:             * Helper method to provide the given field number to the given
3028:             * field manager.
3029:             */
3030:            void provideField(PersistenceCapable pc, FieldManager store,
3031:                    int field) {
3032:                FieldManager beforeFM = _fm;
3033:                _fm = store;
3034:                pc.pcProvideField(field);
3035:                // Retaining original FM because of the possibility of reentrant calls
3036:                _fm = beforeFM;
3037:            }
3038:
3039:            /**
3040:             * Helper method to replace the given field number to the given
3041:             * field manager.
3042:             */
3043:            void replaceField(PersistenceCapable pc, FieldManager load,
3044:                    int field) {
3045:                FieldManager beforeFM = _fm;
3046:                _fm = load;
3047:                pc.pcReplaceField(field);
3048:                // Retaining original FM because of the possibility of reentrant calls
3049:                _fm = beforeFM;
3050:            }
3051:
3052:            /**
3053:             * Mark the field as loaded or unloaded.
3054:             */
3055:            private void setLoaded(int field, boolean isLoaded) {
3056:                // don't continue if loaded state is already correct; otherwise we
3057:                // can end up clearing _fieldImpl when we shouldn't
3058:                if (_loaded.get(field) == isLoaded)
3059:                    return;
3060:
3061:                // if loading, clear intermediate data; if unloading, clear impl data
3062:                if (_fieldImpl != null) {
3063:                    int idx = _meta.getExtraFieldDataIndex(field);
3064:                    if (idx != -1)
3065:                        _fieldImpl[idx] = null;
3066:                }
3067:
3068:                if (isLoaded)
3069:                    _loaded.set(field);
3070:                else
3071:                    _loaded.clear(field);
3072:            }
3073:
3074:            /**
3075:             * Perform post-load steps, including the post load callback.
3076:             * We have to check the dfg after all field loads because it might be
3077:             * loaded in multiple steps when paging is involved; the initial load
3078:             * might exclude some fields which are then immediately loaded in a
3079:             * separate step before being returned to the user.
3080:             *
3081:             * @param field the field index that was loaded, or -1 to indicate
3082:             * that a group of possibly unknown fields was loaded
3083:             */
3084:            private void postLoad(int field, FetchConfiguration fetch) {
3085:                // no need for postLoad callback?
3086:                if ((_flags & FLAG_LOADED) != 0)
3087:                    return;
3088:
3089:                // in the middle of a group load, after which this method will be
3090:                // called again?
3091:                if (field != -1 && isLoading())
3092:                    return;
3093:
3094:                // no listeners?
3095:                LifecycleEventManager mgr = _broker.getLifecycleEventManager();
3096:                if (mgr == null
3097:                        || !mgr.hasLoadListeners(getManagedInstance(), _meta))
3098:                    return;
3099:
3100:                if (fetch == null)
3101:                    fetch = _broker.getFetchConfiguration();
3102:                // is this field a post-load field?
3103:                if (field != -1) {
3104:                    FieldMetaData fmd = _meta.getField(field);
3105:                    if (fmd.isInDefaultFetchGroup()
3106:                            && fetch.hasFetchGroup(FetchGroup.NAME_DEFAULT)
3107:                            && postLoad(FetchGroup.NAME_DEFAULT, fetch))
3108:                        return;
3109:                    String[] fgs = fmd.getCustomFetchGroups();
3110:                    for (int i = 0; i < fgs.length; i++)
3111:                        if (fetch.hasFetchGroup(fgs[i])
3112:                                && postLoad(fgs[i], fetch))
3113:                            return;
3114:                } else {
3115:                    for (Iterator itr = fetch.getFetchGroups().iterator(); itr
3116:                            .hasNext();) {
3117:                        if (postLoad((String) itr.next(), fetch))
3118:                            return;
3119:                    }
3120:                }
3121:            }
3122:
3123:            /**
3124:             * Perform post-load actions if the given fetch group is a post-load group
3125:             * and is fully loaded.
3126:             */
3127:            private boolean postLoad(String fgName, FetchConfiguration fetch) {
3128:                FetchGroup fg = _meta.getFetchGroup(fgName);
3129:                if (fg == null || !fg.isPostLoad())
3130:                    return false;
3131:
3132:                FieldMetaData[] fmds = _meta.getFields();
3133:                for (int i = 0; i < fmds.length; i++)
3134:                    if (!_loaded.get(i) && fmds[i].isInFetchGroup(fgName))
3135:                        return false;
3136:
3137:                _flags |= FLAG_LOADED;
3138:                _broker.fireLifecycleEvent(getManagedInstance(), fetch, _meta,
3139:                        LifecycleEvent.AFTER_LOAD);
3140:                return true;
3141:            }
3142:
3143:            /**
3144:             * Synchronize our version object with the datastore.
3145:             */
3146:            private boolean syncVersion(Object sdata) {
3147:                return _broker.getStoreManager().syncVersion(this , sdata);
3148:            }
3149:
3150:            /**
3151:             * Returns whether this instance needs a version check.
3152:             */
3153:            public boolean isVersionCheckRequired() {
3154:                // explicit flag for version check
3155:                if ((_flags & FLAG_VERSION_CHECK) != 0)
3156:                    return true;
3157:
3158:                if (!_broker.getOptimistic()
3159:                        && !_broker.getConfiguration()
3160:                                .getCompatibilityInstance()
3161:                                .getNonOptimisticVersionCheck())
3162:                    return false;
3163:                return _state.isVersionCheckRequired(this );
3164:            }
3165:
3166:            /**
3167:             * Set whether this instance requires a version check on the next flush.
3168:             */
3169:            void setCheckVersion(boolean versionCheck) {
3170:                if (versionCheck)
3171:                    _flags |= FLAG_VERSION_CHECK;
3172:                else
3173:                    _flags &= ~FLAG_VERSION_CHECK;
3174:            }
3175:
3176:            /**
3177:             * Returns whether this instance needs a version update.
3178:             */
3179:            public boolean isVersionUpdateRequired() {
3180:                return (_flags & FLAG_VERSION_UPDATE) > 0;
3181:            }
3182:
3183:            /**
3184:             * Set whether this instance requires a version update on the next flush.
3185:             */
3186:            void setUpdateVersion(boolean versionUpdate) {
3187:                if (versionUpdate)
3188:                    _flags |= FLAG_VERSION_UPDATE;
3189:                else
3190:                    _flags &= ~FLAG_VERSION_UPDATE;
3191:            }
3192:
3193:            /**
3194:             * Translate the given exception based on the broker's implicit behavior.
3195:             * Translation only occurs if the exception is initiated by a user action
3196:             * on an instance, and therefore will not be caught and translated by the
3197:             * broker.
3198:             */
3199:            protected RuntimeException translate(RuntimeException re) {
3200:                RuntimeExceptionTranslator trans = _broker
3201:                        .getInstanceExceptionTranslator();
3202:                return (trans == null) ? re : trans.translate(re);
3203:            }
3204:
3205:            /**
3206:             * Lock the state manager if the multithreaded option is set.
3207:             */
3208:            protected void lock() {
3209:                // use broker-level lock to avoid deadlock situations with the state
3210:                // manager lock and broker lock being obtained in different orders
3211:                _broker.lock();
3212:            }
3213:
3214:            /**
3215:             * Unlock the state manager.
3216:             */
3217:            protected void unlock() {
3218:                // use broker-level lock to avoid deadlock situations with the state 
3219:                // manager lock and broker lock being obtained in different orders
3220:                _broker.unlock();
3221:            }
3222:
3223:            private void writeObject(ObjectOutputStream oos) throws IOException {
3224:                oos.writeObject(_broker);
3225:                oos.defaultWriteObject();
3226:                oos.writeObject(_meta.getDescribedType());
3227:                writePC(oos, _pc);
3228:            }
3229:
3230:            /**
3231:             * Write <code>pc</code> to <code>oos</code>, handling internal-form
3232:             * serialization. <code>pc</code> must be of the same type that this
3233:             * state manager manages.
3234:             *
3235:             * @since 1.1.0
3236:             */
3237:            void writePC(ObjectOutputStream oos, PersistenceCapable pc)
3238:                    throws IOException {
3239:                if (!Serializable.class.isAssignableFrom(_meta
3240:                        .getDescribedType()))
3241:                    throw new NotSerializableException(_meta.getDescribedType()
3242:                            .getName());
3243:
3244:                oos.writeObject(pc);
3245:            }
3246:
3247:            private void readObject(ObjectInputStream in) throws IOException,
3248:                    ClassNotFoundException {
3249:                _broker = (BrokerImpl) in.readObject();
3250:                in.defaultReadObject();
3251:
3252:                // we need to store the class before the pc instance so that we can
3253:                // create _meta before calling readPC(), which relies on _meta being
3254:                // non-null when reconstituting ReflectingPC instances. Sadly, this
3255:                // penalizes the serialization footprint of non-ReflectingPC SMs also.
3256:                Class managedType = (Class) in.readObject();
3257:                _meta = _broker.getConfiguration()
3258:                        .getMetaDataRepositoryInstance().getMetaData(
3259:                                managedType, null, true);
3260:
3261:                _pc = readPC(in);
3262:            }
3263:
3264:            /**
3265:             * Converts the deserialized <code>o</code> to a {@link PersistenceCapable}
3266:             * instance appropriate for storing in <code>_pc</code>.
3267:             *
3268:             * @since 1.1.0
3269:             */
3270:            PersistenceCapable readPC(ObjectInputStream in)
3271:                    throws ClassNotFoundException, IOException {
3272:                Object o = in.readObject();
3273:
3274:                if (o == null)
3275:                    return null;
3276:
3277:                PersistenceCapable pc;
3278:                if (!(o instanceof  PersistenceCapable))
3279:                    pc = ImplHelper.toPersistenceCapable(o, this );
3280:                else
3281:                    pc = (PersistenceCapable) o;
3282:
3283:                pc.pcReplaceStateManager(this);
3284:                return pc;
3285:            }
3286:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.