0001: /*
0002: * Copyright (c) 1998 - 2005 Versant Corporation
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * Versant Corporation - initial API and implementation
0010: */
0011: package com.versant.core.jdo;
0012:
0013: import com.versant.core.common.Debug;
0014: import com.versant.core.common.Utils;
0015: import com.versant.core.metadata.*;
0016: import com.versant.core.common.NewObjectOID;
0017: import com.versant.core.common.OID;
0018: import com.versant.core.common.*;
0019: import com.versant.core.jdo.sco.VersantSimpleSCO;
0020:
0021: import javax.jdo.InstanceCallbacks;
0022: import javax.jdo.PersistenceManager;
0023: import javax.jdo.spi.JDOImplHelper;
0024: import javax.jdo.spi.PersistenceCapable;
0025: import javax.jdo.spi.StateManager;
0026: import java.util.Collection;
0027: import java.util.Iterator;
0028: import java.util.Map;
0029:
0030: import com.versant.core.common.BindingSupportImpl;
0031:
0032: /**
0033: * JDO Genie State manager.
0034: */
0035: public final class PCStateMan implements VersantStateManager {
0036:
0037: private static final int EVENT_ROLLBACK = 0;
0038: private static final int EVENT_COMMIT = 1;
0039:
0040: private static final int STATE_TRANSIENT = 0;
0041: private static final int STATE_T_CLEAN = 8;
0042: private static final int STATE_T_DIRTY = 12;
0043: private static final int STATE_HOLLOW = 16;
0044: private static final int STATE_P_NON_TX = STATE_HOLLOW;
0045: private static final int STATE_P_CLEAN = 24;
0046: private static final int STATE_P_DIRTY = 28;
0047: private static final int STATE_P_DEL = 29;
0048: private static final int STATE_P_NEW = 30;
0049: private static final int STATE_P_NEW_DEL = 31;
0050:
0051: private static final int MASK_DELETE = 1;
0052: private static final int MASK_NEW = 2;
0053: private static final int MASK_DIRTY = 4;
0054: private static final int MASK_TX = 8;
0055: private static final int MASK_PERSISTENT = 16;
0056:
0057: private static final int MASK_DELETE_TX_DIRTY = MASK_DELETE
0058: + MASK_TX + MASK_DIRTY;
0059:
0060: private boolean readInTx;
0061:
0062: private static DeletedState DELETED_STATE = new DeletedState();
0063: private static InitState INIT_STATE = new InitState();
0064:
0065: /**
0066: * The current values.
0067: */
0068: public State state;
0069: /**
0070: * This state is kept if concurrency checking is done by using changed checking.
0071: */
0072: private State origState;
0073: /**
0074: * This is used to rollback to.
0075: */
0076: private State beforeState;
0077: /**
0078: * This is used to carry the fields to store to the server. This must later
0079: * be replaced by an pool.
0080: */
0081: private State toStoreState;
0082: /**
0083: * This is used for stores that require that all fake and ref fields are
0084: * sent to the server for reads on secondary fields stored as SCOs in VDS.
0085: */
0086: private State forReadState;
0087: /**
0088: * The PersistenceCapable instance that is managed.
0089: */
0090: public PersistenceCapable pc;
0091: /**
0092: * The OID of the managed instance.
0093: */
0094: public OID oid;
0095: /**
0096: * The loadedFields of the managed instance.
0097: */
0098: private boolean[] loadedFields;
0099: /**
0100: * The classmetadata for the managed instance.
0101: */
0102: private ClassMetaData classMetaData;
0103: /**
0104: * field to replace the flags of the pc instance.
0105: */
0106: private byte jdoFlags = PersistenceCapable.LOAD_REQUIRED;
0107: /**
0108: * A mask field that specifies the current lifecycle.
0109: */
0110: private int stateM;
0111: /**
0112: * A flag that is set if this instance is to be evicted at commit.
0113: */
0114: public boolean toBeEvictedFlag;
0115: /**
0116: * If the pc instance is of type InstanceCallbacks then this will be an already casted
0117: * ref.
0118: */
0119:
0120: private InstanceCallbacks instanceCallbacks;
0121:
0122: public final QueryStateWrapper queryStateWrapper;
0123:
0124: private PMProxy pm;
0125: private ModelMetaData jmd;
0126:
0127: /**
0128: * The wrapper for this instance in the managed cache.
0129: */
0130: public PMCacheEntry cacheEntry;
0131:
0132: private LocalPMCache jdoManagedCache;
0133:
0134: private final JDOImplHelper jdoImplHelper = JDOImplHelper
0135: .getInstance();
0136: /**
0137: * If this pc instance has been marked for deletion in this tx.
0138: */
0139: private boolean addedForDelete;
0140:
0141: // These are used by JdoGeniePersistenceManagerImp to form linked lists
0142: public PCStateMan prev;
0143: public PCStateMan next;
0144: public boolean inDirtyList;
0145:
0146: public boolean doChangeChecking;
0147: private boolean rfgLoaded;
0148: /**
0149: * This is to determine if the dfg has been loaded to the pc.
0150: */
0151: private boolean dfgLoaded;
0152: private int[] scoFieldArray;
0153: /**
0154: * If this sm has been prepared in the current commit cycle. This field must
0155: * be cleared after commit/rollback
0156: */
0157: private int preparedStatus;
0158:
0159: /**
0160: * If this is not null then this is an embedded sm.
0161: */
0162: public ClassMetaData owner;
0163:
0164: private VersantPersistenceManagerImp getPm() {
0165: return pm.getRealPM();
0166: }
0167:
0168: public PMProxy getPmProxy() {
0169: return pm;
0170: }
0171:
0172: public PCStateMan(LocalPMCache jdoManagedCache, ModelMetaData jmd,
0173: PMProxy perMan) {
0174: this .jdoManagedCache = jdoManagedCache;
0175: this .jmd = jmd;
0176: this .pm = perMan;
0177: queryStateWrapper = new QueryStateWrapper(this , perMan);
0178: }
0179:
0180: private void init(PersistenceCapable pc, OID oid, ClassMetaData cmd) {
0181:
0182: if (pc instanceof InstanceCallbacks) {
0183: instanceCallbacks = (InstanceCallbacks) pc;
0184: }
0185:
0186: this .classMetaData = cmd;
0187: scoFieldArray = new int[classMetaData.scoFieldNos.length];
0188: queryStateWrapper.setCmd(cmd);
0189: this .pc = pc;
0190: this .oid = oid;
0191:
0192: origState = cmd.createState();
0193: origState.setClassMetaData(cmd);
0194:
0195: state = cmd.createState();
0196: state.setClassMetaData(cmd);
0197: loadedFields = new boolean[cmd.stateFields.length];
0198: doChangeChecking = classMetaData.changedOptimisticLocking;
0199: }
0200:
0201: private State createStateImp() {
0202: State state = classMetaData.createState();
0203: state.setClassMetaData(classMetaData);
0204: return state;
0205: }
0206:
0207: private State createToStoreState() {
0208: if (toStoreState == null) {
0209: toStoreState = classMetaData.createState();
0210: toStoreState.setClassMetaData(classMetaData);
0211: } else {
0212: toStoreState.clear();
0213: }
0214: return toStoreState;
0215: }
0216:
0217: /**
0218: * This initialises the pcStateObject when it is being pushed in from the server
0219: * as a by product of a query or navigation.
0220: */
0221: public void init(OID oid, ClassMetaData cmd, State aState,
0222: VersantPersistenceManagerImp rpm) {
0223: init(jdoImplHelper.newInstance(cmd.cls, rpm
0224: .createStateManagerProxy(this )), oid, cmd);
0225: oid.resolve(aState);
0226: state.updateNonFilled(aState);
0227: updated(rpm, false);
0228: maintainOrigState(aState, rpm);
0229: setLoadRequired();
0230: if (cmd.identityType == MDStatics.IDENTITY_TYPE_APPLICATION) {
0231: state.copyFields(oid);
0232: pc.jdoReplaceFields(classMetaData.pkFieldNos);
0233: }
0234: }
0235:
0236: public EmbeddedStateManager createEmbeddedSM(FieldMetaData fmd) {
0237: EmbeddedStateManager embeddedSm = new EmbeddedStateManager(
0238: this , jmd, jdoImplHelper, fmd);
0239: embeddedSm.setLoadRequired();
0240: return embeddedSm;
0241: }
0242:
0243: public EmbeddedStateManager createEmbeddedSM(
0244: PersistenceCapable embeddedPC, FieldMetaData fmd) {
0245: EmbeddedStateManager embeddedSm = new EmbeddedStateManager(
0246: this , embeddedPC, jmd, fmd);
0247: embeddedPC.jdoReplaceStateManager(embeddedSm);
0248: //ask for all the data from the embedded instance
0249: embeddedPC
0250: .jdoProvideFields(embeddedSm.cmd.allManagedFieldNosArray);
0251: embeddedSm.setLoadRequired();
0252: return embeddedSm;
0253: }
0254:
0255: public void init(VersantDetachable d, OID oid,
0256: VersantPersistenceManagerImp rpm) {
0257: ClassMetaData cmd = oid.getAvailableClassMetaData();
0258: init(pc, oid, cmd);
0259: d.jdoReplaceStateManager(this );
0260: d.jdoProvideFields(cmd.allManagedFieldNosArray);
0261: d.jdoReplaceStateManager(null);
0262: pc = jdoImplHelper.newInstance(cmd.cls, rpm
0263: .createStateManagerProxy(this ));
0264: stateM = STATE_P_NEW;
0265: }
0266:
0267: public ClassMetaData getClassMetaData() {
0268: return classMetaData;
0269: }
0270:
0271: private final void maintainOrigState(State toCopy,
0272: VersantPersistenceManagerImp rpm) {
0273: if (doChangeChecking) {
0274: origState.copyFieldsForOptimisticLocking(toCopy, rpm);
0275: } else {
0276: origState.copyOptimisticLockingField(toCopy);
0277: }
0278: }
0279:
0280: /**
0281: * This is to create a hollow sm for a getObjectById with validate = false.
0282: * Must the oid be resolved.
0283: *
0284: * @param oid
0285: */
0286: public void init(OID oid, VersantPersistenceManagerImp rpm) {
0287: if (!oid.isResolved()
0288: && oid.getAvailableClassMetaData().isInHeirachy()) {
0289: throw BindingSupportImpl
0290: .getInstance()
0291: .internal(
0292: "The oid '"
0293: + oid.toStringImp()
0294: + "' is not resolved to a exact instance type");
0295: }
0296: ClassMetaData cmd = oid.getAvailableClassMetaData();
0297: init(jdoImplHelper.newInstance(cmd.cls, this ), oid, cmd);
0298: oid.resolve(state);
0299: jdoManagedCache.createCacheKey(this );
0300:
0301: setLoadRequired();
0302: if (cmd.identityType == MDStatics.IDENTITY_TYPE_APPLICATION) {
0303: state.copyFields(oid);
0304: pc.jdoReplaceFields(classMetaData.pkFieldNos);
0305: updated(rpm, false);
0306: } else {
0307: stateM = STATE_HOLLOW;
0308: }
0309: }
0310:
0311: /**
0312: * This is to init the sm for a new OID. Therefore either an P-New instance
0313: * or a transient instance.
0314: * <p/>
0315: * TODO must test a transient instance that refs other instances. What must happen to them.
0316: * Must they also propagate to transient.
0317: */
0318: public void init(PersistenceCapable pc, OID oid,
0319: boolean isTransactional) {
0320: if (Debug.DEBUG) {
0321: if (!oid.isNew()) {
0322: throw BindingSupportImpl.getInstance().internal(
0323: "The oid must be of type 'new'");
0324: }
0325: }
0326: init(pc, oid, oid.getClassMetaData());
0327: try {
0328: if (isTransactional) {
0329: stateM = STATE_T_CLEAN;
0330: } else {
0331: stateM = STATE_P_NEW;
0332: }
0333:
0334: oid.resolve(state);
0335: //request all the fields from the pc instance
0336: pc.jdoProvideFields(classMetaData.allManagedFieldNosArray);
0337: state.addOneToManyInverseFieldsForL2Evict(getPm());
0338: //fill the real-oid if possible
0339: getRealOIDIfAppId();
0340: jdoManagedCache.createCacheKey(this );
0341:
0342: //convert all sco fields to be to sco instance and tell pc to reload them
0343: replaceSCOFields();
0344:
0345: jdoFlags = PersistenceCapable.READ_OK;
0346: pc.jdoReplaceFlags();
0347: dfgLoaded = true;
0348: setAllFieldsToLoaded();
0349: } catch (Exception e) {
0350: /**
0351: * Do clean up if exception occured.
0352: */
0353: try {
0354: getPm().removeTxStateObject(this );
0355: } catch (Exception e1) {
0356: //ignore
0357: }
0358:
0359: if (Debug.DEBUG) {
0360: Debug.ERR.println(e.getMessage());
0361: e.printStackTrace(Debug.ERR);
0362: }
0363: handleException(e);
0364: }
0365: }
0366:
0367: public OID getOID() {
0368: return oid;
0369: }
0370:
0371: public PersistenceCapable getPersistenceCapable() {
0372: return pc;
0373: }
0374:
0375: /**
0376: * This will return a internal oid created from the state if
0377: * - app id
0378: * - keygen == null
0379: * or state containsvalid pk fields
0380: *
0381: * @return
0382: */
0383: public OID getRealOIDIfAppId() {
0384: if (!oid.isNew())
0385: return null;
0386: if (!classMetaData.postInsertKeyGenerator
0387: && classMetaData.identityType == MDStatics.IDENTITY_TYPE_APPLICATION
0388: && state.containsValidAppIdFields()) {
0389: NewObjectOID cNOid = (NewObjectOID) oid;
0390: if (cNOid.realOID != null)
0391: return cNOid.realOID;
0392:
0393: final OID rOid = classMetaData.createOID(true);
0394: state.copyKeyFields(rOid);
0395:
0396: /**
0397: * This is to keap the real oid from being gc'd.
0398: */
0399: cNOid.realOID = rOid;
0400: return rOid;
0401: }
0402: return null;
0403: }
0404:
0405: /**
0406: * This will initialise for transient managed use.
0407: *
0408: * @param pc
0409: * @param oid
0410: */
0411: public void initTransient(PersistenceCapable pc, OID oid) {
0412: if (Debug.DEBUG) {
0413: if (!oid.isNew()) {
0414: throw BindingSupportImpl.getInstance().internal(
0415: "The oid must be of type 'new'");
0416: }
0417: }
0418: init(pc, oid, oid.getClassMetaData());
0419: stateM = STATE_T_CLEAN;
0420:
0421: }
0422:
0423: private void replaceSCOFields() {
0424: int count = state.replaceSCOFields(pc, getPm(), scoFieldArray);
0425: for (int i = count - 1; i >= 0; i--) {
0426: pc.jdoReplaceField(scoFieldArray[i]);
0427: }
0428: }
0429:
0430: public void dump() {
0431: if (Debug.DEBUG) {
0432: Debug.OUT
0433: .println("\n\n<PCStateObject oid = "
0434: + oid.toSString()
0435: + "\nstateM = "
0436: + stateM
0437: + "\nstate = "
0438: + state
0439: // + "\nbeforeState = " + beforeState
0440: + "\norigState = "
0441: + origState
0442: + "\nretainValues = "
0443: + getPm().isRetainValues()
0444: + "\nOptimistic = "
0445: + getPm().isOptimistic()
0446: + "\ntxActive = "
0447: + getPm().isActive()
0448: + "###################### end #######################\n\n");
0449: }
0450: }
0451:
0452: public boolean isLoaded(PersistenceCapable pc, FieldMetaData fmd) {
0453: if (Debug.DEBUG) {
0454: checkDfgLoaded();
0455: if (!fmd.embeddedFakeField && dfgLoaded
0456: && fmd.isJDODefaultFetchGroup()
0457: && !pm.getRealPM().isInterceptDfgFieldAccess()) {
0458:
0459: throw BindingSupportImpl
0460: .getInstance()
0461: .internal(
0462: "Default fetch group "
0463: + "fields interception is turned off, but a isLoaded "
0464: + "call was still generated for it");
0465:
0466: }
0467:
0468: if ((jdoFlags == PersistenceCapable.READ_OK) && !dfgLoaded) {
0469: throw BindingSupportImpl.getInstance().internal(
0470: "READ_OK is set but the dfg is not loaded.");
0471: }
0472: }
0473:
0474: checkTxDSReadOnPNonTx();
0475: return isLoadedImp(fmd.stateFieldNo);
0476: }
0477:
0478: public boolean isLoaded(PersistenceCapable pc, int field) {
0479: return isLoaded(pc, getFMD(field));
0480:
0481: }
0482:
0483: public void addToProcessList() {
0484: addToProcessList(getPm());
0485: }
0486:
0487: private void addToProcessList(VersantPersistenceManagerImp rpm) {
0488: //if no active tx then ignore
0489: if (!rpm.isActive())
0490: return;
0491: pm.getRealPM().getCache().addForProcessing(this );
0492: readInTx = true;
0493: }
0494:
0495: public boolean isLoadedImp(int field) {
0496: try {
0497: return loadedFields[field];
0498: } catch (Exception e) {
0499: handleException(e);
0500: }
0501: return false;
0502: }
0503:
0504: private void checkDfgLoaded() {
0505: if (dfgLoaded
0506: && !state.containFields(classMetaData.dfgStateFieldNos)) {
0507: throw BindingSupportImpl
0508: .getInstance()
0509: .internal(
0510: "The default Fetch Group fields"
0511: + " are supposed to be loaded to the pc instance, but the state"
0512: + "does not contain it");
0513: }
0514: }
0515:
0516: /**
0517: * This is the same as isLoaded but will not trigger any state
0518: * transitions.
0519: */
0520: public boolean isLoadedInternal(PersistenceCapable pc, int field) {
0521: int stateFieldNo = classMetaData.absToRel[field];
0522: int cat = classMetaData.stateFields[stateFieldNo].category;
0523: if (cat == MDStatics.CATEGORY_REF
0524: || cat == MDStatics.CATEGORY_POLYREF) {
0525: return loadedFields[field];
0526: } else {
0527: return state.containsField(stateFieldNo);
0528: }
0529: }
0530:
0531: /**
0532: * This is to check if a user is doing a read in an dataStore tx on
0533: * a p-non-tx instance. Such an instance must be cleared of its state
0534: * and re-read from the store. It's state must then propagate as normal
0535: * to P-Clean.
0536: */
0537: private final void checkTxDSReadOnPNonTx() {
0538: if (isPNonTx() && getPm().isActiveDS()) {
0539: changeToHollowState(true);
0540: }
0541: }
0542:
0543: final void setLoaded(FieldMetaData fmd) {
0544: if (Debug.DEBUG) {
0545: if (!fmd.embedded && stateM != STATE_TRANSIENT
0546: && !state.containsField(fmd.stateFieldNo)
0547: && fmd.category != MDStatics.CATEGORY_TRANSACTIONAL) {
0548: throw BindingSupportImpl.getInstance().internal(
0549: "The field " + fmd.name
0550: + " is not contained in the state");
0551: }
0552: }
0553: loadedFields[fmd.stateFieldNo] = true;
0554: }
0555:
0556: public void evict() {
0557: switch (stateM) {
0558: case STATE_P_CLEAN:
0559: changeToHollowState();
0560: cacheEntry.changeToRefType(jdoManagedCache.queue,
0561: VersantPersistenceManager.PM_CACHE_REF_TYPE_WEAK);
0562: break;
0563: case STATE_P_NON_TX:
0564: changeToHollowState();
0565: cacheEntry.changeToRefType(jdoManagedCache.queue,
0566: VersantPersistenceManager.PM_CACHE_REF_TYPE_WEAK);
0567: break;
0568: default:
0569: toBeEvictedFlag = true;
0570: }
0571: }
0572:
0573: /**
0574: * This is an recursive operation. It will retrieve everything that is
0575: * reachable.
0576: */
0577: public void retrieve(VersantPersistenceManagerImp rpm) {
0578: loadAllPersistentFieldsToPC(rpm);
0579: state.retrieve(rpm);
0580: }
0581:
0582: /**
0583: * This will load all the managed-persistent fields to the PC instance.
0584: * Transactional fields are ignored.
0585: */
0586: private void loadAllPersistentFieldsToPC(
0587: VersantPersistenceManagerImp rpm) {
0588: // A new instance does not have any lazy fields that need fetching.
0589: if (isNew())
0590: return;
0591: FetchGroup retrieveFG = classMetaData
0592: .getFetchGroup(FetchGroup.RETRIEVE_NAME);
0593: if (!state.containsFetchGroup(retrieveFG)) {
0594: rpm.getState(oid,
0595: retrieveFG.sendFieldsOnFetch ? getForReadState()
0596: : null, retrieveFG.index, -1, -1, false);
0597: }
0598:
0599: for (int i = 0; i < classMetaData.managedFields.length; i++) {
0600: FieldMetaData fmd = classMetaData.managedFields[i];
0601: if (fmd.persistenceModifier == MDStatics.PERSISTENCE_MODIFIER_PERSISTENT) {
0602: pc.jdoReplaceField(fmd.managedFieldNo);
0603: }
0604:
0605: }
0606: callJDOPostLoad();
0607: dfgLoaded = true;
0608: }
0609:
0610: /**
0611: * Return a state containing the current values of all fake fields. If
0612: * the instance is hollow then null is returned.
0613: */
0614: private State getForReadState() {
0615: if (state.isEmpty())
0616: return null;
0617: if (forReadState == null)
0618: forReadState = classMetaData.createState();
0619: if (forReadState.isEmpty())
0620: state.fillForRead(forReadState, getPm());
0621: return forReadState;
0622: }
0623:
0624: public void deletePersistent() {
0625: if (isDeleted())
0626: return;
0627: if (isTransientManaged()) {
0628: throw BindingSupportImpl.getInstance().invalidOperation(
0629: "The deletion of a transient "
0630: + "managed instance is not allowed.");
0631: }
0632:
0633: // do notification if required
0634: VersantPersistenceManagerImp pm = getPm();
0635: boolean wasDirty = isDirty();
0636: if (!wasDirty && classMetaData.notifyDataStoreOnDirtyOrDelete
0637: && pm.isActiveDS()) {
0638: pm.getStorageManager().notifyDirty(oid);
0639: }
0640:
0641: pm.fireDelete(classMetaData, pc);
0642:
0643: // invoke jdoPreDelete
0644:
0645: if (instanceCallbacks != null) {
0646: instanceCallbacks.jdoPreDelete();
0647: }
0648: /*END_JVAVONLY*/
0649:
0650: //the loaded fields is reset for a deleted instance to force it to try and reread their
0651: //fields and so catch illegal read/write ops on the instance.
0652: resetLoadedFields();
0653: setLoadRequired();
0654:
0655: rfgLoaded = false;
0656: dfgLoaded = false;
0657:
0658: clearMtMCollections();
0659:
0660: // mark us as deleted
0661: stateM |= MASK_DELETE_TX_DIRTY;
0662: pm.addTxStateObject(this );
0663:
0664: deleteDependents();
0665:
0666: // Make sure the fake fields with LOIDs for secondary fields are
0667: // sent to the server if using VDS and the instance was clean
0668: // before delete and has secondary fields. The forRead state is
0669: // included in the DeletePacket if the tx commits.
0670: if (jmd.sendStateOnDelete && classMetaData.hasSecondaryFields
0671: && !wasDirty) {
0672: forReadState = getForReadState();
0673: } else {
0674: forReadState = null;
0675: }
0676:
0677: origState.clear();
0678: state.clear();
0679: if (beforeState != null)
0680: beforeState.clear();
0681:
0682: //replace the state with DELETED_STATE. This will ensure that user
0683: //exception is thrown on field access.
0684: state = DELETED_STATE;
0685: }
0686:
0687: /**
0688: * This is invoked from deletePersistent to delete all the dependent
0689: * references of this instance.
0690: */
0691: private void deleteDependents() {
0692: // make sure that all dependent fields are in state if there are any
0693: FetchGroup dep = classMetaData.depFetchGroup;
0694: if (dep == null)
0695: return;
0696: if (!oid.isNew() && !state.containsFetchGroup(dep)) {
0697: getPm().getState(oid,
0698: dep.sendFieldsOnFetch ? getForReadState() : null,
0699: dep.index, -1, -1, false);
0700: }
0701:
0702: // delete all objects referenced by dependent fields
0703: for (; dep != null; dep = dep.super FetchGroup) {
0704: FetchGroupField[] fields = dep.fields;
0705: int len = fields.length;
0706: for (int j = 0; j < len; j++) {
0707: FetchGroupField field = fields[j];
0708: FieldMetaData fmd = field.fmd;
0709: switch (fmd.category) {
0710: case MDStatics.CATEGORY_ARRAY:
0711: followArray(fmd);
0712: break;
0713: case MDStatics.CATEGORY_COLLECTION:
0714: followCollection(fmd);
0715: break;
0716: case MDStatics.CATEGORY_MAP:
0717: followMap(fmd);
0718: break;
0719: case MDStatics.CATEGORY_POLYREF:
0720: case MDStatics.CATEGORY_REF:
0721: followRef(fmd);
0722: break;
0723: }
0724: }
0725: }
0726: }
0727:
0728: public void collectReachable(String fetchGroup, Collection result) {
0729: FetchGroup fg = classMetaData.getFetchGroup(fetchGroup);
0730:
0731: if (fg == null)
0732: return;
0733: boolean deep = fetchGroup.equals(FetchGroup.REF_NAME);
0734: boolean depend = fetchGroup.equals(FetchGroup.DEP_NAME);
0735: VersantPersistenceManagerImp _pm = getPm();
0736:
0737: // make sure everything required has been fetched
0738: if (!oid.isNew() && !state.containsFetchGroup(fg) && !deep) {
0739: // todo: for FetchGroup.REF_NAME, a NPE is thrown for
0740: // collection fields, because FetchGroup.nextFetchGroup is null
0741: _pm.getState(oid, fg.sendFieldsOnFetch ? getForReadState()
0742: : null, fg.index, -1, -1, false);
0743: }
0744:
0745: // collect all referenced objects
0746: for (; fg != null; fg = fg.super FetchGroup) {
0747: FetchGroupField[] fields = fg.fields;
0748: int len = fields.length;
0749: for (int i = 0; i < len; i++) {
0750: FetchGroupField fgField = fields[i];
0751: int fieldNo = fgField.fmd.stateFieldNo;
0752: int managedFieldNo = fgField.fmd.managedFieldNo;
0753: if (!deep && !oid.isNew())
0754: pc.jdoReplaceField(managedFieldNo);
0755:
0756: String nextFetchGroup = fgField.nextFetchGroup == null ? null
0757: : fgField.nextFetchGroup.name;
0758: String nextKeyFetchGroup = fgField.nextKeyFetchGroup == null ? null
0759: : fgField.nextKeyFetchGroup.name;
0760: if (deep) // nextFetchGroup is null
0761: nextFetchGroup = nextKeyFetchGroup = FetchGroup.REF_NAME;
0762: else if (depend) // nextFetchGroup is default
0763: nextFetchGroup = nextKeyFetchGroup = FetchGroup.DEP_NAME;
0764: switch (fgField.fmd.category) {
0765: case MDStatics.CATEGORY_ARRAY:
0766: if (deep && !oid.isNew())
0767: doRead(fields[i].fmd); // todo: remove
0768: Object[] arr = (Object[]) state.getObjectField(
0769: fieldNo, pc, _pm, oid);
0770: if (arr == null)
0771: continue;
0772: for (int j = 0; j < arr.length; j++) {
0773: Object o = arr[j];
0774: if (o != null
0775: && o instanceof PersistenceCapable)
0776: result
0777: .add(new Object[] { o,
0778: nextFetchGroup });
0779: }
0780: break;
0781: case MDStatics.CATEGORY_COLLECTION:
0782: if (deep && !oid.isNew())
0783: doRead(fields[i].fmd); // todo: remove
0784: Collection c = (Collection) state.getObjectField(
0785: fieldNo, pc, _pm, oid);
0786: if (c == null)
0787: continue;
0788: for (Iterator it = c.iterator(); it.hasNext();) {
0789: Object o = it.next();
0790: if (o != null
0791: && o instanceof PersistenceCapable)
0792: result
0793: .add(new Object[] { o,
0794: nextFetchGroup });
0795: }
0796: break;
0797: case MDStatics.CATEGORY_MAP:
0798: if (deep && !oid.isNew())
0799: doRead(fields[i].fmd); // todo:remove
0800: Map m = (Map) state.getObjectField(fieldNo, pc,
0801: _pm, oid);
0802: if (m == null)
0803: continue;
0804: for (Iterator it = m.entrySet().iterator(); it
0805: .hasNext();) {
0806: Map.Entry e = (Map.Entry) it.next();
0807: Object o = e.getKey();
0808: if (o != null
0809: && o instanceof PersistenceCapable) {
0810: result.add(new Object[] { o,
0811: nextKeyFetchGroup });
0812: }
0813: o = e.getValue();
0814: if (o != null
0815: && o instanceof PersistenceCapable) {
0816: result
0817: .add(new Object[] { o,
0818: nextFetchGroup });
0819: }
0820: }
0821: break;
0822: case MDStatics.CATEGORY_POLYREF:
0823: case MDStatics.CATEGORY_REF:
0824: if (deep && !oid.isNew())
0825: doRead(fields[i].fmd); // todo: remove
0826: Object o = state.getObjectField(fieldNo, pc, _pm,
0827: oid);
0828: if (o != null && (o instanceof PersistenceCapable))
0829: result.add(new Object[] { o, nextFetchGroup });
0830: break;
0831: }
0832: }
0833: }
0834: }
0835:
0836: /**
0837: * Clear any many-to-many managed collections. This makes sure we
0838: * are removed from the other side of any of these before we are
0839: * deleted.
0840: */
0841: private void clearMtMCollections() {
0842: FetchGroup mm = classMetaData.managedManyToManyFetchGroup;
0843: if (mm != null) {
0844:
0845: // make sure the collections have been fetched
0846: if (!oid.isNew() && !state.containsFetchGroup(mm)) {
0847: getPm()
0848: .getState(
0849: oid,
0850: mm.sendFieldsOnFetch ? getForReadState()
0851: : null, mm.index, -1, -1, false);
0852: }
0853:
0854: // now clear all of them skipping non-collections (e.g. version)
0855: for (; mm != null; mm = mm.super FetchGroup) {
0856: FetchGroupField[] fields = mm.fields;
0857: int len = fields.length;
0858: for (int j = 0; j < len; j++) {
0859: FetchGroupField field = fields[j];
0860: FieldMetaData fmd = field.fmd;
0861: if (fmd.category == MDStatics.CATEGORY_COLLECTION) {
0862: Collection c = (Collection) state
0863: .getObjectField(fmd.stateFieldNo, pc,
0864: getPm(), oid);
0865: if (c != null)
0866: c.clear();
0867: }
0868: }
0869: }
0870: }
0871: }
0872:
0873: private void followRef(FieldMetaData fmd) {
0874: Object o = state.getObjectField(fmd.stateFieldNo, pc, getPm(),
0875: oid);
0876: if (o != null)
0877: deletePersistent(o);
0878: }
0879:
0880: private void followCollection(FieldMetaData fmd) {
0881: Collection c = (Collection) state.getObjectField(
0882: fmd.stateFieldNo, pc, getPm(), oid);
0883: if (c == null)
0884: return;
0885: for (Iterator i = c.iterator(); i.hasNext();) {
0886: Object o = i.next();
0887: if (o != null)
0888: deletePersistent(o);
0889: }
0890: }
0891:
0892: private void followArray(FieldMetaData fmd) {
0893: Object[] arr = (Object[]) state.getObjectField(
0894: fmd.stateFieldNo, pc, getPm(), oid);
0895: if (arr == null)
0896: return;
0897: for (int i = 0; i < arr.length; i++) {
0898: Object o = arr[i];
0899: if (o != null)
0900: deletePersistent(o);
0901: }
0902: }
0903:
0904: private void followMap(FieldMetaData fmd) {
0905: Map m = (Map) state.getObjectField(fmd.stateFieldNo, pc,
0906: getPm(), oid);
0907: if (m == null)
0908: return;
0909: for (Iterator i = m.entrySet().iterator(); i.hasNext();) {
0910: Map.Entry e = (Map.Entry) i.next();
0911: if (fmd.dependentKeys)
0912: deletePersistent(e.getKey());
0913: if (fmd.dependentValues) {
0914: Object o = e.getValue();
0915: if (o != null)
0916: deletePersistent(o);
0917: }
0918: }
0919: }
0920:
0921: /**
0922: * This is used when following dependent fields on delete. It avoids
0923: * all the repeat checks done by perMan.deletePersistent(o).
0924: */
0925: private void deletePersistent(Object o) {
0926: getPm().getInternalSM((PersistenceCapable) o)
0927: .deletePersistent();
0928: }
0929:
0930: /**
0931: * The instance is only cleared of object references and not the primitives.
0932: * The loaded fields and the JDO_FLAGS is reset to force the pc to ask the sm for new values.
0933: * <p/>
0934: * For application identity the state will not transition to hollow as the pk
0935: * fields must remain.
0936: */
0937: private final void changeToHollowState(boolean clearBeforeState) {
0938: if (state == null)
0939: return;
0940: if (isHollow())
0941: return;
0942:
0943: if (instanceCallbacks != null) {
0944: instanceCallbacks.jdoPreClear();
0945: }
0946:
0947: stateM = STATE_HOLLOW;
0948:
0949: state.unmanageSCOFields();
0950: state.clear();
0951: State tmpState = state;
0952:
0953: state = INIT_STATE;
0954: //ask pc to replace only the instances that hold refs to other pc instances
0955: //this helps to gc instances quicker
0956: pc.jdoReplaceFields(classMetaData.absPCTypeFields);
0957: state = tmpState;
0958:
0959: origState.clear();
0960: if (clearBeforeState && beforeState != null) {
0961: beforeState.clear();
0962: }
0963:
0964: setLoadRequired();
0965: resetLoadedFields();
0966: rfgLoaded = false;
0967: dfgLoaded = false;
0968:
0969: if (classMetaData.identityType == MDStatics.IDENTITY_TYPE_APPLICATION) {
0970: replaceApplicationPKFields();
0971: }
0972:
0973: if (forReadState != null)
0974: forReadState.clearFilledFlags();
0975:
0976: if (Debug.DEBUG) {
0977: if (!isHollow()
0978: && classMetaData.identityType != MDStatics.IDENTITY_TYPE_APPLICATION) {
0979: if (Debug.DEBUG) {
0980: Debug.OUT.println("isEmpty = " + state.isEmpty());
0981: }
0982: dump();
0983: throw BindingSupportImpl.getInstance().internal(
0984: "The instance is not hollow");
0985: }
0986: }
0987: }
0988:
0989: /**
0990: * The instance is not cleared of its values. The loaded fields and the JDO_FLAGS is
0991: * reset to force the pc to ask the sm for new values.
0992: */
0993: public void changeToHollowState() {
0994: changeToHollowState(false);
0995: }
0996:
0997: public void rollback() {
0998: if (isTx()) {
0999: rollbackImp();
1000: } else if (readInTx) {
1001: changeToHollowState(true);
1002: }
1003: clearTxFlags();
1004: }
1005:
1006: public void commit(VersantPersistenceManagerImp pm) {
1007: if (isTx()) {
1008: commitImp(pm);
1009: } else if (readInTx) {
1010: changeToHollowState(true);
1011: readInTx = false;
1012: }
1013: clearTxFlags();
1014: }
1015:
1016: public final void resetLoadedFields() {
1017: final boolean[] lfs = loadedFields;
1018: for (int i = lfs.length - 1; i >= 0; i--) {
1019: lfs[i] = false;
1020: }
1021: }
1022:
1023: private void setAllFieldsToLoaded() {
1024: final boolean[] lfs = loadedFields;
1025: for (int i = lfs.length - 1; i >= 0; i--) {
1026: lfs[i] = true;
1027: }
1028: }
1029:
1030: private final void changeToTransient(int event) {
1031: stateM = STATE_TRANSIENT;
1032: if (event == EVENT_ROLLBACK) {
1033: if (getPm().isRestoreValues() && beforeState != null) {
1034: state.updateFrom(beforeState);
1035: }
1036: pc.jdoReplaceFields(classMetaData.allManagedFieldNosArray);
1037: } else if (event == EVENT_COMMIT) {
1038: State tmpState = state;
1039: state = INIT_STATE;
1040: pc.jdoReplaceFields(classMetaData.allManagedFieldNosArray);
1041: state = tmpState;
1042: }
1043: unManage();
1044: }
1045:
1046: /**
1047: * Must ensure that all resources is clean up.
1048: */
1049: private final void unManage() {
1050: jdoManagedCache.remove(this );
1051: setSMToNull();
1052: state.unmanageSCOFields();
1053: pc = null;
1054: oid = null;
1055: state = null;
1056: beforeState = null;
1057: origState = null;
1058: toStoreState = null;
1059: }
1060:
1061: private final void setSMToNull() {
1062: /**
1063: * change state to transient so that call back to replacingStateManager will return null.
1064: * and remove it from the txObjects list.
1065: */
1066: stateM = STATE_TRANSIENT;
1067: pc.jdoReplaceStateManager(null);
1068: }
1069:
1070: /**
1071: * Check if the instance is in a managed transient state.
1072: */
1073: public boolean isTransientManaged() {
1074: return (((stateM ^ STATE_T_CLEAN) == 0) || ((stateM ^ STATE_T_DIRTY) == 0));
1075: }
1076:
1077: public boolean isPersistentNew() {
1078: return ((stateM ^ STATE_P_NEW) == 0);
1079: }
1080:
1081: public void loadFetchGroup(String name) {
1082: if (oid.isNew()) {
1083: return;
1084: }
1085: FetchGroup fg = classMetaData.getFetchGroup(name);
1086: if (fg == null) {
1087: throw BindingSupportImpl.getInstance().invalidOperation(
1088: "fetch group '" + name + "' is not defined");
1089: }
1090: if (!state.containsFetchGroup(fg)) {
1091: getPm().getState(this .oid,
1092: fg.sendFieldsOnFetch ? getForReadState() : null,
1093: fg.index, -1, -1, false);
1094: }
1095: }
1096:
1097: /**
1098: * This is here to do any preparation work before the field can be read.
1099: * It will check if the fetchGroup for the field is filled in on the state. If not
1100: * then the required values must be fetched from the server.
1101: * <p/>
1102: * Any state changes must also be done.
1103: * <p/>
1104: * The returned container reference must be kept until all the required
1105: * State instances in the local cache have been referenced or they might
1106: * be GCed. This is important for collections of PC and other fields that
1107: * involve fetching State instances and loading them into the local cache.
1108: * They are only hard referenced when the SCO instance has been created.
1109: */
1110: private StatesReturned doRead(FieldMetaData fmd) {
1111: if (Debug.DEBUG) {
1112: if (isTransientManaged()) {
1113: throw BindingSupportImpl.getInstance().internal(
1114: "A transactional instance must not call this");
1115: }
1116: }
1117: addToProcessList();
1118:
1119: VersantPersistenceManagerImp rpm = getPm();
1120: rpm.checkNonTxRead();
1121: if (fmd.isEmbeddedRef()) {
1122: return null;
1123: }
1124:
1125: StatesReturned container = null;
1126: if (!state.containsField(fmd.stateFieldNo)) {
1127: if (Debug.DEBUG) {
1128: if (oid.isNew()) {
1129: throw BindingSupportImpl.getInstance().internal(
1130: "A new OID is not supposed to reach here");
1131: }
1132: Debug.OUT
1133: .println("\n\n>>>>>>>>>>>The field not contained: field = "
1134: + fmd.managedFieldNo
1135: + " fieldName = "
1136: + fmd.name
1137: + " for "
1138: + classMetaData.qname);
1139: }
1140:
1141: FetchGroup fg = fmd.fetchGroup;
1142: container = rpm.getState(this .oid,
1143: fg.sendFieldsOnFetch ? getForReadState() : null,
1144: fg.index, fmd.managedFieldNo, -1, false);
1145: if (Debug.DEBUG) {
1146: if (!state.containsFetchGroup(fmd.fetchGroup)) {
1147: System.out.println("bad state:\n" + state);
1148: throw BindingSupportImpl.getInstance().internal(
1149: "State does not contain the requested fg");
1150: }
1151: }
1152: }
1153:
1154: if (!fmd.embeddedFakeField) {
1155: if (fmd.isJDODefaultFetchGroup()) {
1156: //replace non loaded dfg fields
1157: if (state.containFields(classMetaData.dfgStateFieldNos)) {
1158: loadDFGIntoPC(rpm);
1159: }
1160: } else {
1161: pc.jdoReplaceField(fmd.managedFieldNo);
1162: setLoaded(fmd);
1163: updated(rpm, true);
1164: }
1165: }
1166:
1167: if (!oid.isNew()) {
1168: if (!(doChangeChecking || rfgLoaded)) {
1169: loadRequiredFetchGroup();
1170: }
1171: }
1172:
1173: return container;
1174: }
1175:
1176: /**
1177: * Loads the required fg into the state if not already done.
1178: */
1179: private void loadRequiredFetchGroup() {
1180: if (rfgLoaded)
1181: return;
1182: final FetchGroup reqFetchGroup = classMetaData.reqFetchGroup;
1183: if (reqFetchGroup != null
1184: && !state.containsFetchGroup(reqFetchGroup)) {
1185: getPm().getState(this .oid, null, reqFetchGroup.index, -1,
1186: -1, false);
1187: }
1188: rfgLoaded = true;
1189: }
1190:
1191: /**
1192: * This gets called from the enhanced pc instances. This is only for
1193: * Application identity key fields. It gives us a chance to
1194: * fill the field with a valid keygened value.
1195: */
1196: public void fillNewAppPKField(int fieldNo) {
1197: if (oid.isNew()) {
1198: NewObjectOID newObjectOID = (NewObjectOID) oid;
1199: if (newObjectOID.realOID == null) {
1200: if (classMetaData.postInsertKeyGenerator) {
1201: getPm().flushRetainState();
1202: } else {
1203: newObjectOID.realOID = getPm().getStorageManager()
1204: .createOID(classMetaData);
1205: newObjectOID.realOID.getClassMetaData();
1206: state.copyFields(newObjectOID.realOID);
1207: pc.jdoReplaceFields(classMetaData.pkFieldNos);
1208: }
1209: }
1210: }
1211: }
1212:
1213: private FieldMetaData getFMD(int fieldNo) {
1214: return classMetaData.managedFields[fieldNo];
1215: }
1216:
1217: /**
1218: * Get the FetchGroup to be loaded with a field.
1219: */
1220: private FetchGroup getFetchGroup(int absField) {
1221: return classMetaData.stateFields[classMetaData.absToRel[absField]].fetchGroup;
1222: }
1223:
1224: /**
1225: * This is here to do any prep. work for a write operation. It must ensure that if a field
1226: * is written to but is not currently loaded and it is using changed checking that it is first loaded
1227: * from the server.
1228: */
1229: private final void doWrite(FieldMetaData fmd, boolean mustLoad) {
1230: VersantPersistenceManagerImp pm = this .pm.getRealPM();
1231: //if this is a transactional field and we should not need to go to the db
1232: if (fmd.category == MDStatics.CATEGORY_TRANSACTIONAL) {
1233: if (pm.isActive())
1234: makeInternalDirty();
1235: return;
1236: }
1237: pm.checkNonTxWrite();
1238:
1239: if (classMetaData.identityType == MDStatics.IDENTITY_TYPE_APPLICATION
1240: && fmd.primaryKey) {
1241: throw BindingSupportImpl.getInstance().unsupported(
1242: "Change of identity is not suppoted");
1243: }
1244:
1245: // if we need to notify the server before we go dirty for the first
1246: // time do so now
1247: if (classMetaData.notifyDataStoreOnDirtyOrDelete && !isDirty()
1248: && pm.isActiveDS()) {
1249: pm.getStorageManager().notifyDirty(oid);
1250: }
1251:
1252: // Check for a write operation that will result in a change from p-non-tx to p-dirty.
1253: // If so then a snapshot of the current state must be taken and the state reloaded from
1254: // the store.
1255: // The current state must only be preserved if restoreValues is set to true.
1256: // If retainValues is set to false then the instance will always be hollow after a commit
1257: // or a rollback and therefore it overrides restoreValues.
1258: if (isPNonTx() && pm.isActive()) {
1259: if (beforeState != null) {
1260: beforeState.clear();
1261: if (pm.isRestoreValues())
1262: beforeState.updateFrom(state);
1263: }
1264: // If is is an dataStore tx then the state must be cleared and reloaded from the
1265: // store. This is done to ensure that the state is in sync with the
1266: // dataStore.
1267: if (!pm.isOptimistic())
1268: changeToHollowState(false);
1269: }
1270:
1271: // Make sure that the state contains required fields before doing the
1272: // write. For JDBC this will ensure that the optimisic locking field
1273: // (if any) is loaded. For VDS this will load all fields.
1274: if (!oid.isNew()) {
1275: if (mustLoad && !state.containsField(fmd.stateFieldNo)) {
1276: FetchGroup fg = fmd.fetchGroup;
1277: getPm()
1278: .getState(
1279: this .oid,
1280: fg.sendFieldsOnFetch ? getForReadState()
1281: : null, fg.index,
1282: fmd.managedFieldNo, -1, false);
1283: } else if (!(doChangeChecking || rfgLoaded)) {
1284: loadRequiredFetchGroup();
1285: } else if (doChangeChecking
1286: && !state.containsField(fmd.stateFieldNo)) {
1287: FetchGroup fg = fmd.fetchGroup;
1288: getPm()
1289: .getState(
1290: this .oid,
1291: fg.sendFieldsOnFetch ? getForReadState()
1292: : null, fg.index,
1293: fmd.managedFieldNo, -1, false);
1294: }
1295: }
1296:
1297: if (getPm().isActive()) {
1298: if (!isTx())
1299: updateDfgFieldMediation();
1300: stateM |= MASK_TX;
1301: stateM |= MASK_DIRTY;
1302: getPm().addTxStateObject(this );
1303: addToProcessList();
1304: }
1305: loadedFields[fmd.stateFieldNo] = false;
1306: }
1307:
1308: private void makeInternalDirty() {
1309: stateM |= MASK_TX;
1310: stateM |= MASK_DIRTY;
1311: getPm().addTxStateObject(this );
1312: addToProcessList();
1313: }
1314:
1315: /**
1316: * This will be called when ever the state has been updated as result of a
1317: * query/navigation that brought extra info back for this state.
1318: * This method will ensure that the proper state changes takes place.
1319: */
1320: final void updated(VersantPersistenceManagerImp rpm,
1321: boolean addToProccessList) {
1322: if (rpm.isActive()) {
1323: if (rpm.isOptimistic()) {
1324: /**
1325: * Must change to pers-non-tx
1326: * eg. This will change a hollow instance to p-non-tx
1327: */
1328: stateM |= MASK_PERSISTENT;
1329: } else {
1330: if (!isTx())
1331: updateDfgFieldMediation();
1332: stateM |= MASK_TX;
1333: stateM |= MASK_PERSISTENT;
1334: rpm.addTxStateObject(this );
1335: }
1336:
1337: if (addToProccessList) {
1338: addToProcessList(rpm);
1339: }
1340: } else {
1341: stateM |= MASK_PERSISTENT;
1342: }
1343: }
1344:
1345: /**
1346: * This is a new State that was received from the server via indirect means.
1347: * This state must be updated with the supplied state. Any state changes nec must
1348: * also be done.
1349: *
1350: * @param suppliedState
1351: */
1352: public PCStateMan updateWith(State suppliedState,
1353: VersantPersistenceManagerImp pm, boolean overWrite) {
1354: if (overWrite) {
1355: changeToHollowState();
1356: }
1357: updated(pm, true);
1358: if (suppliedState != state) {
1359: state.updateNonFilled(suppliedState);
1360: if (doChangeChecking || origState.isEmpty()) {
1361: maintainOrigState(suppliedState, pm);
1362: }
1363: }
1364: return this ;
1365: }
1366:
1367: public boolean isTx() {
1368: return ((stateM & MASK_TX) != 0);
1369: }
1370:
1371: public boolean readInTx(boolean strict) {
1372: if (strict)
1373: return isTx();
1374: return readInTx || isTx();
1375: }
1376:
1377: public boolean isDirty() {
1378: return ((stateM & MASK_DIRTY) != 0);
1379: }
1380:
1381: private final boolean isNew() {
1382: return ((stateM & MASK_NEW) != 0);
1383: }
1384:
1385: public boolean isHollow() {
1386: return (state.isEmpty() && ((stateM ^ STATE_HOLLOW) == 0));
1387: }
1388:
1389: private boolean isDeleted() {
1390: return (stateM & MASK_DELETE) != 0;
1391: }
1392:
1393: public boolean isPNonTx() {
1394: return (((stateM ^ STATE_P_NON_TX) == 0) && !state.isEmpty());
1395: }
1396:
1397: public boolean isPClean() {
1398: return (!state.isDirty() && ((stateM ^ STATE_P_CLEAN) == 0));
1399: }
1400:
1401: public boolean isPNew() {
1402: return ((stateM ^ STATE_P_NEW) == 0);
1403: }
1404:
1405: public boolean isPNewDeleted() {
1406: return ((stateM ^ STATE_P_NEW_DEL) == 0);
1407: }
1408:
1409: public boolean isPDeleted() {
1410: return ((stateM ^ STATE_P_DEL) == 0);
1411: }
1412:
1413: public boolean isTClean() {
1414: return ((stateM ^ STATE_T_CLEAN) == 0);
1415: }
1416:
1417: public boolean isTDirty() {
1418: return ((stateM ^ STATE_T_DIRTY) == 0);
1419: }
1420:
1421: public boolean isPDirty() {
1422: return (state.isDirty() && ((stateM ^ STATE_P_DIRTY) == 0));
1423: }
1424:
1425: /*
1426: private String stateMtoString() {
1427: switch (stateM) {
1428: case STATE_TRANSIENT:
1429: return "STATE_TRANSIENT";
1430: case STATE_T_CLEAN:
1431: return "STATE_T_CLEAN";
1432: case STATE_T_DIRTY:
1433: return "STATE_T_DIRTY";
1434: case STATE_HOLLOW:
1435: return "STATE_HOLLOW";
1436: case STATE_P_CLEAN:
1437: return "STATE_P_CLEAN";
1438: case STATE_P_DIRTY:
1439: return "STATE_P_DIRTY";
1440: case STATE_P_DEL:
1441: return "STATE_P_DEL";
1442: case STATE_P_NEW:
1443: return "STATE_P_NEW";
1444: case STATE_P_NEW_DEL:
1445: return "STATE_P_NEW_DEL";
1446: }
1447: return "UNKNOWN(" + stateM + ")";
1448: }
1449: */
1450:
1451: private void rollbackImp() {
1452: try {
1453: switch (stateM) {
1454: case STATE_TRANSIENT:
1455: break;
1456: case STATE_T_CLEAN:
1457: break;
1458: case STATE_T_DIRTY:
1459: if (beforeState != null) {
1460: State s = state;
1461: state = beforeState;
1462: beforeState = s;
1463: state.updateNonFilled(beforeState);
1464: beforeState.clear();
1465: }
1466: pc
1467: .jdoReplaceFields(classMetaData.allManagedFieldNosArray);
1468: if (forReadState != null)
1469: forReadState.clearFilledFlags();
1470: origState.clear();
1471: stateM = STATE_T_CLEAN;
1472: break;
1473: case STATE_HOLLOW:
1474: break;
1475: case STATE_P_CLEAN:
1476: if (getPm().isRestoreValues()) {
1477: stateM = STATE_P_NON_TX;
1478: } else {
1479: changeToHollowState(true);
1480: }
1481: break;
1482: case STATE_P_DEL:
1483: //the state was replaced with DELETED_STATE so create a new one
1484: state = createStateImp();
1485: changeToHollowState(true);
1486: break;
1487: case STATE_P_DIRTY:
1488: if (getPm().isRestoreValues()) {
1489: stateM = STATE_P_NON_TX;
1490: state.clearDirtyFields();
1491: if (beforeState != null) {
1492: beforeState.clearSCOFields();
1493: state.updateFrom(beforeState);
1494: beforeState.clear();
1495: }
1496: state.clearSCOFields();
1497: if (forReadState != null)
1498: forReadState.clearFilledFlags();
1499: setLoadRequired();
1500: resetLoadedFields();
1501:
1502: //there is no read interrogation for tx transient fields and therefore
1503: //they must be replaced now.
1504: pc
1505: .jdoReplaceFields(classMetaData.txfieldManagedFieldNos);
1506:
1507: rfgLoaded = false;
1508: dfgLoaded = false;
1509: } else {
1510: if (beforeState != null) {
1511: State tmpState = state;
1512: state = beforeState;
1513: pc
1514: .jdoReplaceFields(classMetaData.txfieldManagedFieldNos);
1515: state = tmpState;
1516: }
1517: changeToHollowState(true);
1518: }
1519: break;
1520: case STATE_P_NEW:
1521: changeToTransient(EVENT_ROLLBACK);
1522: break;
1523: case STATE_P_NEW_DEL:
1524: state = createStateImp();
1525: changeToTransient(EVENT_ROLLBACK);
1526: break;
1527: default:
1528: throw BindingSupportImpl.getInstance().internal(
1529: "The state is unreachable");
1530: }
1531: } finally {
1532: if (toStoreState != null)
1533: toStoreState.clear();
1534: clearTxFlags();
1535: }
1536: }
1537:
1538: /**
1539: * This will load the defaulFetchGroup fields into the state and in
1540: * the mananged instance. This is only called to change from hollow.
1541: */
1542: public void loadDfgFromHollow() {
1543: if (Debug.DEBUG) {
1544: if (!isHollow()) {
1545: throw BindingSupportImpl
1546: .getInstance()
1547: .internal(
1548: "This is only allowed to be called on hollow instances");
1549: }
1550: }
1551: getPm().getState(this .oid, null, 0, -1, -1, false);
1552: loadDFGIntoPC(getPm());
1553: }
1554:
1555: /**
1556: * This will load all the dfg fields into the PC instance.
1557: */
1558: public void loadDFGIntoPC(VersantPersistenceManagerImp rpm) {
1559: if (dfgLoaded) {
1560: if (Debug.DEBUG)
1561: checkDfgLoaded();
1562: return;
1563: }
1564: pc.jdoReplaceFields(classMetaData.dfgAbsFieldNos);
1565: updated(rpm, true);
1566: callJDOPostLoad();
1567:
1568: /**
1569: * Why only if it is transactional ??
1570: *
1571: * This is not set because in the case of a datastore tx with non-tx
1572: * read's allowed, and then setting the read ok flag will cause it not
1573: * to ask the sm for the next field access. This means if a ds tx starts
1574: * and the fields is accessed again that the sm will not reload the fields
1575: * from the db.
1576: */
1577:
1578: //todo must also check if this is a subclass of a horizontal class
1579: // where dfg fields have been changed
1580: if (classMetaData.horizontalCMD == null
1581: && (isTx() || !rpm.isInterceptDfgFieldAccess())) {
1582: jdoFlags = PersistenceCapable.READ_OK;
1583: pc.jdoReplaceFlags();
1584: }
1585: dfgLoaded = true;
1586: if (Debug.DEBUG)
1587: checkDfgLoaded();
1588: }
1589:
1590: private void callJDOPostLoad() {
1591:
1592: if (instanceCallbacks != null && !dfgLoaded) {
1593:
1594: instanceCallbacks.jdoPostLoad();
1595:
1596: }
1597: }
1598:
1599: /**
1600: * Utils method to reset the flag of the pc instance to indicate that fields
1601: * must be reloaded.
1602: */
1603: void setLoadRequired() {
1604: jdoFlags = PersistenceCapable.LOAD_REQUIRED;
1605: pc.jdoReplaceFlags();
1606: }
1607:
1608: public void setInterceptDfgFieldAccess(boolean on) {
1609: if (isPNonTx()) {
1610: if (on) {
1611: setLoadRequired();
1612: } else {
1613: updateDfgFieldMediation();
1614: }
1615: }
1616: }
1617:
1618: public void makeTransient() {
1619: if (isDirty(null)) {
1620: throw BindingSupportImpl.getInstance().invalidOperation(
1621: "The instance is dirty.");
1622: }
1623: if (isTransientManaged())
1624: return;
1625: //fill the pc instance with data in state.
1626: final int[] stateFieldNos = new int[classMetaData.stateFieldNos.length];
1627: for (int i = 0; i < state.getFieldNos(stateFieldNos); i++) {
1628: final FieldMetaData fmd = classMetaData.stateFields[stateFieldNos[i]];
1629: int cat = fmd.category;
1630: if (cat == MDStatics.CATEGORY_REF
1631: || cat == MDStatics.CATEGORY_POLYREF)
1632: continue;
1633: if (fmd.managedFieldNo < 0)
1634: continue;
1635: if (!loadedFields[fmd.managedFieldNo]) {
1636: pc.jdoReplaceField(fmd.managedFieldNo);
1637: }
1638: }
1639: unManage();
1640: getPm().removeTxStateObject(this );
1641: }
1642:
1643: public void makeTransientRecursive() {
1644: if (isDirty(null)) {
1645: throw BindingSupportImpl.getInstance().invalidOperation(
1646: "The instance is dirty.");
1647: }
1648: if (isTransientManaged())
1649: return;
1650:
1651: final int[] stateFieldNos = new int[classMetaData.stateFieldNos.length];
1652: for (int i = 0; i < state.getFieldNos(stateFieldNos); i++) {
1653: final FieldMetaData fmd = classMetaData.stateFields[stateFieldNos[i]];
1654: if (fmd.managedFieldNo < 0)
1655: continue;
1656: int cat = fmd.category;
1657: if (!loadedFields[fmd.managedFieldNo]) {
1658: if (cat == MDStatics.CATEGORY_REF
1659: || cat == MDStatics.CATEGORY_POLYREF)
1660: continue;
1661: pc.jdoReplaceField(fmd.managedFieldNo);
1662: } else {
1663: if (cat == MDStatics.CATEGORY_REF
1664: || cat == MDStatics.CATEGORY_POLYREF) {
1665: getPm().makeTransientRecursive(
1666: state.getObjectField(fmd.stateFieldNo, pc,
1667: getPm(), oid));
1668: }
1669: }
1670: }
1671:
1672: unManage();
1673: getPm().removeTxStateObject(this );
1674: }
1675:
1676: public void makeTransactional() {
1677: /**
1678: * This first case cover both ds and optimistic tx.
1679: * For ds the state is cleaned and for optimistic tx
1680: * the refresh depends on the user.
1681: */
1682: if (((stateM ^ STATE_P_NON_TX) == 0)) {
1683: if (!getPm().isOptimistic()) {
1684: changeToHollowState(true);
1685: } else {
1686: updateDfgFieldMediation();
1687: }
1688: stateM = STATE_P_CLEAN;
1689: getPm().addTxStateObject(this );
1690: return;
1691: } else if (((stateM ^ STATE_TRANSIENT) == 0)) {
1692: stateM = STATE_T_CLEAN;
1693: }
1694: }
1695:
1696: /**
1697: * Update the mediation of dfg fields. This method should be called when
1698: * transitioning from p-non-tx to a tx state.
1699: */
1700: private void updateDfgFieldMediation() {
1701: if (dfgLoaded) {
1702: //must reset the dfg field mediation.
1703: jdoFlags = PersistenceCapable.READ_OK;
1704: pc.jdoReplaceFlags();
1705: }
1706: }
1707:
1708: public void makeNonTransactional() {
1709: if (isDirty()) {
1710: throw BindingSupportImpl
1711: .getInstance()
1712: .invalidOperation(
1713: "A Dirty instance may not be made NonTransactional");
1714: }
1715: if (isTClean()) {
1716: changeToTransient(EVENT_COMMIT);
1717: } else if (isPClean()) {
1718: stateM = STATE_P_NON_TX;
1719: }
1720: }
1721:
1722: /**
1723: * The idea behind refresh is to reload the already loaded data from the server.
1724: * This is mostly needed for optismistic transactions to minimize the concurrent
1725: * updates.
1726: * <p/>
1727: * The only state change that occurs is for P-Dirty instances that change to
1728: * P-Clean.
1729: * <p/>
1730: * This call is a no-op for all new instances, because there is nothing to
1731: * relaod from the server.
1732: * Hollow instances are also an no-op because nothing has been fetched.
1733: * <p/>
1734: * For all the rest this is a relead of the currently loaded fields.
1735: */
1736: public void refresh() {
1737: /**
1738: * All new instances are no-ops because there is nothing in the store
1739: * to refresh from.
1740: */
1741: if (isNew()) {
1742: return;
1743: } else {
1744: if (getPm().isActive()) {
1745: if (((stateM ^ STATE_P_DIRTY) == 0)) {
1746: if (getPm().isOptimistic()) {
1747: stateM = STATE_P_NON_TX;
1748: } else {
1749: stateM = STATE_P_CLEAN;
1750: }
1751: getPm().addTxStateObject(this );
1752: }
1753: }
1754: changeToHollowState(true);
1755: getPm()
1756: .getStateForRefresh(
1757: this .oid,
1758: classMetaData.fetchGroups[0].sendFieldsOnFetch ? getForReadState()
1759: : null, 0);
1760: }
1761: }
1762:
1763: /**
1764: * Check the model consistency of all of the fields in our State.
1765: * This currently only makes sure that bidirectional relationships have
1766: * been properly completed but other checks may be added in future.
1767: */
1768: public void checkModelConsistency() {
1769: if (isDeleted())
1770: return;
1771: FieldMetaData[] fields = classMetaData.fields;
1772: for (int fieldNo = 0; fieldNo < fields.length; fieldNo++) {
1773: FieldMetaData fmd = fields[fieldNo];
1774: if (fmd.isMaster) { // one side of one-to-many
1775: checkOneToManyMaster(fieldNo);
1776: } else if (fmd.isDetail) { // many side of one-to-many
1777: checkOneToManyDetail(fieldNo);
1778: } else if (fmd.isManyToMany) {
1779: checkManyToMany(fieldNo);
1780: }
1781: }
1782: }
1783:
1784: /**
1785: * Check the one side of a one-to-many. Make sure that all of the details
1786: * added to the collection have the correct master set.
1787: */
1788: private void checkOneToManyMaster(int fieldNo) {
1789: FieldMetaData fmd = classMetaData.fields[fieldNo];
1790: VersantPersistenceManagerImp realPM = getPm();
1791: Collection col = (Collection) state.getObjectField(
1792: fmd.stateFieldNo, pc, getPm(), oid);
1793: if (col == null)
1794: return;
1795: // check that all of the objects in col have us as the master
1796: int index = 0;
1797: for (Iterator i = col.iterator(); i.hasNext(); index++) {
1798: Object detail = i.next();
1799: if (detail == null) {
1800: throw BindingSupportImpl.getInstance().runtime(
1801: "Inconsistent one-to-many: "
1802: + "null object at index " + index
1803: + " in collection " + fmd.getQName()
1804: + " on " + toErrString(oid, pc));
1805: }
1806: PCStateMan detailSM = realPM
1807: .getInternalSM((PersistenceCapable) detail);
1808: if (detailSM.isDeleted()) {
1809: throw BindingSupportImpl.getInstance().runtime(
1810: "Inconsistent one-to-many: "
1811: + "deleted object "
1812: + toErrString(detailSM.oid, null)
1813: + " at index " + index
1814: + " in collection " + fmd.getQName()
1815: + " on " + toErrString(oid, pc));
1816: }
1817: if (fmd.inverseFieldMetaData.fake)
1818: return;
1819: Object master = detailSM.getObjectField(null,
1820: fmd.inverseFieldNo, null);
1821: if (master != pc) {
1822: StringBuffer s = new StringBuffer();
1823: s.append("Inconsistent one-to-many: object ");
1824: s.append(toErrString(detailSM.oid, detailSM.pc));
1825: s.append(" at index ");
1826: s.append(index);
1827: s.append(" in collection ");
1828: s.append(fmd.getQName());
1829: s.append(" on ");
1830: s.append(toErrString(oid, pc));
1831: if (master == null) {
1832: s.append(" has null ");
1833: } else {
1834: s.append(" has wrong ");
1835: }
1836: s.append(fmd.inverseFieldMetaData.getQName());
1837: if (master != null) {
1838: s.append(' ');
1839: PCStateMan masterSM = realPM
1840: .getInternalSM((PersistenceCapable) master);
1841: s.append(toErrString(masterSM.oid, master));
1842: }
1843: throw BindingSupportImpl.getInstance().runtime(
1844: s.toString());
1845: }
1846: }
1847: }
1848:
1849: /**
1850: * Check the many side of a one-to-many. Make sure that the master has
1851: * been set correctly and that the master has us in its list of details.
1852: */
1853: private void checkOneToManyDetail(int fieldNo) {
1854: FieldMetaData fmd = classMetaData.fields[fieldNo];
1855: VersantPersistenceManagerImp realPM = getPm();
1856: Object master = state.getObjectField(fmd.stateFieldNo, pc,
1857: getPm(), oid);
1858: if (master == null) {
1859: if (fmd.nullValue == MDStatics.NULL_VALUE_EXCEPTION) {
1860: throw BindingSupportImpl.getInstance().runtime(
1861: "Inconsistent one-to-many: " + "'many' object "
1862: + toErrString(oid, pc) + " field "
1863: + fmd.getQName() + " is null");
1864: }
1865: // the master not set case is caught in checkOneToManyMaster
1866: // as it is ok to have a null master if the detail
1867: // is not part of any master's collection
1868: return;
1869: }
1870: if (master instanceof OID) {
1871: try {
1872: master = realPM.getObjectById(master, true);
1873: } catch (RuntimeException e) {
1874: if (BindingSupportImpl.getInstance().isOwnException(e)) {
1875: throw BindingSupportImpl
1876: .getInstance()
1877: .runtime(
1878: "Inconsistent one-to-many: "
1879: + "'many' object "
1880: + toErrString(oid, pc)
1881: + " field "
1882: + fmd.getQName()
1883: + " references invalid 'one' object: "
1884: + e.getMessage(), e);
1885: } else {
1886: throw e;
1887: }
1888: }
1889: }
1890: PCStateMan masterSM = realPM
1891: .getInternalSM((PersistenceCapable) master);
1892: // if(fmd.inverseFieldMetaData.fake)return;
1893: Object o = masterSM.getObjectField(null, fmd.inverseFieldNo,
1894: null);
1895: if (o instanceof Collection) {
1896: if (!((Collection) o).contains(pc)) {
1897: throw BindingSupportImpl
1898: .getInstance()
1899: .runtime(
1900: "Inconsistent one-to-many: "
1901: + "'many' object "
1902: + toErrString(oid, pc)
1903: + " is not in collection on 'one' instance "
1904: + toErrString(masterSM.oid,
1905: masterSM.pc)
1906: + " "
1907: + fmd.inverseFieldMetaData
1908: .getQName());
1909: }
1910: } else {
1911: PersistenceCapable[] pcs = (PersistenceCapable[]) o;
1912: boolean contains = false;
1913: for (int i = 0; i < pcs.length; i++) {
1914: PersistenceCapable persistenceCapable = pcs[i];
1915: if (persistenceCapable == pc) {
1916: contains = true;
1917: break;
1918: }
1919: }
1920: if (!contains) {
1921: throw BindingSupportImpl
1922: .getInstance()
1923: .runtime(
1924: "Inconsistent one-to-many: "
1925: + "'many' object "
1926: + toErrString(oid, pc)
1927: + " is not in collection on 'one' instance "
1928: + toErrString(masterSM.oid,
1929: masterSM.pc)
1930: + " "
1931: + fmd.inverseFieldMetaData
1932: .getQName());
1933: }
1934: }
1935: }
1936:
1937: /**
1938: * Check a many-to-many. Make sure that each collection is the inverse
1939: * of the other.
1940: */
1941: private void checkManyToMany(int fieldNo) {
1942: FieldMetaData fmd = classMetaData.fields[fieldNo];
1943: VersantPersistenceManagerImp realPM = getPm();
1944: Collection col = (Collection) state.getObjectField(
1945: fmd.stateFieldNo, pc, getPm(), oid);
1946: if (col == null)
1947: return;
1948: // check that all of the objects in col have us in their own col
1949: int index = 0;
1950: for (Iterator i = col.iterator(); i.hasNext(); index++) {
1951: Object other = i.next();
1952: if (other == null) {
1953: throw BindingSupportImpl.getInstance().runtime(
1954: "Inconsistent many-to-many: "
1955: + "null object at index " + index
1956: + " in collection " + fmd.getQName()
1957: + " on " + toErrString(oid, pc));
1958: }
1959: PCStateMan otherSM = realPM
1960: .getInternalSM((PersistenceCapable) other);
1961: if (otherSM.isDeleted()) {
1962: throw BindingSupportImpl.getInstance().runtime(
1963: "Inconsistent many-to-many: "
1964: + "deleted object "
1965: + toErrString(otherSM.oid, null)
1966: + " at index " + index
1967: + " in collection " + fmd.getQName()
1968: + " on " + toErrString(oid, pc));
1969: }
1970: Collection otherCol = (Collection) otherSM.getObjectField(
1971: null, fmd.inverseFieldNo, null);
1972: if (!otherCol.contains(pc)) {
1973: throw BindingSupportImpl.getInstance().runtime(
1974: "Inconsistent many-to-many: " + "object "
1975: + toErrString(oid, pc) + " at index "
1976: + index + "in collection "
1977: + fmd.getQName() + " contains "
1978: + toErrString(otherSM.oid, otherSM.pc)
1979: + " but "
1980: + fmd.inverseFieldMetaData.getQName()
1981: + " does not contain it");
1982: }
1983: }
1984: }
1985:
1986: /**
1987: * Format an oid and its associated pc instance (can be null) into a nice
1988: * String for error messages.
1989: */
1990: private static String toErrString(OID oid, Object pc) {
1991: StringBuffer s = new StringBuffer();
1992: s.append('[');
1993: if (oid.isNew()) {
1994: s.append("new");
1995: } else {
1996: s.append(oid.toStringImp());
1997: }
1998: if (pc != null) {
1999: s.append(' ');
2000: s.append(Utils.toString(pc));
2001: }
2002: s.append(']');
2003: return s.toString();
2004: }
2005:
2006: /**
2007: * If the PC instance implements InstanceCallbacks and has not been deleted
2008: * then call its jdoPreStore method and also invoke the store lifecycle
2009: * callback if listeners is not null. Returns true if jdoPreStore was
2010: * called or there were store listeners.
2011: */
2012: public boolean doJDOPreStore(LifecycleListenerManager listeners) {
2013: if ((stateM & MASK_DELETE) == 0) {
2014: boolean ans = listeners != null
2015: && listeners.firePreStore(pc);
2016: if (instanceCallbacks != null) {
2017:
2018: instanceCallbacks.jdoPreStore();
2019:
2020: return true;
2021: }
2022: return ans;
2023: }
2024: return false;
2025: }
2026:
2027: /**
2028: * This is called on all transactional objects so that they can prepare for
2029: * the commit or flush. If the state was deleted it will call add itself
2030: * to the list of instances to be deleted etc.
2031: */
2032: public void prepareCommitOrFlush(boolean commit) {
2033: addToProcessList();
2034: /**
2035: * Add all the instance that must be deleted to the toBeDeleted collection.
2036: * If the oid is new then it must not be added because it is not in the db and therefore
2037: * not to be removed.
2038: */
2039: if (isDeleted()) {
2040: addForDelete();
2041: //ignore
2042: } else if (isDirty()) {
2043:
2044: // If delete-orphans is true and this class contains refs used to
2045: // complete collections mapped using a foreign key in the element
2046: // class and all of these references are null and we are doing
2047: // a commit then delete this instance.
2048: if (commit
2049: && classMetaData.deleteOrphans
2050: && classMetaData.fkCollectionRefStateFieldNos != null) {
2051: int[] a = classMetaData.fkCollectionRefStateFieldNos;
2052: int i;
2053: for (i = a.length - 1; i >= 0; i--) {
2054: int sno = a[i];
2055: if (!state.containsField(sno) || !state.isNull(sno))
2056: break;
2057: }
2058: if (i < 0) {
2059: deletePersistent();
2060: addForDelete();
2061: return;
2062: }
2063: }
2064: preparedStatus = 1;
2065:
2066: // clear transactional fields if this is a commit
2067: if (commit)
2068: state.clearTransactionNonPersistentFields();
2069:
2070: VersantPersistenceManagerImp realPM = getPm();
2071: State toStoreState = createToStoreState();
2072: boolean isNew = oid.isNew();
2073:
2074: if (!oid.isResolved())
2075: oid.resolve(state);
2076: origState.clearCollectionFields();
2077:
2078: // If nothing is copied to toStoreState then only transactional
2079: // fields were dirty. If this is a commit and the instance is new
2080: // then persist it anyway.
2081: if (!state.fillToStoreState(toStoreState, realPM, this )
2082: && (!commit || !isNew)) {
2083: return;
2084: }
2085: addToStoreOidContainer(toStoreState, realPM, isNew);
2086: }
2087: }
2088:
2089: private void addToStoreOidContainer(State toStoreState,
2090: VersantPersistenceManagerImp realPM, boolean aNew) {
2091: if (doChangeChecking) {
2092: if (origState != null)
2093: origState.clearNonFilled(toStoreState);
2094: realPM.storeOidStateContainer.add(oid, toStoreState,
2095: origState, aNew
2096: && classMetaData.postInsertKeyGenerator);
2097: } else {
2098: if (aNew) {
2099: realPM.storeOidStateContainer
2100: .add(oid, toStoreState, null, aNew
2101: && classMetaData.postInsertKeyGenerator);
2102: } else {
2103: realPM.storeOidStateContainer
2104: .add(oid, toStoreState, origState, aNew
2105: && classMetaData.postInsertKeyGenerator);
2106: }
2107: }
2108: preparedStatus = 2;
2109: }
2110:
2111: private void addForDelete() {
2112: if (!oid.isNew() && !addedForDelete) {
2113: // The forReadState must have been previously filled with whatever
2114: // needs to be sent back to the server with the OID.
2115: if (oid.getAvailableClassMetaData() == null) {
2116: // create a typed OID as untyped OIDs cannot be deleted
2117: OID o = classMetaData.createOID(true);
2118: o.setLongPrimaryKey(oid.getLongPrimaryKey());
2119: getPm().addForDelete(o, forReadState);
2120: } else {
2121: getPm().addForDelete(oid, forReadState);
2122: }
2123: addedForDelete = true;
2124: }
2125: }
2126:
2127: public String toString() {
2128: return "SM@" + System.identityHashCode(this ) + " "
2129: + (oid == null ? "null" : oid.toStringImp())
2130: + " cacheKey: "
2131: + (cacheEntry == null ? "NULL" : cacheEntry.toString())
2132: + " inProcessList: "
2133: + pm.getRealPM().getCache().inProcessList(this );
2134: }
2135:
2136: /**
2137: * This is called after the server side commit is done. This will ensure
2138: * that the instance changes to the correct state.
2139: */
2140: private void commitImp(VersantPersistenceManagerImp rpm) {
2141: try {
2142: switch (stateM) {
2143: case STATE_TRANSIENT:
2144: break;
2145: case STATE_T_CLEAN:
2146: break;
2147: case STATE_T_DIRTY:
2148: stateM = STATE_T_CLEAN;
2149: if (beforeState != null)
2150: beforeState.clear();
2151: if (toStoreState != null)
2152: toStoreState.clear();
2153: break;
2154: case STATE_HOLLOW:
2155: break;
2156: case STATE_P_NEW:
2157: changeTmpOIDToRealOID();
2158: case STATE_P_CLEAN:
2159: case STATE_P_DIRTY:
2160: if (rpm.isRetainValues()) {
2161: if (!toBeEvictedFlag) {
2162: changeToPNonTxForCommit(rpm);
2163: } else {
2164: changeToHollowState();
2165: cacheEntry
2166: .changeToRefType(
2167: jdoManagedCache.queue,
2168: VersantPersistenceManager.PM_CACHE_REF_TYPE_WEAK);
2169: }
2170: } else {
2171: changeToHollowState();
2172: if (toBeEvictedFlag) {
2173: cacheEntry
2174: .changeToRefType(
2175: jdoManagedCache.queue,
2176: VersantPersistenceManager.PM_CACHE_REF_TYPE_WEAK);
2177: }
2178: }
2179: if (beforeState != null)
2180: beforeState.clear();
2181: if (toStoreState != null)
2182: toStoreState.clear();
2183: break;
2184: case STATE_P_DEL:
2185: case STATE_P_NEW_DEL:
2186: state = createStateImp();
2187: deleteImpForCommit();
2188: break;
2189: default:
2190: throw BindingSupportImpl.getInstance().internal(
2191: "The state is unreachable");
2192: }
2193: } finally {
2194: clearTxFlags();
2195: }
2196: }
2197:
2198: private void clearTxFlags() {
2199: addedForDelete = false;
2200: readInTx = false;
2201: toBeEvictedFlag = false;
2202: preparedStatus = 0;
2203: }
2204:
2205: public void flushCommit() {
2206: switch (stateM) {
2207: case STATE_TRANSIENT:
2208: break;
2209: case STATE_T_CLEAN:
2210: break;
2211: case STATE_T_DIRTY:
2212: break;
2213: case STATE_HOLLOW:
2214: break;
2215: case STATE_P_NEW:
2216: changeTmpOIDToRealOID();
2217: case STATE_P_CLEAN:
2218: case STATE_P_DIRTY:
2219: this .state.makeClean();
2220: replaceSCOFields();
2221: break;
2222: case STATE_P_DEL:
2223: case STATE_P_NEW_DEL:
2224: break;
2225: default:
2226: throw BindingSupportImpl.getInstance().internal(
2227: "The state is unreachable");
2228: }
2229: }
2230:
2231: public void updateAutoFields(State autoS) {
2232: if (classMetaData.hasAutoSetFields) {
2233: this .state.updateFrom(autoS);
2234: this .origState.updateFrom(autoS);
2235: }
2236: }
2237:
2238: /**
2239: * Helper method for commit to do work for deleting an instance. This must remove all
2240: * resources held by this instance.
2241: */
2242: public void deleteImpForCommit() {
2243: changeToTransient(EVENT_COMMIT);
2244: }
2245:
2246: /**
2247: * This changes the current 'new' oid to an actual oid retrieved from the store. This is
2248: * called as part of a commit from a PNew state.
2249: */
2250: private void changeTmpOIDToRealOID() {
2251: if (!oid.isNew())
2252: return;
2253: if (cacheEntry.mappedOID != oid.getRealOID()) {
2254: jdoManagedCache.addRealOID(this );
2255: }
2256: this .oid = this .oid.getRealOID();
2257: replaceApplicationPKFields();
2258: }
2259:
2260: /**
2261: * This is called from commit and retainValues is set.
2262: * The state must be P-Non-Tx after this.
2263: */
2264: public void changeToPNonTxForCommit(VersantPersistenceManagerImp rpm) {
2265: stateM = STATE_P_NON_TX;
2266: dfgLoaded = false;
2267: setLoadRequired();
2268: resetLoadedFields();
2269: this .state.makeClean();
2270:
2271: replaceSCOFields();
2272:
2273: if (doChangeChecking) {
2274: this .origState.clear();
2275: maintainOrigState(state, rpm);
2276: } else {
2277: this .origState.clear();
2278: }
2279: toBeEvictedFlag = false;
2280: }
2281:
2282: /**
2283: * Make all PC instances referenced by us persistent. This is called by
2284: * the PM on makePersistent and commit as part of the reachability
2285: * search.<p>
2286: */
2287: public void addRefs() {
2288: state.addRefs(getPm(), this );
2289: }
2290:
2291: /**
2292: * This is currently only called for an instance that transitioned from new to
2293: * persistent but is a good method to call if a application pk has changed.
2294: * <p/>
2295: * This is called from the commit method after the new oid is received for
2296: * the state.
2297: */
2298: private final void replaceApplicationPKFields() {
2299: if (classMetaData.identityType != MDStatics.IDENTITY_TYPE_APPLICATION)
2300: return;
2301: this .state.copyFields(oid);
2302: pc.jdoReplaceFields(classMetaData.pkFieldNos);
2303: }
2304:
2305: public byte replacingFlags(PersistenceCapable pc) {
2306: return jdoFlags;
2307: }
2308:
2309: public StateManager replacingStateManager(PersistenceCapable pc,
2310: StateManager sm) {
2311: /**
2312: * The instance is transitioning to transient.
2313: */
2314: if (stateM == STATE_TRANSIENT) {
2315: return null;
2316: }
2317: return sm;
2318: }
2319:
2320: //==============================state checks====================================
2321:
2322: public boolean isDirty(PersistenceCapable pc) {
2323: return ((stateM & MASK_DIRTY) != 0);
2324: }
2325:
2326: public boolean isTransactional(PersistenceCapable pc) {
2327: return ((stateM & MASK_TX) != 0);
2328: }
2329:
2330: public boolean isPersistent(PersistenceCapable pc) {
2331: return ((stateM & MASK_PERSISTENT) != 0);
2332: }
2333:
2334: public boolean isNew(PersistenceCapable pc) {
2335: return ((stateM & MASK_NEW) != 0);
2336: }
2337:
2338: public boolean isDeleted(PersistenceCapable pc) {
2339: return ((stateM & MASK_DELETE) != 0);
2340: }
2341:
2342: //==============================================================================
2343:
2344: public PersistenceManager getPersistenceManager(
2345: PersistenceCapable pc) {
2346: getPm().requestedPCState = this ;
2347: return pm;
2348: }
2349:
2350: public void makeDirty(PersistenceCapable pc, String fieldName) {
2351: try {
2352: final FieldMetaData fmd = oid.getClassMetaData()
2353: .getFieldMetaData(fieldName);
2354: doWrite(fmd, false);
2355: state.makeDirtyAbs(fmd.managedFieldNo);
2356: } catch (Exception e) {
2357: handleException(e);
2358: }
2359: }
2360:
2361: public void makeDirty(PersistenceCapable persistenceCapable,
2362: int fieldNo) {
2363: try {
2364: doWrite(getFMD(fieldNo), false);
2365: state.makeDirtyAbs(fieldNo);
2366: } catch (Exception e) {
2367: handleException(e);
2368: }
2369: }
2370:
2371: /**
2372: * Get the LOID of this instance. This should only be called for classes
2373: * stored in VDS. This will assign it real LOID if it does not already
2374: * have one.
2375: */
2376: public long getLOID() {
2377: return getRealOID().getLongPrimaryKey();
2378: }
2379:
2380: public Object getObjectId(PersistenceCapable pcParam) {
2381: try {
2382: if (classMetaData.identityType == MDStatics.IDENTITY_TYPE_DATASTORE) {
2383: return new VersantOid(this , jmd, oid.isResolved());
2384: } else if (classMetaData.identityType == MDStatics.IDENTITY_TYPE_APPLICATION) {
2385: if (oid.isNew() && classMetaData.postInsertKeyGenerator) {
2386: getPm().flushRetainState();
2387: }
2388: // If this is called directly after a commit with retain values to false
2389: // then the state does not contiain any field and hence
2390: if (oid.isNew()) {
2391: if (classMetaData.useKeyGen) {
2392: NewObjectOID newOID = (NewObjectOID) oid;
2393: if (newOID.realOID == null) {
2394: newOID.realOID = getPm()
2395: .getStorageManager().createOID(
2396: classMetaData);
2397: newOID.realOID.getClassMetaData();
2398: jdoManagedCache.addRealOID(this );
2399: state.copyFields(newOID.realOID);
2400: pc
2401: .jdoReplaceFields(classMetaData.pkFieldNos);
2402: }
2403: } else {
2404: NewObjectOID newOID = (NewObjectOID) oid;
2405: if (newOID.realOID == null) {
2406: newOID.realOID = classMetaData
2407: .createOID(true);
2408: newOID.realOID.getClassMetaData();
2409: state.copyKeyFields(newOID.realOID);
2410: jdoManagedCache.addRealOID(this );
2411: }
2412: }
2413: }
2414: Object pcID = pc.jdoNewObjectIdInstance();
2415: pc.jdoCopyKeyFieldsToObjectId(pcID);
2416: return pcID;
2417: } else {
2418: throw BindingSupportImpl.getInstance().internal(
2419: "Unknown identity type: '"
2420: + classMetaData.identityType + "' for "
2421: + classMetaData.qname);
2422: }
2423: } catch (Exception e) {
2424: handleException(e);
2425: return null; // keep compiler happy
2426: }
2427: }
2428:
2429: /**
2430: * This is called from VersantOid if it need the
2431: */
2432: public OID getRealOID() {
2433: try {
2434: if (classMetaData.identityType == MDStatics.IDENTITY_TYPE_DATASTORE) {
2435: if (oid.isNew()) {
2436: NewObjectOID newOID = (NewObjectOID) oid;
2437: OID realOid = newOID.realOID;
2438: if (realOid == null) {
2439: if (oid.isNew()
2440: && classMetaData.postInsertKeyGenerator) {
2441: getPm().flushRetainState();
2442: }
2443: newOID.realOID = realOid = getPm()
2444: .getStorageManager().createOID(
2445: classMetaData);
2446: realOid.resolve(state);
2447: realOid.getClassMetaData();
2448: jdoManagedCache.addRealOID(this );
2449: }
2450: return newOID.realOID;
2451: }
2452: return oid;
2453: } else {
2454: throw BindingSupportImpl.getInstance().internal(
2455: "This method should only be "
2456: + "called for DataStore identity");
2457: }
2458: } catch (Exception e) {
2459: handleException(e);
2460: return null;
2461: }
2462: }
2463:
2464: public Object getTransactionalObjectId(PersistenceCapable pc) {
2465: return getObjectId(pc);
2466: }
2467:
2468: /**
2469: * This will only load the fields for the pc instance. It does not force aload and not any reachable pc instances.
2470: *
2471: * @param pc
2472: */
2473: public void preSerialize(PersistenceCapable pc) {
2474: loadAllPersistentFieldsToPC(getPm());
2475: }
2476:
2477: //==============================getXXXFields====================================
2478:
2479: public boolean getBooleanField(PersistenceCapable pc, int field,
2480: boolean currentValue) {
2481: try {
2482: return getBooleanFieldImp(pc, getFMD(field), currentValue);
2483: } catch (Exception e) {
2484: handleException(e);
2485: }
2486: return false;
2487: }
2488:
2489: public boolean getBooleanFieldImp(PersistenceCapable pc,
2490: FieldMetaData fmd, boolean currentValue) {
2491: try {
2492: doRead(fmd);
2493: return state.getBooleanField(fmd.stateFieldNo);
2494: } catch (Exception e) {
2495: handleException(e);
2496: }
2497: return false;
2498: }
2499:
2500: public char getCharField(PersistenceCapable pc, int field,
2501: char currentValue) {
2502: try {
2503: return getCharFieldImp(pc, getFMD(field), currentValue);
2504: } catch (Exception e) {
2505: handleException(e);
2506: }
2507: return 0;
2508: }
2509:
2510: public char getCharFieldImp(PersistenceCapable pc,
2511: FieldMetaData fmd, char currentValue) {
2512: try {
2513: doRead(fmd);
2514: return state.getCharField(fmd.stateFieldNo);
2515: } catch (Exception e) {
2516: handleException(e);
2517: }
2518: return 0;
2519: }
2520:
2521: public byte getByteField(PersistenceCapable pc, int field,
2522: byte currentValue) {
2523: try {
2524: return getByteFieldImp(pc, getFMD(field), currentValue);
2525: } catch (Exception e) {
2526: handleException(e);
2527: }
2528: return 0;
2529: }
2530:
2531: public byte getByteFieldImp(PersistenceCapable pc,
2532: FieldMetaData fmd, byte currentValue) {
2533: try {
2534: doRead(fmd);
2535: return state.getByteField(fmd.stateFieldNo);
2536: } catch (Exception e) {
2537: handleException(e);
2538: }
2539: return 0;
2540: }
2541:
2542: public short getShortField(PersistenceCapable pc, int field,
2543: short currentValue) {
2544: try {
2545: return getShortFieldImp(pc, getFMD(field), currentValue);
2546: } catch (Exception e) {
2547: handleException(e);
2548: }
2549: return 0;
2550: }
2551:
2552: public short getShortFieldImp(PersistenceCapable pc,
2553: FieldMetaData fmd, short currentValue) {
2554: try {
2555: doRead(fmd);
2556: return state.getShortField(fmd.stateFieldNo);
2557: } catch (Exception e) {
2558: handleException(e);
2559: }
2560: return 0;
2561: }
2562:
2563: public int getIntField(PersistenceCapable pc, int field,
2564: int currentValue) {
2565: try {
2566: return getIntFieldImp(pc, getFMD(field), currentValue);
2567: } catch (Exception e) {
2568: handleException(e);
2569: }
2570: return 0;
2571: }
2572:
2573: public int getIntFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2574: int currentValue) {
2575: try {
2576: doRead(fmd);
2577: return state.getIntField(fmd.stateFieldNo);
2578: } catch (Exception e) {
2579: handleException(e);
2580: }
2581: return 0;
2582: }
2583:
2584: public float getFloatField(PersistenceCapable pc, int field,
2585: float currentValue) {
2586: try {
2587: return getFloatFieldImp(pc, getFMD(field), currentValue);
2588: } catch (Exception e) {
2589: handleException(e);
2590: }
2591: return 0;
2592: }
2593:
2594: public float getFloatFieldImp(PersistenceCapable pc,
2595: FieldMetaData fmd, float currentValue) {
2596: try {
2597: doRead(fmd);
2598: return state.getFloatField(fmd.stateFieldNo);
2599: } catch (Exception e) {
2600: handleException(e);
2601: }
2602: return 0;
2603: }
2604:
2605: public double getDoubleField(PersistenceCapable pc, int field,
2606: double currentValue) {
2607: try {
2608: return getDoubleFieldImp(pc, getFMD(field), currentValue);
2609: } catch (Exception e) {
2610: handleException(e);
2611: }
2612: return 0;
2613: }
2614:
2615: public double getDoubleFieldImp(PersistenceCapable pc,
2616: FieldMetaData fmd, double currentValue) {
2617: try {
2618: doRead(fmd);
2619: return state.getDoubleField(fmd.stateFieldNo);
2620: } catch (Exception e) {
2621: handleException(e);
2622: }
2623: return 0;
2624: }
2625:
2626: public long getLongField(PersistenceCapable pc, int field,
2627: long currentValue) {
2628: try {
2629: return getLongFieldImp(pc, getFMD(field), currentValue);
2630: } catch (Exception e) {
2631: handleException(e);
2632: }
2633: return 0;
2634: }
2635:
2636: public long getLongFieldImp(PersistenceCapable pc,
2637: FieldMetaData fmd, long currentValue) {
2638: try {
2639: doRead(fmd);
2640: return state.getLongField(fmd.stateFieldNo);
2641: } catch (Exception e) {
2642: handleException(e);
2643: }
2644: return 0;
2645: }
2646:
2647: public String getStringField(PersistenceCapable pc, int field,
2648: String currentValue) {
2649: return getStringFieldImp(pc, getFMD(field), currentValue);
2650: }
2651:
2652: public String getStringFieldImp(PersistenceCapable pc,
2653: FieldMetaData fmd, String currentValue) {
2654: try {
2655: doRead(fmd);
2656: return state.getStringField(fmd.stateFieldNo);
2657: } catch (Exception e) {
2658: handleException(e);
2659: }
2660: return null;
2661: }
2662:
2663: public Object getObjectField(PersistenceCapable pc, int field,
2664: Object currentValue) {
2665: return getObjectFieldImp(pc, getFMD(field), currentValue);
2666: }
2667:
2668: public Object getObjectFieldImp(PersistenceCapable pc,
2669: FieldMetaData fmd, Object currentValue) {
2670: try {
2671: StatesReturned nogc = doRead(fmd);
2672: // Keep a reference to the fetched States (if any) to make sure
2673: // they do not get GCed after being loaded into the local cache.
2674: // This is important for collections of PC and other fields that
2675: // involve fetching State instances and loading them into the local
2676: // cache. They are only hard referenced when the SCO instance has
2677: // been created by the next line.
2678: Object ans = state.getObjectField(fmd.stateFieldNo,
2679: this .pc, getPm(), oid);
2680: if (nogc == null) {
2681: // dummy code to keep IDE happy and to hopefully prevent
2682: // any overzealous optimization from removing nogc
2683: }
2684: return ans;
2685: } catch (Exception e) {
2686: handleException(e);
2687: }
2688: return null;
2689: }
2690:
2691: //================================setXXXField===================================
2692:
2693: public void setBooleanField(PersistenceCapable pc, int field,
2694: boolean currentValue, boolean newValue) {
2695: try {
2696: setBooleanFieldImp(pc, getFMD(field), currentValue,
2697: newValue);
2698: pc.jdoReplaceField(field);
2699: } catch (Exception e) {
2700: handleException(e);
2701: }
2702: }
2703:
2704: public void setBooleanFieldImp(PersistenceCapable pc,
2705: FieldMetaData fmd, boolean currentValue, boolean newValue) {
2706: try {
2707: if (isTransientManaged()) {
2708: state.setBooleanField(fmd.stateFieldNo, newValue);
2709: if (getPm().isActive()) {
2710: stateM |= MASK_DIRTY;
2711: setBeforeState(fmd, currentValue);
2712: }
2713: addToProcessList();
2714: } else {
2715: if (loadedFields[fmd.stateFieldNo]
2716: && newValue == currentValue)
2717: return;
2718: doWrite(fmd, false);
2719: state.setBooleanField(fmd.stateFieldNo, newValue);
2720: setBeforeState(fmd, currentValue);
2721: }
2722: } catch (Exception e) {
2723: handleException(e);
2724: }
2725: }
2726:
2727: public void setCharField(PersistenceCapable pc, int field,
2728: char currentValue, char newValue) {
2729: try {
2730: setCharFieldImp(pc, getFMD(field), currentValue, newValue);
2731: pc.jdoReplaceField(field);
2732: } catch (Exception e) {
2733: handleException(e);
2734: }
2735: }
2736:
2737: public void setCharFieldImp(PersistenceCapable pc,
2738: FieldMetaData fmd, char currentValue, char newValue) {
2739: try {
2740: if (isTransientManaged()) {
2741: state.setCharField(fmd.stateFieldNo, newValue);
2742: if (getPm().isActive()) {
2743: stateM |= MASK_DIRTY;
2744: setBeforeState(fmd, currentValue);
2745: }
2746: addToProcessList();
2747: } else {
2748: if (loadedFields[fmd.stateFieldNo]
2749: && newValue == currentValue)
2750: return;
2751: doWrite(fmd, false);
2752: state.setCharField(fmd.stateFieldNo, newValue);
2753: setBeforeState(fmd, currentValue);
2754: }
2755: } catch (Exception e) {
2756: handleException(e);
2757: }
2758: }
2759:
2760: public void setByteField(PersistenceCapable pc, int field,
2761: byte currentValue, byte newValue) {
2762: try {
2763: setByteFieldImp(pc, getFMD(field), currentValue, newValue);
2764: pc.jdoReplaceField(field);
2765: } catch (Exception e) {
2766: handleException(e);
2767: }
2768: }
2769:
2770: public void setByteFieldImp(PersistenceCapable pc,
2771: FieldMetaData fmd, byte currentValue, byte newValue) {
2772: try {
2773: if (isTransientManaged()) {
2774: state.setByteField(fmd.stateFieldNo, newValue);
2775: if (getPm().isActive()) {
2776: stateM |= MASK_DIRTY;
2777: setBeforeState(fmd, currentValue);
2778: }
2779: addToProcessList();
2780: } else {
2781: if (loadedFields[fmd.stateFieldNo]
2782: && newValue == currentValue)
2783: return;
2784: doWrite(fmd, false);
2785: state.setByteField(fmd.stateFieldNo, newValue);
2786: setBeforeState(fmd, currentValue);
2787: }
2788: } catch (Exception e) {
2789: handleException(e);
2790: }
2791: }
2792:
2793: public void setShortField(PersistenceCapable pc, int field,
2794: short currentValue, short newValue) {
2795: try {
2796: setShortFieldImp(pc, getFMD(field), currentValue, newValue);
2797: pc.jdoReplaceField(field);
2798: } catch (Exception e) {
2799: handleException(e);
2800: }
2801: }
2802:
2803: public void setShortFieldImp(PersistenceCapable pc,
2804: FieldMetaData fmd, short currentValue, short newValue) {
2805: try {
2806: if (isTransientManaged()) {
2807: state.setShortField(fmd.stateFieldNo, newValue);
2808: if (getPm().isActive()) {
2809: stateM |= MASK_DIRTY;
2810: setBeforeState(fmd, currentValue);
2811: }
2812: addToProcessList();
2813: } else {
2814: if (loadedFields[fmd.stateFieldNo]
2815: && newValue == currentValue)
2816: return;
2817: doWrite(fmd, false);
2818: state.setShortField(fmd.stateFieldNo, newValue);
2819: setBeforeState(fmd, currentValue);
2820: }
2821: } catch (Exception e) {
2822: handleException(e);
2823: }
2824: }
2825:
2826: public void setIntField(PersistenceCapable pc, int field,
2827: int currentValue, int newValue) {
2828: try {
2829: setIntFieldImp(pc, getFMD(field), currentValue, newValue);
2830: pc.jdoReplaceField(field);
2831: } catch (Exception e) {
2832: handleException(e);
2833: }
2834: }
2835:
2836: public void setIntFieldImp(PersistenceCapable pc,
2837: FieldMetaData fmd, int currentValue, int newValue) {
2838: try {
2839: if (isTransientManaged()) {
2840: state.setIntField(fmd.stateFieldNo, newValue);
2841: if (getPm().isActive()) {
2842: stateM |= MASK_DIRTY;
2843: setBeforeState(fmd, currentValue);
2844: }
2845: addToProcessList();
2846: } else {
2847: if (loadedFields[fmd.stateFieldNo]
2848: && newValue == currentValue)
2849: return;
2850: doWrite(fmd, false);
2851: state.setIntField(fmd.stateFieldNo, newValue);
2852: setBeforeState(fmd, currentValue);
2853: }
2854: } catch (Exception e) {
2855: handleException(e);
2856: }
2857: }
2858:
2859: public void setFloatField(PersistenceCapable pc, int field,
2860: float currentValue, float newValue) {
2861: try {
2862: setFloatFieldImp(pc, getFMD(field), currentValue, newValue);
2863: pc.jdoReplaceField(field);
2864: } catch (Exception e) {
2865: handleException(e);
2866: }
2867: }
2868:
2869: public void setFloatFieldImp(PersistenceCapable pc,
2870: FieldMetaData fmd, float currentValue, float newValue) {
2871: try {
2872: if (isTransientManaged()) {
2873: state.setFloatField(fmd.stateFieldNo, newValue);
2874: if (getPm().isActive()) {
2875: stateM |= MASK_DIRTY;
2876: setBeforeState(fmd, currentValue);
2877: }
2878: addToProcessList();
2879: } else {
2880: if (loadedFields[fmd.stateFieldNo]
2881: && newValue == currentValue)
2882: return;
2883: doWrite(fmd, false);
2884: state.setFloatField(fmd.stateFieldNo, newValue);
2885: setBeforeState(fmd, currentValue);
2886: }
2887: } catch (Exception e) {
2888: handleException(e);
2889: }
2890: }
2891:
2892: public void setDoubleField(PersistenceCapable pc, int field,
2893: double currentValue, double newValue) {
2894: try {
2895: setDoubleFieldImp(pc, getFMD(field), currentValue, newValue);
2896: pc.jdoReplaceField(field);
2897: } catch (Exception e) {
2898: handleException(e);
2899: }
2900: }
2901:
2902: public void setDoubleFieldImp(PersistenceCapable pc,
2903: FieldMetaData fmd, double currentValue, double newValue) {
2904: try {
2905: if (isTransientManaged()) {
2906: state.setDoubleField(fmd.stateFieldNo, newValue);
2907: if (getPm().isActive()) {
2908: stateM |= MASK_DIRTY;
2909: setBeforeState(fmd, currentValue);
2910: }
2911: addToProcessList();
2912: } else {
2913: if (loadedFields[fmd.stateFieldNo]
2914: && newValue == currentValue)
2915: return;
2916: doWrite(fmd, false);
2917: state.setDoubleField(fmd.stateFieldNo, newValue);
2918: setBeforeState(fmd, currentValue);
2919: }
2920: } catch (Exception e) {
2921: handleException(e);
2922: }
2923: }
2924:
2925: public void setLongField(PersistenceCapable pc, int field,
2926: long currentValue, long newValue) {
2927: try {
2928: setLongFieldImp(pc, getFMD(field), currentValue, newValue);
2929: pc.jdoReplaceField(field);
2930: } catch (Exception e) {
2931: throw BindingSupportImpl.getInstance().internal(
2932: e.getMessage(), e);
2933: }
2934: }
2935:
2936: public void setLongFieldImp(PersistenceCapable pc,
2937: FieldMetaData fmd, long currentValue, long newValue) {
2938: try {
2939: if (isTransientManaged()) {
2940: state.setLongField(fmd.stateFieldNo, newValue);
2941: if (getPm().isActive()) {
2942: stateM |= MASK_DIRTY;
2943: setBeforeState(fmd, currentValue);
2944: }
2945: addToProcessList();
2946: } else {
2947: if (loadedFields[fmd.stateFieldNo]
2948: && newValue == currentValue)
2949: return;
2950: doWrite(fmd, false);
2951: state.setLongField(fmd.stateFieldNo, newValue);
2952: setBeforeState(fmd, currentValue);
2953: }
2954: } catch (Exception e) {
2955: throw BindingSupportImpl.getInstance().internal(
2956: e.getMessage(), e);
2957: }
2958: }
2959:
2960: public void setStringField(PersistenceCapable pc, int field,
2961: String currentValue, String newValue) {
2962: setStringFieldImp(pc, getFMD(field), currentValue, newValue);
2963: pc.jdoReplaceField(field);
2964: }
2965:
2966: public void setStringFieldImp(PersistenceCapable pc,
2967: FieldMetaData fmd, String currentValue, String newValue) {
2968: try {
2969: if (isTransientManaged()) {
2970: state.setStringField(fmd.stateFieldNo, newValue);
2971: if (getPm().isActive()) {
2972: stateM |= MASK_DIRTY;
2973: setBeforeState(fmd, currentValue);
2974: }
2975: addToProcessList();
2976: } else {
2977: if (loadedFields[fmd.stateFieldNo]
2978: && newValue == currentValue)
2979: return;
2980: doWrite(fmd, false);
2981: state.setStringField(fmd.stateFieldNo, newValue);
2982: setBeforeState(fmd, currentValue);
2983: }
2984: } catch (Exception e) {
2985: handleException(e);
2986: }
2987: }
2988:
2989: public void setObjectField(PersistenceCapable pc, int field,
2990: Object currentValue, Object newValue) {
2991: setObjectFieldImp(pc, getFMD(field), currentValue, newValue);
2992: pc.jdoReplaceField(field);
2993: }
2994:
2995: public void setObjectFieldImp(PersistenceCapable pc,
2996: FieldMetaData fmd, Object currentValue, Object newValue) {
2997: try {
2998: if (isTransientManaged()) {
2999: state.setObjectField(fmd.stateFieldNo, newValue);
3000: if (getPm().isActive()) {
3001: stateM |= MASK_DIRTY;
3002: setBeforeState(fmd, currentValue);
3003: }
3004: addToProcessList();
3005: } else {
3006: if (loadedFields[fmd.stateFieldNo]
3007: && newValue == currentValue)
3008: return;
3009: doWrite(fmd, fmd.isDetail && fmd.managed);
3010: if (fmd.isDetail) {
3011: PersistenceCapable currentMaster = (PersistenceCapable) getObjectFieldImp(
3012: null, fmd, null);
3013: VersantPersistenceManagerImp pm = getPm();
3014: if (fmd.managed) {
3015: int mastColFieldNo = fmd.inverseFieldNo;
3016: if (currentMaster != null) {
3017: PCStateMan masterSM = pm
3018: .getInternalSM(currentMaster);
3019: if (masterSM.classMetaData.managedFields[mastColFieldNo].type
3020: .getComponentType() != null) {
3021: PersistenceCapable[] pcs = (PersistenceCapable[]) masterSM
3022: .getObjectField(null,
3023: mastColFieldNo, null);
3024: if (pcs != null) {
3025: for (int i = 0; i < pcs.length; i++) {
3026: PersistenceCapable pcInst = pcs[i];
3027: if (pcInst == this .pc) {
3028: pcs[i] = null;
3029: }
3030: }
3031: }
3032: } else {
3033: ((Collection) masterSM.getObjectField(
3034: null, mastColFieldNo, null))
3035: .remove(this .pc);
3036: }
3037: }
3038: if (newValue != null) {
3039: PersistenceCapable newMaster = (PersistenceCapable) newValue;
3040: if (!newMaster.jdoIsPersistent()) {
3041: this .pc.jdoGetPersistenceManager()
3042: .makePersistent(newMaster);
3043: }
3044: PCStateMan masterSM = pm
3045: .getInternalSM(newMaster);
3046: ((Collection) masterSM.getObjectField(null,
3047: mastColFieldNo, null)).add(this .pc);
3048: }
3049: } else {
3050: // Make sure current master and new value is evicted
3051: // on commit.
3052: // This prevents stale data from remaining in the L2
3053: // cache when only the back reference is updated.
3054: if (currentMaster != null) {
3055: pm
3056: .evictFromL2CacheAfterCommitImp(currentMaster);
3057: }
3058: if (newValue != null) {
3059: pm.evictFromL2CacheAfterCommitImp(newValue);
3060: }
3061: }
3062: } else if (fmd.category == MDStatics.CATEGORY_COLLECTION
3063: && fmd.inverseFieldMetaData != null
3064: && fmd.inverseFieldMetaData.fake) {
3065: if (!state.containsField(fmd.stateFieldNo)) {
3066: FetchGroup fg = getFetchGroup(fmd.managedFieldNo);
3067: getPm()
3068: .getState(
3069: this .oid,
3070: fg.sendFieldsOnFetch ? getForReadState()
3071: : null, fg.index,
3072: fmd.managedFieldNo, -1, false);
3073: }
3074: FieldMetaData inverseFieldMetaData = fmd.inverseFieldMetaData;
3075: Object o = state
3076: .getInternalObjectField(fmd.stateFieldNo);
3077: if (o != null) {
3078: if (o instanceof VersantSimpleSCO) {
3079: VersantPersistenceManagerImp rpm = getPm();
3080: Collection col = (Collection) o;
3081: for (Iterator iterator = col.iterator(); iterator
3082: .hasNext();) {
3083: PCStateMan detailSm = jdoManagedCache
3084: .getByOID(
3085: rpm
3086: .getInternalOID((PersistenceCapable) iterator
3087: .next()),
3088: true);
3089: detailSm.makeInternalDirty();
3090: detailSm.state
3091: .setObjectField(
3092: inverseFieldMetaData.stateFieldNo,
3093: null);
3094: }
3095: } else {
3096: Object[] oa = (Object[]) o;
3097: for (int i = 0; i < oa.length; i++) {
3098: if (oa[i] == null)
3099: break;
3100: PCStateMan detailSm = jdoManagedCache
3101: .getByOID((OID) oa[i], true);
3102: detailSm.makeInternalDirty();
3103: detailSm.state
3104: .setObjectField(
3105: inverseFieldMetaData.stateFieldNo,
3106: null);
3107: }
3108: }
3109: }
3110: }
3111: state.setObjectField(fmd.stateFieldNo, newValue);
3112: setBeforeState(fmd, currentValue);
3113: }
3114: } catch (Exception e) {
3115: handleException(e);
3116: }
3117: }
3118:
3119: /**
3120: * This is called from managed SCO classes to ensure that the back
3121: * reference of a newly added detail is updated property. It is
3122: * not possible to just call setObject in this case as this will result
3123: * in an endless loop as setObject adds the detail to its master.
3124: * If removeFromCurrentMaster is true then this instance is removed
3125: * from its current master (if any and if different).
3126: */
3127: public void setMaster(int field, Object newMaster,
3128: boolean removeFromCurrentMaster) {
3129: try {
3130: Object currentMaster = getObjectField(null, field, null);
3131: if (loadedFields[field] && newMaster == currentMaster)
3132: return;
3133: doWrite(getFMD(field), false);
3134: if (removeFromCurrentMaster && currentMaster != null) {
3135: int mastColFieldNo = getFMD(field).inverseFieldNo;
3136: PCStateMan masterSM = getPm().getInternalSM(
3137: (PersistenceCapable) currentMaster);
3138: ((Collection) masterSM.getObjectField(null,
3139: mastColFieldNo, null)).remove(pc);
3140: }
3141: state.setObjectFieldAbs(field, newMaster);
3142: pc.jdoReplaceField(field);
3143: setBeforeState(getFMD(field), currentMaster);
3144: } catch (Exception e) {
3145: handleException(e);
3146: }
3147: }
3148:
3149: /**
3150: * This is called from managed SCO classes to ensure that the back
3151: * reference of a newly added detail is updated property. It is
3152: * not possible to just call setObject in this case as this will result
3153: * in an endless loop as setObject adds the detail to its master.
3154: * If removeFromCurrentMaster is true then this instance is removed
3155: * from its current master (if any and if different).
3156: */
3157: public void setFakeMaster(int stateFieldNo,
3158: VersantStateManager master, boolean remove) {
3159: VersantPersistenceManagerImp rpm = getPm();
3160:
3161: try {
3162: if (isPrepared()) {
3163: if (inToStoreList()) {
3164: //already prepared so add oid to the tostorestate
3165: setOidOnState(toStoreState, stateFieldNo, master,
3166: remove);
3167: } else {
3168: //prepared was called but no dirty fields was found
3169: //so prepare must be called again
3170: if (setOidOnState(state, stateFieldNo, master,
3171: remove)) {
3172: state.fillToStoreState(toStoreState, rpm, this );
3173: }
3174: //must add to toStoreList
3175: addToStoreOidContainer(toStoreState, rpm, master
3176: .getOID().isNew());
3177: }
3178: } else {
3179: setOidOnState(state, stateFieldNo, master, remove);
3180: }
3181: makeInternalDirty();
3182: } catch (Exception e) {
3183: handleException(e);
3184: }
3185: }
3186:
3187: private boolean setOidOnState(State state, int stateFieldNo,
3188: VersantStateManager master, boolean remove) {
3189: if (state instanceof DeletedState) {
3190: return false;
3191: }
3192: if (remove) {
3193: Object o = state.getInternalObjectField(stateFieldNo);
3194: if (o != null && !o.equals(master.getOID())
3195: && o != master.getPersistenceCapable()) {
3196: return false;
3197: }
3198: }
3199: if (remove) {
3200: state.setObjectField(stateFieldNo, null);
3201: } else {
3202: state.setObjectFieldUnresolved(stateFieldNo, master
3203: .getOID());
3204: }
3205: return true;
3206: }
3207:
3208: private boolean inToStoreList() {
3209: return preparedStatus == 2;
3210: }
3211:
3212: private boolean isPrepared() {
3213: return preparedStatus > 0;
3214: }
3215:
3216: //===================================providedXXXFields============================
3217:
3218: public void providedBooleanField(PersistenceCapable pc, int field,
3219: boolean currentValue) {
3220: try {
3221: providedBooleanFieldImp(pc, getFMD(field), currentValue);
3222: } catch (Exception e) {
3223: handleException(e);
3224: }
3225: }
3226:
3227: public void providedBooleanFieldImp(PersistenceCapable pc,
3228: FieldMetaData fmd, boolean currentValue) {
3229: try {
3230: state.setBooleanField(fmd.stateFieldNo, currentValue);
3231: setBeforeState(fmd, currentValue);
3232: } catch (Exception e) {
3233: handleException(e);
3234: }
3235: }
3236:
3237: public void providedCharField(PersistenceCapable pc, int field,
3238: char currentValue) {
3239: try {
3240: providedCharFieldImp(pc, getFMD(field), currentValue);
3241: } catch (Exception e) {
3242: handleException(e);
3243: }
3244: }
3245:
3246: public void providedCharFieldImp(PersistenceCapable pc,
3247: FieldMetaData fmd, char currentValue) {
3248: try {
3249: state.setCharField(fmd.stateFieldNo, currentValue);
3250: setBeforeState(fmd, currentValue);
3251: } catch (Exception e) {
3252: handleException(e);
3253: }
3254: }
3255:
3256: public void providedByteField(PersistenceCapable pc, int field,
3257: byte currentValue) {
3258: try {
3259: providedByteFieldImp(pc, getFMD(field), currentValue);
3260: } catch (Exception e) {
3261: handleException(e);
3262: }
3263: }
3264:
3265: public void providedByteFieldImp(PersistenceCapable pc,
3266: FieldMetaData fmd, byte currentValue) {
3267: try {
3268: state.setByteField(fmd.stateFieldNo, currentValue);
3269: setBeforeState(fmd, currentValue);
3270: } catch (Exception e) {
3271: handleException(e);
3272: }
3273: }
3274:
3275: public void providedShortField(PersistenceCapable pc, int field,
3276: short currentValue) {
3277: try {
3278: providedShortFieldImp(pc, getFMD(field), currentValue);
3279: } catch (Exception e) {
3280: handleException(e);
3281: }
3282: }
3283:
3284: public void providedShortFieldImp(PersistenceCapable pc,
3285: FieldMetaData fmd, short currentValue) {
3286: try {
3287: state.setShortField(fmd.stateFieldNo, currentValue);
3288: setBeforeState(fmd, currentValue);
3289: } catch (Exception e) {
3290: handleException(e);
3291: }
3292: }
3293:
3294: public void providedIntField(PersistenceCapable pc, int field,
3295: int currentValue) {
3296: try {
3297: providedIntFieldImp(pc, getFMD(field), currentValue);
3298: } catch (Exception e) {
3299: handleException(e);
3300: }
3301: }
3302:
3303: public void providedIntFieldImp(PersistenceCapable pc,
3304: FieldMetaData fmd, int currentValue) {
3305: try {
3306: state.setIntField(fmd.stateFieldNo, currentValue);
3307: setBeforeState(fmd, currentValue);
3308: } catch (Exception e) {
3309: handleException(e);
3310: }
3311: }
3312:
3313: public void providedFloatField(PersistenceCapable pc, int field,
3314: float currentValue) {
3315: try {
3316: providedFloatFieldImp(pc, getFMD(field), currentValue);
3317: } catch (Exception e) {
3318: handleException(e);
3319: }
3320: }
3321:
3322: public void providedFloatFieldImp(PersistenceCapable pc,
3323: FieldMetaData fmd, float currentValue) {
3324: try {
3325: state.setFloatField(fmd.stateFieldNo, currentValue);
3326: setBeforeState(fmd, currentValue);
3327: } catch (Exception e) {
3328: handleException(e);
3329: }
3330: }
3331:
3332: public void providedDoubleField(PersistenceCapable pc, int field,
3333: double currentValue) {
3334: try {
3335: providedDoubleFieldImp(pc, getFMD(field), currentValue);
3336: } catch (Exception e) {
3337: handleException(e);
3338: }
3339: }
3340:
3341: public void providedDoubleFieldImp(PersistenceCapable pc,
3342: FieldMetaData fmd, double currentValue) {
3343: try {
3344: state.setDoubleField(fmd.stateFieldNo, currentValue);
3345: setBeforeState(fmd, currentValue);
3346: } catch (Exception e) {
3347: handleException(e);
3348: }
3349: }
3350:
3351: public void providedLongField(PersistenceCapable pc, int field,
3352: long currentValue) {
3353: try {
3354: providedLongFieldImp(pc, getFMD(field), currentValue);
3355: } catch (Exception e) {
3356: handleException(e);
3357: }
3358: }
3359:
3360: public void providedLongFieldImp(PersistenceCapable pc,
3361: FieldMetaData fmd, long currentValue) {
3362: try {
3363: state.setLongField(fmd.stateFieldNo, currentValue);
3364: setBeforeState(fmd, currentValue);
3365: } catch (Exception e) {
3366: handleException(e);
3367: }
3368: }
3369:
3370: public void providedStringField(PersistenceCapable pc, int field,
3371: String currentValue) {
3372: try {
3373: providedStringFieldImp(pc, getFMD(field), currentValue);
3374: } catch (Exception e) {
3375: handleException(e);
3376: }
3377: }
3378:
3379: public void providedStringFieldImp(PersistenceCapable pc,
3380: FieldMetaData fmd, String currentValue) {
3381: try {
3382: state.setStringField(fmd.stateFieldNo, currentValue);
3383: setBeforeState(fmd, currentValue);
3384: } catch (Exception e) {
3385: handleException(e);
3386: }
3387: }
3388:
3389: public void providedObjectField(PersistenceCapable pc, int field,
3390: Object currentValue) {
3391: providedObjectFieldImp(pc, getFMD(field), currentValue);
3392: }
3393:
3394: public void providedObjectFieldImp(PersistenceCapable pc,
3395: FieldMetaData fmd, Object currentValue) {
3396: try {
3397: state.setObjectField(fmd.stateFieldNo, currentValue);
3398: setBeforeState(fmd, currentValue);
3399: } catch (Exception e) {
3400: handleException(e);
3401: }
3402: }
3403:
3404: //===================================replacingXXXFields============================
3405:
3406: public boolean replacingBooleanField(final PersistenceCapable pc,
3407: final int field) {
3408: return replacingBooleanFieldImp(pc, getFMD(field));
3409: }
3410:
3411: public boolean replacingBooleanFieldImp(
3412: final PersistenceCapable pc, FieldMetaData fmd) {
3413: try {
3414: setLoaded(fmd);
3415: return state.getBooleanField(fmd.stateFieldNo);
3416: } catch (Exception e) {
3417: handleException(e);
3418: }
3419: return false;
3420: }
3421:
3422: public char replacingCharField(final PersistenceCapable pc,
3423: final int field) {
3424: return replacingCharFieldImp(pc, getFMD(field));
3425: }
3426:
3427: public char replacingCharFieldImp(final PersistenceCapable pc,
3428: final FieldMetaData fmd) {
3429: try {
3430: setLoaded(fmd);
3431: return state.getCharField(fmd.stateFieldNo);
3432: } catch (Exception e) {
3433: handleException(e);
3434: }
3435: return 0;
3436: }
3437:
3438: public byte replacingByteField(final PersistenceCapable pc,
3439: final int field) {
3440: return replacingByteFieldImp(pc, getFMD(field));
3441: }
3442:
3443: public byte replacingByteFieldImp(final PersistenceCapable pc,
3444: final FieldMetaData fmd) {
3445: try {
3446: setLoaded(fmd);
3447: return state.getByteField(fmd.stateFieldNo);
3448: } catch (Exception e) {
3449: handleException(e);
3450: }
3451: return 0;
3452: }
3453:
3454: public short replacingShortField(final PersistenceCapable pc,
3455: final int field) {
3456: return replacingShortFieldImp(pc, getFMD(field));
3457: }
3458:
3459: public short replacingShortFieldImp(final PersistenceCapable pc,
3460: final FieldMetaData fmd) {
3461: try {
3462: setLoaded(fmd);
3463: return state.getShortField(fmd.stateFieldNo);
3464: } catch (Exception e) {
3465: handleException(e);
3466: }
3467: return 0;
3468: }
3469:
3470: public int replacingIntField(final PersistenceCapable pc,
3471: final int field) {
3472: return replacingIntFieldImp(pc, getFMD(field));
3473: }
3474:
3475: public int replacingIntFieldImp(final PersistenceCapable pc,
3476: final FieldMetaData fmd) {
3477: try {
3478: setLoaded(fmd);
3479: return state.getIntField(fmd.stateFieldNo);
3480: } catch (Exception e) {
3481: handleException(e);
3482: }
3483: return 0;
3484: }
3485:
3486: public float replacingFloatField(final PersistenceCapable pc,
3487: final int field) {
3488: return replacingFloatFieldImp(pc, getFMD(field));
3489: }
3490:
3491: public float replacingFloatFieldImp(final PersistenceCapable pc,
3492: final FieldMetaData fmd) {
3493: try {
3494: setLoaded(fmd);
3495: return state.getFloatField(fmd.stateFieldNo);
3496: } catch (Exception e) {
3497: handleException(e);
3498: }
3499: return 0;
3500: }
3501:
3502: public double replacingDoubleField(final PersistenceCapable pc,
3503: final int field) {
3504: return replacingDoubleFieldImp(pc, getFMD(field));
3505: }
3506:
3507: public double replacingDoubleFieldImp(final PersistenceCapable pc,
3508: final FieldMetaData fmd) {
3509: try {
3510: setLoaded(fmd);
3511: return state.getDoubleField(fmd.stateFieldNo);
3512: } catch (Exception e) {
3513: handleException(e);
3514: }
3515: return 0;
3516: }
3517:
3518: public long replacingLongField(final PersistenceCapable pc,
3519: final int field) {
3520: return replacingLongFieldImp(pc, getFMD(field));
3521: }
3522:
3523: public long replacingLongFieldImp(final PersistenceCapable pc,
3524: final FieldMetaData fmd) {
3525: try {
3526: setLoaded(fmd);
3527: return state.getLongField(fmd.stateFieldNo);
3528: } catch (Exception e) {
3529: handleException(e);
3530: }
3531: return 0;
3532: }
3533:
3534: public String replacingStringField(final PersistenceCapable pc,
3535: final int field) {
3536: return replacingStringFieldImp(pc, getFMD(field));
3537: }
3538:
3539: public String replacingStringFieldImp(final PersistenceCapable pc,
3540: FieldMetaData fmd) {
3541: try {
3542: setLoaded(fmd);
3543: return state.getStringField(fmd.stateFieldNo);
3544: } catch (Exception e) {
3545: handleException(e);
3546: }
3547: return null;
3548: }
3549:
3550: public Object replacingObjectField(final PersistenceCapable pc,
3551: final int field) {
3552: return replacingObjectFieldImp(pc, getFMD(field));
3553: }
3554:
3555: public Object replacingObjectFieldImp(final PersistenceCapable pc,
3556: final FieldMetaData fmd) {
3557: try {
3558: if (stateM == STATE_TRANSIENT) {
3559: return state.getInternalObjectField(fmd.stateFieldNo);
3560: } else {
3561: setLoaded(fmd);
3562: return state.getObjectField(fmd.stateFieldNo, this .pc,
3563: getPm(), oid);
3564: }
3565: } catch (Exception e) {
3566: handleException(e);
3567: }
3568: return null;
3569: }
3570:
3571: private void setBeforeState(FieldMetaData fmd, long oldValue) {
3572: if (!doBeforeState(fmd))
3573: return;
3574: if (!beforeState.containsField(fmd.stateFieldNo)) {
3575: beforeState.setLongField(fmd.stateFieldNo, oldValue);
3576: }
3577: }
3578:
3579: private boolean doBeforeState(FieldMetaData fmd) {
3580: if (!getPm().doBeforeState(isTransientManaged(),
3581: fmd.category == MDStatics.CATEGORY_TRANSACTIONAL)) {
3582: return false;
3583: }
3584: if (beforeState == null) {
3585: beforeState = createStateImp();
3586: }
3587: return true;
3588: }
3589:
3590: private void setBeforeState(FieldMetaData fmd, int oldValue) {
3591: if (!doBeforeState(fmd))
3592: return;
3593: if (!beforeState.containsField(fmd.stateFieldNo)) {
3594: beforeState.setIntField(fmd.stateFieldNo, oldValue);
3595: }
3596: }
3597:
3598: private void setBeforeState(FieldMetaData fmd, double currentValue) {
3599: if (!doBeforeState(fmd))
3600: return;
3601: if (!beforeState.containsField(fmd.stateFieldNo)) {
3602: beforeState.setDoubleField(fmd.stateFieldNo, currentValue);
3603: }
3604: }
3605:
3606: private void setBeforeState(FieldMetaData fmd, String newValue) {
3607: if (!doBeforeState(fmd))
3608: return;
3609: if (!beforeState.containsField(fmd.stateFieldNo)) {
3610: beforeState.setStringField(fmd.stateFieldNo, newValue);
3611: }
3612: }
3613:
3614: private void setBeforeState(FieldMetaData fmd, Object newValue) {
3615: /**
3616: * Only mutable fields of PNew instance values kept for rollback
3617: * Other states fields are refetched from db.
3618: */
3619: if (!isNew()
3620: && fmd.category != MDStatics.CATEGORY_TRANSACTIONAL)
3621: return;
3622: if (!doBeforeState(fmd))
3623: return;
3624: if (!beforeState.containsField(fmd.stateFieldNo)) {
3625: beforeState.setObjectField(fmd.stateFieldNo, newValue);
3626: }
3627: }
3628:
3629: private void setBeforeState(FieldMetaData fmd, char currentValue) {
3630: if (!doBeforeState(fmd))
3631: return;
3632: if (!beforeState.containsField(fmd.stateFieldNo)) {
3633: beforeState.setCharField(fmd.stateFieldNo, currentValue);
3634: }
3635: }
3636:
3637: private void setBeforeState(FieldMetaData fmd, byte currentValue) {
3638: if (!doBeforeState(fmd))
3639: return;
3640: if (!beforeState.containsField(fmd.stateFieldNo)) {
3641: beforeState.setByteField(fmd.stateFieldNo, currentValue);
3642: }
3643: }
3644:
3645: public void setBeforeState(FieldMetaData fmd, boolean currentValue) {
3646: if (!doBeforeState(fmd))
3647: return;
3648: if (!beforeState.containsField(fmd.stateFieldNo)) {
3649: beforeState.setBooleanField(fmd.stateFieldNo, currentValue);
3650: }
3651: }
3652:
3653: private void setBeforeState(FieldMetaData fmd, short currentValue) {
3654: if (!doBeforeState(fmd))
3655: return;
3656: if (!beforeState.containsField(fmd.stateFieldNo)) {
3657: beforeState.setShortField(fmd.stateFieldNo, currentValue);
3658: }
3659: }
3660:
3661: private void setBeforeState(FieldMetaData fmd, float currentValue) {
3662: if (!doBeforeState(fmd))
3663: return;
3664: if (!beforeState.containsField(fmd.stateFieldNo)) {
3665: beforeState.setFloatField(fmd.stateFieldNo, currentValue);
3666: }
3667: }
3668:
3669: public final void handleException(Exception x) {
3670: if (BindingSupportImpl.getInstance().isOwnException(x)) {
3671: throw (RuntimeException) x;
3672: } else {
3673: throw BindingSupportImpl.getInstance().internal(
3674: x.getMessage(), x);
3675: }
3676: }
3677:
3678: public boolean isInDirtyList(PCStateMan head) {
3679: return head == this || next != null || prev != null;
3680: }
3681:
3682: public Object getOptimisticLockingValue() {
3683: if (oid.isNew())
3684: return null;
3685: getPm().checkNonTxRead();
3686: loadRequiredFetchGroup();
3687: return state.getOptimisticLockingValue();
3688: }
3689:
3690: public void firePostStore(LifecycleListenerManager listeners) {
3691: // pc may be null if the instance has been deleted
3692: if (pc != null) {
3693: listeners.firePostStore(pc);
3694: }
3695: }
3696: }
|