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: }
|