0001: /**********************************************************************
0002: Copyright (c) 2006 Andy Jefferson and others. All rights reserved.
0003: Licensed under the Apache License, Version 2.0 (the "License");
0004: you may not use this file except in compliance with the License.
0005: You may obtain a copy of the License at
0006:
0007: http://www.apache.org/licenses/LICENSE-2.0
0008:
0009: Unless required by applicable law or agreed to in writing, software
0010: distributed under the License is distributed on an "AS IS" BASIS,
0011: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012: See the License for the specific language governing permissions and
0013: limitations under the License.
0014:
0015: Contributors:
0016: 2007 Xuan Baldauf - use IdentityReference instead of super.toString() as a unique identifier.
0017: 2007 Xuan Baldauf - moved initialization of AbstractStateManager to Initialization.
0018: 2007 Xuan Baldauf - remove the field "srm".
0019: 2007 Xuan Baldauf - remove the field "secondClassMutableFieldNumbers".
0020: 2007 Xuan Baldauf - remove the field "allNonPrimaryKeyFieldNumbers".
0021: 2007 Xuan Baldauf - remove the field "allFieldNumbers".
0022: 2007 Xuan Baldauf - remove the field "nonPrimaryKeyFields".
0023: 2007 Xuan Baldauf - remove the field "secondClassMutableFields".
0024: 2007 Xuan Baldauf - move the field "fieldCount" to AbstractClassMetaData.
0025: 2007 Xuan Baldauf - remove the field "callback".
0026: 2007 Andy Jefferson - removed unloadedFields
0027: ...
0028: **********************************************************************/package org.jpox.state;
0029:
0030: import javax.jdo.spi.PersistenceCapable;
0031:
0032: import org.jpox.FetchPlan;
0033: import org.jpox.ObjectManager;
0034: import org.jpox.StateManager;
0035: import org.jpox.exceptions.JPOXException;
0036: import org.jpox.identity.IdentityReference;
0037: import org.jpox.metadata.AbstractClassMetaData;
0038: import org.jpox.metadata.MetaDataManager;
0039: import org.jpox.store.StoreManager;
0040: import org.jpox.store.fieldmanager.FieldManager;
0041: import org.jpox.store.fieldmanager.AbstractFetchFieldManager.EndOfFetchPlanGraphException;
0042: import org.jpox.util.Localiser;
0043: import org.jpox.util.StringUtils;
0044:
0045: /**
0046: * Abstract representation of a StateManager.
0047: * Provides some of the basic StateManager methods that do very little.
0048: * @version $Revision: 1.36 $
0049: */
0050: public abstract class AbstractStateManager implements StateManager {
0051: /** Localiser for messages. */
0052: protected static final Localiser LOCALISER = Localiser
0053: .getInstance("org.jpox.Localisation");
0054:
0055: /** the Object Manager for this StateManager */
0056: protected ObjectManager myOM;
0057:
0058: /** The PersistenceCapable instance managed by this StateManager */
0059: protected PersistenceCapable myPC;
0060:
0061: /** the metadata for the class. */
0062: protected AbstractClassMetaData cmd;
0063:
0064: /** The object identity in the JVM. Will be "myID" (if set) or otherwise a temporary id based on this StateManager. */
0065: protected Object myInternalID;
0066:
0067: /** The object identity in the datastore */
0068: protected Object myID;
0069:
0070: /** The actual LifeCycleState for the persistable instance */
0071: protected LifeCycleState myLC;
0072:
0073: /** version field for optimistic transactions */
0074: protected Object myVersion;
0075:
0076: /** version field for optimistic transactions, after a insert/update but not yet committed. */
0077: protected Object transactionalVersion;
0078:
0079: /** Fetch plan for the class of the managed object. */
0080: protected FetchPlan.FetchPlanForClass myFP;
0081:
0082: /**
0083: * Indicator for whether the persistable instance is dirty.
0084: * Note that "dirty" in this case is not equated to being in the P_DIRTY state.
0085: * The P_DIRTY state means that at least one field in the object has been written by the user during
0086: * the current transaction, whereas for this parameter, a field is "dirty" if it's been written by the
0087: * user but not yet updated in the data store. The difference is, it's possible for an object's state
0088: * to be P_DIRTY, yet have no "dirty" fields because flush() has been called at least once during the transaction.
0089: */
0090: protected boolean dirty = false;
0091:
0092: /** indicators for which fields are currently dirty in the persistable instance. */
0093: protected boolean[] dirtyFields;
0094:
0095: /** indicators for which fields are currently loaded in the persistable instance. */
0096: protected boolean[] loadedFields;
0097:
0098: /** Whether to restore values at StateManager. If true, overwrites the restore values at tx level. */
0099: protected boolean restoreValues = false;
0100:
0101: /** Current FieldManager. */
0102: protected FieldManager currFM = null;
0103:
0104: /** monitor to synchronize execution when replacing/providing fields **/
0105: protected Object currFMmonitor = new Object();
0106:
0107: /** The type of the managed object (0 = PC, 1 = embedded PC, 2 = embedded element, 3 = embedded key, 4 = embedded value. */
0108: protected int pcObjectType = 0;
0109:
0110: /**
0111: * Constructor.
0112: * @param om ObjectManager
0113: * @param cmd the metadata for the class.
0114: */
0115: public AbstractStateManager(ObjectManager om,
0116: AbstractClassMetaData cmd) {
0117: myOM = om;
0118: this .cmd = cmd;
0119:
0120: // Set up the field arrays
0121: initialiseFieldInformation();
0122:
0123: myFP = myOM.getFetchPlan().manageFetchPlanForClass(cmd);
0124: }
0125:
0126: /**
0127: * Convenience method to initialise the field information.
0128: **/
0129: protected void initialiseFieldInformation() {
0130: int fieldCount = getHighestFieldNumber();
0131:
0132: dirtyFields = new boolean[fieldCount];
0133: loadedFields = new boolean[fieldCount];
0134: }
0135:
0136: /**
0137: * returns the handler for callback events.
0138: * @return the handler for callback events.
0139: */
0140: protected CallbackHandler getCallbackHandler() {
0141: return myOM.getCallbackHandler();
0142: }
0143:
0144: /**
0145: * returns indicators for which fields are second-class mutable.
0146: * @return indicators for which fields are second-class mutable.
0147: */
0148: protected boolean[] getSecondClassMutableFields() {
0149: return cmd.getSCOMutableMemberFlags();
0150: }
0151:
0152: /**
0153: * returns indicators for which fields are non-primary key fields.
0154: * @return indicators for which fields are non-primary key fields.
0155: */
0156: protected boolean[] getNonPrimaryKeyFields() {
0157: return cmd.getNonPKMemberFlags();
0158: }
0159:
0160: /**
0161: * returns field numbers of all fields.
0162: * @return field numbers of all fields.
0163: */
0164: protected int[] getAllFieldNumbers() {
0165: return cmd.getAllMemberPositions();
0166: }
0167:
0168: /**
0169: * returns field numbers of all non-primary-key fields.
0170: * @return field numbers of all non-primary-key fields.
0171: */
0172: protected int[] getNonPrimaryKeyFieldNumbers() {
0173: return cmd.getNonPKMemberPositions();
0174: }
0175:
0176: /**
0177: * returns field numbers of all second class mutable fields.
0178: * @return field numbers of all second class mutable fields.
0179: */
0180: protected int[] getSecondClassMutableFieldNumbers() {
0181: return cmd.getSCOMutableMemberPositions();
0182: }
0183:
0184: /**
0185: * Accessor for the StoreManager used for this object.
0186: * @return The StoreManager.
0187: **/
0188: public StoreManager getStoreManager() {
0189: return myOM.getStoreManager();
0190: }
0191:
0192: /**
0193: * Accessor for the ClassMetaData for this object.
0194: * @return The ClassMetaData.
0195: **/
0196: public AbstractClassMetaData getClassMetaData() {
0197: return cmd;
0198: }
0199:
0200: /**
0201: * Accessor for the MetaDataManager to use for this object.
0202: * Simply a wrapper accessor method.
0203: * @return The MetaDataManager.
0204: **/
0205: public MetaDataManager getMetaDataManager() {
0206: return myOM.getMetaDataManager();
0207: }
0208:
0209: /**
0210: * Accessor for the ObjectManager for this object.
0211: * @return The Object Manager.
0212: **/
0213: public ObjectManager getObjectManager() {
0214: return myOM;
0215: }
0216:
0217: /**
0218: * Accessor for the Persistent Capable object.
0219: * @return The PersistentCapable object
0220: **/
0221: public Object getObject() {
0222: return myPC;
0223: }
0224:
0225: /**
0226: * Accessor for the LifeCycleState
0227: * @return the LifeCycleState
0228: */
0229: public LifeCycleState getLifecycleState() {
0230: return myLC;
0231: }
0232:
0233: /**
0234: * Accessor for the Restore Values flag
0235: * @return Whether to restore values
0236: */
0237: public boolean isRestoreValues() {
0238: return restoreValues;
0239: }
0240:
0241: /**
0242: * Mutator for the Restore Values flag
0243: * @param restore_values Whether to restore values
0244: */
0245: protected void setRestoreValues(boolean restore_values) {
0246: restoreValues = restore_values;
0247: }
0248:
0249: /**
0250: * Accessor for the internal object id of the object we are managing.
0251: * This will return the "id" if it has been set, otherwise a temporary id based on this StateManager.
0252: * @return The internal object id
0253: */
0254: public Object getInternalObjectId() {
0255: if (myID != null) {
0256: return myID;
0257: } else if (myInternalID == null) {
0258: // Assign a temporary internal "id" based on the object itself until our real identity is assigned
0259: // myInternalID = super.toString();
0260: myInternalID = new IdentityReference(this );
0261: return myInternalID;
0262: } else {
0263: return myInternalID;
0264: }
0265: }
0266:
0267: // -------------------------- Lifecycle Methods ---------------------------
0268:
0269: /**
0270: * Method to disconnect any cloned persistence capable objects from their
0271: * StateManager.
0272: * @param pc The persistable object
0273: * @return Whether the object was disconnected.
0274: **/
0275: protected abstract boolean disconnectClone(PersistenceCapable pc);
0276:
0277: /**
0278: * Tests whether this object is dirty.
0279: *
0280: * Instances that have been modified, deleted, or newly
0281: * made persistent in the current transaction return true.
0282: *
0283: * <P>Transient nontransactional instances return false (JDO spec), but the
0284: * JPOX implementation does not currently support the transient
0285: * transactional state.
0286: *
0287: * @see PersistenceCapable#jdoMakeDirty(String fieldName)
0288: * @param pc the calling persistable instance
0289: * @return true if this instance has been modified in current transaction.
0290: */
0291: public boolean isDirty(PersistenceCapable pc) {
0292: if (disconnectClone(pc)) {
0293: return false;
0294: } else {
0295: return myLC.isDirty();
0296: }
0297: }
0298:
0299: /**
0300: * Tests whether this object is transactional.
0301: *
0302: * Instances that respect transaction boundaries return true. These
0303: * instances include transient instances made transactional as a result of
0304: * being the target of a makeTransactional method call; newly made
0305: * persistent or deleted persistent instances; persistent instances read
0306: * in data store transactions; and persistent instances modified in
0307: * optimistic transactions.
0308: * <P>
0309: * Transient nontransactional instances return false.
0310: *
0311: * @param pc the calling persistable instance
0312: * @return true if this instance is transactional.
0313: */
0314: public boolean isTransactional(PersistenceCapable pc) {
0315: if (disconnectClone(pc)) {
0316: return false;
0317: } else {
0318: return myLC.isTransactional();
0319: }
0320: }
0321:
0322: /**
0323: * Tests whether this object is persistent.
0324: * Instances whose state is stored in the data store return true.
0325: * Transient instances return false.
0326: * @param pc the calling persistable instance
0327: * @return true if this instance is persistent.
0328: */
0329: public boolean isPersistent(PersistenceCapable pc) {
0330: if (disconnectClone(pc)) {
0331: return false;
0332: } else {
0333: return myLC.isPersistent();
0334: }
0335: }
0336:
0337: /**
0338: * Tests whether this object has been newly made persistent.
0339: * Instances that have been made persistent in the current transaction
0340: * return true.
0341: * <P>
0342: * Transient instances return false.
0343: * @param pc the calling persistable instance
0344: * @return true if this instance was made persistent
0345: * in the current transaction.
0346: */
0347: public boolean isNew(PersistenceCapable pc) {
0348: if (disconnectClone(pc)) {
0349: return false;
0350: } else {
0351: return myLC.isNew();
0352: }
0353: }
0354:
0355: /**
0356: * Tests whether this object has been deleted.
0357: * Instances that have been deleted in the current transaction return true.
0358: * <P>Transient instances return false.
0359: * @param pc the calling persistable instance
0360: * @return true if this instance was deleted in the current transaction.
0361: */
0362: public boolean isDeleted(PersistenceCapable pc) {
0363: if (disconnectClone(pc)) {
0364: return false;
0365: } else {
0366: return myLC.isDeleted();
0367: }
0368: }
0369:
0370: // -------------------------- Version handling ----------------------------
0371:
0372: /**
0373: * Return the object representing the version of the calling instance.
0374: * @param pc the calling persistable instance
0375: * @return the object representing the version of the calling instance
0376: * @since JDO 2.0
0377: */
0378: public Object getVersion(PersistenceCapable pc) {
0379: if (pc == myPC) {
0380: // JIRA-2993 This used to return myVersion but now we use transactionalVersion
0381: return transactionalVersion;
0382: } else {
0383: return null;
0384: }
0385: }
0386:
0387: /**
0388: * Sets the value for the version column in a transaction not yet committed
0389: * @param version The version
0390: */
0391: public void setTransactionalVersion(Object version) {
0392: this .transactionalVersion = version;
0393: }
0394:
0395: /**
0396: * Return the object representing the transactional version of the calling instance.
0397: * @param pc the calling persistable instance
0398: * @return the object representing the version of the calling instance
0399: * @since 1.1.1
0400: */
0401: public Object getTransactionalVersion(Object pc) {
0402: return this .transactionalVersion;
0403: }
0404:
0405: /**
0406: * Sets the value for the version column in the datastore
0407: * @param version The version
0408: */
0409: public void setVersion(Object version) {
0410: this .myVersion = version;
0411: this .transactionalVersion = version;
0412: }
0413:
0414: /**
0415: * Convenience accessor for whether this StateManager manages an embedded/serialised object.
0416: * @return Whether the managed object is embedded/serialised.
0417: */
0418: public boolean isEmbedded() {
0419: return pcObjectType > 0;
0420: }
0421:
0422: /**
0423: * Method to set this StateManager as managing an embedded/serialised object.
0424: * @param embeddedType The type of object being managed
0425: */
0426: public void setPcObjectType(int embeddedType) {
0427: this .pcObjectType = embeddedType;
0428: }
0429:
0430: /**
0431: * Accessor for the PC object type (whether it is PC, embedded PC, etc).
0432: * @return PC Object Type
0433: */
0434: public int getPcObjectType() {
0435: return pcObjectType;
0436: }
0437:
0438: // -------------------------- Field Handling Methods ------------------------------
0439:
0440: /**
0441: * Accessor for the highest field number in this class
0442: * @return The highest field number
0443: */
0444: public int getHighestFieldNumber() {
0445: return cmd.getMemberCount();
0446: }
0447:
0448: /**
0449: * Accessor for whether the current fetch plan fields are loaded.
0450: * @return Whether the fetch plan fields are all loaded.
0451: */
0452: protected boolean isFetchPlanLoaded() {
0453: int[] fpFields = myFP.getFieldsInActualFetchPlan();
0454: for (int i = 0; i < fpFields.length; ++i) {
0455: if (!loadedFields[fpFields[i]]) {
0456: return false;
0457: }
0458: }
0459: return true;
0460: }
0461:
0462: /**
0463: * Accessor for whether the DFG fields are loaded.
0464: * @return Whether the DFG fields are all loaded.
0465: */
0466: protected boolean isDefaultFetchGroupLoaded() {
0467: int[] dfgFields = cmd.getDFGMemberPositions();
0468: for (int i = 0; i < dfgFields.length; ++i) {
0469: if (!loadedFields[dfgFields[i]]) {
0470: return false;
0471: }
0472: }
0473: return true;
0474: }
0475:
0476: /**
0477: * Accessor for the field numbers of all dirty fields.
0478: * @return Absolute field numbers of the dirty fields in this instance.
0479: */
0480: public int[] getDirtyFieldNumbers() {
0481: return getFlagsSetTo(dirtyFields, true);
0482: }
0483:
0484: /**
0485: * Accessor for the field numbers of all loaded fields in this managed instance.
0486: * @return Field numbers of all (currently) loaded fields
0487: */
0488: public int[] getLoadedFieldNumbers() {
0489: return getFlagsSetTo(loadedFields, true);
0490: }
0491:
0492: /**
0493: * Accessor for the names of the fields that are dirty.
0494: * @return Names of the dirty fields
0495: */
0496: public String[] getDirtyFieldNames() {
0497: int[] dirtyFieldNumbers = getFlagsSetTo(dirtyFields, true);
0498: if (dirtyFieldNumbers != null && dirtyFieldNumbers.length > 0) {
0499: String[] dirtyFieldNames = new String[dirtyFieldNumbers.length];
0500: for (int i = 0; i < dirtyFieldNumbers.length; i++) {
0501: dirtyFieldNames[i] = cmd
0502: .getMetaDataForManagedMemberAtAbsolutePosition(
0503: dirtyFieldNumbers[i]).getName();
0504: }
0505: return dirtyFieldNames;
0506: }
0507: return null;
0508: }
0509:
0510: /**
0511: * Accessor for the names of the fields that are loaded.
0512: * @return Names of the loaded fields
0513: */
0514: public String[] getLoadedFieldNames() {
0515: int[] loadedFieldNumbers = getFlagsSetTo(loadedFields, true);
0516: if (loadedFieldNumbers != null && loadedFieldNumbers.length > 0) {
0517: String[] loadedFieldNames = new String[loadedFieldNumbers.length];
0518: for (int i = 0; i < loadedFieldNumbers.length; i++) {
0519: loadedFieldNames[i] = cmd
0520: .getMetaDataForManagedMemberAtAbsolutePosition(
0521: loadedFieldNumbers[i]).getName();
0522: }
0523: return loadedFieldNames;
0524: }
0525: return null;
0526: }
0527:
0528: /**
0529: * Method to clear all dirty flags on the object.
0530: */
0531: protected void clearDirtyFlags() {
0532: dirty = false;
0533: clearFlags(dirtyFields);
0534: }
0535:
0536: /**
0537: * Method to clear all dirty flags on the object.
0538: * @param fields the fields to clear
0539: */
0540: protected void clearDirtyFlags(int[] fields) {
0541: dirty = false;
0542: clearFlags(dirtyFields, fields);
0543: }
0544:
0545: // -------------------------- providedXXXField Methods ----------------------------
0546:
0547: /**
0548: * This method is called from the associated persistable when its
0549: * PersistenceCapable.jdoProvideFields() method is invoked. Its purpose is
0550: * to provide the value of the specified field to the StateManager.
0551: *
0552: * @param pc the calling persistable instance
0553: * @param field the field number
0554: * @param currentValue the current value of the field
0555: */
0556: public void providedBooleanField(PersistenceCapable pc, int field,
0557: boolean currentValue) {
0558: currFM.storeBooleanField(field, currentValue);
0559: }
0560:
0561: /**
0562: * This method is called from the associated persistable when its
0563: * PersistenceCapable.jdoProvideFields() method is invoked. Its purpose is
0564: * to provide the value of the specified field to the StateManager.
0565: *
0566: * @param pc the calling persistable instance
0567: * @param field the field number
0568: * @param currentValue the current value of the field
0569: */
0570: public void providedByteField(PersistenceCapable pc, int field,
0571: byte currentValue) {
0572: currFM.storeByteField(field, currentValue);
0573: }
0574:
0575: /**
0576: * This method is called from the associated PersistenceCapable when its
0577: * PersistenceCapable.jdoProvideFields() method is invoked. Its purpose is
0578: * to provide the value of the specified field to the StateManager.
0579: *
0580: * @param pc the calling persistable instance
0581: * @param field the field number
0582: * @param currentValue the current value of the field
0583: */
0584: public void providedCharField(PersistenceCapable pc, int field,
0585: char currentValue) {
0586: currFM.storeCharField(field, currentValue);
0587: }
0588:
0589: /**
0590: * This method is called from the associated PersistenceCapable when its
0591: * PersistenceCapable.jdoProvideFields() method is invoked. Its purpose is
0592: * to provide the value of the specified field to the StateManager.
0593: *
0594: * @param pc the calling persistable instance
0595: * @param field the field number
0596: * @param currentValue the current value of the field
0597: */
0598: public void providedDoubleField(PersistenceCapable pc, int field,
0599: double currentValue) {
0600: currFM.storeDoubleField(field, currentValue);
0601: }
0602:
0603: /**
0604: * This method is called from the associated PersistenceCapable when its
0605: * PersistenceCapable.jdoProvideFields() method is invoked. Its purpose is
0606: * to provide the value of the specified field to the StateManager.
0607: *
0608: * @param pc the calling persistable instance
0609: * @param field the field number
0610: * @param currentValue the current value of the field
0611: */
0612: public void providedFloatField(PersistenceCapable pc, int field,
0613: float currentValue) {
0614: currFM.storeFloatField(field, currentValue);
0615: }
0616:
0617: /**
0618: * This method is called from the associated PersistenceCapable when its
0619: * PersistenceCapable.jdoProvideFields() method is invoked. Its purpose is
0620: * to provide the value of the specified field to the StateManager.
0621: *
0622: * @param pc the calling persistable instance
0623: * @param field the field number
0624: * @param currentValue the current value of the field
0625: */
0626: public void providedIntField(PersistenceCapable pc, int field,
0627: int currentValue) {
0628: currFM.storeIntField(field, currentValue);
0629: }
0630:
0631: /**
0632: * This method is called from the associated PersistenceCapable when its
0633: * PersistenceCapable.jdoProvideFields() method is invoked. Its purpose is
0634: * to provide the value of the specified field to the StateManager.
0635: *
0636: * @param pc the calling persistable instance
0637: * @param field the field number
0638: * @param currentValue the current value of the field
0639: */
0640: public void providedLongField(PersistenceCapable pc, int field,
0641: long currentValue) {
0642: currFM.storeLongField(field, currentValue);
0643: }
0644:
0645: /**
0646: * This method is called from the associated PersistenceCapable when its
0647: * PersistenceCapable.jdoProvideFields() method is invoked. Its purpose is
0648: * to provide the value of the specified field to the StateManager.
0649: *
0650: * @param pc the calling persistable instance
0651: * @param field the field number
0652: * @param currentValue the current value of the field
0653: */
0654: public void providedShortField(PersistenceCapable pc, int field,
0655: short currentValue) {
0656: currFM.storeShortField(field, currentValue);
0657: }
0658:
0659: /**
0660: * This method is called from the associated persistable when its
0661: * PersistenceCapable.jdoProvideFields() method is invoked. Its purpose is
0662: * to provide the value of the specified field to the StateManager.
0663: *
0664: * @param pc the calling persistable instance
0665: * @param field the field number
0666: * @param currentValue the current value of the field
0667: */
0668: public void providedStringField(PersistenceCapable pc, int field,
0669: String currentValue) {
0670: currFM.storeStringField(field, currentValue);
0671: }
0672:
0673: /**
0674: * This method is called from the associated persistable when its
0675: * PersistenceCapable.jdoProvideFields() method is invoked. Its purpose is
0676: * to provide the value of the specified field to the StateManager.
0677: *
0678: * @param pc the calling PersistenceCapable instance
0679: * @param fieldNumber the field number
0680: * @param currentValue the current value of the field
0681: */
0682: public void providedObjectField(PersistenceCapable pc,
0683: int fieldNumber, Object currentValue) {
0684: currFM.storeObjectField(fieldNumber, currentValue);
0685: }
0686:
0687: // -------------------------- replacingXXXField Methods ----------------------------
0688:
0689: /**
0690: * This method is invoked by the PersistenceCapable object's
0691: * jdoReplaceField() method to refresh the value of a boolean field.
0692: *
0693: * @param pc the calling persistable instance
0694: * @param field the field number
0695: * @return the new value for the field
0696: */
0697: public boolean replacingBooleanField(PersistenceCapable pc,
0698: int field) {
0699: boolean value = currFM.fetchBooleanField(field);
0700: loadedFields[field] = true;
0701:
0702: return value;
0703: }
0704:
0705: /**
0706: * This method is invoked by the PersistenceCapable object's
0707: * jdoReplaceField() method to refresh the value of a byte field.
0708: *
0709: * @param obj the calling persistable instance
0710: * @param field the field number
0711: * @return the new value for the field
0712: */
0713: public byte replacingByteField(PersistenceCapable obj, int field) {
0714: byte value = currFM.fetchByteField(field);
0715: loadedFields[field] = true;
0716:
0717: return value;
0718: }
0719:
0720: /**
0721: * This method is invoked by the PersistenceCapable object's
0722: * jdoReplaceField() method to refresh the value of a char field.
0723: *
0724: * @param obj the calling persistable instance
0725: * @param field the field number
0726: * @return the new value for the field
0727: */
0728: public char replacingCharField(PersistenceCapable obj, int field) {
0729: char value = currFM.fetchCharField(field);
0730: loadedFields[field] = true;
0731:
0732: return value;
0733: }
0734:
0735: /**
0736: * This method is invoked by the PersistenceCapable object's
0737: * jdoReplaceField() method to refresh the value of a double field.
0738: *
0739: * @param obj the calling PersistenceCapable instance
0740: * @param field the field number
0741: * @return the new value for the field
0742: */
0743: public double replacingDoubleField(PersistenceCapable obj, int field) {
0744: double value = currFM.fetchDoubleField(field);
0745: loadedFields[field] = true;
0746:
0747: return value;
0748: }
0749:
0750: /**
0751: * This method is invoked by the PersistenceCapable object's
0752: * jdoReplaceField() method to refresh the value of a float field.
0753: *
0754: * @param obj the calling PersistenceCapable instance
0755: * @param field the field number
0756: * @return the new value for the field
0757: */
0758: public float replacingFloatField(PersistenceCapable obj, int field) {
0759: float value = currFM.fetchFloatField(field);
0760: loadedFields[field] = true;
0761:
0762: return value;
0763: }
0764:
0765: /**
0766: * This method is invoked by the persistable object's
0767: * jdoReplaceField() method to refresh the value of a int field.
0768: *
0769: * @param obj the calling persistable instance
0770: * @param field the field number
0771: * @return the new value for the field
0772: */
0773: public int replacingIntField(PersistenceCapable obj, int field) {
0774: int value = currFM.fetchIntField(field);
0775: loadedFields[field] = true;
0776:
0777: return value;
0778: }
0779:
0780: /**
0781: * This method is invoked by the persistable object's
0782: * jdoReplaceField() method to refresh the value of a long field.
0783: *
0784: * @param obj the calling persistable instance
0785: * @param field the field number
0786: * @return the new value for the field
0787: */
0788: public long replacingLongField(PersistenceCapable obj, int field) {
0789: long value = currFM.fetchLongField(field);
0790: loadedFields[field] = true;
0791:
0792: return value;
0793: }
0794:
0795: /**
0796: * This method is invoked by the persistable object's
0797: * jdoReplaceField() method to refresh the value of a short field.
0798: *
0799: * @param obj the calling persistable instance
0800: * @param field the field number
0801: * @return the new value for the field
0802: */
0803: public short replacingShortField(PersistenceCapable obj, int field) {
0804: short value = currFM.fetchShortField(field);
0805: loadedFields[field] = true;
0806:
0807: return value;
0808: }
0809:
0810: /**
0811: * This method is invoked by the persistable object's
0812: * jdoReplaceField() method to refresh the value of a String field.
0813: *
0814: * @param obj the calling persistable instance
0815: * @param field the field number
0816: * @return the new value for the field
0817: */
0818: public String replacingStringField(PersistenceCapable obj, int field) {
0819: String value = currFM.fetchStringField(field);
0820: loadedFields[field] = true;
0821:
0822: return value;
0823: }
0824:
0825: /**
0826: * This method is invoked by the persistable object's
0827: * jdoReplaceField() method to refresh the value of an Object field.
0828: * @param obj the calling persistable instance
0829: * @param field the field number
0830: * @return the new value for the field
0831: */
0832: public Object replacingObjectField(PersistenceCapable obj, int field) {
0833: try {
0834: Object value = currFM.fetchObjectField(field);
0835: loadedFields[field] = true;
0836: return value;
0837: } catch (EndOfFetchPlanGraphException eodge) {
0838: // Beyond the scope of the fetch-depth when detaching
0839: return null;
0840: }
0841: }
0842:
0843: // -------------------------- getXXXField Methods ----------------------------
0844:
0845: /**
0846: * This method is called by the associated persistable if the
0847: * value for the specified field is not cached (StateManager.isLoaded()
0848: * fails). In this implementation of the StateManager, isLoaded() has a
0849: * side effect of loading unloaded information and will always return true.
0850: * As such, this method should never be called.
0851: * @param pc the calling persistable instance
0852: * @param field the field number
0853: * @param currentValue the current value of the field
0854: * @return the new value for the field
0855: */
0856: public boolean getBooleanField(PersistenceCapable pc, int field,
0857: boolean currentValue) {
0858: throw new JPOXException(LOCALISER.msg("026006"));
0859: }
0860:
0861: /**
0862: * This method is called by the associated PersistenceCapable if the
0863: * value for the specified field is not cached (StateManager.isLoaded()
0864: * fails). In this implementation of the StateManager, isLoaded() has a
0865: * side effect of loading unloaded information and will always return true.
0866: * As such, this method should never be called.
0867: * @param pc the calling PersistenceCapable instance
0868: * @param field the field number
0869: * @param currentValue the current value of the field
0870: * @return the new value for the field
0871: */
0872: public byte getByteField(PersistenceCapable pc, int field,
0873: byte currentValue) {
0874: throw new JPOXException(LOCALISER.msg("026006"));
0875: }
0876:
0877: /**
0878: * This method is called by the associated persistable if the
0879: * value for the specified field is not cached (StateManager.isLoaded()
0880: * fails). In this implementation of the StateManager, isLoaded() has a
0881: * side effect of loading unloaded information and will always return true.
0882: * As such, this method should never be called.
0883: * @param pc the calling persistable instance
0884: * @param field the field number
0885: * @param currentValue the current value of the field
0886: * @return the new value for the field
0887: */
0888: public char getCharField(PersistenceCapable pc, int field,
0889: char currentValue) {
0890: throw new JPOXException(LOCALISER.msg("026006"));
0891: }
0892:
0893: /**
0894: * This method is called by the associated persistable if the
0895: * value for the specified field is not cached (StateManager.isLoaded()
0896: * fails). In this implementation of the StateManager, isLoaded() has a
0897: * side effect of loading unloaded information and will always return true.
0898: * As such, this method should never be called.
0899: * @param pc the calling persistable instance
0900: * @param field the field number
0901: * @param currentValue the current value of the field
0902: * @return the new value for the field
0903: */
0904: public double getDoubleField(PersistenceCapable pc, int field,
0905: double currentValue) {
0906: throw new JPOXException(LOCALISER.msg("026006"));
0907: }
0908:
0909: /**
0910: * This method is called by the associated persistable if the
0911: * value for the specified field is not cached (StateManager.isLoaded()
0912: * fails). In this implementation of the StateManager, isLoaded() has a
0913: * side effect of loading unloaded information and will always return true.
0914: * As such, this method should never be called.
0915: * @param pc the calling persistable instance
0916: * @param field the field number
0917: * @param currentValue the current value of the field
0918: * @return the new value for the field
0919: */
0920: public float getFloatField(PersistenceCapable pc, int field,
0921: float currentValue) {
0922: throw new JPOXException(LOCALISER.msg("026006"));
0923: }
0924:
0925: /**
0926: * This method is called by the associated persistable if the
0927: * value for the specified field is not cached (StateManager.isLoaded()
0928: * fails). In this implementation of the StateManager, isLoaded() has a
0929: * side effect of loading unloaded information and will always return true.
0930: * As such, this method should never be called.
0931: * @param pc the calling persistable instance
0932: * @param field the field number
0933: * @param currentValue the current value of the field
0934: * @return the new value for the field
0935: */
0936: public int getIntField(PersistenceCapable pc, int field,
0937: int currentValue) {
0938: throw new JPOXException(LOCALISER.msg("026006"));
0939: }
0940:
0941: /**
0942: * This method is called by the associated persistable if the
0943: * value for the specified field is not cached (StateManager.isLoaded()
0944: * fails). In this implementation of the StateManager, isLoaded() has a
0945: * side effect of loading unloaded information and will always return true.
0946: * As such, this method should never be called.
0947: * @param pc the calling persistable instance
0948: * @param field the field number
0949: * @param currentValue the current value of the field
0950: * @return the new value for the field
0951: */
0952: public long getLongField(PersistenceCapable pc, int field,
0953: long currentValue) {
0954: throw new JPOXException(LOCALISER.msg("026006"));
0955: }
0956:
0957: /**
0958: * This method is called by the associated persistable if the
0959: * value for the specified field is not cached (StateManager.isLoaded()
0960: * fails). In this implementation of the StateManager, isLoaded() has a
0961: * side effect of loading unloaded information and will always return true.
0962: * As such, this method should never be called.
0963: * @param pc the calling persistable instance
0964: * @param field the field number
0965: * @param currentValue the current value of the field
0966: * @return the new value for the field
0967: */
0968: public short getShortField(PersistenceCapable pc, int field,
0969: short currentValue) {
0970: throw new JPOXException(LOCALISER.msg("026006"));
0971: }
0972:
0973: /**
0974: * This method is called by the associated persistable if the
0975: * value for the specified field is not cached (StateManager.isLoaded()
0976: * fails). In this implementation of the StateManager, isLoaded() has a
0977: * side effect of loading unloaded information and will always return true.
0978: * As such, this method should never be called.
0979: * @param pc the calling persistable instance
0980: * @param field the field number
0981: * @param currentValue the current value of the field
0982: * @return the new value for the field
0983: */
0984: public String getStringField(PersistenceCapable pc, int field,
0985: String currentValue) {
0986: throw new JPOXException(LOCALISER.msg("026006"));
0987: }
0988:
0989: /**
0990: * This method is called by the associated persistable if the
0991: * value for the specified field is not cached (StateManager.isLoaded()
0992: * fails). In this implementation of the StateManager, isLoaded() has a
0993: * side effect of loading unloaded information and will always return true.
0994: * As such, this method should never be called.
0995: * @param pc the calling persistable instance
0996: * @param field the field number
0997: * @param currentValue the current value of the field
0998: * @return the new value for the field
0999: */
1000: public Object getObjectField(PersistenceCapable pc, int field,
1001: Object currentValue) {
1002: throw new JPOXException(LOCALISER.msg("026006"));
1003: }
1004:
1005: // ------------------------------ Helper Methods ---------------------------
1006:
1007: /**
1008: * Compares two objects for equality, where one or both of the object
1009: * references may be null.
1010: *
1011: * @return <code>true</code> if the objects are both <code>null</code> or
1012: * compare equal according to their equals() method,
1013: * <code>false</code> otherwise.
1014: */
1015: protected static boolean equals(Object o1, Object o2) {
1016: return o1 == null ? (o2 == null) : o1.equals(o2);
1017: }
1018:
1019: /**
1020: * Utility to clear the supplied flags.
1021: * @param flags
1022: */
1023: protected static void clearFlags(boolean[] flags) {
1024: for (int i = 0; i < flags.length; i++) {
1025: flags[i] = false;
1026: }
1027: }
1028:
1029: /**
1030: * Utility to clear the supplied flags.
1031: * @param flags
1032: * @param fields fields numbers where the flags will be cleared
1033: */
1034: protected static void clearFlags(boolean[] flags, int[] fields) {
1035: for (int i = 0; i < fields.length; i++) {
1036: flags[fields[i]] = false;
1037: }
1038: }
1039:
1040: /**
1041: * Returns an array of integers containing the indices of all elements in
1042: * <tt>flags</tt> that are in the <tt>state</tt> passed as argument.
1043: * @param flags Array of flags (true or false)
1044: * @param state The state to search (true or false)
1045: * @return The settings of the flags
1046: */
1047: public static int[] getFlagsSetTo(boolean[] flags, boolean state) {
1048: int[] temp = new int[flags.length];
1049: int j = 0;
1050:
1051: for (int i = 0; i < flags.length; i++) {
1052: if (flags[i] == state) {
1053: temp[j++] = i;
1054: }
1055: }
1056:
1057: if (j != 0) {
1058: int[] fieldNumbers = new int[j];
1059: System.arraycopy(temp, 0, fieldNumbers, 0, j);
1060:
1061: return fieldNumbers;
1062: } else {
1063: return null;
1064: }
1065: }
1066:
1067: /**
1068: * Returns an array of integers containing the indices of all elements in
1069: * <tt>flags</tt> whose index occurs in <tt>indices</tt> and whose value is
1070: * <tt>state</tt>.
1071: */
1072: protected static int[] getFlagsSetTo(boolean[] flags,
1073: int[] indices, boolean state) {
1074: int[] temp = new int[indices.length];
1075: int j = 0;
1076:
1077: for (int i = 0; i < indices.length; i++) {
1078: if (flags[indices[i]] == state) {
1079: temp[j++] = indices[i];
1080: }
1081: }
1082:
1083: if (j != 0) {
1084: int[] fieldNumbers = new int[j];
1085: System.arraycopy(temp, 0, fieldNumbers, 0, j);
1086:
1087: return fieldNumbers;
1088: } else {
1089: return null;
1090: }
1091: }
1092:
1093: /**
1094: * Utility to take a peek at a field in the persistable object.
1095: * @param obj The persistable object
1096: * @param fieldName The field to peek at
1097: * @return The value of the field.
1098: */
1099: protected static Object peekField(Object obj, String fieldName) {
1100: try {
1101: /*
1102: * This doesn't work due to security problems but you get the idea.
1103: * I'm trying to get field values directly without going through
1104: * the provideField machinery.
1105: */
1106: Object value = obj.getClass().getDeclaredField(fieldName)
1107: .get(obj);
1108: if (value instanceof PersistenceCapable) {
1109: return StringUtils.toJVMIDString(value);
1110: } else {
1111: return value;
1112: }
1113: } catch (Exception e) {
1114: return e.toString();
1115: }
1116: }
1117:
1118: /**
1119: * Stringifier method.
1120: * @return String form of the StateManager
1121: */
1122: public String toString() {
1123: return "StateManager[pc=" + StringUtils.toJVMIDString(myPC)
1124: + ", lifecycle=" + myLC + "]";
1125: }
1126: }
|