KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > versant > core > jdo > PCStateMan


1
2 /*
3  * Copyright (c) 1998 - 2005 Versant Corporation
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  * Versant Corporation - initial API and implementation
11  */

12 package com.versant.core.jdo;
13
14 import com.versant.core.common.Debug;
15 import com.versant.core.common.Utils;
16 import com.versant.core.metadata.*;
17 import com.versant.core.common.NewObjectOID;
18 import com.versant.core.common.OID;
19 import com.versant.core.common.*;
20 import com.versant.core.jdo.sco.VersantSimpleSCO;
21
22 import javax.jdo.InstanceCallbacks;
23 import javax.jdo.PersistenceManager;
24 import javax.jdo.spi.JDOImplHelper;
25 import javax.jdo.spi.PersistenceCapable;
26 import javax.jdo.spi.StateManager;
27 import java.util.Collection JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.Map JavaDoc;
30
31 import com.versant.core.common.BindingSupportImpl;
32
33
34
35 /**
36  * JDO Genie State manager.
37  */

38 public final class PCStateMan implements VersantStateManager
39  {
40
41     private static final int EVENT_ROLLBACK = 0;
42     private static final int EVENT_COMMIT = 1;
43
44     private static final int STATE_TRANSIENT = 0;
45     private static final int STATE_T_CLEAN = 8;
46     private static final int STATE_T_DIRTY = 12;
47     private static final int STATE_HOLLOW = 16;
48     private static final int STATE_P_NON_TX = STATE_HOLLOW;
49     private static final int STATE_P_CLEAN = 24;
50     private static final int STATE_P_DIRTY = 28;
51     private static final int STATE_P_DEL = 29;
52     private static final int STATE_P_NEW = 30;
53     private static final int STATE_P_NEW_DEL = 31;
54
55     private static final int MASK_DELETE = 1;
56     private static final int MASK_NEW = 2;
57     private static final int MASK_DIRTY = 4;
58     private static final int MASK_TX = 8;
59     private static final int MASK_PERSISTENT = 16;
60
61     private static final int MASK_DELETE_TX_DIRTY = MASK_DELETE + MASK_TX + MASK_DIRTY;
62
63     private boolean readInTx;
64
65     private static DeletedState DELETED_STATE = new DeletedState();
66     private static InitState INIT_STATE = new InitState();
67
68     /**
69      * The current values.
70      */

71     public State state;
72     /**
73      * This state is kept if concurrency checking is done by using changed checking.
74      */

75     private State origState;
76     /**
77      * This is used to rollback to.
78      */

79     private State beforeState;
80     /**
81      * This is used to carry the fields to store to the server. This must later
82      * be replaced by an pool.
83      */

84     private State toStoreState;
85     /**
86      * This is used for stores that require that all fake and ref fields are
87      * sent to the server for reads on secondary fields stored as SCOs in VDS.
88      */

89     private State forReadState;
90     /**
91      * The PersistenceCapable instance that is managed.
92      */

93     public PersistenceCapable pc;
94     /**
95      * The OID of the managed instance.
96      */

97     public OID oid;
98     /**
99      * The loadedFields of the managed instance.
100      */

101     private boolean[] loadedFields;
102     /**
103      * The classmetadata for the managed instance.
104      */

105     private ClassMetaData classMetaData;
106     /**
107      * field to replace the flags of the pc instance.
108      */

109     private byte jdoFlags = PersistenceCapable.LOAD_REQUIRED;
110     /**
111      * A mask field that specifies the current lifecycle.
112      */

113     private int stateM;
114     /**
115      * A flag that is set if this instance is to be evicted at commit.
116      */

117     public boolean toBeEvictedFlag;
118     /**
119      * If the pc instance is of type InstanceCallbacks then this will be an already casted
120      * ref.
121      */

122
123     private InstanceCallbacks instanceCallbacks;
124
125
126
127
128     public final QueryStateWrapper queryStateWrapper;
129
130     private PMProxy pm;
131     private ModelMetaData jmd;
132
133     /**
134      * The wrapper for this instance in the managed cache.
135      */

136     public PMCacheEntry cacheEntry;
137
138     private LocalPMCache jdoManagedCache;
139
140     private final JDOImplHelper jdoImplHelper = JDOImplHelper.getInstance();
141     /**
142      * If this pc instance has been marked for deletion in this tx.
143      */

144     private boolean addedForDelete;
145
146     // These are used by JdoGeniePersistenceManagerImp to form linked lists
147
public PCStateMan prev;
148     public PCStateMan next;
149     public boolean inDirtyList;
150
151     public boolean doChangeChecking;
152     private boolean rfgLoaded;
153     /**
154      * This is to determine if the dfg has been loaded to the pc.
155      */

156     private boolean dfgLoaded;
157     private int[] scoFieldArray;
158     /**
159      * If this sm has been prepared in the current commit cycle. This field must
160      * be cleared after commit/rollback
161      */

162     private int preparedStatus;
163
164     /**
165      * If this is not null then this is an embedded sm.
166      */

167     public ClassMetaData owner;
168
169     private VersantPersistenceManagerImp getPm() {
170         return pm.getRealPM();
171     }
172
173     public PMProxy getPmProxy() {
174         return pm;
175     }
176
177     public PCStateMan(LocalPMCache jdoManagedCache, ModelMetaData jmd,
178             PMProxy perMan) {
179         this.jdoManagedCache = jdoManagedCache;
180         this.jmd = jmd;
181         this.pm = perMan;
182         queryStateWrapper = new QueryStateWrapper(this, perMan);
183     }
184
185     private void init(PersistenceCapable pc, OID oid, ClassMetaData cmd) {
186         
187         if (pc instanceof InstanceCallbacks) {
188             instanceCallbacks = (InstanceCallbacks)pc;
189         }
190
191            
192         this.classMetaData = cmd;
193         scoFieldArray = new int[classMetaData.scoFieldNos.length];
194         queryStateWrapper.setCmd(cmd);
195         this.pc = pc;
196         this.oid = oid;
197
198         origState = cmd.createState();
199         origState.setClassMetaData(cmd);
200
201         state = cmd.createState();
202         state.setClassMetaData(cmd);
203         loadedFields = new boolean[cmd.stateFields.length];
204         doChangeChecking = classMetaData.changedOptimisticLocking;
205     }
206
207     private State createStateImp() {
208         State state = classMetaData.createState();
209         state.setClassMetaData(classMetaData);
210         return state;
211     }
212
213     private State createToStoreState() {
214         if (toStoreState == null) {
215             toStoreState = classMetaData.createState();
216             toStoreState.setClassMetaData(classMetaData);
217         } else {
218             toStoreState.clear();
219         }
220         return toStoreState;
221     }
222
223     /**
224      * This initialises the pcStateObject when it is being pushed in from the server
225      * as a by product of a query or navigation.
226      */

227     public void init(OID oid, ClassMetaData cmd, State aState,
228             VersantPersistenceManagerImp rpm) {
229         init(jdoImplHelper.newInstance(cmd.cls, rpm.createStateManagerProxy(this)),
230                 oid, cmd);
231         oid.resolve(aState);
232         state.updateNonFilled(aState);
233         updated(rpm, false);
234         maintainOrigState(aState, rpm);
235         setLoadRequired();
236         if (cmd.identityType == MDStatics.IDENTITY_TYPE_APPLICATION) {
237             state.copyFields(oid);
238             pc.jdoReplaceFields(classMetaData.pkFieldNos);
239         }
240     }
241
242     public EmbeddedStateManager createEmbeddedSM(FieldMetaData fmd) {
243         EmbeddedStateManager embeddedSm = new EmbeddedStateManager(this, jmd,
244                 jdoImplHelper, fmd);
245         embeddedSm.setLoadRequired();
246         return embeddedSm;
247     }
248
249     public EmbeddedStateManager createEmbeddedSM(PersistenceCapable embeddedPC,
250             FieldMetaData fmd) {
251         EmbeddedStateManager embeddedSm = new EmbeddedStateManager(this,
252                 embeddedPC, jmd, fmd);
253         embeddedPC.jdoReplaceStateManager(embeddedSm);
254         //ask for all the data from the embedded instance
255
embeddedPC.jdoProvideFields(embeddedSm.cmd.allManagedFieldNosArray);
256         embeddedSm.setLoadRequired();
257         return embeddedSm;
258     }
259
260
261     public void init(VersantDetachable d, OID oid, VersantPersistenceManagerImp rpm) {
262         ClassMetaData cmd = oid.getAvailableClassMetaData();
263         init(pc, oid, cmd);
264         d.jdoReplaceStateManager(this);
265         d.jdoProvideFields(cmd.allManagedFieldNosArray);
266         d.jdoReplaceStateManager(null);
267         pc = jdoImplHelper.newInstance(cmd.cls,
268                 rpm.createStateManagerProxy(this));
269         stateM = STATE_P_NEW;
270     }
271
272     public ClassMetaData getClassMetaData() {
273         return classMetaData;
274     }
275
276     private final void maintainOrigState(State toCopy,
277             VersantPersistenceManagerImp rpm) {
278         if (doChangeChecking) {
279             origState.copyFieldsForOptimisticLocking(toCopy, rpm);
280         } else {
281             origState.copyOptimisticLockingField(toCopy);
282         }
283     }
284
285     /**
286      * This is to create a hollow sm for a getObjectById with validate = false.
287      * Must the oid be resolved.
288      *
289      * @param oid
290      */

291     public void init(OID oid, VersantPersistenceManagerImp rpm) {
292         if (!oid.isResolved() && oid.getAvailableClassMetaData().isInHeirachy()) {
293             throw BindingSupportImpl.getInstance().internal("The oid '" + oid.toStringImp()
294                     + "' is not resolved to a exact instance type");
295         }
296         ClassMetaData cmd = oid.getAvailableClassMetaData();
297         init(jdoImplHelper.newInstance(cmd.cls, this), oid, cmd);
298         oid.resolve(state);
299         jdoManagedCache.createCacheKey(this);
300
301         setLoadRequired();
302         if (cmd.identityType == MDStatics.IDENTITY_TYPE_APPLICATION) {
303             state.copyFields(oid);
304             pc.jdoReplaceFields(classMetaData.pkFieldNos);
305             updated(rpm, false);
306         } else {
307             stateM = STATE_HOLLOW;
308         }
309     }
310
311     /**
312      * This is to init the sm for a new OID. Therefore either an P-New instance
313      * or a transient instance.
314      * <p/>
315      * TODO must test a transient instance that refs other instances. What must happen to them.
316      * Must they also propagate to transient.
317      */

318     public void init(PersistenceCapable pc, OID oid, boolean isTransactional) {
319         if (Debug.DEBUG) {
320             if (!oid.isNew()) {
321                 throw BindingSupportImpl.getInstance().internal(
322                         "The oid must be of type 'new'");
323             }
324         }
325         init(pc, oid, oid.getClassMetaData());
326         try {
327             if (isTransactional) {
328                 stateM = STATE_T_CLEAN;
329             } else {
330                 stateM = STATE_P_NEW;
331             }
332
333             oid.resolve(state);
334             //request all the fields from the pc instance
335
pc.jdoProvideFields(classMetaData.allManagedFieldNosArray);
336             state.addOneToManyInverseFieldsForL2Evict(getPm());
337             //fill the real-oid if possible
338
getRealOIDIfAppId();
339             jdoManagedCache.createCacheKey(this);
340
341             //convert all sco fields to be to sco instance and tell pc to reload them
342
replaceSCOFields();
343
344             jdoFlags = PersistenceCapable.READ_OK;
345             pc.jdoReplaceFlags();
346             dfgLoaded = true;
347             setAllFieldsToLoaded();
348         } catch (Exception JavaDoc e) {
349             /**
350              * Do clean up if exception occured.
351              */

352             try {
353                 getPm().removeTxStateObject(this);
354             } catch (Exception JavaDoc e1) {
355                 //ignore
356
}
357
358             if (Debug.DEBUG) {
359                 Debug.ERR.println(e.getMessage());
360                 e.printStackTrace(Debug.ERR);
361             }
362             handleException(e);
363         }
364     }
365
366     public OID getOID() {
367         return oid;
368     }
369
370     public PersistenceCapable getPersistenceCapable() {
371         return pc;
372     }
373
374     /**
375      * This will return a internal oid created from the state if
376      * - app id
377      * - keygen == null
378      * or state containsvalid pk fields
379      *
380      * @return
381      */

382     public OID getRealOIDIfAppId() {
383         if (!oid.isNew()) return null;
384         if (!classMetaData.postInsertKeyGenerator
385                 && classMetaData.identityType == MDStatics.IDENTITY_TYPE_APPLICATION
386                 && state.containsValidAppIdFields()) {
387             NewObjectOID cNOid = (NewObjectOID)oid;
388             if (cNOid.realOID != null) return cNOid.realOID;
389
390             final OID rOid = classMetaData.createOID(true);
391             state.copyKeyFields(rOid);
392
393             /**
394              * This is to keap the real oid from being gc'd.
395              */

396             cNOid.realOID = rOid;
397             return rOid;
398         }
399         return null;
400     }
401
402     /**
403      * This will initialise for transient managed use.
404      *
405      * @param pc
406      * @param oid
407      */

408     public void initTransient(PersistenceCapable pc, OID oid) {
409         if (Debug.DEBUG) {
410             if (!oid.isNew()) {
411                 throw BindingSupportImpl.getInstance().internal(
412                         "The oid must be of type 'new'");
413             }
414         }
415         init(pc, oid, oid.getClassMetaData());
416         stateM = STATE_T_CLEAN;
417
418     }
419
420     private void replaceSCOFields() {
421         int count = state.replaceSCOFields(pc, getPm(), scoFieldArray);
422         for (int i = count - 1; i >= 0; i--) {
423             pc.jdoReplaceField(scoFieldArray[i]);
424         }
425     }
426
427
428
429
430     public void dump() {
431         if (Debug.DEBUG) {
432             Debug.OUT.println("\n\n<PCStateObject oid = " + oid.toSString()
433                     + "\nstateM = " + stateM
434                     + "\nstate = " + state
435 // + "\nbeforeState = " + beforeState
436
+ "\norigState = " + origState
437                     + "\nretainValues = " + getPm().isRetainValues()
438                     + "\nOptimistic = " + getPm().isOptimistic()
439                     + "\ntxActive = " + getPm().isActive()
440                     + "###################### end #######################\n\n");
441         }
442     }
443
444     public boolean isLoaded(PersistenceCapable pc, FieldMetaData fmd) {
445         if (Debug.DEBUG) {
446             checkDfgLoaded();
447             if (!fmd.embeddedFakeField && dfgLoaded && fmd.isJDODefaultFetchGroup()
448                     && !pm.getRealPM().isInterceptDfgFieldAccess()) {
449
450                 throw BindingSupportImpl.getInstance().internal("Default fetch group " +
451                         "fields interception is turned off, but a isLoaded " +
452                         "call was still generated for it");
453
454             }
455
456             if ((jdoFlags == PersistenceCapable.READ_OK) && !dfgLoaded) {
457                 throw BindingSupportImpl.getInstance().internal(
458                         "READ_OK is set but the dfg is not loaded.");
459             }
460         }
461
462         checkTxDSReadOnPNonTx();
463         return isLoadedImp(fmd.stateFieldNo);
464     }
465
466     public boolean isLoaded(PersistenceCapable pc, int field) {
467         return isLoaded(pc, getFMD(field));
468
469     }
470
471     public void addToProcessList() {
472         addToProcessList(getPm());
473     }
474
475     private void addToProcessList(VersantPersistenceManagerImp rpm) {
476         //if no active tx then ignore
477
if (!rpm.isActive()) return;
478         pm.getRealPM().getCache().addForProcessing(this);
479         readInTx = true;
480     }
481
482     public boolean isLoadedImp(int field) {
483         try {
484             return loadedFields[field];
485         } catch (Exception JavaDoc e) {
486             handleException(e);
487         }
488         return false;
489     }
490
491     private void checkDfgLoaded() {
492         if (dfgLoaded &&
493                 !state.containFields(classMetaData.dfgStateFieldNos)) {
494             throw BindingSupportImpl.getInstance().internal("The default Fetch Group fields" +
495                     " are supposed to be loaded to the pc instance, but the state" +
496                     "does not contain it");
497         }
498     }
499
500     /**
501      * This is the same as isLoaded but will not trigger any state
502      * transitions.
503      */

504     public boolean isLoadedInternal(PersistenceCapable pc, int field) {
505         int stateFieldNo = classMetaData.absToRel[field];
506         int cat = classMetaData.stateFields[stateFieldNo].category;
507         if (cat == MDStatics.CATEGORY_REF || cat == MDStatics.CATEGORY_POLYREF) {
508             return loadedFields[field];
509         } else {
510             return state.containsField(stateFieldNo);
511         }
512     }
513
514     /**
515      * This is to check if a user is doing a read in an dataStore tx on
516      * a p-non-tx instance. Such an instance must be cleared of its state
517      * and re-read from the store. It's state must then propagate as normal
518      * to P-Clean.
519      */

520     private final void checkTxDSReadOnPNonTx() {
521         if (isPNonTx() && getPm().isActiveDS()) {
522             changeToHollowState(true);
523         }
524     }
525
526     final void setLoaded(FieldMetaData fmd) {
527         if (Debug.DEBUG) {
528             if (!fmd.embedded && stateM != STATE_TRANSIENT
529                     && !state.containsField(fmd.stateFieldNo)
530                     && fmd.category != MDStatics.CATEGORY_TRANSACTIONAL) {
531                 throw BindingSupportImpl.getInstance().internal(
532                         "The field " + fmd.name + " is not contained in the state");
533             }
534         }
535         loadedFields[fmd.stateFieldNo] = true;
536     }
537
538     public void evict() {
539         switch (stateM) {
540             case STATE_P_CLEAN:
541                 changeToHollowState();
542                 cacheEntry.changeToRefType(jdoManagedCache.queue,
543                         VersantPersistenceManager.PM_CACHE_REF_TYPE_WEAK);
544                 break;
545             case STATE_P_NON_TX:
546                 changeToHollowState();
547                 cacheEntry.changeToRefType(jdoManagedCache.queue,
548                         VersantPersistenceManager.PM_CACHE_REF_TYPE_WEAK);
549                 break;
550             default:
551                 toBeEvictedFlag = true;
552         }
553     }
554
555     /**
556      * This is an recursive operation. It will retrieve everything that is
557      * reachable.
558      */

559     public void retrieve(VersantPersistenceManagerImp rpm) {
560         loadAllPersistentFieldsToPC(rpm);
561         state.retrieve(rpm);
562     }
563
564     /**
565      * This will load all the managed-persistent fields to the PC instance.
566      * Transactional fields are ignored.
567      */

568     private void loadAllPersistentFieldsToPC(VersantPersistenceManagerImp rpm) {
569         // A new instance does not have any lazy fields that need fetching.
570
if (isNew()) return;
571         FetchGroup retrieveFG = classMetaData.getFetchGroup(
572                 FetchGroup.RETRIEVE_NAME);
573         if (!state.containsFetchGroup(retrieveFG)) {
574             rpm.getState(oid,
575                     retrieveFG.sendFieldsOnFetch ? getForReadState() : null,
576                     retrieveFG.index, -1, -1, false);
577         }
578
579         for (int i = 0; i < classMetaData.managedFields.length; i++) {
580             FieldMetaData fmd = classMetaData.managedFields[i];
581             if (fmd.persistenceModifier == MDStatics.PERSISTENCE_MODIFIER_PERSISTENT) {
582                 pc.jdoReplaceField(fmd.managedFieldNo);
583             }
584
585         }
586         callJDOPostLoad();
587         dfgLoaded = true;
588     }
589
590     /**
591      * Return a state containing the current values of all fake fields. If
592      * the instance is hollow then null is returned.
593      */

594     private State getForReadState() {
595         if (state.isEmpty()) return null;
596         if (forReadState == null) forReadState = classMetaData.createState();
597         if (forReadState.isEmpty()) state.fillForRead(forReadState, getPm());
598         return forReadState;
599     }
600
601     public void deletePersistent() {
602         if (isDeleted()) return;
603         if (isTransientManaged()) {
604             throw BindingSupportImpl.getInstance().invalidOperation("The deletion of a transient " +
605                     "managed instance is not allowed.");
606         }
607
608         // do notification if required
609
VersantPersistenceManagerImp pm = getPm();
610         boolean wasDirty = isDirty();
611         if (!wasDirty && classMetaData.notifyDataStoreOnDirtyOrDelete
612                 && pm.isActiveDS()) {
613             pm.getStorageManager().notifyDirty(oid);
614         }
615
616         pm.fireDelete(classMetaData, pc);
617
618         // invoke jdoPreDelete
619

620         if (instanceCallbacks != null) {
621             instanceCallbacks.jdoPreDelete();
622         }
623 /*END_JVAVONLY*/
624         
625
626         //the loaded fields is reset for a deleted instance to force it to try and reread their
627
//fields and so catch illegal read/write ops on the instance.
628
resetLoadedFields();
629         setLoadRequired();
630
631         rfgLoaded = false;
632         dfgLoaded = false;
633
634         clearMtMCollections();
635
636         // mark us as deleted
637
stateM |= MASK_DELETE_TX_DIRTY;
638         pm.addTxStateObject(this);
639
640         deleteDependents();
641
642         // Make sure the fake fields with LOIDs for secondary fields are
643
// sent to the server if using VDS and the instance was clean
644
// before delete and has secondary fields. The forRead state is
645
// included in the DeletePacket if the tx commits.
646
if (jmd.sendStateOnDelete && classMetaData.hasSecondaryFields && !wasDirty) {
647             forReadState = getForReadState();
648         } else {
649             forReadState = null;
650         }
651
652         origState.clear();
653         state.clear();
654         if (beforeState != null) beforeState.clear();
655
656         //replace the state with DELETED_STATE. This will ensure that user
657
//exception is thrown on field access.
658
state = DELETED_STATE;
659     }
660
661     /**
662      * This is invoked from deletePersistent to delete all the dependent
663      * references of this instance.
664      */

665     private void deleteDependents() {
666         // make sure that all dependent fields are in state if there are any
667
FetchGroup dep = classMetaData.depFetchGroup;
668         if (dep == null) return;
669         if (!oid.isNew() && !state.containsFetchGroup(dep)) {
670             getPm().getState(oid,
671                     dep.sendFieldsOnFetch ? getForReadState() : null,
672                     dep.index, -1, -1, false);
673         }
674
675         // delete all objects referenced by dependent fields
676
for (; dep != null; dep = dep.superFetchGroup) {
677             FetchGroupField[] fields = dep.fields;
678             int len = fields.length;
679             for (int j = 0; j < len; j++) {
680                 FetchGroupField field = fields[j];
681                 FieldMetaData fmd = field.fmd;
682                 switch (fmd.category) {
683                     case MDStatics.CATEGORY_ARRAY:
684                         followArray(fmd);
685                         break;
686                     case MDStatics.CATEGORY_COLLECTION:
687                         followCollection(fmd);
688                         break;
689                     case MDStatics.CATEGORY_MAP:
690                         followMap(fmd);
691                         break;
692                     case MDStatics.CATEGORY_POLYREF:
693                     case MDStatics.CATEGORY_REF:
694                         followRef(fmd);
695                         break;
696                 }
697             }
698         }
699     }
700
701     public void collectReachable(String JavaDoc fetchGroup, Collection JavaDoc result) {
702         FetchGroup fg = classMetaData.getFetchGroup(fetchGroup);
703         
704         if (fg == null)
705             return;
706         boolean deep = fetchGroup.equals(FetchGroup.REF_NAME);
707         boolean depend = fetchGroup.equals(FetchGroup.DEP_NAME);
708         VersantPersistenceManagerImp _pm = getPm();
709         
710         // make sure everything required has been fetched
711
if (!oid.isNew() && !state.containsFetchGroup(fg) && !deep) {
712             // todo: for FetchGroup.REF_NAME, a NPE is thrown for
713
// collection fields, because FetchGroup.nextFetchGroup is null
714
_pm.getState(oid, fg.sendFieldsOnFetch ? getForReadState() : null,
715                          fg.index, -1, -1, false);
716         }
717
718         // collect all referenced objects
719
for (; fg != null; fg = fg.superFetchGroup) {
720             FetchGroupField[] fields = fg.fields;
721             int len = fields.length;
722             for (int i = 0; i < len; i++) {
723                 FetchGroupField fgField = fields[i];
724                 int fieldNo = fgField.fmd.stateFieldNo;
725                 int managedFieldNo = fgField.fmd.managedFieldNo;
726                 if (!deep && !oid.isNew())
727                     pc.jdoReplaceField(managedFieldNo);
728
729                 String JavaDoc nextFetchGroup = fgField.nextFetchGroup==null?
730                     null:fgField.nextFetchGroup.name;
731                 String JavaDoc nextKeyFetchGroup = fgField.nextKeyFetchGroup==null?
732                     null:fgField.nextKeyFetchGroup.name;
733                 if (deep) // nextFetchGroup is null
734
nextFetchGroup = nextKeyFetchGroup = FetchGroup.REF_NAME;
735                 else if (depend) // nextFetchGroup is default
736
nextFetchGroup = nextKeyFetchGroup = FetchGroup.DEP_NAME;
737                 switch (fgField.fmd.category) {
738                     case MDStatics.CATEGORY_ARRAY:
739                         if (deep && !oid.isNew())
740                             doRead(fields[i].fmd); // todo: remove
741
Object JavaDoc[] arr = (Object JavaDoc[])
742                             state.getObjectField(fieldNo, pc, _pm, oid);
743                         if (arr == null) continue;
744                         for (int j=0; j<arr.length; j++){
745                             Object JavaDoc o = arr[j];
746                             if (o != null && o instanceof PersistenceCapable)
747                                 result.add(new Object JavaDoc[] {o, nextFetchGroup});
748                         }
749                         break;
750                     case MDStatics.CATEGORY_COLLECTION:
751                         if (deep && !oid.isNew())
752                             doRead(fields[i].fmd); // todo: remove
753
Collection JavaDoc c = (Collection JavaDoc)
754                             state.getObjectField(fieldNo, pc, _pm, oid);
755                         if (c == null) continue;
756                         for (Iterator JavaDoc it = c.iterator(); it.hasNext();) {
757                             Object JavaDoc o = it.next();
758                             if (o != null && o instanceof PersistenceCapable)
759                                 result.add(new Object JavaDoc[] {o, nextFetchGroup});
760                         }
761                         break;
762                     case MDStatics.CATEGORY_MAP:
763                         if (deep && !oid.isNew())
764                             doRead(fields[i].fmd); // todo:remove
765
Map JavaDoc m = (Map JavaDoc)
766                             state.getObjectField(fieldNo, pc, _pm, oid);
767                         if (m == null) continue;
768                         for (Iterator JavaDoc it = m.entrySet().iterator();
769                              it.hasNext();) {
770                             Map.Entry JavaDoc e = (Map.Entry JavaDoc)it.next();
771                             Object JavaDoc o = e.getKey();
772                             if (o != null && o instanceof PersistenceCapable) {
773                                 result.add(new Object JavaDoc[] {o, nextKeyFetchGroup});
774                             }
775                             o = e.getValue();
776                             if (o != null && o instanceof PersistenceCapable) {
777                                 result.add(new Object JavaDoc[] {o, nextFetchGroup});
778                             }
779                         }
780                         break;
781                     case MDStatics.CATEGORY_POLYREF:
782                     case MDStatics.CATEGORY_REF:
783                         if (deep && !oid.isNew())
784                             doRead(fields[i].fmd); // todo: remove
785
Object JavaDoc o = state.getObjectField(fieldNo, pc, _pm, oid);
786                         if (o != null && (o instanceof PersistenceCapable))
787                             result.add(new Object JavaDoc[] {o, nextFetchGroup});
788                         break;
789                 }
790             }
791         }
792     }
793
794     /**
795      * Clear any many-to-many managed collections. This makes sure we
796      * are removed from the other side of any of these before we are
797      * deleted.
798      */

799     private void clearMtMCollections() {
800         FetchGroup mm = classMetaData.managedManyToManyFetchGroup;
801         if (mm != null) {
802
803             // make sure the collections have been fetched
804
if (!oid.isNew() && !state.containsFetchGroup(mm)) {
805                 getPm().getState(oid,
806                         mm.sendFieldsOnFetch ? getForReadState() : null,
807                         mm.index, -1, -1, false);
808             }
809
810             // now clear all of them skipping non-collections (e.g. version)
811
for (; mm != null; mm = mm.superFetchGroup) {
812                 FetchGroupField[] fields = mm.fields;
813                 int len = fields.length;
814                 for (int j = 0; j < len; j++) {
815                     FetchGroupField field = fields[j];
816                     FieldMetaData fmd = field.fmd;
817                     if (fmd.category == MDStatics.CATEGORY_COLLECTION) {
818                         Collection JavaDoc c = (Collection JavaDoc)state.getObjectField(
819                                 fmd.stateFieldNo, pc, getPm(), oid);
820                         if (c != null) c.clear();
821                     }
822                 }
823             }
824         }
825     }
826
827     private void followRef(FieldMetaData fmd) {
828         Object JavaDoc o = state.getObjectField(fmd.stateFieldNo, pc, getPm(), oid);
829         if (o != null) deletePersistent(o);
830     }
831
832     private void followCollection(FieldMetaData fmd) {
833         Collection JavaDoc c = (Collection JavaDoc)state.getObjectField(fmd.stateFieldNo, pc,
834                 getPm(), oid);
835         if (c == null) return;
836         for (Iterator JavaDoc i = c.iterator(); i.hasNext();) {
837             Object JavaDoc o = i.next();
838             if (o != null) deletePersistent(o);
839         }
840     }
841
842     private void followArray(FieldMetaData fmd) {
843         Object JavaDoc[] arr = (Object JavaDoc[])state.getObjectField(fmd.stateFieldNo, pc,
844                                                       getPm(), oid);
845         if (arr == null) return;
846         for (int i=0; i<arr.length; i++) {
847             Object JavaDoc o = arr[i];
848             if (o != null) deletePersistent(o);
849         }
850     }
851
852
853     private void followMap(FieldMetaData fmd) {
854         Map JavaDoc m = (Map JavaDoc)state.getObjectField(fmd.stateFieldNo, pc, getPm(), oid);
855         if (m == null) return;
856         for (Iterator JavaDoc i = m.entrySet().iterator(); i.hasNext();) {
857             Map.Entry JavaDoc e = (Map.Entry JavaDoc)i.next();
858             if (fmd.dependentKeys) deletePersistent(e.getKey());
859             if (fmd.dependentValues) {
860                 Object JavaDoc o = e.getValue();
861                 if (o != null) deletePersistent(o);
862             }
863         }
864     }
865
866     /**
867      * This is used when following dependent fields on delete. It avoids
868      * all the repeat checks done by perMan.deletePersistent(o).
869      */

870     private void deletePersistent(Object JavaDoc o) {
871         getPm().getInternalSM((PersistenceCapable)o).deletePersistent();
872     }
873
874     /**
875      * The instance is only cleared of object references and not the primitives.
876      * The loaded fields and the JDO_FLAGS is reset to force the pc to ask the sm for new values.
877      * <p/>
878      * For application identity the state will not transition to hollow as the pk
879      * fields must remain.
880      */

881     private final void changeToHollowState(boolean clearBeforeState) {
882         if (state == null) return;
883         if (isHollow()) return;
884         
885         if (instanceCallbacks != null) {
886             instanceCallbacks.jdoPreClear();
887         }
888         
889         stateM = STATE_HOLLOW;
890
891         state.unmanageSCOFields();
892         state.clear();
893         State tmpState = state;
894
895         state = INIT_STATE;
896         //ask pc to replace only the instances that hold refs to other pc instances
897
//this helps to gc instances quicker
898
pc.jdoReplaceFields(classMetaData.absPCTypeFields);
899         state = tmpState;
900
901         origState.clear();
902         if (clearBeforeState && beforeState != null) {
903             beforeState.clear();
904         }
905
906         setLoadRequired();
907         resetLoadedFields();
908         rfgLoaded = false;
909         dfgLoaded = false;
910
911         if (classMetaData.identityType == MDStatics.IDENTITY_TYPE_APPLICATION) {
912             replaceApplicationPKFields();
913         }
914
915         if (forReadState != null) forReadState.clearFilledFlags();
916
917         if (Debug.DEBUG) {
918             if (!isHollow() && classMetaData.identityType != MDStatics.IDENTITY_TYPE_APPLICATION) {
919                 if (Debug.DEBUG) {
920                     Debug.OUT.println("isEmpty = " + state.isEmpty());
921                 }
922                 dump();
923                 throw BindingSupportImpl.getInstance().internal(
924                         "The instance is not hollow");
925             }
926         }
927     }
928
929     /**
930      * The instance is not cleared of its values. The loaded fields and the JDO_FLAGS is
931      * reset to force the pc to ask the sm for new values.
932      */

933     public void changeToHollowState() {
934         changeToHollowState(false);
935     }
936
937     public void rollback() {
938         if (isTx()) {
939             rollbackImp();
940         } else if (readInTx) {
941             changeToHollowState(true);
942         }
943         clearTxFlags();
944     }
945
946     public void commit(VersantPersistenceManagerImp pm) {
947         if (isTx()) {
948             commitImp(pm);
949         } else if (readInTx) {
950             changeToHollowState(true);
951             readInTx = false;
952         }
953         clearTxFlags();
954     }
955
956     public final void resetLoadedFields() {
957         final boolean[] lfs = loadedFields;
958         for (int i = lfs.length - 1; i >= 0; i--) {
959             lfs[i] = false;
960         }
961     }
962
963     private void setAllFieldsToLoaded() {
964         final boolean[] lfs = loadedFields;
965         for (int i = lfs.length - 1; i >= 0; i--) {
966             lfs[i] = true;
967         }
968     }
969
970     private final void changeToTransient(int event) {
971         stateM = STATE_TRANSIENT;
972         if (event == EVENT_ROLLBACK) {
973             if (getPm().isRestoreValues() && beforeState != null) {
974                 state.updateFrom(beforeState);
975             }
976             pc.jdoReplaceFields(classMetaData.allManagedFieldNosArray);
977         } else if (event == EVENT_COMMIT) {
978             State tmpState = state;
979             state = INIT_STATE;
980             pc.jdoReplaceFields(classMetaData.allManagedFieldNosArray);
981             state = tmpState;
982         }
983         unManage();
984     }
985
986     /**
987      * Must ensure that all resources is clean up.
988      */

989     private final void unManage() {
990         jdoManagedCache.remove(this);
991         setSMToNull();
992         state.unmanageSCOFields();
993         pc = null;
994         oid = null;
995         state = null;
996         beforeState = null;
997         origState = null;
998         toStoreState = null;
999     }
1000
1001    private final void setSMToNull() {
1002        /**
1003         * change state to transient so that call back to replacingStateManager will return null.
1004         * and remove it from the txObjects list.
1005         */

1006        stateM = STATE_TRANSIENT;
1007        pc.jdoReplaceStateManager(null);
1008    }
1009
1010    /**
1011     * Check if the instance is in a managed transient state.
1012     */

1013    public boolean isTransientManaged() {
1014        return (((stateM ^ STATE_T_CLEAN) == 0) || ((stateM ^ STATE_T_DIRTY) == 0));
1015    }
1016
1017    public boolean isPersistentNew() {
1018        return ((stateM ^ STATE_P_NEW) == 0);
1019    }
1020
1021    public void loadFetchGroup(String JavaDoc name) {
1022        if (oid.isNew()) {
1023            return;
1024        }
1025        FetchGroup fg = classMetaData.getFetchGroup(name);
1026        if (fg == null) {
1027            throw BindingSupportImpl.getInstance().invalidOperation(
1028                    "fetch group '" + name + "' is not defined");
1029        }
1030        if (!state.containsFetchGroup(fg)) {
1031            getPm().getState(this.oid,
1032                    fg.sendFieldsOnFetch ? getForReadState() : null,
1033                    fg.index, -1, -1, false);
1034        }
1035    }
1036
1037    /**
1038     * This is here to do any preparation work before the field can be read.
1039     * It will check if the fetchGroup for the field is filled in on the state. If not
1040     * then the required values must be fetched from the server.
1041     * <p/>
1042     * Any state changes must also be done.
1043     * <p/>
1044     * The returned container reference must be kept until all the required
1045     * State instances in the local cache have been referenced or they might
1046     * be GCed. This is important for collections of PC and other fields that
1047     * involve fetching State instances and loading them into the local cache.
1048     * They are only hard referenced when the SCO instance has been created.
1049     */

1050    private StatesReturned doRead(FieldMetaData fmd) {
1051        if (Debug.DEBUG) {
1052            if (isTransientManaged()) {
1053                throw BindingSupportImpl.getInstance().internal(
1054                        "A transactional instance must not call this");
1055            }
1056        }
1057        addToProcessList();
1058
1059        VersantPersistenceManagerImp rpm = getPm();
1060        rpm.checkNonTxRead();
1061        if (fmd.isEmbeddedRef()) {
1062            return null;
1063        }
1064
1065        StatesReturned container = null;
1066        if (!state.containsField(fmd.stateFieldNo)) {
1067            if (Debug.DEBUG) {
1068                if (oid.isNew()) {
1069                    throw BindingSupportImpl.getInstance().internal(
1070                            "A new OID is not supposed to reach here");
1071                }
1072                Debug.OUT.println("\n\n>>>>>>>>>>>The field not contained: field = " + fmd.managedFieldNo
1073                        + " fieldName = " + fmd.name
1074                        + " for " + classMetaData.qname);
1075            }
1076
1077            FetchGroup fg = fmd.fetchGroup;
1078            container = rpm.getState(this.oid,
1079                    fg.sendFieldsOnFetch ? getForReadState() : null,
1080                    fg.index, fmd.managedFieldNo, -1, false);
1081            if (Debug.DEBUG) {
1082                if (!state.containsFetchGroup(
1083                        fmd.fetchGroup)) {
1084                    System.out.println("bad state:\n" + state);
1085                    throw BindingSupportImpl.getInstance().internal(
1086                            "State does not contain the requested fg");
1087                }
1088            }
1089        }
1090
1091        if (!fmd.embeddedFakeField) {
1092            if (fmd.isJDODefaultFetchGroup()) {
1093                //replace non loaded dfg fields
1094
if (state.containFields(classMetaData.dfgStateFieldNos)) {
1095                    loadDFGIntoPC(rpm);
1096                }
1097            } else {
1098                pc.jdoReplaceField(fmd.managedFieldNo);
1099                setLoaded(fmd);
1100                updated(rpm, true);
1101            }
1102        }
1103
1104        if (!oid.isNew()) {
1105            if (!(doChangeChecking || rfgLoaded)) {
1106                loadRequiredFetchGroup();
1107            }
1108        }
1109
1110        return container;
1111    }
1112
1113    /**
1114     * Loads the required fg into the state if not already done.
1115     */

1116    private void loadRequiredFetchGroup() {
1117        if (rfgLoaded) return;
1118        final FetchGroup reqFetchGroup = classMetaData.reqFetchGroup;
1119        if (reqFetchGroup != null && !state.containsFetchGroup(reqFetchGroup)) {
1120            getPm().getState(this.oid, null, reqFetchGroup.index, -1, -1,
1121                    false);
1122        }
1123        rfgLoaded = true;
1124    }
1125
1126    /**
1127     * This gets called from the enhanced pc instances. This is only for
1128     * Application identity key fields. It gives us a chance to
1129     * fill the field with a valid keygened value.
1130     */

1131    public void fillNewAppPKField(int fieldNo) {
1132        if (oid.isNew()) {
1133            NewObjectOID newObjectOID = (NewObjectOID)oid;
1134            if (newObjectOID.realOID == null) {
1135                if (classMetaData.postInsertKeyGenerator) {
1136                    getPm().flushRetainState();
1137                } else {
1138                    newObjectOID.realOID =
1139                            getPm().getStorageManager().createOID(classMetaData);
1140                    newObjectOID.realOID.getClassMetaData();
1141                    state.copyFields(newObjectOID.realOID);
1142                    pc.jdoReplaceFields(classMetaData.pkFieldNos);
1143                }
1144            }
1145        }
1146    }
1147
1148    private FieldMetaData getFMD(int fieldNo) {
1149        return classMetaData.managedFields[fieldNo];
1150    }
1151
1152    /**
1153     * Get the FetchGroup to be loaded with a field.
1154     */

1155    private FetchGroup getFetchGroup(int absField) {
1156        return classMetaData.stateFields[classMetaData.absToRel[absField]].fetchGroup;
1157    }
1158
1159    /**
1160     * This is here to do any prep. work for a write operation. It must ensure that if a field
1161     * is written to but is not currently loaded and it is using changed checking that it is first loaded
1162     * from the server.
1163     */

1164    private final void doWrite(FieldMetaData fmd, boolean mustLoad) {
1165        VersantPersistenceManagerImp pm = this.pm.getRealPM();
1166        //if this is a transactional field and we should not need to go to the db
1167
if (fmd.category == MDStatics.CATEGORY_TRANSACTIONAL) {
1168            if (pm.isActive()) makeInternalDirty();
1169            return;
1170        }
1171        pm.checkNonTxWrite();
1172
1173        if (classMetaData.identityType == MDStatics.IDENTITY_TYPE_APPLICATION
1174                && fmd.primaryKey) {
1175            throw BindingSupportImpl.getInstance().unsupported(
1176                    "Change of identity is not suppoted");
1177        }
1178
1179        // if we need to notify the server before we go dirty for the first
1180
// time do so now
1181
if (classMetaData.notifyDataStoreOnDirtyOrDelete && !isDirty()
1182                && pm.isActiveDS()) {
1183            pm.getStorageManager().notifyDirty(oid);
1184        }
1185
1186        // Check for a write operation that will result in a change from p-non-tx to p-dirty.
1187
// If so then a snapshot of the current state must be taken and the state reloaded from
1188
// the store.
1189
// The current state must only be preserved if restoreValues is set to true.
1190
// If retainValues is set to false then the instance will always be hollow after a commit
1191
// or a rollback and therefore it overrides restoreValues.
1192
if (isPNonTx() && pm.isActive()) {
1193            if (beforeState != null) {
1194                beforeState.clear();
1195                if (pm.isRestoreValues()) beforeState.updateFrom(state);
1196            }
1197            // If is is an dataStore tx then the state must be cleared and reloaded from the
1198
// store. This is done to ensure that the state is in sync with the
1199
// dataStore.
1200
if (!pm.isOptimistic()) changeToHollowState(false);
1201        }
1202
1203        // Make sure that the state contains required fields before doing the
1204
// write. For JDBC this will ensure that the optimisic locking field
1205
// (if any) is loaded. For VDS this will load all fields.
1206
if (!oid.isNew()) {
1207            if (mustLoad && !state.containsField(fmd.stateFieldNo)) {
1208                FetchGroup fg = fmd.fetchGroup;
1209                getPm().getState(this.oid,
1210                        fg.sendFieldsOnFetch ? getForReadState() : null,
1211                        fg.index, fmd.managedFieldNo, -1, false);
1212            } else if (!(doChangeChecking || rfgLoaded)) {
1213                loadRequiredFetchGroup();
1214            } else if (doChangeChecking && !state.containsField(fmd.stateFieldNo)) {
1215                FetchGroup fg = fmd.fetchGroup;
1216                getPm().getState(this.oid,
1217                        fg.sendFieldsOnFetch ? getForReadState() : null,
1218                        fg.index, fmd.managedFieldNo, -1, false);
1219            }
1220        }
1221
1222        if (getPm().isActive()) {
1223            if (!isTx()) updateDfgFieldMediation();
1224            stateM |= MASK_TX;
1225            stateM |= MASK_DIRTY;
1226            getPm().addTxStateObject(this);
1227            addToProcessList();
1228        }
1229        loadedFields[fmd.stateFieldNo] = false;
1230    }
1231
1232    private void makeInternalDirty() {
1233        stateM |= MASK_TX;
1234        stateM |= MASK_DIRTY;
1235        getPm().addTxStateObject(this);
1236        addToProcessList();
1237    }
1238
1239    /**
1240     * This will be called when ever the state has been updated as result of a
1241     * query/navigation that brought extra info back for this state.
1242     * This method will ensure that the proper state changes takes place.
1243     */

1244    final void updated(VersantPersistenceManagerImp rpm,
1245            boolean addToProccessList) {
1246        if (rpm.isActive()) {
1247            if (rpm.isOptimistic()) {
1248                /**
1249                 * Must change to pers-non-tx
1250                 * eg. This will change a hollow instance to p-non-tx
1251                 */

1252                stateM |= MASK_PERSISTENT;
1253            } else {
1254                if (!isTx()) updateDfgFieldMediation();
1255                stateM |= MASK_TX;
1256                stateM |= MASK_PERSISTENT;
1257                rpm.addTxStateObject(this);
1258            }
1259
1260            if (addToProccessList) {
1261                addToProcessList(rpm);
1262            }
1263        } else {
1264            stateM |= MASK_PERSISTENT;
1265        }
1266    }
1267
1268    /**
1269     * This is a new State that was received from the server via indirect means.
1270     * This state must be updated with the supplied state. Any state changes nec must
1271     * also be done.
1272     *
1273     * @param suppliedState
1274     */

1275    public PCStateMan updateWith(State suppliedState,
1276            VersantPersistenceManagerImp pm, boolean overWrite) {
1277        if (overWrite) {
1278            changeToHollowState();
1279        }
1280        updated(pm, true);
1281        if (suppliedState != state) {
1282            state.updateNonFilled(suppliedState);
1283            if (doChangeChecking || origState.isEmpty()) {
1284                maintainOrigState(suppliedState, pm);
1285            }
1286        }
1287        return this;
1288    }
1289
1290    public boolean isTx() {
1291        return ((stateM & MASK_TX) != 0);
1292    }
1293
1294    public boolean readInTx(boolean strict) {
1295        if (strict) return isTx();
1296        return readInTx || isTx();
1297    }
1298
1299    public boolean isDirty() {
1300        return ((stateM & MASK_DIRTY) != 0);
1301    }
1302
1303    private final boolean isNew() {
1304        return ((stateM & MASK_NEW) != 0);
1305    }
1306
1307    public boolean isHollow() {
1308        return (state.isEmpty() && ((stateM ^ STATE_HOLLOW) == 0));
1309    }
1310
1311    private boolean isDeleted() {
1312        return (stateM & MASK_DELETE) != 0;
1313    }
1314
1315    public boolean isPNonTx() {
1316        return (((stateM ^ STATE_P_NON_TX) == 0) && !state.isEmpty());
1317    }
1318
1319    public boolean isPClean() {
1320        return (!state.isDirty() && ((stateM ^ STATE_P_CLEAN) == 0));
1321    }
1322
1323    public boolean isPNew() {
1324        return ((stateM ^ STATE_P_NEW) == 0);
1325    }
1326
1327    public boolean isPNewDeleted() {
1328        return ((stateM ^ STATE_P_NEW_DEL) == 0);
1329    }
1330
1331    public boolean isPDeleted() {
1332        return ((stateM ^ STATE_P_DEL) == 0);
1333    }
1334
1335    public boolean isTClean() {
1336        return ((stateM ^ STATE_T_CLEAN) == 0);
1337    }
1338
1339    public boolean isTDirty() {
1340        return ((stateM ^ STATE_T_DIRTY) == 0);
1341    }
1342
1343    public boolean isPDirty() {
1344        return (state.isDirty() && ((stateM ^ STATE_P_DIRTY) == 0));
1345    }
1346
1347    /*
1348    private String stateMtoString() {
1349        switch (stateM) {
1350            case STATE_TRANSIENT:
1351                return "STATE_TRANSIENT";
1352            case STATE_T_CLEAN:
1353                return "STATE_T_CLEAN";
1354            case STATE_T_DIRTY:
1355                return "STATE_T_DIRTY";
1356            case STATE_HOLLOW:
1357                return "STATE_HOLLOW";
1358            case STATE_P_CLEAN:
1359                return "STATE_P_CLEAN";
1360            case STATE_P_DIRTY:
1361                return "STATE_P_DIRTY";
1362            case STATE_P_DEL:
1363                return "STATE_P_DEL";
1364            case STATE_P_NEW:
1365                return "STATE_P_NEW";
1366            case STATE_P_NEW_DEL:
1367                return "STATE_P_NEW_DEL";
1368        }
1369        return "UNKNOWN(" + stateM + ")";
1370    }
1371    */

1372
1373    private void rollbackImp() {
1374        try {
1375            switch (stateM) {
1376                case STATE_TRANSIENT:
1377                    break;
1378                case STATE_T_CLEAN:
1379                    break;
1380                case STATE_T_DIRTY:
1381                    if (beforeState != null) {
1382                        State s = state;
1383                        state = beforeState;
1384                        beforeState = s;
1385                        state.updateNonFilled(beforeState);
1386                        beforeState.clear();
1387                    }
1388                    pc.jdoReplaceFields(classMetaData.allManagedFieldNosArray);
1389                    if (forReadState != null) forReadState.clearFilledFlags();
1390                    origState.clear();
1391                    stateM = STATE_T_CLEAN;
1392                    break;
1393                case STATE_HOLLOW:
1394                    break;
1395                case STATE_P_CLEAN:
1396                    if (getPm().isRestoreValues()) {
1397                        stateM = STATE_P_NON_TX;
1398                    } else {
1399                        changeToHollowState(true);
1400                    }
1401                    break;
1402                case STATE_P_DEL:
1403                    //the state was replaced with DELETED_STATE so create a new one
1404
state = createStateImp();
1405                    changeToHollowState(true);
1406                    break;
1407                case STATE_P_DIRTY:
1408                    if (getPm().isRestoreValues()) {
1409                        stateM = STATE_P_NON_TX;
1410                        state.clearDirtyFields();
1411                        if (beforeState != null) {
1412                            beforeState.clearSCOFields();
1413                            state.updateFrom(beforeState);
1414                            beforeState.clear();
1415                        }
1416                        state.clearSCOFields();
1417                        if (forReadState != null) forReadState.clearFilledFlags();
1418                        setLoadRequired();
1419                        resetLoadedFields();
1420
1421                        //there is no read interrogation for tx transient fields and therefore
1422
//they must be replaced now.
1423
pc.jdoReplaceFields(classMetaData.txfieldManagedFieldNos);
1424
1425                        rfgLoaded = false;
1426                        dfgLoaded = false;
1427                    } else {
1428                        if (beforeState != null) {
1429                            State tmpState = state;
1430                            state = beforeState;
1431                            pc.jdoReplaceFields(classMetaData.txfieldManagedFieldNos);
1432                            state = tmpState;
1433                        }
1434                        changeToHollowState(true);
1435                    }
1436                    break;
1437                case STATE_P_NEW:
1438                    changeToTransient(EVENT_ROLLBACK);
1439                    break;
1440                case STATE_P_NEW_DEL:
1441                    state = createStateImp();
1442                    changeToTransient(EVENT_ROLLBACK);
1443                    break;
1444                default:
1445                    throw BindingSupportImpl.getInstance().internal(
1446                            "The state is unreachable");
1447            }
1448        } finally {
1449            if (toStoreState != null) toStoreState.clear();
1450            clearTxFlags();
1451        }
1452    }
1453
1454    /**
1455     * This will load the defaulFetchGroup fields into the state and in
1456     * the mananged instance. This is only called to change from hollow.
1457     */

1458    public void loadDfgFromHollow() {
1459        if (Debug.DEBUG) {
1460            if (!isHollow()) {
1461                throw BindingSupportImpl.getInstance().internal(
1462                        "This is only allowed to be called on hollow instances");
1463            }
1464        }
1465        getPm().getState(this.oid, null, 0, -1, -1, false);
1466        loadDFGIntoPC(getPm());
1467    }
1468
1469    /**
1470     * This will load all the dfg fields into the PC instance.
1471     */

1472    public void loadDFGIntoPC(VersantPersistenceManagerImp rpm) {
1473        if (dfgLoaded) {
1474            if (Debug.DEBUG) checkDfgLoaded();
1475            return;
1476        }
1477        pc.jdoReplaceFields(classMetaData.dfgAbsFieldNos);
1478        updated(rpm, true);
1479        callJDOPostLoad();
1480
1481        /**
1482         * Why only if it is transactional ??
1483         *
1484         * This is not set because in the case of a datastore tx with non-tx
1485         * read's allowed, and then setting the read ok flag will cause it not
1486         * to ask the sm for the next field access. This means if a ds tx starts
1487         * and the fields is accessed again that the sm will not reload the fields
1488         * from the db.
1489         */

1490
1491        //todo must also check if this is a subclass of a horizontal class
1492
// where dfg fields have been changed
1493
if (classMetaData.horizontalCMD == null && (isTx() || !rpm.isInterceptDfgFieldAccess())) {
1494            jdoFlags = PersistenceCapable.READ_OK;
1495            pc.jdoReplaceFlags();
1496        }
1497        dfgLoaded = true;
1498        if (Debug.DEBUG) checkDfgLoaded();
1499    }
1500
1501    private void callJDOPostLoad() {
1502
1503        if (instanceCallbacks != null && !dfgLoaded) {
1504            
1505            instanceCallbacks.jdoPostLoad();
1506
1507
1508        }
1509    }
1510
1511    /**
1512     * Utils method to reset the flag of the pc instance to indicate that fields
1513     * must be reloaded.
1514     */

1515    void setLoadRequired() {
1516        jdoFlags = PersistenceCapable.LOAD_REQUIRED;
1517        pc.jdoReplaceFlags();
1518    }
1519
1520    public void setInterceptDfgFieldAccess(boolean on) {
1521        if (isPNonTx()) {
1522            if (on) {
1523                setLoadRequired();
1524            } else {
1525                updateDfgFieldMediation();
1526            }
1527        }
1528    }
1529
1530    public void makeTransient() {
1531        if (isDirty(null)) {
1532            throw BindingSupportImpl.getInstance().invalidOperation(
1533                    "The instance is dirty.");
1534        }
1535        if (isTransientManaged()) return;
1536        //fill the pc instance with data in state.
1537
final int[] stateFieldNos = new int[classMetaData.stateFieldNos.length];
1538        for (int i = 0; i < state.getFieldNos(stateFieldNos); i++) {
1539            final FieldMetaData fmd = classMetaData.stateFields[stateFieldNos[i]];
1540            int cat = fmd.category;
1541            if (cat == MDStatics.CATEGORY_REF || cat == MDStatics.CATEGORY_POLYREF) continue;
1542            if (fmd.managedFieldNo < 0) continue;
1543            if (!loadedFields[fmd.managedFieldNo]) {
1544                pc.jdoReplaceField(fmd.managedFieldNo);
1545            }
1546        }
1547        unManage();
1548        getPm().removeTxStateObject(this);
1549    }
1550
1551    public void makeTransientRecursive() {
1552        if (isDirty(null)) {
1553            throw BindingSupportImpl.getInstance().invalidOperation(
1554                    "The instance is dirty.");
1555        }
1556        if (isTransientManaged()) return;
1557
1558        final int[] stateFieldNos = new int[classMetaData.stateFieldNos.length];
1559        for (int i = 0; i < state.getFieldNos(stateFieldNos); i++) {
1560            final FieldMetaData fmd = classMetaData.stateFields[stateFieldNos[i]];
1561            if (fmd.managedFieldNo < 0) continue;
1562            int cat = fmd.category;
1563            if (!loadedFields[fmd.managedFieldNo]) {
1564                if (cat == MDStatics.CATEGORY_REF || cat == MDStatics.CATEGORY_POLYREF) continue;
1565                pc.jdoReplaceField(fmd.managedFieldNo);
1566            } else {
1567                if (cat == MDStatics.CATEGORY_REF || cat == MDStatics.CATEGORY_POLYREF) {
1568                    getPm().makeTransientRecursive(state.getObjectField(
1569                            fmd.stateFieldNo, pc, getPm(),
1570                            oid));
1571                }
1572            }
1573        }
1574
1575        unManage();
1576        getPm().removeTxStateObject(this);
1577    }
1578
1579    public void makeTransactional() {
1580        /**
1581         * This first case cover both ds and optimistic tx.
1582         * For ds the state is cleaned and for optimistic tx
1583         * the refresh depends on the user.
1584         */

1585        if (((stateM ^ STATE_P_NON_TX) == 0)) {
1586            if (!getPm().isOptimistic()) {
1587                changeToHollowState(true);
1588            } else {
1589                updateDfgFieldMediation();
1590            }
1591            stateM = STATE_P_CLEAN;
1592            getPm().addTxStateObject(this);
1593            return;
1594        } else if (((stateM ^ STATE_TRANSIENT) == 0)) {
1595            stateM = STATE_T_CLEAN;
1596        }
1597    }
1598
1599    /**
1600     * Update the mediation of dfg fields. This method should be called when
1601     * transitioning from p-non-tx to a tx state.
1602     */

1603    private void updateDfgFieldMediation() {
1604        if (dfgLoaded) {
1605            //must reset the dfg field mediation.
1606
jdoFlags = PersistenceCapable.READ_OK;
1607            pc.jdoReplaceFlags();
1608        }
1609    }
1610
1611    public void makeNonTransactional() {
1612        if (isDirty()) {
1613            throw BindingSupportImpl.getInstance().invalidOperation(
1614                    "A Dirty instance may not be made NonTransactional");
1615        }
1616        if (isTClean()) {
1617            changeToTransient(EVENT_COMMIT);
1618        } else if (isPClean()) {
1619            stateM = STATE_P_NON_TX;
1620        }
1621    }
1622
1623    /**
1624     * The idea behind refresh is to reload the already loaded data from the server.
1625     * This is mostly needed for optismistic transactions to minimize the concurrent
1626     * updates.
1627     * <p/>
1628     * The only state change that occurs is for P-Dirty instances that change to
1629     * P-Clean.
1630     * <p/>
1631     * This call is a no-op for all new instances, because there is nothing to
1632     * relaod from the server.
1633     * Hollow instances are also an no-op because nothing has been fetched.
1634     * <p/>
1635     * For all the rest this is a relead of the currently loaded fields.
1636     */

1637    public void refresh() {
1638        /**
1639         * All new instances are no-ops because there is nothing in the store
1640         * to refresh from.
1641         */

1642        if (isNew()) {
1643            return;
1644        } else {
1645            if (getPm().isActive()) {
1646                if (((stateM ^ STATE_P_DIRTY) == 0)) {
1647                    if (getPm().isOptimistic()) {
1648                        stateM = STATE_P_NON_TX;
1649                    } else {
1650                        stateM = STATE_P_CLEAN;
1651                    }
1652                    getPm().addTxStateObject(this);
1653                }
1654            }
1655            changeToHollowState(true);
1656            getPm().getStateForRefresh(this.oid,
1657                    classMetaData.fetchGroups[0].sendFieldsOnFetch ? getForReadState() : null,
1658                    0);
1659        }
1660    }
1661
1662    /**
1663     * Check the model consistency of all of the fields in our State.
1664     * This currently only makes sure that bidirectional relationships have
1665     * been properly completed but other checks may be added in future.
1666     */

1667    public void checkModelConsistency() {
1668        if (isDeleted()) return;
1669        FieldMetaData[] fields = classMetaData.fields;
1670        for (int fieldNo = 0; fieldNo < fields.length; fieldNo++) {
1671            FieldMetaData fmd = fields[fieldNo];
1672            if (fmd.isMaster) { // one side of one-to-many
1673
checkOneToManyMaster(fieldNo);
1674            } else if (fmd.isDetail) { // many side of one-to-many
1675
checkOneToManyDetail(fieldNo);
1676            } else if (fmd.isManyToMany) {
1677                checkManyToMany(fieldNo);
1678            }
1679        }
1680    }
1681
1682    /**
1683     * Check the one side of a one-to-many. Make sure that all of the details
1684     * added to the collection have the correct master set.
1685     */

1686    private void checkOneToManyMaster(int fieldNo) {
1687        FieldMetaData fmd = classMetaData.fields[fieldNo];
1688        VersantPersistenceManagerImp realPM = getPm();
1689        Collection JavaDoc col = (Collection JavaDoc)state.getObjectField(fmd.stateFieldNo,
1690                pc, getPm(), oid);
1691        if (col == null) return;
1692        // check that all of the objects in col have us as the master
1693
int index = 0;
1694        for (Iterator JavaDoc i = col.iterator(); i.hasNext(); index++) {
1695            Object JavaDoc detail = i.next();
1696            if (detail == null) {
1697                throw BindingSupportImpl.getInstance().runtime("Inconsistent one-to-many: " +
1698                        "null object at index " + index + " in collection " + fmd.getQName() +
1699                        " on " + toErrString(oid, pc));
1700            }
1701            PCStateMan detailSM = realPM.getInternalSM(
1702                    (PersistenceCapable)detail);
1703            if (detailSM.isDeleted()) {
1704                throw BindingSupportImpl.getInstance().runtime("Inconsistent one-to-many: " +
1705                        "deleted object " + toErrString(detailSM.oid, null) +
1706                        " at index " + index + " in collection " + fmd.getQName() +
1707                        " on " + toErrString(oid, pc));
1708            }
1709            if (fmd.inverseFieldMetaData.fake) return;
1710            Object JavaDoc master = detailSM.getObjectField(null, fmd.inverseFieldNo,
1711                    null);
1712            if (master != pc) {
1713                StringBuffer JavaDoc s = new StringBuffer JavaDoc();
1714                s.append("Inconsistent one-to-many: object ");
1715                s.append(toErrString(detailSM.oid, detailSM.pc));
1716                s.append(" at index ");
1717                s.append(index);
1718                s.append(" in collection ");
1719                s.append(fmd.getQName());
1720                s.append(" on ");
1721                s.append(toErrString(oid, pc));
1722                if (master == null) {
1723                    s.append(" has null ");
1724                } else {
1725                    s.append(" has wrong ");
1726                }
1727                s.append(fmd.inverseFieldMetaData.getQName());
1728                if (master != null) {
1729                    s.append(' ');
1730                    PCStateMan masterSM = realPM.getInternalSM(
1731                            (PersistenceCapable)master);
1732                    s.append(toErrString(masterSM.oid, master));
1733                }
1734                throw BindingSupportImpl.getInstance().runtime(s.toString());
1735            }
1736        }
1737    }
1738
1739    /**
1740     * Check the many side of a one-to-many. Make sure that the master has
1741     * been set correctly and that the master has us in its list of details.
1742     */

1743    private void checkOneToManyDetail(int fieldNo) {
1744        FieldMetaData fmd = classMetaData.fields[fieldNo];
1745        VersantPersistenceManagerImp realPM = getPm();
1746        Object JavaDoc master = state.getObjectField(fmd.stateFieldNo, pc, getPm(),
1747                oid);
1748        if (master == null) {
1749            if (fmd.nullValue == MDStatics.NULL_VALUE_EXCEPTION) {
1750                throw BindingSupportImpl.getInstance().runtime("Inconsistent one-to-many: " +
1751                        "'many' object " + toErrString(oid, pc) + " field " +
1752                        fmd.getQName() + " is null");
1753            }
1754            // the master not set case is caught in checkOneToManyMaster
1755
// as it is ok to have a null master if the detail
1756
// is not part of any master's collection
1757
return;
1758        }
1759        if (master instanceof OID) {
1760            try {
1761                master = realPM.getObjectById(master, true);
1762            } catch (RuntimeException JavaDoc e) {
1763                if (BindingSupportImpl.getInstance().isOwnException(e)) {
1764                    throw BindingSupportImpl.getInstance().runtime("Inconsistent one-to-many: " +
1765                            "'many' object " + toErrString(oid, pc) + " field " +
1766                            fmd.getQName() + " references invalid 'one' object: " +
1767                            e.getMessage(), e);
1768                } else {
1769                    throw e;
1770                }
1771            }
1772        }
1773        PCStateMan masterSM = realPM.getInternalSM((PersistenceCapable)master);
1774// if(fmd.inverseFieldMetaData.fake)return;
1775
Object JavaDoc o = masterSM.getObjectField(null, fmd.inverseFieldNo, null);
1776        if (o instanceof Collection JavaDoc) {
1777            if (!((Collection JavaDoc)o).contains(pc)) {
1778                throw BindingSupportImpl.getInstance().runtime("Inconsistent one-to-many: " +
1779                        "'many' object " + toErrString(oid, pc) +
1780                        " is not in collection on 'one' instance " +
1781                        toErrString(masterSM.oid, masterSM.pc) + " " +
1782                        fmd.inverseFieldMetaData.getQName());
1783            }
1784        } else {
1785            PersistenceCapable[] pcs = (PersistenceCapable[])o;
1786            boolean contains = false;
1787            for (int i = 0; i < pcs.length; i++) {
1788                PersistenceCapable persistenceCapable = pcs[i];
1789                if (persistenceCapable == pc) {
1790                    contains = true;
1791                    break;
1792                }
1793            }
1794            if (!contains) {
1795                throw BindingSupportImpl.getInstance().runtime("Inconsistent one-to-many: " +
1796                        "'many' object " + toErrString(oid, pc) +
1797                        " is not in collection on 'one' instance " +
1798                        toErrString(masterSM.oid, masterSM.pc) + " " +
1799                        fmd.inverseFieldMetaData.getQName());
1800            }
1801        }
1802    }
1803
1804    /**
1805     * Check a many-to-many. Make sure that each collection is the inverse
1806     * of the other.
1807     */

1808    private void checkManyToMany(int fieldNo) {
1809        FieldMetaData fmd = classMetaData.fields[fieldNo];
1810        VersantPersistenceManagerImp realPM = getPm();
1811        Collection JavaDoc col = (Collection JavaDoc)state.getObjectField(fmd.stateFieldNo,
1812                pc, getPm(), oid);
1813        if (col == null) return;
1814        // check that all of the objects in col have us in their own col
1815
int index = 0;
1816        for (Iterator JavaDoc i = col.iterator(); i.hasNext(); index++) {
1817            Object JavaDoc other = i.next();
1818            if (other == null) {
1819                throw BindingSupportImpl.getInstance().runtime("Inconsistent many-to-many: " +
1820                        "null object at index " + index + " in collection " + fmd.getQName() +
1821                        " on " + toErrString(oid, pc));
1822            }
1823            PCStateMan otherSM = realPM.getInternalSM(
1824                    (PersistenceCapable)other);
1825            if (otherSM.isDeleted()) {
1826                throw BindingSupportImpl.getInstance().runtime("Inconsistent many-to-many: " +
1827                        "deleted object " + toErrString(otherSM.oid, null) +
1828                        " at index " + index + " in collection " + fmd.getQName() +
1829                        " on " + toErrString(oid, pc));
1830            }
1831            Collection JavaDoc otherCol = (Collection JavaDoc)otherSM.getObjectField(null,
1832                    fmd.inverseFieldNo, null);
1833            if (!otherCol.contains(pc)) {
1834                throw BindingSupportImpl.getInstance().runtime("Inconsistent many-to-many: " +
1835                        "object " + toErrString(oid, pc) + " at index " + index +
1836                        "in collection " + fmd.getQName() + " contains " +
1837                        toErrString(otherSM.oid, otherSM.pc) + " but " +
1838                        fmd.inverseFieldMetaData.getQName() +
1839                        " does not contain it");
1840            }
1841        }
1842    }
1843
1844    /**
1845     * Format an oid and its associated pc instance (can be null) into a nice
1846     * String for error messages.
1847     */

1848    private static String JavaDoc toErrString(OID oid, Object JavaDoc pc) {
1849        StringBuffer JavaDoc s = new StringBuffer JavaDoc();
1850        s.append('[');
1851        if (oid.isNew()) {
1852            s.append("new");
1853        } else {
1854            s.append(oid.toStringImp());
1855        }
1856        if (pc != null) {
1857            s.append(' ');
1858            s.append(Utils.toString(pc));
1859        }
1860        s.append(']');
1861        return s.toString();
1862    }
1863
1864    /**
1865     * If the PC instance implements InstanceCallbacks and has not been deleted
1866     * then call its jdoPreStore method and also invoke the store lifecycle
1867     * callback if listeners is not null. Returns true if jdoPreStore was
1868     * called or there were store listeners.
1869     */

1870    public boolean doJDOPreStore(LifecycleListenerManager listeners) {
1871        if ((stateM & MASK_DELETE) == 0) {
1872            boolean ans = listeners != null && listeners.firePreStore(pc);
1873            if (instanceCallbacks != null) {
1874
1875                instanceCallbacks.jdoPreStore();
1876
1877
1878                return true;
1879            }
1880            return ans;
1881        }
1882        return false;
1883    }
1884
1885    /**
1886     * This is called on all transactional objects so that they can prepare for
1887     * the commit or flush. If the state was deleted it will call add itself
1888     * to the list of instances to be deleted etc.
1889     */

1890    public void prepareCommitOrFlush(boolean commit) {
1891        addToProcessList();
1892        /**
1893         * Add all the instance that must be deleted to the toBeDeleted collection.
1894         * If the oid is new then it must not be added because it is not in the db and therefore
1895         * not to be removed.
1896         */

1897        if (isDeleted()) {
1898            addForDelete();
1899            //ignore
1900
} else if (isDirty()) {
1901
1902            // If delete-orphans is true and this class contains refs used to
1903
// complete collections mapped using a foreign key in the element
1904
// class and all of these references are null and we are doing
1905
// a commit then delete this instance.
1906
if (commit && classMetaData.deleteOrphans
1907                    && classMetaData.fkCollectionRefStateFieldNos != null) {
1908                int[] a = classMetaData.fkCollectionRefStateFieldNos;
1909                int i;
1910                for (i = a.length - 1; i >= 0; i--) {
1911                    int sno = a[i];
1912                    if (!state.containsField(sno) || !state.isNull(sno)) break;
1913                }
1914                if (i < 0) {
1915                    deletePersistent();
1916                    addForDelete();
1917                    return;
1918                }
1919            }
1920            preparedStatus = 1;
1921
1922            // clear transactional fields if this is a commit
1923
if (commit) state.clearTransactionNonPersistentFields();
1924
1925            VersantPersistenceManagerImp realPM = getPm();
1926            State toStoreState = createToStoreState();
1927            boolean isNew = oid.isNew();
1928
1929            if (!oid.isResolved()) oid.resolve(state);
1930            origState.clearCollectionFields();
1931
1932            // If nothing is copied to toStoreState then only transactional
1933
// fields were dirty. If this is a commit and the instance is new
1934
// then persist it anyway.
1935
if (!state.fillToStoreState(toStoreState, realPM, this)
1936                    && (!commit || !isNew)) {
1937                return;
1938            }
1939            addToStoreOidContainer(toStoreState, realPM, isNew);
1940        }
1941    }
1942
1943    private void addToStoreOidContainer(State toStoreState,
1944            VersantPersistenceManagerImp realPM, boolean aNew) {
1945        if (doChangeChecking) {
1946            if (origState != null) origState.clearNonFilled(toStoreState);
1947            realPM.storeOidStateContainer.add(oid, toStoreState,
1948                    origState,
1949                    aNew && classMetaData.postInsertKeyGenerator);
1950        } else {
1951            if (aNew) {
1952                realPM.storeOidStateContainer.add(oid, toStoreState, null,
1953                        aNew && classMetaData.postInsertKeyGenerator);
1954            } else {
1955                realPM.storeOidStateContainer.add(oid, toStoreState,
1956                        origState,
1957                        aNew && classMetaData.postInsertKeyGenerator);
1958            }
1959        }
1960        preparedStatus = 2;
1961    }
1962
1963    private void addForDelete() {
1964        if (!oid.isNew() && !addedForDelete) {
1965            // The forReadState must have been previously filled with whatever
1966
// needs to be sent back to the server with the OID.
1967
if (oid.getAvailableClassMetaData() == null) {
1968                // create a typed OID as untyped OIDs cannot be deleted
1969
OID o = classMetaData.createOID(true);
1970                o.setLongPrimaryKey(oid.getLongPrimaryKey());
1971                getPm().addForDelete(o, forReadState);
1972            } else {
1973                getPm().addForDelete(oid, forReadState);
1974            }
1975            addedForDelete = true;
1976        }
1977    }
1978
1979    public String JavaDoc toString() {
1980        return "SM@" + System.identityHashCode(this) + " "
1981                + (oid == null ? "null" : oid.toStringImp())
1982                + " cacheKey: " + (cacheEntry == null ? "NULL" : cacheEntry.toString())
1983                + " inProcessList: " + pm.getRealPM().getCache().inProcessList(this);
1984    }
1985
1986    /**
1987     * This is called after the server side commit is done. This will ensure
1988     * that the instance changes to the correct state.
1989     */

1990    private void commitImp(VersantPersistenceManagerImp rpm) {
1991        try {
1992            switch (stateM) {
1993                case STATE_TRANSIENT:
1994                    break;
1995                case STATE_T_CLEAN:
1996                    break;
1997                case STATE_T_DIRTY:
1998                    stateM = STATE_T_CLEAN;
1999                    if (beforeState != null) beforeState.clear();
2000                    if (toStoreState != null) toStoreState.clear();
2001                    break;
2002                case STATE_HOLLOW:
2003                    break;
2004                case STATE_P_NEW:
2005                    changeTmpOIDToRealOID();
2006                case STATE_P_CLEAN:
2007                case STATE_P_DIRTY:
2008                    if (rpm.isRetainValues()) {
2009                        if (!toBeEvictedFlag) {
2010                            changeToPNonTxForCommit(rpm);
2011                        } else {
2012                            changeToHollowState();
2013                            cacheEntry.changeToRefType(jdoManagedCache.queue,
2014                                    VersantPersistenceManager.PM_CACHE_REF_TYPE_WEAK);
2015                        }
2016                    } else {
2017                        changeToHollowState();
2018                        if (toBeEvictedFlag) {
2019                            cacheEntry.changeToRefType(jdoManagedCache.queue,
2020                                    VersantPersistenceManager.PM_CACHE_REF_TYPE_WEAK);
2021                        }
2022                    }
2023                    if (beforeState != null) beforeState.clear();
2024                    if (toStoreState != null) toStoreState.clear();
2025                    break;
2026                case STATE_P_DEL:
2027                case STATE_P_NEW_DEL:
2028                    state = createStateImp();
2029                    deleteImpForCommit();
2030                    break;
2031                default:
2032                    throw BindingSupportImpl.getInstance().internal(
2033                            "The state is unreachable");
2034            }
2035        } finally {
2036            clearTxFlags();
2037        }
2038    }
2039
2040    private void clearTxFlags() {
2041        addedForDelete = false;
2042        readInTx = false;
2043        toBeEvictedFlag = false;
2044        preparedStatus = 0;
2045    }
2046
2047    public void flushCommit() {
2048        switch (stateM) {
2049            case STATE_TRANSIENT:
2050                break;
2051            case STATE_T_CLEAN:
2052                break;
2053            case STATE_T_DIRTY:
2054                break;
2055            case STATE_HOLLOW:
2056                break;
2057            case STATE_P_NEW:
2058                changeTmpOIDToRealOID();
2059            case STATE_P_CLEAN:
2060            case STATE_P_DIRTY:
2061                this.state.makeClean();
2062                replaceSCOFields();
2063                break;
2064            case STATE_P_DEL:
2065            case STATE_P_NEW_DEL:
2066                break;
2067            default:
2068                throw BindingSupportImpl.getInstance().internal(
2069                        "The state is unreachable");
2070        }
2071    }
2072
2073    public void updateAutoFields(State autoS) {
2074        if (classMetaData.hasAutoSetFields) {
2075            this.state.updateFrom(autoS);
2076            this.origState.updateFrom(autoS);
2077        }
2078    }
2079
2080    /**
2081     * Helper method for commit to do work for deleting an instance. This must remove all
2082     * resources held by this instance.
2083     */

2084    public void deleteImpForCommit() {
2085        changeToTransient(EVENT_COMMIT);
2086    }
2087
2088    /**
2089     * This changes the current 'new' oid to an actual oid retrieved from the store. This is
2090     * called as part of a commit from a PNew state.
2091     */

2092    private void changeTmpOIDToRealOID() {
2093        if (!oid.isNew()) return;
2094        if (cacheEntry.mappedOID != oid.getRealOID()) {
2095            jdoManagedCache.addRealOID(this);
2096        }
2097        this.oid = this.oid.getRealOID();
2098        replaceApplicationPKFields();
2099    }
2100
2101    /**
2102     * This is called from commit and retainValues is set.
2103     * The state must be P-Non-Tx after this.
2104     */

2105    public void changeToPNonTxForCommit(VersantPersistenceManagerImp rpm) {
2106        stateM = STATE_P_NON_TX;
2107        dfgLoaded = false;
2108        setLoadRequired();
2109        resetLoadedFields();
2110        this.state.makeClean();
2111
2112        replaceSCOFields();
2113
2114        if (doChangeChecking) {
2115            this.origState.clear();
2116            maintainOrigState(state, rpm);
2117        } else {
2118            this.origState.clear();
2119        }
2120        toBeEvictedFlag = false;
2121    }
2122
2123    /**
2124     * Make all PC instances referenced by us persistent. This is called by
2125     * the PM on makePersistent and commit as part of the reachability
2126     * search.<p>
2127     */

2128    public void addRefs() {
2129        state.addRefs(getPm(), this);
2130    }
2131
2132    /**
2133     * This is currently only called for an instance that transitioned from new to
2134     * persistent but is a good method to call if a application pk has changed.
2135     * <p/>
2136     * This is called from the commit method after the new oid is received for
2137     * the state.
2138     */

2139    private final void replaceApplicationPKFields() {
2140        if (classMetaData.identityType != MDStatics.IDENTITY_TYPE_APPLICATION) return;
2141        this.state.copyFields(oid);
2142        pc.jdoReplaceFields(classMetaData.pkFieldNos);
2143    }
2144
2145    public byte replacingFlags(PersistenceCapable pc) {
2146        return jdoFlags;
2147    }
2148
2149    public StateManager replacingStateManager(PersistenceCapable pc,
2150            StateManager sm) {
2151        /**
2152         * The instance is transitioning to transient.
2153         */

2154        if (stateM == STATE_TRANSIENT) {
2155            return null;
2156        }
2157        return sm;
2158    }
2159
2160//==============================state checks====================================
2161

2162    public boolean isDirty(PersistenceCapable pc) {
2163        return ((stateM & MASK_DIRTY) != 0);
2164    }
2165
2166    public boolean isTransactional(PersistenceCapable pc) {
2167        return ((stateM & MASK_TX) != 0);
2168    }
2169
2170    public boolean isPersistent(PersistenceCapable pc) {
2171        return ((stateM & MASK_PERSISTENT) != 0);
2172    }
2173
2174    public boolean isNew(PersistenceCapable pc) {
2175        return ((stateM & MASK_NEW) != 0);
2176    }
2177
2178    public boolean isDeleted(PersistenceCapable pc) {
2179        return ((stateM & MASK_DELETE) != 0);
2180    }
2181
2182//==============================================================================
2183

2184    public PersistenceManager getPersistenceManager(PersistenceCapable pc) {
2185        getPm().requestedPCState = this;
2186        return pm;
2187    }
2188
2189    public void makeDirty(PersistenceCapable pc, String JavaDoc fieldName) {
2190        try {
2191            final FieldMetaData fmd = oid.getClassMetaData().getFieldMetaData(
2192                    fieldName);
2193            doWrite(fmd, false);
2194            state.makeDirtyAbs(fmd.managedFieldNo);
2195        } catch (Exception JavaDoc e) {
2196            handleException(e);
2197        }
2198    }
2199
2200    public void makeDirty(PersistenceCapable persistenceCapable, int fieldNo) {
2201        try {
2202            doWrite(getFMD(fieldNo), false);
2203            state.makeDirtyAbs(fieldNo);
2204        } catch (Exception JavaDoc e) {
2205            handleException(e);
2206        }
2207    }
2208
2209    /**
2210     * Get the LOID of this instance. This should only be called for classes
2211     * stored in VDS. This will assign it real LOID if it does not already
2212     * have one.
2213     */

2214    public long getLOID() {
2215        return getRealOID().getLongPrimaryKey();
2216    }
2217
2218    public Object JavaDoc getObjectId(PersistenceCapable pcParam) {
2219        try {
2220            if (classMetaData.identityType == MDStatics.IDENTITY_TYPE_DATASTORE) {
2221                return new VersantOid(this, jmd, oid.isResolved());
2222            } else if (classMetaData.identityType == MDStatics.IDENTITY_TYPE_APPLICATION) {
2223                if (oid.isNew() && classMetaData.postInsertKeyGenerator) {
2224                    getPm().flushRetainState();
2225                }
2226                // If this is called directly after a commit with retain values to false
2227
// then the state does not contiain any field and hence
2228
if (oid.isNew()) {
2229                    if (classMetaData.useKeyGen) {
2230                        NewObjectOID newOID = (NewObjectOID)oid;
2231                        if (newOID.realOID == null) {
2232                            newOID.realOID = getPm().getStorageManager().createOID(
2233                                    classMetaData);
2234                            newOID.realOID.getClassMetaData();
2235                            jdoManagedCache.addRealOID(this);
2236                            state.copyFields(newOID.realOID);
2237                            pc.jdoReplaceFields(classMetaData.pkFieldNos);
2238                        }
2239                    } else {
2240                        NewObjectOID newOID = (NewObjectOID)oid;
2241                        if (newOID.realOID == null) {
2242                            newOID.realOID = classMetaData.createOID(true);
2243                            newOID.realOID.getClassMetaData();
2244                            state.copyKeyFields(newOID.realOID);
2245                            jdoManagedCache.addRealOID(this);
2246                        }
2247                    }
2248                }
2249                Object JavaDoc pcID = pc.jdoNewObjectIdInstance();
2250                pc.jdoCopyKeyFieldsToObjectId(pcID);
2251                return pcID;
2252            } else {
2253                throw BindingSupportImpl.getInstance().internal("Unknown identity type: '" + classMetaData.identityType +
2254                        "' for " + classMetaData.qname);
2255            }
2256        } catch (Exception JavaDoc e) {
2257            handleException(e);
2258            return null; // keep compiler happy
2259
}
2260    }
2261
2262    /**
2263     * This is called from VersantOid if it need the
2264     */

2265    public OID getRealOID() {
2266        try {
2267            if (classMetaData.identityType == MDStatics.IDENTITY_TYPE_DATASTORE) {
2268                if (oid.isNew()) {
2269                    NewObjectOID newOID = (NewObjectOID)oid;
2270                    OID realOid = newOID.realOID;
2271                    if (realOid == null) {
2272                        if (oid.isNew() && classMetaData.postInsertKeyGenerator) {
2273                            getPm().flushRetainState();
2274                        }
2275                        newOID.realOID = realOid = getPm().getStorageManager().createOID(
2276                                classMetaData);
2277                        realOid.resolve(state);
2278                        realOid.getClassMetaData();
2279                        jdoManagedCache.addRealOID(this);
2280                    }
2281                    return newOID.realOID;
2282                }
2283                return oid;
2284            } else {
2285                throw BindingSupportImpl.getInstance().internal("This method should only be " +
2286                        "called for DataStore identity");
2287            }
2288        } catch (Exception JavaDoc e) {
2289            handleException(e);
2290            return null;
2291        }
2292    }
2293
2294    public Object JavaDoc getTransactionalObjectId(PersistenceCapable pc) {
2295        return getObjectId(pc);
2296    }
2297
2298    /**
2299     * This will only load the fields for the pc instance. It does not force aload and not any reachable pc instances.
2300     *
2301     * @param pc
2302     */

2303    public void preSerialize(PersistenceCapable pc) {
2304        loadAllPersistentFieldsToPC(getPm());
2305    }
2306
2307//==============================getXXXFields====================================
2308

2309    public boolean getBooleanField(PersistenceCapable pc, int field,
2310            boolean currentValue) {
2311        try {
2312            return getBooleanFieldImp(pc, getFMD(field), currentValue);
2313        } catch (Exception JavaDoc e) {
2314            handleException(e);
2315        }
2316        return false;
2317    }
2318
2319    public boolean getBooleanFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2320            boolean currentValue) {
2321        try {
2322            doRead(fmd);
2323            return state.getBooleanField(fmd.stateFieldNo);
2324        } catch (Exception JavaDoc e) {
2325            handleException(e);
2326        }
2327        return false;
2328    }
2329
2330    public char getCharField(PersistenceCapable pc, int field,
2331            char currentValue) {
2332        try {
2333            return getCharFieldImp(pc, getFMD(field), currentValue);
2334        } catch (Exception JavaDoc e) {
2335            handleException(e);
2336        }
2337        return 0;
2338    }
2339
2340    public char getCharFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2341            char currentValue) {
2342        try {
2343            doRead(fmd);
2344            return state.getCharField(fmd.stateFieldNo);
2345        } catch (Exception JavaDoc e) {
2346            handleException(e);
2347        }
2348        return 0;
2349    }
2350
2351    public byte getByteField(PersistenceCapable pc, int field,
2352            byte currentValue) {
2353        try {
2354            return getByteFieldImp(pc, getFMD(field), currentValue);
2355        } catch (Exception JavaDoc e) {
2356            handleException(e);
2357        }
2358        return 0;
2359    }
2360
2361    public byte getByteFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2362            byte currentValue) {
2363        try {
2364            doRead(fmd);
2365            return state.getByteField(fmd.stateFieldNo);
2366        } catch (Exception JavaDoc e) {
2367            handleException(e);
2368        }
2369        return 0;
2370    }
2371
2372    public short getShortField(PersistenceCapable pc, int field,
2373            short currentValue) {
2374        try {
2375            return getShortFieldImp(pc, getFMD(field), currentValue);
2376        } catch (Exception JavaDoc e) {
2377            handleException(e);
2378        }
2379        return 0;
2380    }
2381
2382    public short getShortFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2383            short currentValue) {
2384        try {
2385            doRead(fmd);
2386            return state.getShortField(fmd.stateFieldNo);
2387        } catch (Exception JavaDoc e) {
2388            handleException(e);
2389        }
2390        return 0;
2391    }
2392
2393    public int getIntField(PersistenceCapable pc, int field, int currentValue) {
2394        try {
2395            return getIntFieldImp(pc, getFMD(field), currentValue);
2396        } catch (Exception JavaDoc e) {
2397            handleException(e);
2398        }
2399        return 0;
2400    }
2401
2402    public int getIntFieldImp(PersistenceCapable pc, FieldMetaData fmd, int currentValue) {
2403        try {
2404            doRead(fmd);
2405            return state.getIntField(fmd.stateFieldNo);
2406        } catch (Exception JavaDoc e) {
2407            handleException(e);
2408        }
2409        return 0;
2410    }
2411
2412    public float getFloatField(PersistenceCapable pc, int field,
2413            float currentValue) {
2414        try {
2415            return getFloatFieldImp(pc, getFMD(field), currentValue);
2416        } catch (Exception JavaDoc e) {
2417            handleException(e);
2418        }
2419        return 0;
2420    }
2421
2422    public float getFloatFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2423            float currentValue) {
2424        try {
2425            doRead(fmd);
2426            return state.getFloatField(fmd.stateFieldNo);
2427        } catch (Exception JavaDoc e) {
2428            handleException(e);
2429        }
2430        return 0;
2431    }
2432
2433    public double getDoubleField(PersistenceCapable pc, int field,
2434            double currentValue) {
2435        try {
2436            return getDoubleFieldImp(pc, getFMD(field), currentValue);
2437        } catch (Exception JavaDoc e) {
2438            handleException(e);
2439        }
2440        return 0;
2441    }
2442    public double getDoubleFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2443            double currentValue) {
2444        try {
2445            doRead(fmd);
2446            return state.getDoubleField(fmd.stateFieldNo);
2447        } catch (Exception JavaDoc e) {
2448            handleException(e);
2449        }
2450        return 0;
2451    }
2452
2453    public long getLongField(PersistenceCapable pc, int field,
2454            long currentValue) {
2455        try {
2456            return getLongFieldImp(pc, getFMD(field), currentValue);
2457        } catch (Exception JavaDoc e) {
2458            handleException(e);
2459        }
2460        return 0;
2461    }
2462
2463    public long getLongFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2464            long currentValue) {
2465        try {
2466            doRead(fmd);
2467            return state.getLongField(fmd.stateFieldNo);
2468        } catch (Exception JavaDoc e) {
2469            handleException(e);
2470        }
2471        return 0;
2472    }
2473
2474    public String JavaDoc getStringField(PersistenceCapable pc, int field,
2475            String JavaDoc currentValue) {
2476       return getStringFieldImp(pc, getFMD(field), currentValue);
2477    }
2478
2479    public String JavaDoc getStringFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2480            String JavaDoc currentValue) {
2481        try {
2482            doRead(fmd);
2483            return state.getStringField(fmd.stateFieldNo);
2484        } catch (Exception JavaDoc e) {
2485            handleException(e);
2486        }
2487        return null;
2488    }
2489
2490    public Object JavaDoc getObjectField(PersistenceCapable pc, int field,
2491            Object JavaDoc currentValue) {
2492        return getObjectFieldImp(pc, getFMD(field), currentValue);
2493    }
2494
2495    public Object JavaDoc getObjectFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2496            Object JavaDoc currentValue) {
2497        try {
2498            StatesReturned nogc = doRead(fmd);
2499            // Keep a reference to the fetched States (if any) to make sure
2500
// they do not get GCed after being loaded into the local cache.
2501
// This is important for collections of PC and other fields that
2502
// involve fetching State instances and loading them into the local
2503
// cache. They are only hard referenced when the SCO instance has
2504
// been created by the next line.
2505
Object JavaDoc ans = state.getObjectField(fmd.stateFieldNo, this.pc, getPm(), oid);
2506            if (nogc == null) {
2507                // dummy code to keep IDE happy and to hopefully prevent
2508
// any overzealous optimization from removing nogc
2509
}
2510            return ans;
2511        } catch (Exception JavaDoc e) {
2512            handleException(e);
2513        }
2514        return null;
2515    }
2516//================================setXXXField===================================
2517

2518    public void setBooleanField(PersistenceCapable pc, int field,
2519            boolean currentValue, boolean newValue) {
2520        try {
2521            setBooleanFieldImp(pc, getFMD(field), currentValue, newValue);
2522            pc.jdoReplaceField(field);
2523        } catch (Exception JavaDoc e) {
2524            handleException(e);
2525        }
2526    }
2527
2528    public void setBooleanFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2529            boolean currentValue, boolean newValue) {
2530        try {
2531            if (isTransientManaged()) {
2532                state.setBooleanField(fmd.stateFieldNo, newValue);
2533                if (getPm().isActive()) {
2534                    stateM |= MASK_DIRTY;
2535                    setBeforeState(fmd, currentValue);
2536                }
2537                addToProcessList();
2538            } else {
2539                if (loadedFields[fmd.stateFieldNo] && newValue == currentValue) return;
2540                doWrite(fmd, false);
2541                state.setBooleanField(fmd.stateFieldNo, newValue);
2542                setBeforeState(fmd, currentValue);
2543            }
2544        } catch (Exception JavaDoc e) {
2545            handleException(e);
2546        }
2547    }
2548
2549    public void setCharField(PersistenceCapable pc, int field,
2550            char currentValue, char newValue) {
2551        try {
2552            setCharFieldImp(pc, getFMD(field), currentValue, newValue);
2553            pc.jdoReplaceField(field);
2554        } catch (Exception JavaDoc e) {
2555            handleException(e);
2556        }
2557    }
2558
2559    public void setCharFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2560            char currentValue, char newValue) {
2561        try {
2562            if (isTransientManaged()) {
2563                state.setCharField(fmd.stateFieldNo, newValue);
2564                if (getPm().isActive()) {
2565                    stateM |= MASK_DIRTY;
2566                    setBeforeState(fmd, currentValue);
2567                }
2568                addToProcessList();
2569            } else {
2570                if (loadedFields[fmd.stateFieldNo] && newValue == currentValue) return;
2571                doWrite(fmd, false);
2572                state.setCharField(fmd.stateFieldNo, newValue);
2573                setBeforeState(fmd, currentValue);
2574            }
2575        } catch (Exception JavaDoc e) {
2576            handleException(e);
2577        }
2578    }
2579
2580    public void setByteField(PersistenceCapable pc, int field,
2581            byte currentValue, byte newValue) {
2582        try {
2583            setByteFieldImp(pc, getFMD(field), currentValue, newValue);
2584            pc.jdoReplaceField(field);
2585        } catch (Exception JavaDoc e) {
2586            handleException(e);
2587        }
2588    }
2589
2590    public void setByteFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2591            byte currentValue, byte newValue) {
2592        try {
2593            if (isTransientManaged()) {
2594                state.setByteField(fmd.stateFieldNo, newValue);
2595                if (getPm().isActive()) {
2596                    stateM |= MASK_DIRTY;
2597                    setBeforeState(fmd, currentValue);
2598                }
2599                addToProcessList();
2600            } else {
2601                if (loadedFields[fmd.stateFieldNo] && newValue == currentValue) return;
2602                doWrite(fmd, false);
2603                state.setByteField(fmd.stateFieldNo, newValue);
2604                setBeforeState(fmd, currentValue);
2605            }
2606        } catch (Exception JavaDoc e) {
2607            handleException(e);
2608        }
2609    }
2610
2611    public void setShortField(PersistenceCapable pc, int field,
2612            short currentValue, short newValue) {
2613        try {
2614            setShortFieldImp(pc, getFMD(field), currentValue, newValue);
2615            pc.jdoReplaceField(field);
2616        } catch (Exception JavaDoc e) {
2617            handleException(e);
2618        }
2619    }
2620
2621    public void setShortFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2622            short currentValue, short newValue) {
2623        try {
2624            if (isTransientManaged()) {
2625                state.setShortField(fmd.stateFieldNo, newValue);
2626                if (getPm().isActive()) {
2627                    stateM |= MASK_DIRTY;
2628                    setBeforeState(fmd, currentValue);
2629                }
2630                addToProcessList();
2631            } else {
2632                if (loadedFields[fmd.stateFieldNo] && newValue == currentValue) return;
2633                doWrite(fmd, false);
2634                state.setShortField(fmd.stateFieldNo, newValue);
2635                setBeforeState(fmd, currentValue);
2636            }
2637        } catch (Exception JavaDoc e) {
2638            handleException(e);
2639        }
2640    }
2641
2642    public void setIntField(PersistenceCapable pc, int field, int currentValue,
2643            int newValue) {
2644        try {
2645            setIntFieldImp(pc, getFMD(field), currentValue, newValue);
2646            pc.jdoReplaceField(field);
2647        } catch (Exception JavaDoc e) {
2648            handleException(e);
2649        }
2650    }
2651
2652    public void setIntFieldImp(PersistenceCapable pc, FieldMetaData fmd, int currentValue,
2653            int newValue) {
2654        try {
2655            if (isTransientManaged()) {
2656                state.setIntField(fmd.stateFieldNo, newValue);
2657                if (getPm().isActive()) {
2658                    stateM |= MASK_DIRTY;
2659                    setBeforeState(fmd, currentValue);
2660                }
2661                addToProcessList();
2662            } else {
2663                if (loadedFields[fmd.stateFieldNo] && newValue == currentValue) return;
2664                doWrite(fmd, false);
2665                state.setIntField(fmd.stateFieldNo, newValue);
2666                setBeforeState(fmd, currentValue);
2667            }
2668        } catch (Exception JavaDoc e) {
2669            handleException(e);
2670        }
2671    }
2672
2673    public void setFloatField(PersistenceCapable pc, int field,
2674            float currentValue, float newValue) {
2675        try {
2676            setFloatFieldImp(pc, getFMD(field), currentValue, newValue);
2677            pc.jdoReplaceField(field);
2678        } catch (Exception JavaDoc e) {
2679            handleException(e);
2680        }
2681    }
2682
2683    public void setFloatFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2684            float currentValue, float newValue) {
2685        try {
2686            if (isTransientManaged()) {
2687                state.setFloatField(fmd.stateFieldNo, newValue);
2688                if (getPm().isActive()) {
2689                    stateM |= MASK_DIRTY;
2690                    setBeforeState(fmd, currentValue);
2691                }
2692                addToProcessList();
2693            } else {
2694                if (loadedFields[fmd.stateFieldNo] && newValue == currentValue) return;
2695                doWrite(fmd, false);
2696                state.setFloatField(fmd.stateFieldNo, newValue);
2697                setBeforeState(fmd, currentValue);
2698            }
2699        } catch (Exception JavaDoc e) {
2700            handleException(e);
2701        }
2702    }
2703
2704    public void setDoubleField(PersistenceCapable pc, int field,
2705            double currentValue, double newValue) {
2706        try {
2707            setDoubleFieldImp(pc, getFMD(field), currentValue, newValue);
2708            pc.jdoReplaceField(field);
2709        } catch (Exception JavaDoc e) {
2710            handleException(e);
2711        }
2712    }
2713
2714    public void setDoubleFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2715            double currentValue, double newValue) {
2716        try {
2717            if (isTransientManaged()) {
2718                state.setDoubleField(fmd.stateFieldNo, newValue);
2719                if (getPm().isActive()) {
2720                    stateM |= MASK_DIRTY;
2721                    setBeforeState(fmd, currentValue);
2722                }
2723                addToProcessList();
2724            } else {
2725                if (loadedFields[fmd.stateFieldNo] && newValue == currentValue) return;
2726                doWrite(fmd, false);
2727                state.setDoubleField(fmd.stateFieldNo, newValue);
2728                setBeforeState(fmd, currentValue);
2729            }
2730        } catch (Exception JavaDoc e) {
2731            handleException(e);
2732        }
2733    }
2734
2735    public void setLongField(PersistenceCapable pc, int field,
2736            long currentValue, long newValue) {
2737        try {
2738            setLongFieldImp(pc, getFMD(field), currentValue, newValue);
2739            pc.jdoReplaceField(field);
2740        } catch (Exception JavaDoc e) {
2741            throw BindingSupportImpl.getInstance().internal(e.getMessage(), e);
2742        }
2743    }
2744
2745    public void setLongFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2746            long currentValue, long newValue) {
2747        try {
2748            if (isTransientManaged()) {
2749                state.setLongField(fmd.stateFieldNo, newValue);
2750                if (getPm().isActive()) {
2751                    stateM |= MASK_DIRTY;
2752                    setBeforeState(fmd, currentValue);
2753                }
2754                addToProcessList();
2755            } else {
2756                if (loadedFields[fmd.stateFieldNo] && newValue == currentValue) return;
2757                doWrite(fmd, false);
2758                state.setLongField(fmd.stateFieldNo, newValue);
2759                setBeforeState(fmd, currentValue);
2760            }
2761        } catch (Exception JavaDoc e) {
2762            throw BindingSupportImpl.getInstance().internal(e.getMessage(), e);
2763        }
2764    }
2765
2766    public void setStringField(PersistenceCapable pc, int field,
2767            String JavaDoc currentValue, String JavaDoc newValue) {
2768        setStringFieldImp(pc, getFMD(field) , currentValue, newValue);
2769        pc.jdoReplaceField(field);
2770    }
2771
2772    public void setStringFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2773            String JavaDoc currentValue, String JavaDoc newValue) {
2774        try {
2775            if (isTransientManaged()) {
2776                state.setStringField(fmd.stateFieldNo, newValue);
2777                if (getPm().isActive()) {
2778                    stateM |= MASK_DIRTY;
2779                    setBeforeState(fmd, currentValue);
2780                }
2781                addToProcessList();
2782            } else {
2783                if (loadedFields[fmd.stateFieldNo] && newValue == currentValue) return;
2784                doWrite(fmd, false);
2785                state.setStringField(fmd.stateFieldNo, newValue);
2786                setBeforeState(fmd, currentValue);
2787            }
2788        } catch (Exception JavaDoc e) {
2789            handleException(e);
2790        }
2791    }
2792
2793    public void setObjectField(PersistenceCapable pc, int field,
2794            Object JavaDoc currentValue, Object JavaDoc newValue) {
2795        setObjectFieldImp(pc, getFMD(field), currentValue, newValue);
2796        pc.jdoReplaceField(field);
2797    }
2798
2799    public void setObjectFieldImp(PersistenceCapable pc, FieldMetaData fmd,
2800            Object JavaDoc currentValue, Object JavaDoc newValue) {
2801        try {
2802            if (isTransientManaged()) {
2803                state.setObjectField(fmd.stateFieldNo, newValue);
2804                if (getPm().isActive()) {
2805                    stateM |= MASK_DIRTY;
2806                    setBeforeState(fmd, currentValue);
2807                }
2808                addToProcessList();
2809            } else {
2810                if (loadedFields[fmd.stateFieldNo] && newValue == currentValue) return;
2811                doWrite(fmd, fmd.isDetail && fmd.managed);
2812                if (fmd.isDetail) {
2813                    PersistenceCapable currentMaster = (PersistenceCapable)getObjectFieldImp(
2814                            null, fmd, null);
2815                    VersantPersistenceManagerImp pm = getPm();
2816                    if (fmd.managed) {
2817                        int mastColFieldNo = fmd.inverseFieldNo;
2818                        if (currentMaster != null) {
2819                            PCStateMan masterSM = pm.getInternalSM(
2820                                    currentMaster);
2821                            if (masterSM.classMetaData.managedFields[mastColFieldNo].type.getComponentType() != null) {
2822                                PersistenceCapable[] pcs = (PersistenceCapable[])masterSM.getObjectField(
2823                                        null,
2824                                        mastColFieldNo, null);
2825                                if (pcs != null) {
2826                                    for (int i = 0; i < pcs.length; i++) {
2827                                        PersistenceCapable pcInst = pcs[i];
2828                                        if (pcInst == this.pc) {
2829                                            pcs[i] = null;
2830                                        }
2831                                    }
2832                                }
2833                            } else {
2834                                ((Collection JavaDoc)masterSM.getObjectField(null,
2835                                        mastColFieldNo, null)).remove(this.pc);
2836                            }
2837                        }
2838                        if (newValue != null) {
2839                            PersistenceCapable newMaster = (PersistenceCapable)newValue;
2840                            if (!newMaster.jdoIsPersistent()) {
2841                                this.pc.jdoGetPersistenceManager().makePersistent(
2842                                        newMaster);
2843                            }
2844                            PCStateMan masterSM = pm.getInternalSM(newMaster);
2845                            ((Collection JavaDoc)masterSM.getObjectField(null,
2846                                    mastColFieldNo, null)).add(this.pc);
2847                        }
2848                    } else {
2849                        // Make sure current master and new value is evicted
2850
// on commit.
2851
// This prevents stale data from remaining in the L2
2852
// cache when only the back reference is updated.
2853
if (currentMaster != null) {
2854                            pm.evictFromL2CacheAfterCommitImp(currentMaster);
2855                        }
2856                        if (newValue != null) {
2857                            pm.evictFromL2CacheAfterCommitImp(newValue);
2858                        }
2859                    }
2860                } else if (fmd.category == MDStatics.CATEGORY_COLLECTION
2861                        && fmd.inverseFieldMetaData != null
2862                        && fmd.inverseFieldMetaData.fake) {
2863                    if (!state.containsField(fmd.stateFieldNo)) {
2864                        FetchGroup fg = getFetchGroup(fmd.managedFieldNo);
2865                        getPm().getState(this.oid, fg.sendFieldsOnFetch ? getForReadState() : null,
2866                                fg.index, fmd.managedFieldNo, -1, false);
2867                    }
2868                    FieldMetaData inverseFieldMetaData = fmd.inverseFieldMetaData;
2869                    Object JavaDoc o = state.getInternalObjectField(fmd.stateFieldNo);
2870                    if (o != null) {
2871                        if (o instanceof VersantSimpleSCO) {
2872                            VersantPersistenceManagerImp rpm = getPm();
2873                            Collection JavaDoc col = (Collection JavaDoc)o;
2874                            for (Iterator JavaDoc iterator = col.iterator();
2875                                 iterator.hasNext();) {
2876                                PCStateMan detailSm = jdoManagedCache.getByOID(
2877                                        rpm.getInternalOID(
2878                                                (PersistenceCapable)iterator.next()),
2879                                        true);
2880                                detailSm.makeInternalDirty();
2881                                detailSm.state.setObjectField(
2882                                        inverseFieldMetaData.stateFieldNo,
2883                                        null);
2884                            }
2885                        } else {
2886                            Object JavaDoc[] oa = (Object JavaDoc[])o;
2887                            for (int i = 0; i < oa.length; i++) {
2888                                if (oa[i] == null) break;
2889                                PCStateMan detailSm = jdoManagedCache.getByOID(
2890                                        (OID)oa[i],
2891                                        true);
2892                                detailSm.makeInternalDirty();
2893                                detailSm.state.setObjectField(
2894                                        inverseFieldMetaData.stateFieldNo,
2895                                        null);
2896                            }
2897                        }
2898                    }
2899                }
2900                state.setObjectField(fmd.stateFieldNo, newValue);
2901                setBeforeState(fmd, currentValue);
2902            }
2903        } catch (Exception JavaDoc e) {
2904            handleException(e);
2905        }
2906    }
2907
2908    /**
2909     * This is called from managed SCO classes to ensure that the back
2910     * reference of a newly added detail is updated property. It is
2911     * not possible to just call setObject in this case as this will result
2912     * in an endless loop as setObject adds the detail to its master.
2913     * If removeFromCurrentMaster is true then this instance is removed
2914     * from its current master (if any and if different).
2915     */

2916    public void setMaster(int field, Object JavaDoc newMaster,
2917            boolean removeFromCurrentMaster) {
2918        try {
2919            Object JavaDoc currentMaster = getObjectField(null, field, null);
2920            if (loadedFields[field] && newMaster == currentMaster) return;
2921            doWrite(getFMD(field), false);
2922            if (removeFromCurrentMaster && currentMaster != null) {
2923                int mastColFieldNo = getFMD(field).inverseFieldNo;
2924                PCStateMan masterSM = getPm().getInternalSM(
2925                        (PersistenceCapable)currentMaster);
2926                ((Collection JavaDoc)masterSM.getObjectField(null,
2927                        mastColFieldNo, null)).remove(pc);
2928            }
2929            state.setObjectFieldAbs(field, newMaster);
2930            pc.jdoReplaceField(field);
2931            setBeforeState(getFMD(field), currentMaster);
2932        } catch (Exception JavaDoc e) {
2933            handleException(e);
2934        }
2935    }
2936
2937    /**
2938     * This is called from managed SCO classes to ensure that the back
2939     * reference of a newly added detail is updated property. It is
2940     * not possible to just call setObject in this case as this will result
2941     * in an endless loop as setObject adds the detail to its master.
2942     * If removeFromCurrentMaster is true then this instance is removed
2943     * from its current master (if any and if different).
2944     */

2945    public void setFakeMaster(int stateFieldNo, VersantStateManager master,
2946            boolean remove) {
2947        VersantPersistenceManagerImp rpm = getPm();
2948
2949        try {
2950            if (isPrepared()) {
2951                if (inToStoreList()) {
2952                    //already prepared so add oid to the tostorestate
2953
setOidOnState(toStoreState, stateFieldNo, master, remove);
2954                } else {
2955                    //prepared was called but no dirty fields was found
2956
//so prepare must be called again
2957
if (setOidOnState(state, stateFieldNo, master, remove)) {
2958                        state.fillToStoreState(toStoreState, rpm, this);
2959                    }
2960                    //must add to toStoreList
2961
addToStoreOidContainer(toStoreState, rpm,
2962                            master.getOID().isNew());
2963                }
2964            } else {
2965                setOidOnState(state, stateFieldNo, master, remove);
2966            }
2967            makeInternalDirty();
2968        } catch (Exception JavaDoc e) {
2969            handleException(e);
2970        }
2971    }
2972
2973    private boolean setOidOnState(State state, int stateFieldNo, VersantStateManager master,
2974            boolean remove) {
2975        if (state instanceof DeletedState) {
2976            return false;
2977        }
2978        if (remove) {
2979            Object JavaDoc o = state.getInternalObjectField(stateFieldNo);
2980            if (o != null && !o.equals(master.getOID()) && o != master.getPersistenceCapable()) {
2981                return false;
2982            }
2983        }
2984        if (remove) {
2985            state.setObjectField(stateFieldNo, null);
2986        } else {
2987            state.setObjectFieldUnresolved(stateFieldNo, master.getOID());
2988        }
2989        return true;
2990    }
2991
2992    private boolean inToStoreList() {
2993        return preparedStatus == 2;
2994    }
2995
2996    private boolean isPrepared() {
2997        return preparedStatus > 0;
2998    }
2999
3000//===================================providedXXXFields============================
3001

3002    public void providedBooleanField(PersistenceCapable pc, int field,
3003            boolean currentValue) {
3004        try {
3005            providedBooleanFieldImp(pc, getFMD(field), currentValue);
3006        } catch (Exception JavaDoc e) {
3007            handleException(e);
3008        }
3009    }
3010
3011    public void providedBooleanFieldImp(PersistenceCapable pc, FieldMetaData fmd,
3012            boolean currentValue) {
3013        try {
3014            state.setBooleanField(fmd.stateFieldNo, currentValue);
3015            setBeforeState(fmd, currentValue);
3016        } catch (Exception JavaDoc e) {
3017            handleException(e);
3018        }
3019    }
3020
3021    public void providedCharField(PersistenceCapable pc, int field,
3022            char currentValue) {
3023        try {
3024            providedCharFieldImp(pc, getFMD(field), currentValue);
3025        } catch (Exception JavaDoc e) {
3026            handleException(e);
3027        }
3028    }
3029
3030    public void providedCharFieldImp(PersistenceCapable pc, FieldMetaData fmd,
3031            char currentValue) {
3032        try {
3033            state.setCharField(fmd.stateFieldNo, currentValue);
3034            setBeforeState(fmd, currentValue);
3035        } catch (Exception JavaDoc e) {
3036            handleException(e);
3037        }
3038    }
3039
3040    public void providedByteField(PersistenceCapable pc, int field,
3041            byte currentValue) {
3042        try {
3043            providedByteFieldImp(pc, getFMD(field), currentValue);
3044        } catch (Exception JavaDoc e) {
3045            handleException(e);
3046        }
3047    }
3048
3049    public void providedByteFieldImp(PersistenceCapable pc, FieldMetaData fmd,
3050            byte currentValue) {
3051        try {
3052            state.setByteField(fmd.stateFieldNo, currentValue);
3053            setBeforeState(fmd, currentValue);
3054        } catch (Exception JavaDoc e) {
3055            handleException(e);
3056        }
3057    }
3058
3059    public void providedShortField(PersistenceCapable pc, int field,
3060            short currentValue) {
3061        try {
3062            providedShortFieldImp(pc, getFMD(field), currentValue);
3063        } catch (Exception JavaDoc e) {
3064            handleException(e);
3065        }
3066    }
3067
3068    public void providedShortFieldImp(PersistenceCapable pc, FieldMetaData fmd,
3069            short currentValue) {
3070        try {
3071            state.setShortField(fmd.stateFieldNo, currentValue);
3072            setBeforeState(fmd, currentValue);
3073        } catch (Exception JavaDoc e) {
3074            handleException(e);
3075        }
3076    }
3077
3078    public void providedIntField(PersistenceCapable pc, int field,
3079            int currentValue) {
3080        try {
3081            providedIntFieldImp(pc, getFMD(field), currentValue);
3082        } catch (Exception JavaDoc e) {
3083            handleException(e);
3084        }
3085    }
3086
3087    public void providedIntFieldImp(PersistenceCapable pc, FieldMetaData fmd,
3088            int currentValue) {
3089        try {
3090            state.setIntField(fmd.stateFieldNo, currentValue);
3091            setBeforeState(fmd, currentValue);
3092        } catch (Exception JavaDoc e) {
3093            handleException(e);
3094        }
3095    }
3096
3097    public void providedFloatField(PersistenceCapable pc, int field,
3098            float currentValue) {
3099        try {
3100            providedFloatFieldImp(pc, getFMD(field), currentValue);
3101        } catch (Exception JavaDoc e) {
3102            handleException(e);
3103        }
3104    }
3105
3106    public void providedFloatFieldImp(PersistenceCapable pc, FieldMetaData fmd,
3107            float currentValue) {
3108        try {
3109            state.setFloatField(fmd.stateFieldNo, currentValue);
3110            setBeforeState(fmd, currentValue);
3111        } catch (Exception JavaDoc e) {
3112            handleException(e);
3113        }
3114    }
3115
3116    public void providedDoubleField(PersistenceCapable pc, int field,
3117            double currentValue) {
3118        try {
3119            providedDoubleFieldImp(pc, getFMD(field), currentValue);
3120        } catch (Exception JavaDoc e) {
3121            handleException(e);
3122        }
3123    }
3124
3125    public void providedDoubleFieldImp(PersistenceCapable pc, FieldMetaData fmd,
3126            double currentValue) {
3127        try {
3128            state.setDoubleField(fmd.stateFieldNo, currentValue);
3129            setBeforeState(fmd, currentValue);
3130        } catch (Exception JavaDoc e) {
3131            handleException(e);
3132        }
3133    }
3134
3135    public void providedLongField(PersistenceCapable pc, int field,
3136            long currentValue) {
3137        try {
3138            providedLongFieldImp(pc, getFMD(field), currentValue);
3139        } catch (Exception JavaDoc e) {
3140            handleException(e);
3141        }
3142    }
3143
3144    public void providedLongFieldImp(PersistenceCapable pc, FieldMetaData fmd,
3145            long currentValue) {
3146        try {
3147            state.setLongField(fmd.stateFieldNo, currentValue);
3148            setBeforeState(fmd, currentValue);
3149        } catch (Exception JavaDoc e) {
3150            handleException(e);
3151        }
3152    }
3153
3154    public void providedStringField(PersistenceCapable pc, int field,
3155            String JavaDoc currentValue) {
3156        try {
3157            providedStringFieldImp(pc, getFMD(field), currentValue);
3158        } catch (Exception JavaDoc e) {
3159            handleException(e);
3160        }
3161    }
3162
3163    public void providedStringFieldImp(PersistenceCapable pc, FieldMetaData fmd,
3164            String JavaDoc currentValue) {
3165        try {
3166            state.setStringField(fmd.stateFieldNo, currentValue);
3167            setBeforeState(fmd, currentValue);
3168        } catch (Exception JavaDoc e) {
3169            handleException(e);
3170        }
3171    }
3172
3173    public void providedObjectField(PersistenceCapable pc, int field,
3174            Object JavaDoc currentValue) {
3175        providedObjectFieldImp(pc, getFMD(field), currentValue);
3176    }
3177
3178    public void providedObjectFieldImp(PersistenceCapable pc, FieldMetaData fmd,
3179            Object JavaDoc currentValue) {
3180        try {
3181            state.setObjectField(fmd.stateFieldNo, currentValue);
3182            setBeforeState(fmd, currentValue);
3183        } catch (Exception JavaDoc e) {
3184            handleException(e);
3185        }
3186    }
3187
3188//===================================replacingXXXFields============================
3189

3190    public boolean replacingBooleanField(final PersistenceCapable pc,
3191            final int field) {
3192        return replacingBooleanFieldImp(pc, getFMD(field));
3193    }
3194
3195    public boolean replacingBooleanFieldImp(final PersistenceCapable pc,
3196            FieldMetaData fmd) {
3197        try {
3198            setLoaded(fmd);
3199            return state.getBooleanField(fmd.stateFieldNo);
3200        } catch (Exception JavaDoc e) {
3201            handleException(e);
3202        }
3203        return false;
3204    }
3205
3206    public char replacingCharField(final PersistenceCapable pc,
3207            final int field) {
3208        return replacingCharFieldImp(pc, getFMD(field));
3209    }
3210
3211    public char replacingCharFieldImp(final PersistenceCapable pc,
3212            final FieldMetaData fmd) {
3213        try {
3214            setLoaded(fmd);
3215            return state.getCharField(fmd.stateFieldNo);
3216        } catch (Exception JavaDoc e) {
3217            handleException(e);
3218        }
3219        return 0;
3220    }
3221
3222    public byte replacingByteField(final PersistenceCapable pc,
3223            final int field) {
3224        return replacingByteFieldImp(pc, getFMD(field));
3225    }
3226
3227    public byte replacingByteFieldImp(final PersistenceCapable pc,
3228            final FieldMetaData fmd) {
3229        try {
3230            setLoaded(fmd);
3231            return state.getByteField(fmd.stateFieldNo);
3232        } catch (Exception JavaDoc e) {
3233            handleException(e);
3234        }
3235        return 0;
3236    }
3237
3238    public short replacingShortField(final PersistenceCapable pc,
3239            final int field) {
3240        return replacingShortFieldImp(pc, getFMD(field));
3241    }
3242
3243    public short replacingShortFieldImp(final PersistenceCapable pc,
3244            final FieldMetaData fmd) {
3245        try {
3246            setLoaded(fmd);
3247            return state.getShortField(fmd.stateFieldNo);
3248        } catch (Exception JavaDoc e) {
3249            handleException(e);
3250        }
3251        return 0;
3252    }
3253
3254    public int replacingIntField(final PersistenceCapable pc, final int field) {
3255        return replacingIntFieldImp(pc, getFMD(field));
3256    }
3257
3258    public int replacingIntFieldImp(final PersistenceCapable pc, final FieldMetaData fmd) {
3259        try {
3260            setLoaded(fmd);
3261            return state.getIntField(fmd.stateFieldNo);
3262        } catch (Exception JavaDoc e) {
3263            handleException(e);
3264        }
3265        return 0;
3266    }
3267
3268    public float replacingFloatField(final PersistenceCapable pc,
3269            final int field) {
3270        return replacingFloatFieldImp(pc, getFMD(field));
3271    }
3272
3273    public float replacingFloatFieldImp(final PersistenceCapable pc,
3274            final FieldMetaData fmd) {
3275        try {
3276            setLoaded(fmd);
3277            return state.getFloatField(fmd.stateFieldNo);
3278        } catch (Exception JavaDoc e) {
3279            handleException(e);
3280        }
3281        return 0;
3282    }
3283
3284    public double replacingDoubleField(final PersistenceCapable pc,
3285            final int field) {
3286        return replacingDoubleFieldImp(pc, getFMD(field));
3287    }
3288
3289    public double replacingDoubleFieldImp(final PersistenceCapable pc,
3290            final FieldMetaData fmd) {
3291        try {
3292            setLoaded(fmd);
3293            return state.getDoubleField(fmd.stateFieldNo);
3294        } catch (Exception JavaDoc e) {
3295            handleException(e);
3296        }
3297        return 0;
3298    }
3299
3300    public long replacingLongField(final PersistenceCapable pc,
3301            final int field) {
3302        return replacingLongFieldImp(pc, getFMD(field));
3303    }
3304
3305    public long replacingLongFieldImp(final PersistenceCapable pc,
3306            final FieldMetaData fmd) {
3307        try {
3308            setLoaded(fmd);
3309            return state.getLongField(fmd.stateFieldNo);
3310        } catch (Exception JavaDoc e) {
3311            handleException(e);
3312        }
3313        return 0;
3314    }
3315
3316    public String JavaDoc replacingStringField(final PersistenceCapable pc, final int field) {
3317        return replacingStringFieldImp(pc, getFMD(field));
3318    }
3319
3320    public String JavaDoc replacingStringFieldImp(final PersistenceCapable pc, FieldMetaData fmd) {
3321        try {
3322            setLoaded(fmd);
3323            return state.getStringField(fmd.stateFieldNo);
3324        } catch (Exception JavaDoc e) {
3325            handleException(e);
3326        }
3327        return null;
3328    }
3329
3330    public Object JavaDoc replacingObjectField(final PersistenceCapable pc,
3331            final int field) {
3332        return replacingObjectFieldImp(pc, getFMD(field));
3333    }
3334
3335    public Object JavaDoc replacingObjectFieldImp(final PersistenceCapable pc,
3336            final FieldMetaData fmd) {
3337        try {
3338            if (stateM == STATE_TRANSIENT) {
3339                return state.getInternalObjectField(fmd.stateFieldNo);
3340            } else {
3341                setLoaded(fmd);
3342                return state.getObjectField(fmd.stateFieldNo, this.pc, getPm(), oid);
3343            }
3344        } catch (Exception JavaDoc e) {
3345            handleException(e);
3346        }
3347        return null;
3348    }
3349
3350    private void setBeforeState(FieldMetaData fmd, long oldValue) {
3351        if (!doBeforeState(fmd)) return;
3352        if (!beforeState.containsField(fmd.stateFieldNo)) {
3353            beforeState.setLongField(fmd.stateFieldNo, oldValue);
3354        }
3355    }
3356
3357    private boolean doBeforeState(FieldMetaData fmd) {
3358        if (!getPm().doBeforeState(isTransientManaged(),
3359                fmd.category == MDStatics.CATEGORY_TRANSACTIONAL)) {
3360            return false;
3361        }
3362        if (beforeState == null) {
3363            beforeState = createStateImp();
3364        }
3365        return true;
3366    }
3367
3368    private void setBeforeState(FieldMetaData fmd, int oldValue) {
3369        if (!doBeforeState(fmd)) return;
3370        if (!beforeState.containsField(fmd.stateFieldNo)) {
3371            beforeState.setIntField(fmd.stateFieldNo, oldValue);
3372        }
3373    }
3374
3375    private void setBeforeState(FieldMetaData fmd, double currentValue) {
3376        if (!doBeforeState(fmd)) return;
3377        if (!beforeState.containsField(fmd.stateFieldNo)) {
3378            beforeState.setDoubleField(fmd.stateFieldNo, currentValue);
3379        }
3380    }
3381
3382    private void setBeforeState(FieldMetaData fmd, String JavaDoc newValue) {
3383        if (!doBeforeState(fmd)) return;
3384        if (!beforeState.containsField(fmd.stateFieldNo)) {
3385            beforeState.setStringField(fmd.stateFieldNo, newValue);
3386        }
3387    }
3388
3389    private void setBeforeState(FieldMetaData fmd, Object JavaDoc newValue) {
3390        /**
3391         * Only mutable fields of PNew instance values kept for rollback
3392         * Other states fields are refetched from db.
3393         */

3394        if (!isNew() && fmd.category != MDStatics.CATEGORY_TRANSACTIONAL) return;
3395        if (!doBeforeState(fmd)) return;
3396        if (!beforeState.containsField(fmd.stateFieldNo)) {
3397            beforeState.setObjectField(fmd.stateFieldNo, newValue);
3398        }
3399    }
3400
3401    private void setBeforeState(FieldMetaData fmd, char currentValue) {
3402        if (!doBeforeState(fmd)) return;
3403        if (!beforeState.containsField(fmd.stateFieldNo)) {
3404            beforeState.setCharField(fmd.stateFieldNo, currentValue);
3405        }
3406    }
3407
3408    private void setBeforeState(FieldMetaData fmd, byte currentValue) {
3409        if (!doBeforeState(fmd)) return;
3410        if (!beforeState.containsField(fmd.stateFieldNo)) {
3411            beforeState.setByteField(fmd.stateFieldNo, currentValue);
3412        }
3413    }
3414
3415    public void setBeforeState(FieldMetaData fmd, boolean currentValue) {
3416        if (!doBeforeState(fmd)) return;
3417        if (!beforeState.containsField(fmd.stateFieldNo)) {
3418            beforeState.setBooleanField(fmd.stateFieldNo, currentValue);
3419        }
3420    }
3421
3422    private void setBeforeState(FieldMetaData fmd, short currentValue) {
3423        if (!doBeforeState(fmd)) return;
3424        if (!beforeState.containsField(fmd.stateFieldNo)) {
3425            beforeState.setShortField(fmd.stateFieldNo, currentValue);
3426        }
3427    }
3428
3429    private void setBeforeState(FieldMetaData fmd, float currentValue) {
3430        if (!doBeforeState(fmd)) return;
3431        if (!beforeState.containsField(fmd.stateFieldNo)) {
3432            beforeState.setFloatField(fmd.stateFieldNo, currentValue);
3433        }
3434    }
3435
3436    public final void handleException(Exception JavaDoc x) {
3437        if (BindingSupportImpl.getInstance().isOwnException(x)) {
3438            throw (RuntimeException JavaDoc)x;
3439        } else {
3440            throw BindingSupportImpl.getInstance().internal(x.getMessage(), x);
3441        }
3442    }
3443
3444    public boolean isInDirtyList(PCStateMan head) {
3445        return head == this || next != null || prev != null;
3446    }
3447
3448
3449
3450
3451
3452
3453    public Object JavaDoc getOptimisticLockingValue() {
3454        if (oid.isNew()) return null;
3455        getPm().checkNonTxRead();
3456        loadRequiredFetchGroup();
3457        return state.getOptimisticLockingValue();
3458    }
3459    
3460    public void firePostStore(LifecycleListenerManager listeners) {
3461        // pc may be null if the instance has been deleted
3462
if (pc != null) {
3463            listeners.firePostStore(pc);
3464        }
3465    }
3466}
3467
Popular Tags