001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.common;
012:
013: import com.versant.core.jdo.PCStateMan;
014: import com.versant.core.metadata.*;
015: import com.versant.core.jdo.DetachStateContainer;
016: import com.versant.core.jdo.VersantPersistenceManagerImp;
017: import com.versant.core.jdo.*;
018: import com.versant.core.server.OIDGraph;
019: import com.versant.core.server.PersistGraph;
020: import com.versant.core.util.IntArray;
021: import com.versant.core.util.OIDObjectOutput;
022: import com.versant.core.util.OIDObjectInput;
023:
024: import javax.jdo.spi.PersistenceCapable;
025: import java.util.*;
026: import java.lang.reflect.Array;
027: import java.io.IOException;
028:
029: /**
030: * This is an abstract base class for State classes. Each State class is
031: * a container for the persistent fields of a PC class and all of its
032: * superclasses. These fields may include fake fields generated by the
033: * store to hold extra store specific information (e.g. row version column
034: * values).<p>
035: * <p/>
036: * Methods always use field numbers relative to the topmost class in the
037: * heirachy. This range of numbers includes fake fields present in each
038: * class.<p>
039: * <p/>
040: * Example of the State fieldNo range for C extends B extends A:<br>
041: * A.superFieldCount[A fields] (A.superFieldCount + A.realFieldCount)[A fakes]<br>
042: * B.superFieldCount[B fields] (B.superFieldCount + B.realFieldCount)[B fakes]<br>
043: * C.superFieldCount[C fields] (C.superFieldCount + C.realFieldCount)[C fakes]<p>
044: * <p/>
045: * Each PC class has its own implementation generated for it at runtime.
046: * These classes have fast implementations of various methods in the
047: * base class designed for different data stores. The JDO meta data for each
048: * PC class is a factory for its State instances.<p>
049: *
050: *
051: * Lifecycle:
052: *
053: *
054: * State is create in datastore on a request for data. This state is offered to
055: * the l2cache and returned to the requesting client. There the state is eiter used to
056: * update the state of a PCStateMan or added directly to the LocalPMCache.
057: *
058: * Any mutable data in that is contained in a state should be considered immutable. This
059: * is because if can share the same data that was returned by a state and changing it would result
060: * in weird behaviour.
061: *
062: * TODO: Go through all data struct that is returned by state and check if
063: * immutablility can be enforced.
064: *
065: * @see ClassMetaData#fields
066: * @see ClassMetaData#realFieldCount
067: * @see ClassMetaData#superFieldCount
068: */
069: public abstract class State {
070:
071: /**
072: * To check if the state is hollow.
073: * This is for debug/testing only.
074: *
075: * @return
076: */
077: public abstract boolean isHollow();
078:
079: /**
080: * Return a new State instance
081: *
082: * @return new State instance
083: */
084: public abstract State newInstance();
085:
086: /**
087: * Return the index of our PC class in the meta data. Do not use this
088: * to get the meta data for our class. Call getClassMetaData instead.
089: *
090: * @see ModelMetaData#classes
091: * @see #getClassMetaData
092: */
093: public abstract int getClassIndex();
094:
095: /**
096: * Get the meta data for our class.
097: *
098: * @param jmd The meta data we belong to
099: */
100: public abstract ClassMetaData getClassMetaData(ModelMetaData jmd);
101:
102: /**
103: * Return true if any field is dirty.
104: *
105: * @return
106: */
107: public abstract boolean isDirty();
108:
109: /**
110: * Check if a specific field is dirty.
111: *
112: * @param fieldNo
113: * @return
114: */
115: public abstract boolean isDirty(int fieldNo);
116:
117: /**
118: * This is just for testing and will not be called in (real)runtime.
119: */
120: public void validateForCache() {
121:
122: }
123:
124: /**
125: * Mark the specified field as dirty.
126: *
127: * @param fieldNo
128: */
129: public abstract void makeDirtyAbs(int fieldNo);
130:
131: /**
132: * Mark all dirty fields as clean and not filled and not resolved.
133: */
134: public abstract void clearDirtyFields();
135:
136: /**
137: * Update this state from the supplied state. All fields will be updated even
138: * if it is filled in on this state.
139: *
140: * @param state
141: */
142: public abstract void updateFrom(State state);
143:
144: /**
145: * Update this state from the supplied state. Only the fields not filled in
146: * on the current state and filled in on the supplied state will be updated.
147: *
148: * @param state
149: */
150: public abstract void updateNonFilled(State state);
151:
152: /**
153: * Clear all the non autoSet fields.
154: */
155: public abstract void clearNonAutoSetFields();
156:
157: public abstract void retrieve(VersantPersistenceManagerImp sm);
158:
159: /**
160: * Clear the fields in this state that is not filled in on the supplied state.
161: *
162: * @param state
163: */
164: public abstract void clearNonFilled(State state);
165:
166: /**
167: * Clear all fields of type mem.
168: */
169: public abstract void clearCollectionFields();
170:
171: /**
172: * This cleares all the sco fields of the state of their values and sets it
173: * to non filled.
174: */
175: public abstract void clearSCOFields();
176:
177: /**
178: * Clear all the transaction but non persistent fields.
179: */
180: public abstract void clearTransactionNonPersistentFields();
181:
182: /**
183: * <p>This return a deep clone of this state instance with only fields that
184: * must be sent to the server to persist changes to this instance filled
185: * in. For JdbcDataStore this will include only the dirty fields. For
186: * VdsDataStore this includes all fields so the whole DataStoreObject
187: * can be written.</p>
188: * <p/>
189: * <p>All 'First Class Objects' will be resolved to an OID and
190: * 'Second Class Objects' will be resolved to some serializable/storable
191: * format that represents the state of the field.</p>
192: *
193: * @return True if some fields were written to stateToStore and false if
194: * not (i.e. we have no dirty fields)
195: */
196: public abstract boolean fillToStoreState(State stateToStore,
197: PersistenceContext sm, VersantStateManager pcStateMan);
198:
199: /**
200: * Fill dest with all of the fake and ref fields of this State. This is used
201: * for stores that require the current values of fake fields to be sent when
202: * fetching certain fields (e.g. fetching a Collection stored as an SCO
203: * in VDS). The ref fields are converted into OIDs if they are pc.
204: */
205: public abstract void fillForRead(State dest,
206: VersantPersistenceManagerImp sm);
207:
208: /**
209: * Make a shallow copy of the state.
210: *
211: * @return
212: */
213: public abstract State getCopy();
214:
215: /**
216: * This must copy the fields from the supplied to the current state. The copied
217: * fields is used for to compare against to detect concurrent updates.
218: *
219: * @param state
220: * @param sm
221: */
222: public abstract void copyFieldsForOptimisticLocking(State state,
223: VersantPersistenceManagerImp sm);
224:
225: /**
226: * This copies the optimistic locking field if not already set.
227: * @param state
228: */
229: public abstract void copyOptimisticLockingField(State state);
230:
231: /**
232: * This will replace all fields that should be a SCO field with it's SCO implementation.
233: * This is used for retain values where the client has set a field that must be a sco field and
234: * this must be converted after commit.
235: */
236: public abstract int replaceSCOFields(PersistenceCapable owner,
237: VersantPersistenceManagerImp sm, int[] absFieldNos);
238:
239: /**
240: * Called when the pc instance is made transient to unset the sco instance of
241: * the pc owner.
242: */
243: public abstract void unmanageSCOFields();
244:
245: /**
246: */
247: public abstract void addRefs(VersantPersistenceManagerImp sm,
248: PCStateMan pcStateMan);
249:
250: /**
251: * Clear the state of all its fields and reset it to notFilled.
252: */
253: public abstract void clear();
254:
255: /**
256: * Reset the filled flag for each field.
257: */
258: public abstract void clearFilledFlags();
259:
260: /**
261: * Reset the dirty status of the state and its fields.
262: */
263: public abstract void makeClean();
264:
265: /**
266: * Set the meta data for this State. If this is stored in a field it
267: * must be transient. This will be called again when saving so there
268: * is no need to trundle it back and forth.
269: */
270: public abstract void setClassMetaData(ClassMetaData cmd);
271:
272: /**
273: * Return the ClassMetaData.
274: */
275: public abstract ClassMetaData getClassMetaData();
276:
277: /**
278: * Return true if the value for this stateFieldNo is valid i.e. it has been
279: * read from the data store or set by a client etc etc.
280: */
281: public abstract boolean containsField(int stateFieldNo);
282:
283: /**
284: * Return true if the value for this absFieldNo is valid i.e. it has been
285: * read from the data store or set by a client etc etc.
286: */
287: public abstract boolean containsFieldAbs(int absFieldNo);
288:
289: /**
290: * Check if the state contains the specified stateFieldNos.
291: */
292: public abstract boolean containFields(int[] stateFieldNos);
293:
294: /**
295: * Check if the state contains the specified absFieldNos.
296: */
297: public abstract boolean containFieldsAbs(int[] absFieldNos);
298:
299: /**
300: * Check if the state holds any values.
301: */
302: public abstract boolean isEmpty();
303:
304: /**
305: * Return true if all the fields defined in the specified fetch group
306: * are filled in.
307: */
308: public abstract boolean containsFetchGroup(FetchGroup fetchGroup);
309:
310: /**
311: * Put the numbers of all fields we have into buf. The number of field
312: * numbers stored is returned.
313: */
314: public abstract int getFieldNos(int[] buf);
315:
316: /**
317: * Put the numbers of all pass 1 fields we have into buf. The number of
318: * field numbers stored is returned.
319: *
320: * @see FieldMetaData#secondaryField
321: * @see ClassMetaData#pass2Fields
322: */
323: public abstract int getPass1FieldNos(int[] buf);
324:
325: /**
326: * Fill the array with the stateFieldNo of reference fields that contain
327: * NewOid's.
328: */
329: public abstract int getPass1FieldRefFieldNosWithNewOids(
330: int[] stateFieldNoBuf);
331:
332: /**
333: * Put the numbers of all pass 2 fields we have into buf. The number of
334: * field numbers stored is returned.
335: *
336: * @see FieldMetaData#secondaryField
337: * @see ClassMetaData#pass2Fields
338: */
339: public abstract int getPass2FieldNos(int[] buf);
340:
341: /**
342: * Do we contain any pass 1 fields?
343: *
344: * @see FieldMetaData#secondaryField
345: * @see ClassMetaData#pass2Fields
346: */
347: public abstract boolean containsPass1Fields();
348:
349: /**
350: * Do we contain any pass 2 fields?
351: *
352: * @see FieldMetaData#secondaryField
353: * @see ClassMetaData#pass2Fields
354: */
355: public abstract boolean containsPass2Fields();
356:
357: /**
358: * Return 0 if state has the same field numbers as us, less than 0 we are
359: * less than it or greater than 0 if we are greater than it. The definition
360: * of less than and greater than is up to the state implementation but
361: * must be detirministic. For fields that are stored using Oracle style
362: * LOBs then the nullness of the value must also be considered in the
363: * comparison i.e. states with field x null and not null respectively
364: * are different.
365: *
366: * @param state State to compare to (will be for same class)
367: */
368: public abstract int compareToPass1(State state);
369:
370: /**
371: * Does this State contain exactly the same fields as the supplied State?
372: *
373: * @param state State to compare to (will be for same class)
374: */
375: public abstract boolean hasSameFields(State state);
376:
377: /**
378: * Is the supplied stateFieldNo null?
379: */
380: public abstract boolean isNull(int stateFieldNo);
381:
382: /**
383: * Does this State contain all of the application identity fields for
384: * its class? This returns false if the class does not use application
385: * identity.
386: */
387: public abstract boolean containsApplicationIdentityFields();
388:
389: /**
390: * Does this State contain all of the application identity fields for
391: * its class with values different to a default instance of the application
392: * identity class? This returns false if the class does not use application
393: * identity.
394: */
395: public abstract boolean containsValidAppIdFields();
396:
397: /**
398: * Clear any application identity fields from this State. This is a NOP
399: * if the class does not use application identity.
400: */
401: public abstract void clearApplicationIdentityFields();
402:
403: /**
404: * Populate the primary key fields from the OID. This is only called
405: * for PC classes that are using application identity.
406: */
407: public abstract void copyFields(OID oid);
408:
409: /**
410: * Replace any NewObjectOID's in fields in fieldNos in this state with
411: * their realOID's. Entries in fieldNos that are less than 0 should be
412: * skipped. Note that skipped entries will never be for fields that could
413: * hold OIDs.
414: */
415: public abstract boolean replaceNewObjectOIDs(int[] fieldNos,
416: int fieldNosLength);
417:
418: /**
419: * Add the graph indexes of all OIDs that we have direct references to
420: * (e.g. foreign keys) to edges. This is called as part of the graph
421: * sorting process.
422: *
423: * @see PersistGraph#sort
424: */
425: public abstract void findDirectEdges(OIDGraph graph, IntArray edges);
426:
427: /**
428: * Update all autoset fields that must be set on commit of a new JDO
429: * instance.
430: *
431: * @see FieldMetaData#autoSet
432: */
433: public abstract void updateAutoSetFieldsCreated(Date now);
434:
435: /**
436: * Update all autoset fields that must be set on commit of modifications
437: * to an existing JDO instance.
438: *
439: * @param oldState The pre-modification state of the instance.
440: * @see FieldMetaData#autoSet
441: */
442: public abstract void updateAutoSetFieldsModified(Date now,
443: State oldState);
444:
445: /**
446: * Populate the OID from this state. This is called for classes
447: * using application identity when a new object is persisted. It will
448: * not be called otherwise.
449: */
450: public abstract void copyKeyFields(OID oid);
451:
452: /**
453: * Check to see if the state contains the same id field as the oid. The oid
454: * that is passed in is filled correctly.
455: */
456: public abstract boolean checkKeyFields(OID oid);
457:
458: /**
459: * Populate the OID from this state. This is called for classes
460: * using application identity when a primary key field of an existing
461: * object is updated. It will not be called otherwise. Note that if the
462: * primary key consists of multiple fields then those that have not
463: * changed may not be in state.
464: */
465: public abstract void copyKeyFieldsUpdate(OID oid);
466:
467: /**
468: * Return the value for the field.
469: */
470: public abstract boolean getBooleanField(int stateFieldNo);
471:
472: public abstract boolean getBooleanFieldAbs(int absFieldNo);
473:
474: /**
475: * Return the value for the field.
476: */
477: public abstract char getCharField(int stateFieldNo);
478:
479: public abstract char getCharFieldAbs(int absFieldNo);
480:
481: /**
482: * Return the value for the field.
483: */
484: public abstract byte getByteField(int stateFieldNo);
485:
486: public abstract byte getByteFieldAbs(int absFieldNo);
487:
488: /**
489: * Return the value for the field.
490: */
491: public abstract short getShortField(int stateFieldNo);
492:
493: public abstract short getShortFieldAbs(int absFieldNo);
494:
495: /**
496: * Return the value for the field.
497: */
498: public abstract int getIntField(int stateFieldNo);
499:
500: public abstract int getIntFieldAbs(int absFieldNo);
501:
502: /**
503: * Return the value for the field.
504: */
505: public abstract long getLongField(int stateFieldNo);
506:
507: public abstract long getLongFieldAbs(int absFieldNo);
508:
509: /**
510: * Return the value for the field or 0L if it is not filled.
511: */
512: public abstract long getLongFieldInternal(int stateFieldNo);
513:
514: /**
515: * Return the value for the field.
516: */
517: public abstract float getFloatField(int stateFieldNo);
518:
519: public abstract float getFloatFieldAbs(int absFieldNo);
520:
521: /**
522: * Return the value for the field.
523: */
524: public abstract double getDoubleField(int stateFieldNo);
525:
526: public abstract double getDoubleFieldAbs(int absFieldNo);
527:
528: /**
529: * Return the value for the field.
530: */
531: public abstract String getStringField(int stateFieldNo);
532:
533: public abstract String getStringFieldAbs(int absFieldNo);
534:
535: /**
536: * Return the value for the field.
537: */
538: public abstract Object getObjectField(int stateFieldNo,
539: PersistenceCapable owningPC, PersistenceContext pm, OID oid);
540:
541: public abstract Object getObjectFieldAbs(int absFieldNo,
542: PersistenceCapable owningPC, PersistenceContext pm, OID oid);
543:
544: /**
545: * Set the value of the field.
546: */
547: public abstract void setBooleanField(int stateFieldNo,
548: boolean newValue);
549:
550: public abstract void setBooleanFieldAbs(int absFieldNo,
551: boolean newValue);
552:
553: /**
554: * Set the value of the field.
555: */
556: public abstract void setCharField(int stateFieldNo, char newValue);
557:
558: public abstract void setCharFieldAbs(int absFieldNo, char newValue);
559:
560: /**
561: * Set the value of the field.
562: */
563: public abstract void setByteField(int stateFieldNo, byte newValue);
564:
565: public abstract void setByteFieldAbs(int absFieldNo, byte newValue);
566:
567: /**
568: * Set the value of the field.
569: */
570: public abstract void setShortField(int stateFieldNo, short newValue);
571:
572: public abstract void setShortFieldAbs(int absFieldNo, short newValue);
573:
574: /**
575: * Set the value of the field.
576: */
577: public abstract void setIntField(int stateFieldNo, int newValue);
578:
579: public abstract void setIntFieldAbs(int absFieldNo, int newValue);
580:
581: /**
582: * Set the value of the field.
583: */
584: public abstract void setLongField(int stateFieldNo, long newValue);
585:
586: public abstract void setLongFieldAbs(int absFieldNo, long newValue);
587:
588: /**
589: * Set the value of the field.
590: */
591: public abstract void setFloatField(int stateFieldNo, float newValue);
592:
593: public abstract void setFloatFieldAbs(int absFieldNo, float newValue);
594:
595: /**
596: * Set the value of the field.
597: */
598: public abstract void setDoubleField(int stateFieldNo,
599: double newValue);
600:
601: public abstract void setDoubleFieldAbs(int absFieldNo,
602: double newValue);
603:
604: /**
605: * Set the value of the field.
606: */
607: public abstract void setStringField(int stateFieldNo,
608: String newValue);
609:
610: public abstract void setStringFieldAbs(int absFieldNo,
611: String newValue);
612:
613: /**
614: * Set the value of the field.
615: */
616: public abstract void setObjectField(int stateFieldNo,
617: Object newValue);
618:
619: public abstract void setObjectFieldAbs(int absFieldNo,
620: Object newValue);
621:
622: public abstract void setObjectFieldUnresolved(int field,
623: Object newValue);
624:
625: public abstract void setObjectFieldUnresolvedAbs(int field,
626: Object newValue);
627:
628: //==============================internal usage==================================
629:
630: /**
631: * Return the internal value for the field.
632: */
633: public abstract Object getInternalObjectField(int field);
634:
635: public abstract Object getInternalObjectFieldAbs(int field);
636:
637: /**
638: * Set the value of the field internally.
639: */
640: public abstract void setInternalBooleanField(int field,
641: boolean newValue);
642:
643: public abstract void setInternalBooleanFieldAbs(int field,
644: boolean newValue);
645:
646: /**
647: * Set the value of the field internally.
648: */
649: public abstract void setInternalCharField(int field, char newValue);
650:
651: public abstract void setInternalCharFieldAbs(int field,
652: char newValue);
653:
654: /**
655: * Set the value of the field internally.
656: */
657: public abstract void setInternalByteField(int field, byte newValue);
658:
659: public abstract void setInternalByteFieldAbs(int field,
660: byte newValue);
661:
662: /**
663: * Set the value of the field internally.
664: */
665: public abstract void setInternalShortField(int field, short newValue);
666:
667: public abstract void setInternalShortFieldAbs(int field,
668: short newValue);
669:
670: /**
671: * Set the value of the field internally.
672: */
673: public abstract void setInternalIntField(int field, int newValue);
674:
675: public abstract void setInternalIntFieldAbs(int field, int newValue);
676:
677: /**
678: * Set the value of the field internally.
679: */
680: public abstract void setInternalLongField(int field, long newValue);
681:
682: public abstract void setInternalLongFieldAbs(int field,
683: long newValue);
684:
685: /**
686: * Set the value of the field internally.
687: */
688: public abstract void setInternalFloatField(int field, float newValue);
689:
690: public abstract void setInternalFloatFieldAbs(int field,
691: float newValue);
692:
693: /**
694: * Set the value of the field internally.
695: */
696: public abstract void setInternalDoubleField(int field,
697: double newValue);
698:
699: public abstract void setInternalDoubleFieldAbs(int field,
700: double newValue);
701:
702: /**
703: * Set the value of the field internally.
704: */
705: public abstract void setInternalStringField(int field,
706: String newValue);
707:
708: public abstract void setInternalStringFieldAbs(int field,
709: String newValue);
710:
711: /**
712: * Set the value of the field internally.
713: */
714: public abstract void setInternalObjectField(int field,
715: Object newValue);
716:
717: public abstract void setInternalObjectFieldAbs(int field,
718: Object newValue);
719:
720: // public void readExternal(ObjectInput in, JDOMetaData jmd,
721: // IntObjectHashMap map) throws IOException, ClassNotFoundException {
722: // }
723:
724: public abstract String getVersion();
725:
726: /**
727: * Add all states referenced by fields in fg to the dcs.
728: */
729: public void addFetchGroupStatesToDCS(FetchGroup fg,
730: DetachStateContainer dcs, VersantPersistenceManagerImp pm,
731: OID oid, ClassMetaData cmd) {
732: // we need to check all fields that may reference other states and
733: // add those states to the dcs with the "nextFetchGroups" so they
734: // are checked in turn
735: FetchGroupField[] fields = fg.fields;
736: boolean defaultFG = fg == cmd.fetchGroups[0];
737: int length = fields.length;
738: for (int fieldNo = 0; fieldNo < length; fieldNo++) {
739: FetchGroupField field = fields[fieldNo];
740: FieldMetaData fmd = field.fmd;
741: if (fmd.fake)
742: continue;
743: if (defaultFG && !fmd.isJDODefaultFetchGroup())
744: continue;
745: FetchGroup nextFetchGroup = field.nextFetchGroup;
746: FetchGroup nextKeyFetchGroup = field.nextKeyFetchGroup;
747: if (nextFetchGroup == null && nextKeyFetchGroup == null)
748: continue;
749: int category = fmd.category;
750: int stateFieldNo;
751: Object o;
752: switch (category) {
753: case MDStatics.CATEGORY_COLLECTION:
754: o = getInternalObjectField(stateFieldNo = fmd.stateFieldNo);
755: if (o != null) {
756: if (isResolvedForClient(stateFieldNo)) {
757: // TODO add method to SCOs to get data w/o iterator
758: for (Iterator i = ((Collection) o).iterator(); i
759: .hasNext();) {
760: addPCToDCS(dcs, (PersistenceCapable) i
761: .next(), nextFetchGroup, pm);
762: }
763: } else {
764: Object[] a = (Object[]) o;
765: int c = a.length;
766: for (int i = 0; i < c; i++) {
767: Object object = a[i];
768: if (object == null)
769: break;
770: addOIDToDCS(dcs, (OID) object,
771: nextFetchGroup, pm);
772: }
773: }
774: }
775: break;
776: case MDStatics.CATEGORY_ARRAY:
777: if (fmd.elementTypeMetaData != null) {
778: o = getInternalObjectField(stateFieldNo = fmd.stateFieldNo);
779: if (o != null) {
780: if (isResolvedForClient(stateFieldNo)) {
781: Object[] a = (Object[]) o;
782: int c = a.length;
783: for (int i = 0; i < c; i++) {
784: Object object = a[i];
785: if (object != null) {
786: addPCToDCS(
787: dcs,
788: (PersistenceCapable) object,
789: nextFetchGroup, pm);
790: }
791: }
792: } else {
793: Object[] a = (Object[]) o;
794: int c = a.length;
795: for (int i = 0; i < c; i++) {
796: Object object = a[i];
797: if (object != null) {
798: addOIDToDCS(dcs, (OID) object,
799: nextFetchGroup, pm);
800: }
801: }
802: }
803: }
804: }
805: break;
806: case MDStatics.CATEGORY_MAP:
807: o = getInternalObjectField(stateFieldNo = fmd.stateFieldNo);
808: if (o != null) {
809: if (isResolvedForClient(stateFieldNo)) {
810: // TODO add method to SCOs to get data w/o iterator
811: for (Iterator i = ((Map) o).entrySet()
812: .iterator(); i.hasNext();) {
813: Map.Entry e = (Map.Entry) i.next();
814: if (nextKeyFetchGroup != null) {
815: addPCToDCS(dcs, (PersistenceCapable) e
816: .getKey(), nextKeyFetchGroup,
817: pm);
818: }
819: if (nextFetchGroup != null) {
820: addPCToDCS(dcs, (PersistenceCapable) e
821: .getValue(), nextFetchGroup, pm);
822: }
823: }
824: } else {
825: MapEntries e = (MapEntries) o;
826: if (nextKeyFetchGroup != null) {
827: Object[] a = e.keys;
828: int c = a.length;
829: for (int i = 0; i < c; i++) {
830: OID nextOid = (OID) a[i];
831: if (nextOid == null)
832: break;
833: addOIDToDCS(dcs, nextOid,
834: nextKeyFetchGroup, pm);
835: }
836: }
837: if (nextFetchGroup != null) {
838: Object[] a = e.values;
839: int c = a.length;
840: for (int i = 0; i < c; i++) {
841: OID nextOid = (OID) a[i];
842: if (nextOid == null)
843: break;
844: addOIDToDCS(dcs, nextOid,
845: nextFetchGroup, pm);
846: }
847: }
848: }
849: }
850: break;
851: case MDStatics.CATEGORY_REF:
852: case MDStatics.CATEGORY_POLYREF:
853: o = getInternalObjectField(stateFieldNo = fmd.stateFieldNo);
854: if (o != null) {
855: if (isResolvedForClient(stateFieldNo)) {
856: addPCToDCS(dcs, (PersistenceCapable) o,
857: nextFetchGroup, pm);
858: } else {
859: OID nextOid = (OID) o;
860: if (nextOid != null) {
861: addOIDToDCS(dcs, nextOid, nextFetchGroup,
862: pm);
863: }
864: }
865: }
866: break;
867: }
868: }
869: }
870:
871: /**
872: * Get the state for the oid from the local cache (if any). Add the oid
873: * and state to the dcs. This does not check if it is already present.
874: */
875: private void addOIDToDCS(DetachStateContainer dcs, OID oid,
876: FetchGroup nextFetchGroup, VersantPersistenceManagerImp pm) {
877: State ns = pm.getCache().getStateByOID(oid);
878: dcs.add(oid, ns, nextFetchGroup);
879: // it is ok if ns is null as it will be fetched later
880: }
881:
882: /**
883: * Add the state for the pc and its oid to dcs. This is a NOP if the oid
884: * is already present.
885: */
886: private void addPCToDCS(DetachStateContainer dcs,
887: PersistenceCapable pc, FetchGroup nextFetchGroup,
888: VersantPersistenceManagerImp pm) {
889: PCStateMan internalSM = pm.getInternalSM(pc);
890: dcs.add(internalSM.oid, internalSM.state, nextFetchGroup);
891: // dcs.add will do nothing if the oid is already present
892: }
893:
894: public Object resolveArrayOIDs(Object[] oids,
895: PersistenceContext sm, Class type) {
896: Object[] vals = (Object[]) Array.newInstance(type, oids.length);
897: for (int i = 0; i < vals.length; i++) {
898: if (oids[i] != null) {
899: vals[i] = sm.getObjectById(oids[i], false);
900: }
901: }
902: return vals;
903: }
904:
905: public Object resolveArrayValues(Object vals[],
906: PersistenceContext pm) {
907: OID oids[] = new OID[vals.length];
908: for (int i = 0; i < oids.length; i++) {
909: if (vals[i] != null) {
910: oids[i] = pm
911: .getInternalOID((PersistenceCapable) vals[i]);
912: }
913: }
914:
915: return oids;
916: }
917:
918: /**
919: * Is this state field nummber resolved for the Client
920: */
921: public abstract boolean isResolvedForClient(int stateFieldNo);
922:
923: /**
924: * The value of the version field on the pc.
925: * This will return null if there are no version fields.
926: */
927: public abstract Object getOptimisticLockingValue();
928:
929: /**
930: * Mark field as filled.
931: */
932: public abstract void setFilled(int stateFieldNo);
933:
934: /**
935: * Add the values of any non-null reference fields used as back or inverse
936: * fields for unmanaged one-to-many collections for eviction from the L2
937: * cache on commit. Note that the filled status of the field is not
938: * checked. This method is called only for newly managed instances so
939: * all fields will be filled.
940: */
941: public abstract void addOneToManyInverseFieldsForL2Evict(
942: VersantPersistenceManagerImp pm);
943:
944: /**
945: * If the data of this state may be used to update the cache.
946: */
947: public boolean isCacheble() {
948: return true;
949: }
950:
951: /**
952: * Find the graph indexes of all the OIDs directly referenced by fieldNo
953: * and add them to edges. Any referenced OIDs that are not in the graph
954: * should be ignored.
955: */
956: protected void findDirectEdges(OIDGraph graph, ClassMetaData cmd,
957: int fieldNo, State state, IntArray edges) {
958: OID oid = (OID) state.getInternalObjectField(fieldNo);
959: if (oid == null)
960: return;
961: int index = graph.indexOf(oid);
962: if (index >= 0)
963: edges.add(index);
964: }
965:
966: /**
967: * Is the field null or zero?
968: */
969: public abstract boolean isFieldNullorZero(int stateFieldNo);
970:
971: /**
972: * Our version of writeExternal for serialization.
973: */
974: public abstract void writeExternal(OIDObjectOutput os)
975: throws IOException;
976:
977: /**
978: * Our version of readExternal for serialization.
979: */
980: public abstract void readExternal(OIDObjectInput is)
981: throws IOException, ClassNotFoundException;
982:
983: }
|