0001: /*
0002: * Copyright (c) 1998 - 2005 Versant Corporation
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * Versant Corporation - initial API and implementation
0010: */
0011: package com.versant.core.common;
0012:
0013: import com.versant.core.jdo.sco.VersantSimpleSCO;
0014: import com.versant.core.jdo.*;
0015: import com.versant.core.metadata.*;
0016: import com.versant.core.server.OIDGraph;
0017: import com.versant.core.util.IntArray;
0018: import com.versant.core.util.OIDObjectOutput;
0019: import com.versant.core.util.OIDObjectInput;
0020:
0021: import javax.jdo.spi.PersistenceCapable;
0022: import java.io.*;
0023: import java.util.*;
0024:
0025: /**
0026: * This is a State implementation suitable for use with any PC class. It is
0027: * intended for use during development when the State class generating code is
0028: * broken. The meta data OID factory method can just return these for all
0029: * PC classes. Performance is not important for this class as it will not
0030: * be used in a production release.
0031: */
0032: public class GenericState extends State {
0033:
0034: protected transient ClassMetaData cmd;
0035:
0036: /**
0037: * The JDBC tests set this flag to disable the checkFilled calls on
0038: * getString etc.
0039: */
0040: public static boolean RUNNING_JDBC_TESTS = false;
0041:
0042: /**
0043: * This holds the data for all of the persistent fields and any extra
0044: * data required for a particular store. The persistent fields are
0045: * stored first in fieldNo order (i.e. alphabetically) followed by
0046: * the store defined values (if any).
0047: */
0048: protected Object[] data;
0049: /**
0050: * Each field or extra store value that has a valid entry in data has a
0051: * flag set here.
0052: */
0053: protected boolean[] filled;
0054:
0055: /**
0056: * Keeps track of dirty fields. This is the result of all setXXX methods. The
0057: * setInternalXXX method does not change the status to dirty. This is only
0058: * used on the client side.
0059: */
0060: protected transient boolean[] dirtyFields;
0061: /**
0062: * Keeps tracks of which fields have been resolved for client side usage. eg
0063: * ensure that an oid field is resolved to the actual PersistantCapable instance.
0064: */
0065: protected transient boolean[] resolvedForClient;
0066:
0067: /**
0068: * A global indication if this state has any dirty fields.
0069: */
0070: protected boolean dirty;
0071:
0072: /**
0073: * The index of the persistant class.
0074: */
0075: protected int classIndex;
0076:
0077: public GenericState() {
0078: }
0079:
0080: public GenericState(ClassMetaData cmd) {
0081: this .cmd = cmd;
0082: classIndex = cmd.index;
0083: int n = cmd.super FieldCount + cmd.fields.length;
0084: data = new Object[n];
0085: filled = new boolean[n];
0086: }
0087:
0088: /**
0089: * Return a new State instance
0090: *
0091: * @return new State instance
0092: */
0093: public State newInstance() {
0094: return new GenericState(cmd);
0095: }
0096:
0097: /**
0098: * Return the index of our PC class in the meta data. Do not use this
0099: * to get the meta data for our class. Call getClassMetaData instead.
0100: *
0101: * @see ModelMetaData#classes
0102: * @see #getClassMetaData
0103: */
0104: public int getClassIndex() {
0105: return classIndex;
0106: }
0107:
0108: private final int convertAbsToState(int managedFieldNo) {
0109: return cmd.managedFields[managedFieldNo].stateFieldNo;
0110: }
0111:
0112: /**
0113: * Get the meta data for our class.
0114: *
0115: * @param jmd The meta data we belong to
0116: */
0117: public ClassMetaData getClassMetaData(ModelMetaData jmd) {
0118: return jmd.classes[classIndex];
0119: }
0120:
0121: public void setClassMetaData(ClassMetaData cmd) {
0122: this .cmd = cmd;
0123: int n = cmd.super FieldCount + cmd.fields.length;
0124: dirtyFields = new boolean[n];
0125: resolvedForClient = new boolean[n];
0126: }
0127:
0128: public ClassMetaData getClassMetaData() {
0129: return cmd;
0130: }
0131:
0132: public boolean containsField(int stateFieldNo) {
0133: return filled[stateFieldNo];
0134: }
0135:
0136: public boolean containsFieldAbs(int absFieldNo) {
0137: return containsField(convertAbsToState(absFieldNo));
0138: }
0139:
0140: public boolean containFields(int[] stateFieldNos) {
0141: for (int i = 0; i < stateFieldNos.length; i++) {
0142: if (!filled[stateFieldNos[i]])
0143: return false;
0144: }
0145: return true;
0146: }
0147:
0148: public boolean containFieldsAbs(int[] absFieldNos) {
0149: int[] stateFieldNos = new int[absFieldNos.length];
0150: for (int i = 0; i < absFieldNos.length; i++) {
0151: stateFieldNos[i] = convertAbsToState(absFieldNos[i]);
0152: }
0153: return containFields(stateFieldNos);
0154: }
0155:
0156: public boolean isEmpty() {
0157: for (int i = 0; i < filled.length; i++) {
0158: if (filled[i])
0159: return false;
0160: }
0161: return true;
0162: }
0163:
0164: public boolean containsFetchGroup(FetchGroup fetchGroup) {
0165: while (fetchGroup != null) {
0166: int[] fgn = fetchGroup.stateFieldNos;
0167: for (int i = fgn.length - 1; i >= 0; i--) {
0168: if (!containsField(fgn[i])) {
0169: return false;
0170: }
0171: }
0172: fetchGroup = fetchGroup.super FetchGroup;
0173: }
0174: return true;
0175: }
0176:
0177: /**
0178: * Put the stateField numbers of all fields we have into stateFieldNoBuf. The number of field
0179: * numbers stored is returned.
0180: */
0181: public int getFieldNos(int[] stateFieldNoBuf) {
0182: int c = 0;
0183: for (int i = 0; i < filled.length; i++) {
0184: if (filled[i])
0185: stateFieldNoBuf[c++] = i;
0186: }
0187: return c;
0188: }
0189:
0190: /**
0191: * Put the stateField numbers of all pass 1 fields we have into stateFieldNoBuf. The number of
0192: * field numbers stored is returned.
0193: *
0194: * @see FieldMetaData#secondaryField
0195: * @see ClassMetaData#pass2Fields
0196: */
0197: public int getPass1FieldNos(int[] stateFieldNoBuf) {
0198: int c = 0;
0199: for (int i = 0; i < filled.length; i++) {
0200: if (filled[i] && cmd.stateFields[i].primaryField)
0201: stateFieldNoBuf[c++] = i;
0202: }
0203: return c;
0204: }
0205:
0206: public int getPass1FieldRefFieldNosWithNewOids(int[] stateFieldNoBuf) {
0207: int c = 0;
0208: for (int i = 0; i < filled.length; i++) {
0209: if (filled[i]
0210: && cmd.stateFields[i].primaryField
0211: && (cmd.stateFields[i].category == MDStatics.CATEGORY_REF || cmd.stateFields[i].category == MDStatics.CATEGORY_POLYREF))
0212: stateFieldNoBuf[c++] = i;
0213: }
0214: return c;
0215: }
0216:
0217: /**
0218: * Put the stateField numbers of all pass 2 fields we have into stateFieldNoBuf. The number of
0219: * field numbers stored is returned.
0220: *
0221: * @see FieldMetaData#secondaryField
0222: * @see ClassMetaData#pass2Fields
0223: */
0224: public int getPass2FieldNos(int[] stateFieldNoBuf) {
0225: checkCmd();
0226: int c = 0;
0227: for (int i = 0; i < filled.length; i++) {
0228: if (filled[i] && cmd.stateFields[i].secondaryField)
0229: stateFieldNoBuf[c++] = i;
0230: }
0231: return c;
0232: }
0233:
0234: /**
0235: * Do we contain any pass 1 fields?
0236: *
0237: * @see FieldMetaData#secondaryField
0238: * @see ClassMetaData#pass2Fields
0239: */
0240: public boolean containsPass1Fields() {
0241: checkCmd();
0242: for (int i = 0; i < filled.length; i++) {
0243: if (filled[i] && cmd.stateFields[i].primaryField)
0244: return true;
0245: }
0246: return false;
0247: }
0248:
0249: /**
0250: * Do we contain any pass 2 fields?
0251: *
0252: * @see FieldMetaData#secondaryField
0253: * @see ClassMetaData#pass2Fields
0254: */
0255: public boolean containsPass2Fields() {
0256: checkCmd();
0257: for (int i = 0; i < filled.length; i++) {
0258: if (filled[i] && cmd.stateFields[i].secondaryField)
0259: return true;
0260: }
0261: return false;
0262: }
0263:
0264: /**
0265: * Return 0 if state has the same field numbers as us, less than 0 we are
0266: * less than it or greater than 0 if we are greater than it. The definition
0267: * of less than and greater than is up to the state implementation but
0268: * must be detirministic. For fields that are stored using Oracle style
0269: * LOBs then the nullness of the value must also be considered in the
0270: * comparison i.e. states with field x null and not null respectively
0271: * are different.
0272: *
0273: * @param state State to compare to (will be for same class)
0274: */
0275: public int compareToPass1(State state) {
0276: GenericState s = (GenericState) state;
0277: checkCmd();
0278: boolean[] sf = s.filled;
0279: for (int i = 0; i < filled.length; i++) {
0280: if (!cmd.stateFields[i].primaryField)
0281: continue;
0282: boolean a = filled[i];
0283: boolean b = sf[i];
0284: if (a && !b)
0285: return -1;
0286: if (!a && b)
0287: return +1;
0288: }
0289: return 0;
0290: }
0291:
0292: public void clear() {
0293: data = new Object[data.length];
0294: filled = new boolean[filled.length];
0295: makeClean();
0296: if (resolvedForClient != null) {
0297: resolvedForClient = new boolean[resolvedForClient.length];
0298: }
0299: }
0300:
0301: public void clearFilledFlags() {
0302: filled = new boolean[filled.length];
0303: }
0304:
0305: public void makeClean() {
0306: Arrays.fill(dirtyFields, false);
0307: dirty = false;
0308: }
0309:
0310: public void clearNonFilled(State state) {
0311: GenericState gState = (GenericState) state;
0312: boolean[] localFilled = gState.filled;
0313: for (int i = localFilled.length - 1; i >= 0; i--) {
0314: if (!localFilled[i]
0315: && (cmd.stateFields[i].autoSet == MDStatics.AUTOSET_NO)) {
0316: data[i] = null;
0317: filled[i] = false;
0318: resolvedForClient[i] = false;
0319: }
0320: }
0321: }
0322:
0323: public void clearCollectionFields() {
0324: checkCmd();
0325: for (int i = 0; i < data.length; i++) {
0326: int category = cmd.stateFields[i].category;
0327: if (category == MDStatics.CATEGORY_COLLECTION
0328: || category == MDStatics.CATEGORY_MAP
0329: || category == MDStatics.CATEGORY_ARRAY) {
0330: data[i] = null;
0331: filled[i] = false;
0332: if (resolvedForClient != null)
0333: resolvedForClient[i] = false;
0334: }
0335: }
0336: }
0337:
0338: public void clearSCOFields() {
0339: checkCmd();
0340: for (int i = 0; i < cmd.scoFieldNos.length; i++) {
0341: int scoFieldNo = cmd.scoFieldNos[i];
0342: data[scoFieldNo] = null;
0343: filled[scoFieldNo] = false;
0344: resolvedForClient[scoFieldNo] = false;
0345: }
0346: }
0347:
0348: public final void clearTransactionNonPersistentFields() {
0349: checkCmd();
0350: final int n = cmd.txFieldNos.length;
0351: for (int i = 0; i < n; i++) {
0352: dirtyFields[cmd.txFieldNos[i]] = false;
0353: }
0354: }
0355:
0356: /**
0357: * Does this State contain exactly the same fields as the supplied State?
0358: *
0359: * @param state State to compare to (will be for same class)
0360: */
0361: public boolean hasSameFields(State state) {
0362: GenericState s = (GenericState) state;
0363: int n = filled.length;
0364: int i;
0365: for (i = 0; i < n && filled[i] == s.filled[i]; i++)
0366: ;
0367: return i == n;
0368: }
0369:
0370: /**
0371: * Is the supplied stateFieldNo null?
0372: */
0373: public boolean isNull(int stateFieldNo) {
0374: return data[stateFieldNo] == null;
0375: }
0376:
0377: /**
0378: * Does this State contain all of the application identity fields for
0379: * its class? This returns false if the class does not use application
0380: * identity.
0381: */
0382: public boolean containsApplicationIdentityFields() {
0383: checkCmd();
0384: if (cmd.identityType != MDStatics.IDENTITY_TYPE_APPLICATION)
0385: return false;
0386: FieldMetaData[] pkf = cmd.pcHeirachy[0].pkFields;
0387: for (int i = pkf.length - 1; i >= 0; i--) {
0388: if (!containsField(pkf[i].stateFieldNo))
0389: return false;
0390: }
0391: return true;
0392: }
0393:
0394: public boolean containsValidAppIdFields() {
0395: checkCmd();
0396: if (cmd.identityType != MDStatics.IDENTITY_TYPE_APPLICATION)
0397: return false;
0398: FieldMetaData[] pkf = cmd.pcHeirachy[0].pkFields;
0399: for (int i = pkf.length - 1; i >= 0; i--) {
0400: if (!containsField(pkf[i].stateFieldNo))
0401: return false;
0402: if (data[pkf[i].stateFieldNo] == null)
0403: return false;
0404: if (data[pkf[i].stateFieldNo].equals(pkf[i]
0405: .getPKDefaultValue()))
0406: return false;
0407: }
0408: return true;
0409: }
0410:
0411: /**
0412: * Clear any application identity fields from this State. This is a NOP
0413: * if the class does not use application identity.
0414: */
0415: public void clearApplicationIdentityFields() {
0416: checkCmd();
0417: if (cmd.top.identityType != MDStatics.IDENTITY_TYPE_APPLICATION)
0418: return;
0419: FieldMetaData[] pkf = cmd.top.pkFields;
0420: for (int i = pkf.length - 1; i >= 0; i--) {
0421: data[pkf[i].stateFieldNo] = null;
0422: filled[pkf[i].stateFieldNo] = false;
0423: }
0424: }
0425:
0426: /**
0427: * Populate the primary key fields from the OID. This is only called
0428: * for PC classes that are using application identity.
0429: */
0430: public void copyFields(OID oid) {
0431: checkCmd();
0432: if (cmd.identityType != MDStatics.IDENTITY_TYPE_APPLICATION)
0433: return;
0434: GenericOID goid = (GenericOID) oid;
0435: Object[] pk = goid.getPk();
0436: FieldMetaData[] pkFields = cmd.pcHeirachy[0].pkFields;
0437: for (int i = 0; i < pk.length; i++) {
0438: data[pkFields[i].stateFieldNo] = pk[i];
0439: filled[pkFields[i].stateFieldNo] = true;
0440: }
0441: }
0442:
0443: /**
0444: * Replace any NewObjectOID's in fields in fieldNos in this state with
0445: * their realOID's. Entries in fieldNos that are less than 0 should be
0446: * skipped. Note that skipped entries will never be for fields that could
0447: * hold OIDs.
0448: */
0449: public boolean replaceNewObjectOIDs(int[] fieldNos,
0450: int fieldNosLength) {
0451: boolean containsUnResolvedNewOids = false;
0452: for (int i = 0; i < fieldNosLength; i++) {
0453: int fieldNo = fieldNos[i];
0454: if (fieldNo >= 0) {
0455: FieldMetaData fmd = cmd.stateFields[fieldNo];
0456: Object o;
0457: switch (fmd.category) {
0458: case MDStatics.CATEGORY_REF:
0459: case MDStatics.CATEGORY_POLYREF:
0460: o = data[fieldNo];
0461: if (o != null && o instanceof NewObjectOID) {
0462: if (((NewObjectOID) o).realOID == null) {
0463: containsUnResolvedNewOids = true;
0464: } else {
0465: data[fieldNo] = ((NewObjectOID) o).realOID;
0466: }
0467: }
0468: break;
0469: }
0470: }
0471: }
0472: return containsUnResolvedNewOids;
0473: }
0474:
0475: /**
0476: * Populate the OID from this state. This is called for classes
0477: * using application identity when a new object is persisted. It will
0478: * not be called otherwise.
0479: */
0480: public void copyKeyFields(OID oid) {
0481: GenericOID gOid = (GenericOID) oid;
0482: Object[] pk = gOid.getPk();
0483: FieldMetaData[] pkFields = cmd.pkFields;
0484: for (int i = 0; i < pk.length; i++) {
0485: pk[i] = getInternalObjectField(pkFields[i].stateFieldNo);
0486: }
0487: }
0488:
0489: public boolean checkKeyFields(OID oid) {
0490: GenericOID gOid = (GenericOID) oid;
0491: Object[] pk = gOid.getPk();
0492: for (int i = 0; i < pk.length; i++) {
0493: if (!pk[i]
0494: .equals(getInternalObjectField(cmd.pkFields[i].stateFieldNo))) {
0495: return false;
0496: }
0497: }
0498: return true;
0499: }
0500:
0501: /**
0502: * Populate the OID from this state. This is called for classes
0503: * using application identity when a primary key field of an existing
0504: * object is updated. It will not be called otherwise. Note that if the
0505: * primary key consists of multiple fields then those that have not
0506: * changed may not be in state.
0507: */
0508: public void copyKeyFieldsUpdate(OID oid) {
0509: GenericOID gOid = (GenericOID) oid;
0510: Object[] pk = gOid.getPk();
0511: FieldMetaData[] pkFields = cmd.pkFields;
0512: for (int i = 0; i < pk.length; i++) {
0513: int fieldNo = pkFields[i].stateFieldNo;
0514: if (containsField(fieldNo)) {
0515: pk[i] = getInternalObjectField(fieldNo);
0516: }
0517: }
0518: }
0519:
0520: /**
0521: * Add the graph indexes of all OIDs that we have direct references to
0522: * (e.g. foreign keys) to edges. This is called as part of the graph
0523: * sorting process.
0524: *
0525: * @see com.versant.core.server.PersistGraph#sort
0526: */
0527: public void findDirectEdges(OIDGraph graph, IntArray edges) {
0528: int[] fieldNos = cmd.directRefStateFieldNos;
0529: int n = fieldNos.length;
0530: for (int i = 0; i < n; i++) {
0531: int fieldNo = fieldNos[i];
0532: if (!containsField(fieldNo))
0533: continue;
0534: findDirectEdges(graph, cmd, fieldNo, this , edges);
0535: }
0536: }
0537:
0538: /**
0539: * Update all autoset fields that must be set on commit of a new JDO
0540: * instance.
0541: *
0542: * @see FieldMetaData#autoSet
0543: */
0544: public void updateAutoSetFieldsCreated(Date now) {
0545: if (!cmd.hasAutoSetFields)
0546: return;
0547: FieldMetaData[] stateFields = cmd.stateFields;
0548: for (int i = stateFields.length - 1; i >= 0; i--) {
0549: FieldMetaData fmd = cmd.stateFields[i];
0550: int autoset = fmd.autoSet;
0551: if (autoset != MDStatics.AUTOSET_CREATED
0552: && autoset != MDStatics.AUTOSET_BOTH) {
0553: continue;
0554: }
0555: switch (fmd.typeCode) {
0556: case MDStatics.DATE:
0557: setInternalObjectField(i, now);
0558: break;
0559:
0560: case MDStatics.INT:
0561: setInternalIntField(i, 1);
0562: break;
0563: case MDStatics.SHORT:
0564: setInternalShortField(i, (short) 1);
0565: break;
0566: case MDStatics.BYTE:
0567: setInternalByteField(i, (byte) 1);
0568: break;
0569: default:
0570: throw BindingSupportImpl.getInstance().internal(
0571: "Invalid typeCode " + fmd.typeCode
0572: + " for autoset field: stateFieldNo "
0573: + i + " " + fmd.name);
0574: }
0575: }
0576: }
0577:
0578: /**
0579: * Update all autoset fields that must be set on commit of modifications
0580: * to an existing JDO instance.
0581: *
0582: * @param oldState The pre-modification state of the instance.
0583: * @see FieldMetaData#autoSet
0584: */
0585: public void updateAutoSetFieldsModified(Date now, State oldState) {
0586: if (!cmd.hasAutoSetFields)
0587: return;
0588: FieldMetaData[] stateFields = cmd.stateFields;
0589: for (int i = stateFields.length - 1; i >= 0; i--) {
0590: FieldMetaData fmd = cmd.stateFields[i];
0591: int autoset = fmd.autoSet;
0592: if (autoset != MDStatics.AUTOSET_MODIFIED
0593: && autoset != MDStatics.AUTOSET_BOTH) {
0594: continue;
0595: }
0596: // carl leave this check out of the generated State class
0597: if (fmd.typeCode != MDStatics.DATE
0598: && !oldState.containsField(i)) {
0599: throw BindingSupportImpl.getInstance().internal(
0600: "oldState does not contain version field: "
0601: + "stateFieldNo " + i + " " + fmd.name);
0602: }
0603: switch (fmd.typeCode) {
0604: case MDStatics.DATE:
0605: setInternalObjectField(i, now);
0606: break;
0607:
0608: case MDStatics.INT:
0609: setInternalIntField(i,
0610: (oldState.getIntField(i) + 1) & 0x7FFFFFFF);
0611: break;
0612: case MDStatics.SHORT:
0613: setInternalShortField(i, (short) ((oldState
0614: .getShortField(i) + 1) & 0x7FFF));
0615: break;
0616: case MDStatics.BYTE:
0617: setInternalByteField(i, (byte) ((oldState
0618: .getByteField(i) + 1) & 0x7F));
0619: break;
0620: default:
0621: throw BindingSupportImpl.getInstance().internal(
0622: "Invalid typeCode " + fmd.typeCode
0623: + " for autoset field: stateFieldNo "
0624: + i + " " + fmd.name);
0625: }
0626: }
0627: }
0628:
0629: public boolean getBooleanField(int stateFieldNo) {
0630: return data[stateFieldNo] != null ? ((Boolean) data[stateFieldNo])
0631: .booleanValue()
0632: : false;
0633: }
0634:
0635: public boolean getBooleanFieldAbs(int field) {
0636: return getBooleanField(convertAbsToState(field));
0637: }
0638:
0639: public char getCharField(int stateFieldNo) {
0640: return data[stateFieldNo] != null ? ((Character) data[stateFieldNo])
0641: .charValue()
0642: : '0';
0643: }
0644:
0645: public char getCharFieldAbs(int field) {
0646: return getCharField(convertAbsToState(field));
0647: }
0648:
0649: public byte getByteField(int stateFieldNo) {
0650: return data[stateFieldNo] != null ? ((Byte) data[stateFieldNo])
0651: .byteValue() : (byte) 0;
0652: }
0653:
0654: public byte getByteFieldAbs(int field) {
0655: return getByteField(convertAbsToState(field));
0656: }
0657:
0658: public short getShortField(int stateFieldNo) {
0659: return data[stateFieldNo] != null ? ((Short) data[stateFieldNo])
0660: .shortValue()
0661: : (short) 0;
0662: }
0663:
0664: public short getShortFieldAbs(int field) {
0665: return getShortField(convertAbsToState(field));
0666: }
0667:
0668: public int getIntField(int stateFieldNo) {
0669: return data[stateFieldNo] != null ? ((Integer) data[stateFieldNo])
0670: .intValue()
0671: : 0;
0672: }
0673:
0674: public int getIntFieldAbs(int field) {
0675: return getIntField(convertAbsToState(field));
0676: }
0677:
0678: public long getLongField(int stateFieldNo) {
0679: return data[stateFieldNo] != null ? ((Long) data[stateFieldNo])
0680: .longValue() : 0;
0681: }
0682:
0683: public long getLongFieldInternal(int stateFieldNo) {
0684: return data[stateFieldNo] != null ? ((Long) data[stateFieldNo])
0685: .longValue() : 0;
0686: }
0687:
0688: public long getLongFieldAbs(int field) {
0689: return getLongField(convertAbsToState(field));
0690: }
0691:
0692: public float getFloatField(int stateFieldNo) {
0693: return data[stateFieldNo] != null ? ((Float) data[stateFieldNo])
0694: .floatValue()
0695: : 0;
0696: }
0697:
0698: public float getFloatFieldAbs(int field) {
0699: return getFloatField(convertAbsToState(field));
0700: }
0701:
0702: public double getDoubleField(int stateFieldNo) {
0703: return data[stateFieldNo] != null ? ((Double) data[stateFieldNo])
0704: .doubleValue()
0705: : 0;
0706: }
0707:
0708: public double getDoubleFieldAbs(int field) {
0709: return getDoubleField(convertAbsToState(field));
0710: }
0711:
0712: public String getStringField(int stateFieldNo) {
0713: return (String) data[stateFieldNo];
0714: }
0715:
0716: public String getStringFieldAbs(int field) {
0717: return getStringField(convertAbsToState(field));
0718: }
0719:
0720: public Object getObjectField(int stateFieldNo,
0721: PersistenceCapable owningPC, PersistenceContext pm, OID oid) {
0722: Object o = data[stateFieldNo];
0723: if (!resolvedForClient[stateFieldNo]) {
0724: if (o != null) {
0725: FieldMetaData fmd = cmd.stateFields[stateFieldNo];
0726: if (fmd.scoField) {
0727: if (fmd.category == MDStatics.CATEGORY_ARRAY) {
0728: if (fmd.elementTypeMetaData != null) {
0729: o = data[stateFieldNo] = resolveArrayOIDs(
0730: (Object[]) o, pm, fmd.elementType);
0731: }
0732: } else {
0733: data[stateFieldNo] = fmd.createSCO(pm, pm
0734: .getInternalSM(owningPC), fmd,
0735: owningPC, o);
0736: o = data[stateFieldNo];
0737: }
0738: } else {
0739: switch (fmd.category) {
0740: case MDStatics.CATEGORY_EXTERNALIZED:
0741: data[stateFieldNo] = o = fmd.externalizer
0742: .fromExternalForm(pm, o);
0743: break;
0744: case MDStatics.CATEGORY_REF:
0745: case MDStatics.CATEGORY_POLYREF:
0746: data[stateFieldNo] = o = pm
0747: .getObjectByIdForState((OID) o,
0748: stateFieldNo, classIndex, oid);
0749: break;
0750: }
0751: }
0752: resolvedForClient[stateFieldNo] = true;
0753: } else if (cmd.isEmbeddedRef(stateFieldNo)) {
0754: data[stateFieldNo] = o = pm.getObjectByIdForState(null,
0755: stateFieldNo, classIndex, oid);
0756: resolvedForClient[stateFieldNo] = true;
0757: }
0758: }
0759: if (Debug.DEBUG) {
0760: if (o != null
0761: && !cmd.stateFields[stateFieldNo].type
0762: .isAssignableFrom(o.getClass())) {
0763: Debug.OUT.println("########### stateFieldNo = "
0764: + stateFieldNo);
0765: cmd.dump();
0766: throw BindingSupportImpl.getInstance().internal(
0767: "Type error");
0768: }
0769: }
0770: return o;
0771: }
0772:
0773: public boolean isFieldNullorZero(int stateFieldNo) {
0774: if (Debug.DEBUG) {
0775: if (!filled[stateFieldNo]) {
0776: throw BindingSupportImpl.getInstance().internal(
0777: "Field " + stateFieldNo + " is not loaded");
0778: }
0779: }
0780: Object o = data[stateFieldNo];
0781: if (o == null) {
0782: return true;
0783: }
0784: FieldMetaData f = cmd.stateFields[stateFieldNo];
0785: switch (f.typeCode) {
0786: case MDStatics.BOOLEAN:
0787: case MDStatics.BOOLEANW:
0788: return !((Boolean) o).booleanValue();
0789: case MDStatics.BYTE:
0790: case MDStatics.BYTEW:
0791: case MDStatics.SHORT:
0792: case MDStatics.SHORTW:
0793: case MDStatics.INT:
0794: case MDStatics.INTW:
0795: return ((Number) o).intValue() == 0;
0796: case MDStatics.LONG:
0797: case MDStatics.LONGW:
0798: return ((Long) o).longValue() == 0L;
0799: case MDStatics.FLOAT:
0800: case MDStatics.FLOATW:
0801: return ((Float) o).floatValue() == 0.0f;
0802: case MDStatics.DOUBLE:
0803: case MDStatics.DOUBLEW:
0804: case MDStatics.BIGDECIMAL:
0805: case MDStatics.BIGINTEGER:
0806: return ((Number) o).doubleValue() == 0.0;
0807: }
0808: return false;
0809: }
0810:
0811: public Object getObjectFieldAbs(int absFieldNo,
0812: PersistenceCapable owningPC, PersistenceContext sm, OID oid) {
0813: return getObjectField(convertAbsToState(absFieldNo), owningPC,
0814: sm, oid);
0815: }
0816:
0817: public void setBooleanField(int field, boolean newValue) {
0818: makeDirty(field);
0819: setInternalBooleanField(field, newValue);
0820: }
0821:
0822: public void setBooleanFieldAbs(int field, boolean newValue) {
0823: setBooleanField(convertAbsToState(field), newValue);
0824: }
0825:
0826: public void setCharField(int stateFieldNo, char newValue) {
0827: makeDirty(stateFieldNo);
0828: setInternalCharField(stateFieldNo, newValue);
0829: }
0830:
0831: public void setCharFieldAbs(int absFieldNo, char newValue) {
0832: setCharField(convertAbsToState(absFieldNo), newValue);
0833: }
0834:
0835: public void setByteField(int field, byte newValue) {
0836: makeDirty(field);
0837: setInternalByteField(field, newValue);
0838: }
0839:
0840: public void setByteFieldAbs(int absFieldNo, byte newValue) {
0841: setByteField(convertAbsToState(absFieldNo), newValue);
0842: }
0843:
0844: public void setShortField(int field, short newValue) {
0845: makeDirty(field);
0846: setInternalShortField(field, newValue);
0847: }
0848:
0849: public void setShortFieldAbs(int field, short newValue) {
0850: setShortField(convertAbsToState(field), newValue);
0851: }
0852:
0853: public void setIntField(int field, int newValue) {
0854: makeDirty(field);
0855: setInternalIntField(field, newValue);
0856: }
0857:
0858: public void setIntFieldAbs(int absFieldNo, int newValue) {
0859: setIntField(convertAbsToState(absFieldNo), newValue);
0860: }
0861:
0862: public void setLongField(int field, long newValue) {
0863: makeDirty(field);
0864: setInternalLongField(field, newValue);
0865: }
0866:
0867: public void setLongFieldAbs(int field, long newValue) {
0868: setLongField(convertAbsToState(field), newValue);
0869: }
0870:
0871: public void setFloatField(int field, float newValue) {
0872: makeDirty(field);
0873: setInternalFloatField(field, newValue);
0874: }
0875:
0876: public void setFloatFieldAbs(int field, float newValue) {
0877: setFloatField(convertAbsToState(field), newValue);
0878: }
0879:
0880: public void setDoubleField(int field, double newValue) {
0881: makeDirty(field);
0882: setInternalDoubleField(field, newValue);
0883: }
0884:
0885: public void setDoubleFieldAbs(int field, double newValue) {
0886: setDoubleField(convertAbsToState(field), newValue);
0887: }
0888:
0889: public void setStringField(int field, String newValue) {
0890: makeDirty(field);
0891: setInternalStringField(field, newValue);
0892: }
0893:
0894: public void setStringFieldAbs(int field, String newValue) {
0895: setStringField(convertAbsToState(field), newValue);
0896: }
0897:
0898: public void setObjectField(int field, Object newValue) {
0899: checkCmd();
0900: makeDirty(field);
0901: resolvedForClient[field] = true;
0902: if (Debug.DEBUG) {
0903: if (newValue != null
0904: && !cmd.stateFields[field].type
0905: .isAssignableFrom(newValue.getClass())) {
0906: Debug.OUT.println("########### field = " + field);
0907: Debug.OUT.println("## field type = "
0908: + cmd.stateFields[field].type.getName());
0909: Debug.OUT.println("## object type = "
0910: + newValue.getClass().getName());
0911: cmd.dump();
0912: throw BindingSupportImpl.getInstance().internal(
0913: "Type error");
0914: }
0915: }
0916: setInternalObjectField(field, newValue);
0917: }
0918:
0919: public void setObjectFieldAbs(int field, Object newValue) {
0920: setObjectField(convertAbsToState(field), newValue);
0921: }
0922:
0923: public void setObjectFieldUnresolved(int field, Object newValue) {
0924: checkCmd();
0925: makeDirty(field);
0926: resolvedForClient[field] = false;
0927: setInternalObjectField(field, newValue);
0928: }
0929:
0930: public void setObjectFieldUnresolvedAbs(int field, Object newValue) {
0931: setObjectFieldUnresolved(convertAbsToState(field), newValue);
0932: }
0933:
0934: //=======================setInternalXXX====================================
0935:
0936: public void setInternalBooleanField(int field, boolean newValue) {
0937: data[field] = newValue ? Boolean.TRUE : Boolean.FALSE;
0938: filled[field] = true;
0939: }
0940:
0941: public void setInternalBooleanFieldAbs(int field, boolean newValue) {
0942: setInternalBooleanField(convertAbsToState(field), newValue);
0943: }
0944:
0945: public void setInternalCharField(int field, char newValue) {
0946: data[field] = new Character(newValue);
0947: filled[field] = true;
0948: }
0949:
0950: public void setInternalCharFieldAbs(int field, char newValue) {
0951: setInternalCharField(convertAbsToState(field), newValue);
0952: }
0953:
0954: public void setInternalByteField(int field, byte newValue) {
0955: data[field] = new Byte(newValue);
0956: filled[field] = true;
0957: }
0958:
0959: public void setInternalByteFieldAbs(int field, byte newValue) {
0960: setInternalByteField(convertAbsToState(field), newValue);
0961: }
0962:
0963: public void setInternalShortField(int field, short newValue) {
0964: data[field] = new Short(newValue);
0965: filled[field] = true;
0966: }
0967:
0968: public void setInternalShortFieldAbs(int field, short newValue) {
0969: setInternalShortField(convertAbsToState(field), newValue);
0970: }
0971:
0972: public void setInternalIntField(int field, int newValue) {
0973: data[field] = new Integer(newValue);
0974: filled[field] = true;
0975: }
0976:
0977: public void setInternalIntFieldAbs(int field, int newValue) {
0978: setInternalIntField(convertAbsToState(field), newValue);
0979: }
0980:
0981: public void setInternalLongField(int field, long newValue) {
0982: data[field] = new Long(newValue);
0983: filled[field] = true;
0984: }
0985:
0986: public void setFilled(int stateFieldNo) {
0987: filled[stateFieldNo] = true;
0988: }
0989:
0990: public void setInternalLongFieldAbs(int field, long newValue) {
0991: setInternalLongField(convertAbsToState(field), newValue);
0992: }
0993:
0994: public void setInternalFloatField(int field, float newValue) {
0995: data[field] = new Float(newValue);
0996: filled[field] = true;
0997: }
0998:
0999: public void setInternalFloatFieldAbs(int field, float newValue) {
1000: setInternalFloatField(convertAbsToState(field), newValue);
1001: }
1002:
1003: public void setInternalDoubleField(int field, double newValue) {
1004: data[field] = new Double(newValue);
1005: filled[field] = true;
1006: }
1007:
1008: public void setInternalDoubleFieldAbs(int field, double newValue) {
1009: setInternalDoubleField(convertAbsToState(field), newValue);
1010: }
1011:
1012: public void setInternalStringField(int field, String newValue) {
1013: data[field] = newValue;
1014: filled[field] = true;
1015: }
1016:
1017: public void setInternalStringFieldAbs(int field, String newValue) {
1018: setInternalStringField(convertAbsToState(field), newValue);
1019: }
1020:
1021: public void setInternalObjectField(int field, Object newValue) {
1022: data[field] = newValue;
1023: filled[field] = true;
1024: }
1025:
1026: public void setInternalObjectFieldAbs(int field, Object newValue) {
1027: setInternalObjectField(convertAbsToState(field), newValue);
1028: }
1029:
1030: //==========================getInternalXXX======================================
1031:
1032: public Object getInternalObjectField(int stateFieldNo) {
1033: return data[stateFieldNo];
1034: }
1035:
1036: public Object getInternalObjectFieldAbs(int field) {
1037: return getInternalObjectField(convertAbsToState(field));
1038: }
1039:
1040: public void updateFrom(State state) {
1041: GenericState gState = (GenericState) state;
1042: boolean[] fields = gState.filled;
1043: Object[] otherData = gState.data;
1044: for (int i = 0; i < fields.length; i++) {
1045: if (fields[i]) {
1046: data[i] = otherData[i];
1047: filled[i] = true;
1048: }
1049: }
1050: }
1051:
1052: /**
1053: * Mark all dirty fields as clean and not filled and not resolved.
1054: * <p/>
1055: * filled &= ~dirty
1056: * resolved &= ~dirty
1057: * dirty = 0
1058: */
1059: public void clearDirtyFields() {
1060: for (int i = 0; i < dirtyFields.length; i++) {
1061: if (dirtyFields[i]) {
1062: dirtyFields[i] = false;
1063: filled[i] = false;
1064: resolvedForClient[i] = false;
1065: }
1066: }
1067: }
1068:
1069: public void updateNonFilled(State state) {
1070: GenericState gState = (GenericState) state;
1071: if (Debug.DEBUG) {
1072: if (gState.getClassIndex() != getClassIndex()) {
1073: throw BindingSupportImpl.getInstance().internal(
1074: "Incompatible states");
1075: }
1076: }
1077: boolean[] fields = gState.filled;
1078: Object[] otherData = gState.data;
1079: for (int i = 0; i < fields.length; i++) {
1080: if (fields[i] && !filled[i]) {
1081: data[i] = otherData[i];
1082: filled[i] = true;
1083: }
1084: }
1085: }
1086:
1087: public void clearNonAutoSetFields() {
1088: for (int i = 0; i < cmd.nonAutoSetStateFieldNos.length; i++) {
1089: int f = cmd.nonAutoSetStateFieldNos[i];
1090: data[f] = null;
1091: filled[f] = false;
1092: }
1093: }
1094:
1095: public void retrieve(VersantPersistenceManagerImp sm) {
1096: FetchGroup fg = cmd.refFetchGroup;
1097: while (fg != null) {
1098: retrieveImp(fg.stateFieldNos, sm);
1099: fg = fg.super FetchGroup;
1100: }
1101: }
1102:
1103: private void retrieveImp(int[] fieldNos,
1104: VersantPersistenceManagerImp sm) {
1105: int fieldNo = 0;
1106: FieldMetaData fmd = null;
1107: for (int i = fieldNos.length - 1; i >= 0; i--) {
1108: fieldNo = fieldNos[i];
1109: if (data[fieldNo] != null) {
1110: fmd = cmd.stateFields[fieldNo];
1111: if (fmd.persistenceModifier != MDStatics.PERSISTENCE_MODIFIER_TRANSACTIONAL) {
1112: switch (fmd.category) {
1113: case MDStatics.CATEGORY_ARRAY:
1114: sm.retrieveAllImp((Object[]) data[fieldNo]);
1115: break;
1116: case MDStatics.CATEGORY_COLLECTION:
1117: sm.retrieveAllImp((Collection) data[fieldNo]);
1118: break;
1119: case MDStatics.CATEGORY_MAP:
1120: StateUtil
1121: .retrieve((Map) data[fieldNo], sm, fmd);
1122: break;
1123: case MDStatics.CATEGORY_REF:
1124: case MDStatics.CATEGORY_POLYREF:
1125: sm.retrieveImp(data[fieldNo]);
1126: break;
1127: default:
1128: throw BindingSupportImpl.getInstance()
1129: .internal("Type not allowed");
1130: }
1131: }
1132: }
1133: }
1134: }
1135:
1136: /**
1137: * @param pm
1138: * @param pcStateMan
1139: */
1140: public void addRefs(VersantPersistenceManagerImp pm,
1141: PCStateMan pcStateMan) {
1142: if (dirty) {
1143: FetchGroup fg = findFirstRefFG(cmd);
1144: while (fg != null) {
1145: addRefs(fg.stateFieldNos, pm, pcStateMan);
1146: fg = fg.super FetchGroup;
1147: }
1148: }
1149: }
1150:
1151: private FetchGroup findFirstRefFG(ClassMetaData cmd) {
1152: if (cmd.refFetchGroup != null)
1153: return cmd.refFetchGroup;
1154: if (cmd.refFetchGroup == null && cmd.pcSuperMetaData == null)
1155: return null;
1156: return findFirstRefFG(cmd.pcSuperMetaData);
1157: }
1158:
1159: /**
1160: * A ref may be a direct ref or an item in collection/map/array.
1161: */
1162: private final void addRefs(int[] fieldNos,
1163: VersantPersistenceManagerImp pm, PCStateMan sm) {
1164: int fieldNo = 0;
1165: FieldMetaData fmd = null;
1166: // the fields MUST be processed in ascending order or embedded
1167: // reference fields containing other embedded reference fields
1168: // will not work as the embedded-embedded field will be
1169: // processed prior to being filled
1170: for (int i = 0; i < fieldNos.length; i++) {
1171: fieldNo = fieldNos[i];
1172: if (dirtyFields[fieldNo]) {
1173: if (data[fieldNo] != null) {
1174: fmd = cmd.stateFields[fieldNo];
1175: if (fmd.persistenceModifier != MDStatics.PERSISTENCE_MODIFIER_TRANSACTIONAL) {
1176: switch (fmd.category) {
1177: case MDStatics.CATEGORY_ARRAY:
1178: StateUtil.doReachable(
1179: (Object[]) data[fieldNo], pm);
1180: break;
1181: case MDStatics.CATEGORY_COLLECTION:
1182: StateUtil.doReachable(
1183: (Collection) data[fieldNo], pm);
1184: break;
1185: case MDStatics.CATEGORY_MAP:
1186: StateUtil.doReachable((Map) data[fieldNo],
1187: pm, fmd);
1188: break;
1189: case MDStatics.CATEGORY_REF:
1190: case MDStatics.CATEGORY_POLYREF:
1191: if (data[fieldNo] instanceof PersistenceCapable) {
1192: if (fmd.embedded) {
1193: StateUtil
1194: .doReachableEmbeddedReference(
1195: (PersistenceCapable) data[fieldNo],
1196: pm, sm, fmd);
1197: } else {
1198: StateUtil
1199: .doReachable(
1200: (PersistenceCapable) data[fieldNo],
1201: pm);
1202: }
1203: }
1204: break;
1205: default:
1206: throw BindingSupportImpl.getInstance()
1207: .internal("Type not allowed");
1208: }
1209: }
1210: }
1211: }
1212: }
1213: }
1214:
1215: public void validateForCache() {
1216: checkCmd();
1217: FieldMetaData[] fmds = cmd.stateFields;
1218: for (int i = 0; i < fmds.length; i++) {
1219: FieldMetaData fieldMetaData = fmds[i];
1220: Object o = data[fieldMetaData.stateFieldNo];
1221: if (o != null) {
1222: int cat = fieldMetaData.category;
1223: if (cat == MDStatics.CATEGORY_REF
1224: || cat == MDStatics.CATEGORY_POLYREF) {
1225: if (!(o instanceof OID)) {
1226: fieldMetaData.dump(Debug.OUT, " ");
1227: throw BindingSupportImpl
1228: .getInstance()
1229: .internal(
1230: "The instance is not valid to be added to cache");
1231: }
1232: }
1233: }
1234: }
1235: }
1236:
1237: public void makeDirty(int stateFieldNo) {
1238: dirty = true;
1239: dirtyFields[stateFieldNo] = true;
1240: }
1241:
1242: public void makeDirtyAbs(int absFieldNo) {
1243: makeDirty(convertAbsToState(absFieldNo));
1244: }
1245:
1246: public boolean isDirty() {
1247: return dirty;
1248: }
1249:
1250: public boolean isDirty(int absFieldNo) {
1251: return dirtyFields[convertAbsToState(absFieldNo)];
1252: }
1253:
1254: /**
1255: * This must be called once the state is ready to be sent off to the server.
1256: * <p/>
1257: * All FirstClass instances will be resolved to an OID and second class
1258: * instances will be resolved to some serializable/storable format that represents the
1259: * state of the field.
1260: */
1261: private void prepare(PersistenceContext pm, VersantStateManager sm) {
1262: FieldMetaData fmd = null;
1263: for (int i = 0; i < data.length; i++) {
1264: if (filled[i] && data[i] != null) {
1265: fmd = cmd.stateFields[i];
1266: if (fmd.scoField) {
1267: if (fmd.typeCode == MDStatics.DATE) {
1268: data[i] = StateUtil
1269: .getPValueForSCO((java.util.Date) data[i]);
1270:
1271: } else {
1272: switch (fmd.category) {
1273: case MDStatics.CATEGORY_ARRAY:
1274: if ((data[i] instanceof OID[]) == false
1275: && fmd.isElementTypePC()) {
1276: data[i] = resolveArrayValues(
1277: (Object[]) data[i], pm);
1278: }
1279: break;
1280: case MDStatics.CATEGORY_COLLECTION:
1281: if ((data[i] instanceof OID[]) == false) {
1282: data[i] = StateUtil.getPValueForSCO(
1283: (Collection) data[i], pm, sm,
1284: fmd);
1285: }
1286: break;
1287: case MDStatics.CATEGORY_MAP:
1288: if ((data[i] instanceof MapEntries) == false) {
1289: data[i] = StateUtil.getPValueForSCO(
1290: (Map) data[i], pm, fmd);
1291: }
1292: break;
1293: default:
1294: throw BindingSupportImpl
1295: .getInstance()
1296: .internal(
1297: "No logic defined for field type "
1298: + MDStaticUtils
1299: .toSimpleName(fmd.typeCode)
1300: + " field name = "
1301: + fmd.name);
1302: }
1303: }
1304: } else {
1305: switch (fmd.category) {
1306: case MDStatics.CATEGORY_EXTERNALIZED:
1307: data[i] = fmd.externalizer.toExternalForm(pm
1308: .getPersistenceManager(), data[i]);
1309: break;
1310: case MDStatics.CATEGORY_REF:
1311: case MDStatics.CATEGORY_POLYREF:
1312: if (fmd.embedded) {
1313: data[i] = null;
1314: } else if (data[i] instanceof PersistenceCapable) {
1315: data[i] = StateUtil.getPValueForRef(
1316: (PersistenceCapable) data[i], pm);
1317: }
1318: break;
1319: }
1320: }
1321: }
1322: }
1323: }
1324:
1325: /**
1326: * This is to copy the fields that is filled in on the supplied state to the
1327: * current state. The objective behind it is to keep a copy of the date to
1328: * compare against the db at the time of commit. The only field types of interest
1329: * is java.util.Date and Reference fields.
1330: *
1331: * @param state
1332: * @param sm
1333: */
1334: public void copyFieldsForOptimisticLocking(State state,
1335: VersantPersistenceManagerImp sm) {
1336: GenericState gState = (GenericState) state;
1337: boolean[] fields = gState.filled;
1338: Object[] otherData = gState.data;
1339: FieldMetaData fmd = null;
1340: for (int i = 0; i < fields.length; i++) {
1341: if (fields[i] && !filled[i]) {
1342: if (otherData[i] != null) {
1343: fmd = cmd.stateFields[i];
1344: boolean resolved = gState.resolvedForClient != null ? gState.resolvedForClient[i]
1345: : false;
1346: if (fmd.typeCode == MDStatics.DATE) {
1347: if (resolved) {
1348:
1349: data[i] = ((Date) otherData[i]).clone();
1350:
1351: } else {
1352: data[i] = otherData[i];
1353: }
1354: filled[i] = true;
1355: } else if (fmd.category == MDStatics.CATEGORY_REF
1356: || fmd.category == MDStatics.CATEGORY_POLYREF) {
1357: if (resolved) {
1358: data[i] = sm
1359: .getInternalOID((PersistenceCapable) otherData[i]);
1360: } else {
1361: data[i] = otherData[i];
1362: }
1363: filled[i] = true;
1364: } else {
1365: data[i] = otherData[i];
1366: filled[i] = true;
1367: }
1368: }
1369: }
1370: }
1371: }
1372:
1373: /**
1374: * This copies all the fakeFields from one the supplied state.
1375: *
1376: * @param state
1377: */
1378: public void copyOptimisticLockingField(State state) {
1379: GenericState gState = (GenericState) state;
1380: FieldMetaData optimisticLockingField = cmd.optimisticLockingField;
1381: if (optimisticLockingField == null)
1382: return;
1383: if (gState.filled[optimisticLockingField.stateFieldNo]) {
1384: data[optimisticLockingField.stateFieldNo] = gState.data[optimisticLockingField.stateFieldNo];
1385: filled[optimisticLockingField.stateFieldNo] = true;
1386: }
1387: }
1388:
1389: /**
1390: * This will replace all fields that should be a SCO field with it's SCO implementation.
1391: */
1392: public int replaceSCOFields(PersistenceCapable owner,
1393: VersantPersistenceManagerImp sm, int[] absFields) {
1394: if (cmd.scoFieldNos.length == 0)
1395: return 0;
1396: int[] scoStateFieldNos = cmd.scoFieldNos;
1397: int count = 0;
1398: for (int i = 0; i < scoStateFieldNos.length; i++) {
1399: int scoStateFieldNo = scoStateFieldNos[i];
1400: if (data[scoStateFieldNo] != null) {
1401: FieldMetaData fmd = cmd.stateFields[scoStateFieldNo];
1402: data[scoStateFieldNo] = fmd.createSCO(sm, sm
1403: .getInternalSM(owner), fmd, owner,
1404: data[scoStateFieldNo]);
1405: absFields[count++] = cmd.stateFields[scoStateFieldNo].managedFieldNo;
1406: }
1407: }
1408: return count;
1409: }
1410:
1411: public void unmanageSCOFields() {
1412: final Object[] d = data;
1413: for (int i = 0; i < cmd.scoFieldNos.length; i++) {
1414: final int scoFieldNo = cmd.scoFieldNos[i];
1415: if ((d[scoFieldNo] != null)) {
1416: if ((d[scoFieldNo] instanceof VersantSimpleSCO)) {
1417: ((VersantSimpleSCO) d[scoFieldNo]).makeTransient();
1418: }
1419: }
1420: }
1421: }
1422:
1423: public State getCopy() {
1424: checkCmd();
1425: final GenericState copy = new GenericState(cmd);
1426: System.arraycopy(this .filled, 0, copy.filled, 0,
1427: copy.filled.length);
1428: System.arraycopy(this .data, 0, copy.data, 0, copy.data.length);
1429: return copy;
1430: }
1431:
1432: /**
1433: * <p>This return a deep clone of this state instance with only fields that
1434: * must be sent to the server to persist changes to this instance filled
1435: * in. For JdbcDataStore this will include only the dirty fields. For
1436: * VdsDataStore this includes all fields so the whole DataStoreObject
1437: * can be written.</p>
1438: * <p/>
1439: * <p>All 'First Class Objects' will be resolved to an OID and
1440: * 'Second Class Objects' will be resolved to some serializable/storable
1441: * format that represents the state of the field.</p>
1442: *
1443: * @return True if some fields were written to stateToStore and false if
1444: * not (i.e. we have no dirty fields)
1445: */
1446: public boolean fillToStoreState(State stateToStore,
1447: PersistenceContext pm, VersantStateManager sm) {
1448: GenericState state = (GenericState) stateToStore;
1449: if (dirty) {
1450: if (cmd.storeAllFields) {
1451: // we must include all primary fields not just the dirty ones
1452: for (int i = 0; i < data.length; i++) {
1453: FieldMetaData fmd = cmd.stateFields[i];
1454: if (fmd.persistenceModifier == MDStatics.PERSISTENCE_MODIFIER_TRANSACTIONAL) {
1455: continue;
1456: } else if (fmd.primaryField) {
1457: if (filled[i]) {
1458: state.data[i] = data[i];
1459: state.filled[i] = true;
1460: }
1461: } else if (fmd.secondaryField) {
1462: if (dirtyFields[i]) {
1463: state.data[i] = data[i];
1464: state.filled[i] = true;
1465: } else {
1466: state.data[i] = null;
1467: state.filled[i] = false;
1468: }
1469: } else {
1470: throw BindingSupportImpl.getInstance()
1471: .internal(
1472: "not primaryField "
1473: + "or secondaryField: "
1474: + fmd.getQName());
1475: }
1476: }
1477: state.prepare(pm, sm);
1478: } else {
1479: int count = 0;
1480: for (int i = 0; i < data.length; i++) {
1481: if (dirtyFields[i]) {
1482: count++;
1483: state.data[i] = data[i];
1484: state.filled[i] = true;
1485: } else {
1486: state.data[i] = null;
1487: state.filled[i] = false;
1488: }
1489: }
1490: if (count == 0) {
1491: dirty = false;
1492: state = null;
1493: } else {
1494: state.prepare(pm, sm);
1495: }
1496: }
1497: } else {
1498: state = null;
1499: }
1500: return state != null;
1501: }
1502:
1503: public void fillForRead(State dest, VersantPersistenceManagerImp pm) {
1504: if (Debug.DEBUG) {
1505: // method only implemented for VDS - should not be called for JDBC
1506: if (!cmd.storeAllFields) {
1507: throw BindingSupportImpl
1508: .getInstance()
1509: .internal(
1510: "Only implemented for "
1511: + "classes with cmd.storeAllFields true");
1512: }
1513: }
1514: GenericState state = (GenericState) dest;
1515: for (int i = 0; i < data.length; i++) {
1516: FieldMetaData fmd = cmd.stateFields[i];
1517: // filled[i] will be true for VDS so we do not need to check it
1518: if (fmd.fake) {
1519: state.data[i] = data[i];
1520: state.filled[i] = true;
1521: } else {
1522: int cat = fmd.category;
1523: if (cat == MDStatics.CATEGORY_REF
1524: || cat == MDStatics.CATEGORY_POLYREF) {
1525: Object o = data[i];
1526: if (o instanceof PersistenceCapable) {
1527: PersistenceCapable pc = (PersistenceCapable) o;
1528: if (pc.jdoGetPersistenceManager() == null) {
1529: o = null;
1530: } else {
1531: o = StateUtil.getPValueForRef(pc, pm);
1532: }
1533: }
1534: state.data[i] = o;
1535: state.filled[i] = true;
1536: }
1537: }
1538: }
1539: }
1540:
1541: public String toString() {
1542: checkCmd();
1543: StringBuffer s = new StringBuffer();
1544: s.append("GenericState@");
1545: s.append(Integer.toHexString(System.identityHashCode(this )));
1546: s.append(" ");
1547: String name = cmd.qname;
1548: int i = name.lastIndexOf('.');
1549: if (i >= 0)
1550: name = name.substring(i + 1);
1551: s.append(name);
1552: s.append(" {\n");
1553: boolean first = true;
1554: int n = data.length;
1555: for (i = 0; i < n; i++) {
1556: if (!filled[i])
1557: continue;
1558: if (first) {
1559: first = false;
1560: } else {
1561: s.append(",\n ");
1562: }
1563: s.append(cmd.stateFields[i].name);
1564: s.append('[');
1565: s.append(cmd.stateFields[i].stateFieldNo);
1566: s.append(']');
1567: s.append('=');
1568: s.append(toString(data[i]));
1569: s.append(" type = "
1570: + (data[i] != null ? data[i].getClass().getName()
1571: : " null"));
1572: s.append(" SysId = " + System.identityHashCode(data[i]));
1573: s.append(" jdoClsId = " + cmd.classId);
1574: if (resolvedForClient != null) {
1575: s.append(" res = " + resolvedForClient[i]);
1576: }
1577: }
1578: s.append('}');
1579: return s.toString();
1580: }
1581:
1582: private String toString(Object o) {
1583: if (o == null)
1584: return "null";
1585: if (o instanceof String) {
1586: String s = (String) o;
1587: if (s.length() > 100)
1588: return s.substring(0, 100) + " ...";
1589: return s;
1590: } else if (o instanceof OID) {
1591: return ((OID) o).toStringImp();
1592: } else {
1593: return o.toString();
1594: }
1595: }
1596:
1597: protected final void checkCmd() {
1598: if (cmd == null) {
1599: throw BindingSupportImpl.getInstance().internal(
1600: "the cmd is null");
1601: }
1602: }
1603:
1604: public void writeExternal(OIDObjectOutput os) throws IOException {
1605: // if (Debug.DEBUG) {
1606: // System.out.println("%%% GenericState.writeExternal " + cmd.qname);
1607: // }
1608: os.writeBoolean(dirty);
1609: for (int i = 0; i < filled.length; i++) {
1610: os.writeBoolean(filled[i]);
1611: }
1612: for (int i = 0; i < data.length; i++) {
1613: if (!filled[i]) {
1614: continue;
1615: }
1616: FieldMetaData fmd = cmd.stateFields[i];
1617: // if (Debug.DEBUG) {
1618: // Object o = data[i];
1619: // System.out.println("%%% GenericState.writeExternal " + fmd +
1620: // " " + (o instanceof OID ? ((OID)o).toStringImp() : String.valueOf(o)));
1621: // os.writeUTF("begin " + fmd.name);
1622: // }
1623: switch (fmd.category) {
1624: case MDStatics.CATEGORY_ARRAY:
1625: SerUtils.writeArrayField(fmd, os, data[i]);
1626: break;
1627: case MDStatics.CATEGORY_COLLECTION:
1628: case MDStatics.CATEGORY_MAP:
1629: SerUtils.writeCollectionOrMapField(os, fmd, data[i]);
1630: break;
1631: case MDStatics.CATEGORY_EXTERNALIZED:
1632: case MDStatics.CATEGORY_SIMPLE:
1633: SerUtils.writeSimpleField(fmd, os, data[i]);
1634: break;
1635: case MDStatics.CATEGORY_REF:
1636: case MDStatics.CATEGORY_POLYREF:
1637: os.write((OID) data[i]);
1638: break;
1639: case MDStatics.CATEGORY_TRANSACTIONAL:
1640: break;
1641: default:
1642: throw BindingSupportImpl.getInstance().internal(
1643: "No logic defined for field type "
1644: + MDStaticUtils
1645: .toSimpleName(fmd.typeCode)
1646: + " field name = " + fmd.name);
1647: }
1648: // if (Debug.DEBUG) {
1649: // os.writeUTF("end " + fmd.name);
1650: // }
1651: }
1652: }
1653:
1654: // private void expect(OIDObjectInput is, String expected)
1655: // throws IOException {
1656: // String s = is.readUTF();
1657: // if (!expected.equals(s)) {
1658: // throw new StreamCorruptedException("Expected: '" + expected +
1659: // "' got '" + s + "'");
1660: // }
1661: // }
1662:
1663: public void readExternal(OIDObjectInput is)
1664: throws ClassNotFoundException, IOException {
1665: // if (Debug.DEBUG) {
1666: // System.out.println("%%% GenericState.readExternal " + cmd);
1667: // }
1668: // no need to read the classIndex and cmd as they are set in the
1669: // constructor
1670: dirty = is.readBoolean();
1671: for (int i = 0; i < filled.length; i++) {
1672: filled[i] = is.readBoolean();
1673: }
1674: for (int i = 0; i < data.length; i++) {
1675: if (!filled[i]) {
1676: continue;
1677: }
1678: FieldMetaData fmd = cmd.stateFields[i];
1679: // if (Debug.DEBUG) {
1680: // System.out.println("%%% GenericState.readExternal " + fmd);
1681: // expect(is, "begin " + fmd.name);
1682: // }
1683: switch (fmd.category) {
1684: case MDStatics.CATEGORY_ARRAY:
1685: data[i] = SerUtils.readArrayField(fmd, is);
1686: break;
1687: case MDStatics.CATEGORY_COLLECTION:
1688: case MDStatics.CATEGORY_MAP:
1689: data[i] = SerUtils.readCollectionOrMapField(is, fmd);
1690: break;
1691: case MDStatics.CATEGORY_SIMPLE:
1692: case MDStatics.CATEGORY_EXTERNALIZED:
1693: data[i] = SerUtils.readSimpleField(fmd, is);
1694: break;
1695: case MDStatics.CATEGORY_REF:
1696: case MDStatics.CATEGORY_POLYREF:
1697: data[i] = is.readOID();
1698: break;
1699: case MDStatics.CATEGORY_TRANSACTIONAL:
1700: break;
1701: default:
1702: throw BindingSupportImpl.getInstance().internal(
1703: "No logic defined for field type "
1704: + MDStaticUtils
1705: .toSimpleName(fmd.typeCode)
1706: + " field name = " + fmd.name);
1707: }
1708: ;
1709: // if (Debug.DEBUG) {
1710: // Object o = data[i];
1711: // System.out.println("%%% GenericState.readExternal " + fmd +
1712: // " " + (o instanceof OID ? ((OID)o).toStringImp() : String.valueOf(o)));
1713: // expect(is, "end " + fmd.name);
1714: // }
1715: }
1716: }
1717:
1718: public String getVersion() {
1719: return Debug.VERSION;
1720: }
1721:
1722: public static Object readSimple(int type, DataInput is)
1723: throws IOException {
1724: if (is.readInt() == 0) {
1725: return null;
1726: } else {
1727: switch (type) {
1728: case MDStatics.INTW:
1729: case MDStatics.INT:
1730: return new Integer(is.readInt());
1731: case MDStatics.SHORTW:
1732: case MDStatics.SHORT:
1733: return new Short(is.readShort());
1734: case MDStatics.STRING:
1735: return is.readUTF();
1736: case MDStatics.BOOLEANW:
1737: case MDStatics.BOOLEAN:
1738: return new Boolean(is.readBoolean());
1739: case MDStatics.BYTEW:
1740: case MDStatics.BYTE:
1741: return new Byte(is.readByte());
1742: case MDStatics.DOUBLEW:
1743: case MDStatics.DOUBLE:
1744: return new Double(is.readDouble());
1745: case MDStatics.FLOATW:
1746: case MDStatics.FLOAT:
1747: return new Float(is.readFloat());
1748: case MDStatics.LONGW:
1749: case MDStatics.LONG:
1750: return new Long(is.readLong());
1751: case MDStatics.DATE:
1752: return new Date(is.readLong());
1753: case MDStatics.LOCALE:
1754: return new Locale(is.readUTF(), is.readUTF(), is
1755: .readUTF());
1756: default:
1757: throw BindingSupportImpl.getInstance().internal(
1758: "readSimpleField for " + type
1759: + " is not supported");
1760: }
1761: }
1762: }
1763:
1764: public boolean isHollow() {
1765: for (int i = 0; i < filled.length; i++) {
1766: if (filled[i])
1767: return false;
1768: }
1769: for (int i = 0; i < data.length; i++) {
1770: if (data[i] != null)
1771: return false;
1772: }
1773: return true;
1774: }
1775:
1776: public boolean equals(Object obj) {
1777: try {
1778: GenericState state = (GenericState) obj;
1779: int n = filled.length;
1780: for (int i = 0; i < n; i++) {
1781: if (filled[i] != state.filled[i]) {
1782: return false;
1783: }
1784: if (data[i] != null) {
1785: if (!data[i].equals(state.data[i])) {
1786: return false;
1787: }
1788: } else {
1789: if (state.data != null) {
1790: return false;
1791: }
1792: }
1793: return true;
1794: }
1795: } catch (ClassCastException e) {
1796: return false;
1797: }
1798: return false;
1799: }
1800:
1801: public boolean isResolvedForClient(int stateFieldNo) {
1802: if (resolvedForClient != null
1803: && resolvedForClient[stateFieldNo]) {
1804: return true;
1805: }
1806: return false;
1807: }
1808:
1809: /**
1810: * The value of the version field on the pc.
1811: * This will return null if there are no version fields.
1812: */
1813: public Object getOptimisticLockingValue() {
1814: if (cmd.optimisticLockingField != null) {
1815: return data[cmd.optimisticLockingField.stateFieldNo];
1816: }
1817: return null;
1818: }
1819:
1820: /**
1821: * Add the values of any non-null reference fields used as back or inverse
1822: * fields for unmanaged one-to-many collections for eviction from the L2
1823: * cache on commit. Note that the filled status of the field is not
1824: * checked. This method is called only for newly managed instances so
1825: * all fields will be filled.
1826: */
1827: public void addOneToManyInverseFieldsForL2Evict(
1828: VersantPersistenceManagerImp pm) {
1829: checkCmd();
1830: for (int i = 0; i < data.length; i++) {
1831: FieldMetaData fmd = cmd.stateFields[i];
1832: if (fmd.isDetail && !fmd.managed) {
1833: Object o = data[i];
1834: if (o != null) {
1835: pm.evictFromL2CacheAfterCommitImp(o);
1836: }
1837: }
1838: }
1839: }
1840:
1841: }
|