| /* |
| * Copyright 2005 The Apache Software Foundation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* |
| * StateManagerImpl.java |
| * |
| * Created on September 1, 2000, 2:29 PM |
| */ |
| |
| package org.apache.jdo.impl.state; |
| |
| import java.util.*; |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| |
| import javax.jdo.*; |
| |
| import javax.jdo.spi.Detachable; |
| import javax.jdo.spi.JDOImplHelper; |
| import javax.jdo.spi.PersistenceCapable; |
| import javax.jdo.spi.StateManager; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import org.apache.jdo.impl.model.java.runtime.RuntimeJavaModelFactory; |
| import org.apache.jdo.model.jdo.JDOClass; |
| import org.apache.jdo.model.jdo.JDOField; |
| import org.apache.jdo.pm.PersistenceManagerInternal; |
| import org.apache.jdo.sco.SCO; |
| import org.apache.jdo.sco.SCOCollection; |
| import org.apache.jdo.sco.SCOMap; |
| import org.apache.jdo.state.FieldManager; |
| import org.apache.jdo.state.StateManagerInternal; |
| import org.apache.jdo.store.StoreManager; |
| import org.apache.jdo.util.I18NHelper; |
| |
| /** |
| * This is the StoreManager independent implemetation of |
| * javax.jdo.spi.StateManager interface. Delegates state transition |
| * requests to LifeCycleState. |
| * |
| * @author Marina Vatkina |
| * @version 2.0 |
| */ |
| class StateManagerImpl implements StateManagerInternal { |
| |
| // Reference to the associated PersistenceManager as |
| // PersistenceManagerInternal |
| private PersistenceManagerInternal myPM = null; |
| |
| // Current Transaction |
| private Transaction tx = null; |
| |
| // Associated PersistenceCapable object |
| private PersistenceCapable myPC = null; |
| |
| /** Detached state of Detachable instance. |
| */ |
| private Object[] detachedState = null; |
| |
| // LifeCycle state to handle state transition requests. |
| private LifeCycleState myLC = null; |
| |
| private byte jdoFlags = 0; |
| |
| /** beforeImage represents state of an instance before |
| * any change or as of the call to makePersistent/deletePersistent |
| */ |
| private PersistenceCapable beforeImage = null; |
| |
| /** flushedImage represents state of an instance as of the last flush |
| * to the datastore. |
| */ |
| private PersistenceCapable flushedImage = null; |
| |
| /** Helper StateFieldManager instance for resetting fields in a Hollow |
| * instance at commit/rollback. |
| */ |
| private final static StateFieldManager hollowFieldManager = |
| new StateFieldManager(); |
| |
| /** Helper StateFieldManager instance for fetching Object fields values for |
| * reachability and SCO processing. |
| */ |
| private StateFieldManager objectFieldManager = new StateFieldManager(); |
| |
| /** Reference to JDO Model. |
| */ |
| private Object metaData = null; |
| private Class myPCClass = null; |
| |
| // Flag that indicates processing inside Transaction.afterCompletion when |
| // fields are being reset to Java default values |
| private boolean inAfterCompletion = false; |
| |
| // Flag that indicates state transition to Transient inside |
| // disconnect() method to allow setting jdoStateManager to null |
| // from call-back replacingStateManager() |
| private boolean transitionTransient = false; |
| |
| // Flag that indicates that PersistenceManagerFactory supports option |
| // javax.jdo.option.ChangeApplicationIdentity. |
| private boolean allowedChangeApplicationIdentity = false; |
| |
| // Representation of the available ("get") fields |
| private BitSet loadedFields = null; |
| |
| // Representation of the changed ("set") fields |
| private BitSet dirtyFields = null; |
| |
| // Representation of the fieldspresent in the beforeImage |
| private BitSet biFields = null; |
| |
| // Helper array to keep a single field number. |
| private int[] fieldArr = new int[1]; |
| |
| // The objectId of the object associated with this StateManager. |
| private Object objectId; |
| |
| // The transactional objectId of the object associated with this |
| // StateManager. |
| private Object txObjectId; |
| |
| // Object contains dependency information specific to this |
| // instance of the StateManager |
| private Object dependency = null; |
| |
| // Assists in moving data from this StateManager's object to/from the |
| // store. See provideFields(), replaceFields(), and the getXXXField() |
| // and providedXXXField() methods. |
| private FieldManager fieldManager; |
| |
| // Reference to the instance requested to provide fields via fieldManager. |
| private Object expectedProvider; |
| |
| // Class model information |
| private JDOClass jdoClass; |
| |
| // Number of persistent fields |
| private int numFields = 0; |
| |
| // JDOImplHelper instance |
| static final JDOImplHelper jdoImplHelper = |
| (JDOImplHelper) AccessController.doPrivileged ( |
| // Need to have privileges to perform JDOImplHelper.getInstance(). |
| new PrivilegedAction () { |
| public Object run () { |
| try { |
| return JDOImplHelper.getInstance(); |
| } |
| catch (SecurityException e) { |
| throw new JDOFatalUserException (msg.msg( |
| "EXC_CannotGetJDOImplHelper"), e); // NOI18N |
| } |
| } |
| } |
| ); |
| |
| /** RuntimeJavaModelFactory. */ |
| private static final RuntimeJavaModelFactory javaModelFactory = |
| (RuntimeJavaModelFactory) AccessController.doPrivileged( |
| new PrivilegedAction () { |
| public Object run () { |
| return RuntimeJavaModelFactory.getInstance(); |
| } |
| } |
| ); |
| |
| // ReachabilityHandler instance |
| private final static ReachabilityHandler reachabilityHandler = |
| ReachabilityHandler.getInstance(); |
| |
| // SCOProcessor instance |
| private final static SCOProcessor scoProcessor = |
| SCOProcessor.getInstance(); |
| |
| // Helper string |
| private final static String ChangeApplicationIdentityOption = |
| "javax.jdo.option.ChangeApplicationIdentity"; // NOI18N |
| |
| /** |
| * I18N message handler |
| */ |
| private final static I18NHelper msg = |
| I18NHelper.getInstance("org.apache.jdo.impl.state.Bundle"); // NOI18N |
| |
| /** |
| * Logger instance |
| */ |
| private static final Log logger = LogFactory.getFactory().getInstance( |
| "org.apache.jdo.impl.state"); // NOI18N |
| |
| /** Register this class with the JDOImplHelper as an authorized class |
| * for replaceStateManager. |
| */ |
| static { |
| AccessController.doPrivileged( |
| new PrivilegedAction () { |
| public Object run () { |
| JDOImplHelper.registerAuthorizedStateManagerClass(StateManagerImpl.class); |
| return null; |
| } |
| } |
| ); |
| } |
| |
| /** Constructs a new <code>StateManagerImpl</code> to process |
| * future makePersistent request. |
| * @param pc the reference to the associated PersistenceCapable instance |
| * @param pm the reference to the associated |
| * PersistenceManagerInternal instance |
| */ |
| StateManagerImpl(PersistenceCapable pc, PersistenceManagerInternal pm) { |
| if (debugging()) |
| debug("constructor with PC: " + pc); // NOI18N |
| |
| myPC = pc; |
| myPCClass = pc.getClass(); |
| initializePM(pm); |
| initializePCInfo(); |
| } |
| |
| /** Constructs a new <code>StateManagerImpl</code> when requested |
| * from query processing. |
| * @param uoid the reference to the user object ID |
| * @param ioid the reference to the internal object ID |
| * @param pm the reference to the associated |
| * PersistenceManagerInternal instance |
| * @param clazz Class of the PersistenceCapable instance |
| */ |
| StateManagerImpl(Object uoid, Object ioid, PersistenceManagerInternal pm, |
| Class clazz) { |
| this.objectId = ioid; |
| this.txObjectId = this.objectId; |
| if (debugging()) |
| debug("constructor with user OID: " + uoid); // NOI18N |
| |
| initializePM(pm); |
| StoreManager srm = myPM.getStoreManager(); |
| myPCClass = clazz; |
| |
| if (uoid == null) { // Requested by the store. |
| initializePC(srm); |
| |
| } else if (srm.hasActualPCClass(ioid)){ |
| initializePCInfo(); |
| myPC = jdoImplHelper.newInstance (myPCClass, this, uoid); |
| markPKFieldsAsLoaded(); |
| |
| } // else do nothing. |
| |
| if (tx.isActive() && (tx.getOptimistic() == false)) { |
| myLC = LifeCycleState.getLifeCycleState(LifeCycleState.HOLLOW); |
| } else { |
| myLC = LifeCycleState.getLifeCycleState(LifeCycleState.P_NON_TX); |
| } |
| |
| if (debugging()) |
| debug("constructor " + myLC + " for: " + myPCClass); // NOI18N |
| |
| registerNonTransactional(); |
| } |
| |
| /** Initialize PC Class information. |
| */ |
| private void initializePCInfo() { |
| if (debugging()) |
| debug("initializePCInfo"); // NOI18N |
| |
| jdoClass = javaModelFactory.getJavaType(myPCClass).getJDOClass(); |
| |
| // RESOLVE: remember JDOFields of FieldDescriptors. |
| numFields = jdoClass.getManagedFields().length; |
| |
| loadedFields = new BitSet(numFields); |
| |
| dirtyFields = new BitSet(numFields); |
| biFields = new BitSet(numFields); |
| } |
| |
| /** Initialize PersistenceManager related information. |
| * @param pm the reference to the associated |
| * PersistenceManagerInternal instance |
| */ |
| private void initializePM(PersistenceManagerInternal pm) { |
| if (debugging()) |
| debug("initializePM: " + pm); // NOI18N |
| |
| myPM = pm; |
| tx = myPM.currentTransaction(); |
| PersistenceManagerFactory pmf = myPM.getPersistenceManagerFactory(); |
| allowedChangeApplicationIdentity = pmf.supportedOptions().contains( |
| ChangeApplicationIdentityOption); |
| |
| } |
| |
| /** Mark PK fields as loaded: |
| */ |
| private void markPKFieldsAsLoaded() { |
| int[] pkfields = jdoClass.getPrimaryKeyFieldNumbers(); |
| for (int i = 0; i < pkfields.length; i++) { |
| if (debugging()) |
| debug("markPKFieldsAsLoaded " + myPCClass.getName() + "." + // NOI18N |
| getFieldName(pkfields[i])); |
| |
| loadedFields.set(pkfields[i]); |
| } |
| } |
| |
| /** Clears the loaded field bits and marks only the key fields, if |
| * any, as loaded. Note: The key fields must always be marked as |
| * loaded for Application Identity. |
| */ |
| private void clearLoadedFields() { |
| loadedFields.andNot(loadedFields); |
| markPKFieldsAsLoaded(); |
| } |
| |
| // |
| // ------------ State transition methods ------------ |
| // |
| |
| /** Transitions LifeCycleState on afterCompletion. |
| * @param abort true if rollback |
| * @param retainValues the flag that indicates how to proceed on commit. |
| * @param restoreValues the flag that indicates how to proceed on rollback. |
| */ |
| public void afterCompletion(boolean abort, boolean retainValues, |
| boolean restoreValues) { |
| inAfterCompletion = true; |
| |
| if (debugging()) |
| debug("afterCompletion " + myLC); // NOI18N |
| |
| if (abort) |
| myLC = myLC.transitionRollback(restoreValues, this); |
| else |
| myLC = myLC.transitionCommit(retainValues, this); |
| |
| if (debugging()) |
| debug("afterCompletion " + myLC); // NOI18N |
| |
| inAfterCompletion = false; |
| } |
| |
| /** Transition to Persistent-New |
| */ |
| public void makePersistent() { |
| LifeCycleState st = myLC; |
| |
| if (debugging()) |
| debug("makePersistent " + myLC); // NOI18N |
| |
| if (myLC == null) { |
| // New request. |
| initializeSM(LifeCycleState.P_NEW); |
| } else { |
| // LifeCycle is already asigned. |
| myLC = myLC.transitionMakePersistent(this); |
| } |
| if (st != myLC) { |
| // It was not a no-op... |
| createAllBeforeImage(); |
| |
| // Replace java.util SCO instances with tracked SCOs. |
| replaceSCOFields(); |
| processReachability(false); |
| setSCOOwner(true); |
| } |
| if (debugging()) |
| debug("makePersistent " + myLC); // NOI18N |
| } |
| |
| /** delete persistencecapable |
| */ |
| public void deletePersistent() { |
| if (debugging()) |
| debug("deletePersistent " + myLC); // NOI18N |
| |
| myLC = myLC.transitionDeletePersistent(this); |
| //deleteRelationships(); |
| if (debugging()) |
| debug("deletePersistent " + myLC); // NOI18N |
| } |
| |
| /** Transition to Transactional |
| */ |
| public void makeTransactional() { |
| if (debugging()) |
| debug("makeTransactional " + myLC); // NOI18N |
| |
| if (myLC == null) { |
| // New request. |
| initializeSM(LifeCycleState.T_CLEAN); |
| markAllDirty(); |
| createBeforeImage(); |
| } else if (tx.isActive()); { |
| // LifeCycle is already asigned. |
| myLC = myLC.transitionMakeTransactional(this, tx); |
| } |
| if (debugging()) |
| debug("makeTransactional " + myLC); // NOI18N |
| } |
| |
| /** Transition to Nontransactional |
| */ |
| public void makeNontransactional() { |
| if (debugging()) |
| debug("makeNontransactional " + myLC); // NOI18N |
| |
| myLC = myLC.transitionMakeNontransactional(this, tx); |
| if (debugging()) |
| debug("makeNontransactional " + myLC); // NOI18N |
| } |
| |
| /** Transition to Transient |
| */ |
| public void makeTransient() { |
| if (debugging()) |
| debug("makeTransient " + myLC); // NOI18N |
| |
| myLC = myLC.transitionMakeTransient(this, tx); |
| if (debugging()) |
| debug("makeTransient " + myLC); // NOI18N |
| } |
| |
| /** Transition to Hollow |
| */ |
| public void evictInstance() { |
| if (debugging()) |
| debug("evictInstance " + myLC); // NOI18N |
| |
| myLC = myLC.transitionEvict(this, tx); |
| if (debugging()) |
| debug("evictInstance " + myLC); // NOI18N |
| } |
| |
| /** Transition to Clean |
| */ |
| public void refreshInstance() { |
| if (debugging()) |
| debug("refreshInstance " + myLC); // NOI18N |
| |
| myLC = myLC.transitionRefresh(this, tx); |
| if (debugging()) |
| debug("refreshInstance " + myLC); // NOI18N |
| } |
| |
| /** Transition on retrieve request. This fetches Hollow instance |
| * and transitions to the appropriate LifeCycle state. |
| */ |
| public void retrieve() { |
| if (debugging()) |
| debug("retrieve " + myLC); // NOI18N |
| |
| myLC = myLC.transitionRetrieve(this, tx); |
| if (debugging()) |
| debug("retrieve " + myLC); // NOI18N |
| } |
| |
| /** |
| * Transition the lifecycle state as if the instance is retrieved from the |
| * datastore, but use the specified field values instead of loading them |
| * from the datastore. |
| * @param fields Indicates which fields should be replaced in the PC. |
| * @param fieldManager FieldManager from which the field's value should be |
| * obtained. |
| */ |
| // Synchronized to avoid conflicts w.r.t. fieldManager. |
| public synchronized void replace(int[] fields, FieldManager fieldManager) { |
| if (debugging()) |
| debug("replace " + myLC); // NOI18N |
| |
| myLC = myLC.transitionReplace(this, tx, fields, fieldManager); |
| |
| if (debugging()) |
| debug("replace " + myLC); // NOI18N |
| } |
| |
| /** Fetches or refreshes pc instance. Called by |
| * PersistenceManager.getObjectById with validate flag set to true. |
| */ |
| public void reload() { |
| if (debugging()) |
| debug("reload " + myLC); // NOI18N |
| |
| try { |
| myLC = myLC.transitionReload(this, tx); |
| } catch (JDOException e) { |
| // RESOLVE - disconnect or just deregister? |
| disconnect(); |
| throw e; |
| } |
| if (debugging()) |
| debug("reload " + myLC); // NOI18N |
| } |
| |
| /** |
| * @see org.apache.jdo.state.StateManagerInternal#flush(StoreManager srm) |
| */ |
| public boolean flush(StoreManager srm) { |
| LifeCycleState st = myLC; |
| try { |
| myLC = myLC.flush(loadedFields, dirtyFields, srm, this); |
| } catch (JDOException e) { |
| myLC = st; |
| throw e; |
| } |
| return true; |
| } |
| |
| /** |
| * @see org.apache.jdo.state.StateManagerInternal#handleReachability( |
| * boolean flag) |
| */ |
| public void handleReachability(boolean commit) { |
| if (myLC.isDeleted) { |
| // Don't do reachability for deleted instances. |
| return; |
| } else { |
| processReachability(commit); |
| if (!commit && myLC.isPersistent() && ! myLC.isAutoPersistent()) { |
| // Set owner only inside an active transaction and |
| // only for persistent instances. |
| setSCOOwner(true); |
| } |
| } |
| } |
| |
| /** |
| * Replaces field values that are regular SCO instances with tracked SCOs. |
| * @see org.apache.jdo.state.StateManagerInternal#replaceSCOFields() |
| */ |
| public void replaceSCOFields() { |
| SCO sco = null; |
| Object o = null; |
| Class cls = null; |
| JDOField jdoField = null; |
| int[] nonpkfields = jdoClass.getPersistentNonPrimaryKeyFieldNumbers(); |
| |
| for (int i = 0; i < nonpkfields.length; i++) { |
| int field = nonpkfields[i]; |
| jdoField = jdoClass.getField(field); |
| if (isSCOType(javaModelFactory.getJavaClass(jdoField.getType()))) { |
| o = fetchObjectField(field); |
| sco = scoProcessor.getSCOField(o, jdoField, myPM); |
| replaceSCO(sco, field); |
| |
| } // else primitive - do nothing. |
| } |
| } |
| |
| /** |
| * Unsets owner of tracked SCO field values and marks fields as not loaded. |
| */ |
| protected void unsetSCOFields() { |
| Object o = null; |
| JDOField jdoField = null; |
| int[] nonpkfields = jdoClass.getPersistentNonPrimaryKeyFieldNumbers(); |
| int tmp[] = new int[nonpkfields.length]; |
| int l = 0; |
| |
| for (int i = 0; i < nonpkfields.length; i++) { |
| int field = nonpkfields[i]; |
| jdoField = jdoClass.getField(field); |
| if (isSCOType(javaModelFactory.getJavaClass(jdoField.getType()))) { |
| o = fetchObjectField(field); |
| if (org.apache.jdo.sco.SCO.class.isInstance(o)) { |
| resetOwner((SCO)o, field, false); |
| loadedFields.clear(field); |
| tmp[l] = field; |
| l++; |
| } |
| |
| } // else primitive - do nothing. |
| } |
| /* DO NOT SET TO NULL |
| // Now set those references to null. |
| int[] fields = new int[l]; |
| System.arraycopy(tmp, 0, fields, 0, l); |
| |
| this.fieldManager = hollowFieldManager; // Save for callback in giveXXXField |
| |
| expectedProvider = myPC; // Save for verification. |
| myPC.jdoReplaceFields(fields); |
| expectedProvider = null; // No expected request. |
| */ |
| |
| } |
| |
| /** |
| * @see org.apache.jdo.state.StateManagerInternal#makeDirty (int field) |
| */ |
| public void makeDirty (int field) { |
| if (debugging()) |
| debug("makeDirty " + field); // NOI18N |
| |
| // Reload field if necessary: |
| if(myLC.isPersistent()) { |
| loadField(field); |
| } |
| |
| if (debugging()) |
| debug("makeDirty " + myLC); // NOI18N |
| |
| myLC = myLC.transitionWriteField(this, tx); |
| |
| if (debugging()) |
| debug("makeDirty " + myLC); // NOI18N |
| |
| updateBeforeImage(getFields(field)); |
| dirtyFields.set(field); |
| } |
| |
| /** |
| * Makes newly added instances to an SCO Collection or SCO Map |
| * auto-persistent. |
| * |
| * @see org.apache.jdo.state.StateManagerInternal#trackUpdates (int field, |
| * SCO sco) |
| */ |
| public void trackUpdates (int field, SCO sco) { |
| if (debugging()) |
| debug("trackUpdates " + field); // NOI18N |
| |
| scoProcessor.trackUpdates(this, field, sco); |
| } |
| |
| /** |
| * @see org.apache.jdo.state.StateManagerInternal#getFieldName (int field) |
| */ |
| public String getFieldName (int field) { |
| return jdoClass.getField(field).getName(); |
| } |
| |
| /** |
| * @see org.apache.jdo.state.StateManagerInternal#getPCClass () |
| */ |
| public Class getPCClass () { |
| return myPCClass; |
| } |
| |
| /** |
| * @see org.apache.jdo.state.StateManagerInternal#setPCClass (Class pcClass) |
| */ |
| public void setPCClass (Class pcClass) { |
| if (myPC == null) { |
| // myPC will be null if its class cannot be resolved |
| // until fetch. |
| if (debugging()) |
| debug("setPCClass " + myLC + " for: " + pcClass); // NOI18N |
| |
| myPCClass = pcClass; |
| initializePC(myPM.getStoreManager()); |
| } |
| } |
| |
| /** Tests whether this StateManager represents a instance made persistent |
| * object. |
| * |
| * @see org.apache.jdo.state.StateManagerInternal#isNew () |
| * @return <code>true</code> if this StateManager represents an |
| * instance made persistent in the current transaction. |
| */ |
| public boolean isNew() { |
| return myLC.isNew(); |
| } |
| |
| /** |
| * Returns <code>true</code>, if a before image must be created. The |
| * decision is based on the current lifecycle state plus other conditions |
| * e.g. transaction type, restore values flag, etc. |
| * @see org.apache.jdo.state.StateManagerInternal#isBeforeImageRequired () |
| * @return <code>true</code> if a before image must be created. |
| */ |
| public boolean isBeforeImageRequired() { |
| boolean isTransientTransactional = |
| !myLC.isPersistent() && myLC.isTransactional(); |
| return (tx.getOptimistic() || tx.getRestoreValues() || |
| isTransientTransactional); |
| } |
| |
| // |
| // LifeCycleState transition requests |
| // |
| |
| /** Transition to Auto-Persistent-New (persistence-by-reachability) |
| */ |
| protected void makeAutoPersistent() { |
| LifeCycleState st = myLC; |
| if (debugging()) |
| debug("makeAutoPersistent " + myLC); // NOI18N |
| |
| if (myLC == null) { |
| initializeSM(LifeCycleState.AP_NEW); |
| } else { |
| myLC = myLC.transitionToAutoPersistent(this); |
| } |
| if (st != myLC) { |
| // It was not a no-op... |
| createAllBeforeImage(); |
| handleReachability(false); |
| } |
| if (debugging()) |
| debug("makeAutoPersistent " + myLC); // NOI18N |
| } |
| |
| /** Processes Array of referenced objects for possible auto-persistence |
| * (persistence-by-reachability). |
| * @param o Array of referenced objects |
| */ |
| protected void makeAutoPersistent(Object[] o) { |
| if (o != null) { |
| for (int i = 0; i < o.length; i++) { |
| if (o[i] != null) { |
| reachabilityHandler.process(o[i], myPM, false); |
| } // else nothing to do. |
| } |
| } |
| } |
| |
| /** Set owner on elements of an Array of SCO objects. |
| * @param o array of referenced objects. |
| * @param field the field number. |
| * @param set true if owner field should be set, false if unset. |
| */ |
| protected void resetOwner(Object[] o, int field, boolean set) { |
| if (o == null) { |
| // Nothing to do. |
| return; |
| } |
| for (int i = 0; i < o.length; i++) { |
| if (o[i] != null) { |
| resetOwner(o[i], field, set); |
| } // else nothing to do. |
| } |
| } |
| |
| /** Set owner on elements of an Iterator of SCO objects. |
| * @param it Iterator over referenced objects. |
| * @param field the field number. |
| * @param set true if owner field should be set, false if unset. |
| */ |
| protected void resetOwner(Iterator it, int field, boolean set) { |
| if (it == null) { |
| // Nothing to do. |
| return; |
| } |
| while (it.hasNext()) { |
| Object o = it.next(); |
| if (o != null) { |
| if (o instanceof Map.Entry) { |
| Map.Entry mapEntry = (Map.Entry)o; |
| resetOwner(mapEntry.getKey(), field, set); |
| resetOwner(mapEntry.getValue(), field, set); |
| } else { |
| resetOwner(o, field, set); |
| } |
| } |
| } |
| } |
| |
| /** Restore fields from beforeImage on commit or rollback |
| * called by LifeCycle on commit or rollback transition. |
| */ |
| protected void restoreFields() { |
| // |
| // Only restore if there is a before image |
| // |
| if (beforeImage != null) { |
| myPC.jdoCopyFields(beforeImage, getFieldNums(loadedFields)); |
| } |
| } |
| |
| /** Clear fields on commit or rollback |
| * called by LifeCycle on commit or rollback transition. |
| */ |
| protected void clearFields() { |
| if (javax.jdo.InstanceCallbacks.class.isInstance(myPC)) { |
| ((InstanceCallbacks)myPC).jdoPreClear(); |
| } |
| // Unset owner on SCO fields. |
| setSCOOwner(false); |
| |
| // CLEAR FIELDS: myPC.clearFields(); |
| this.fieldManager = hollowFieldManager; // Save for callback in giveXXXField |
| |
| expectedProvider = myPC; // Save for verification. |
| myPC.jdoReplaceFields(jdoClass.getPersistentNonPrimaryKeyFieldNumbers()); |
| expectedProvider = null; // No expected request. |
| |
| // Mark only the key fields as loaded for Application Identity |
| clearLoadedFields(); |
| } |
| |
| /** Disconnect StateManager and PC. Called by LifeCycle when |
| * transition to Transient. |
| */ |
| protected void disconnect() { |
| deregister(); |
| |
| if (myPC != null) { |
| // myPC will be null if its class cannot be resolved |
| // until fetch. |
| // Need to set jdoFlag to READ_WRITE_OK for transient instance. |
| jdoFlags = PersistenceCapable.READ_WRITE_OK; |
| myPC.jdoReplaceFlags(); |
| |
| transitionTransient = true; |
| myPC.jdoReplaceStateManager(null); |
| transitionTransient = false; |
| } |
| |
| resetRef(); |
| } |
| |
| /** Reset all settings |
| */ |
| protected void reset() { |
| if (debugging()) |
| debug("reset"); // NOI18N |
| |
| beforeImage = null; |
| flushedImage = null; |
| this.txObjectId = this.objectId; |
| |
| dirtyFields.andNot(dirtyFields); |
| biFields.andNot(biFields); |
| } |
| |
| /** Refresh object inside of an active transaction as requested by |
| * the LifeCycle. |
| */ |
| protected void refresh() { |
| int[] fields = null; |
| if (myPC != null) { |
| // myPC will be null if its class cannot be resolved |
| // until fetch. |
| resetDirtyFields(); |
| fields = getFieldNums(loadedFields); |
| |
| // Mark only the key fields as loaded for Application Identity |
| clearLoadedFields(); |
| } |
| |
| fetch (myPM.getStoreManager(), fields); |
| |
| } |
| |
| /** Load all persistent fields as requested by the LifeCycle. |
| */ |
| protected void loadUnloaded() { |
| // Check if some fields were not loaded yet: |
| int[] fields = getUnloaded(jdoClass.getPersistentFieldNumbers(), |
| loadedFields); |
| if (fields != null && fields.length > 0) { |
| StoreManager srm = myPM.getStoreManager(); |
| fetch (myPM.getStoreManager(), fields); |
| } |
| } |
| |
| /** |
| * Adds this StateManager to all caches |
| */ |
| protected void registerTransactional() { |
| myPM.register(this, objectId, true, false); |
| } |
| |
| /** |
| * Adds this StateManager to non-transactional caches |
| */ |
| protected void registerNonTransactional() { |
| myPM.register(this, objectId, false, false); |
| } |
| |
| /** |
| * Removes this StateManager from all the caches |
| */ |
| protected void deregister() { |
| if (myLC.isPersistent()) { |
| myPM.deregister(objectId); |
| } else { |
| myPM.deregisterTransient(this); |
| } |
| } |
| |
| // For some unknown reason, the @see for jdoPreDelete results in an error |
| // message from javadoc. We don't know why. We have tried to fix it, |
| // and have tried javadoc in JDK 1.3 and 1.4beta1, to no avail. |
| /** |
| * @see javax.jdo.InstanceCallbacks#jdoPreDelete() |
| */ |
| protected void preDelete() { |
| if (javax.jdo.InstanceCallbacks.class.isInstance(myPC)) { |
| ((InstanceCallbacks)myPC).jdoPreDelete(); |
| } |
| } |
| |
| /** If this class implements InstanceCallbacks, call the jdoPostLoad |
| * method. This is done after the default fetch group values have been |
| * loaded from the store. |
| */ |
| protected void postLoad() { |
| if (javax.jdo.InstanceCallbacks.class.isInstance(myPC)) { |
| ((InstanceCallbacks)myPC).jdoPostLoad(); |
| } |
| } |
| |
| /** |
| * Called by LifeCycleState when transition persistent instance to the |
| * corresponding flushed state. |
| */ |
| protected void markAsFlushed() { |
| // |
| // reset the current state to the point where we can accept more changes. |
| // |
| resetDirtyFields(); |
| myPM.markAsFlushed(this); |
| } |
| |
| /** |
| * Reset beforeImage on refresh or flush |
| */ |
| protected void unsetBeforeImage() { |
| if (debugging()) |
| debug("unsetBeforeImage"); // NOI18N |
| |
| beforeImage = null; |
| biFields.andNot(biFields); |
| } |
| |
| /** |
| * Create a new beforeImage in an active optimistic transaction or |
| * an active datastore transaction with restoreValues flag set to true |
| * or for a transient-transactional instance. |
| */ |
| protected void createBeforeImage() { |
| if (debugging()) |
| debug("createBeforeImage: new " + (beforeImage == null) + // NOI18N |
| " Tx is active: " + tx.isActive()); // NOI18N |
| |
| if (beforeImage == null && tx.isActive() && |
| isBeforeImageRequired()) { |
| |
| beforeImage = jdoImplHelper.newInstance (myPCClass, this); |
| int[] fields = getFieldNums(loadedFields); |
| beforeImage.jdoCopyFields(myPC, fields); |
| replaceSCOWithClones(fields); |
| |
| biFields.or(loadedFields); |
| } |
| } |
| |
| /** |
| * Verifies that this class type is a supported SCO type. |
| * @param type Class type to check. |
| * @return true if this type is a supported SCO type. |
| */ |
| protected boolean isSCOType(Class type) { |
| return myPM.isSupportedSCOType(type); |
| } |
| |
| // |
| // Private helper methods for state transitions |
| // |
| |
| /** |
| * Replaces SCO instances with clones in the before image |
| * to preserve the state. |
| * @param fields array of field numbers to process. |
| */ |
| private void replaceSCOWithClones(int[] fields) { |
| for (int i = 0; i < fields.length; i++) { |
| int field = fields[i]; |
| JDOField jdoField = jdoClass.getField(field); |
| Class type = javaModelFactory.getJavaClass(jdoField.getType()); |
| if (isSCOType(type)) { |
| Object o = fetchObjectField(field); |
| if (o == null) { |
| // Nothing to do. |
| continue; |
| } |
| Object clone = null; |
| if (o instanceof SCO) { |
| clone = ((SCO)o).clone(); |
| } else { |
| try { |
| java.lang.reflect.Method m = |
| o.getClass().getMethod("clone", (Class[]) null); // NOI18N |
| if (m != null) { |
| clone = m.invoke(o, (Object[]) null); |
| } |
| } catch (Exception e) { |
| throw new JDOFatalInternalException( |
| msg.msg("EXC_SCONotCloneable", o.getClass().getName())); //NOI18N |
| } |
| } |
| fieldManager = objectFieldManager; |
| fieldManager.storeObjectField(field, clone); |
| expectedProvider = beforeImage; // Save for verification. |
| beforeImage.jdoReplaceField(field) ; //getFields(field)); |
| expectedProvider = null; // No expected request. |
| } |
| } |
| } |
| |
| /** Returns current value from the Object type field. |
| * @param field the field number |
| * @return current value as Object. |
| */ |
| private Object fetchObjectField(int field) { |
| this.fieldManager = objectFieldManager; |
| |
| expectedProvider = myPC; // Save for verification. |
| myPC.jdoProvideField(field); |
| expectedProvider = null; // No expected request. |
| |
| return fieldManager.fetchObjectField(field); |
| } |
| |
| /** Transition referenced fields to Persistent at commit |
| * (persistence-by-reachability) |
| * @param commit true if it is called during commit. |
| */ |
| private void processReachability(boolean commit) { |
| int[] relfields = jdoClass.getPersistentRelationshipFieldNumbers(); |
| for (int i = 0; i < relfields.length; i++) { |
| Object o = fetchObjectField(relfields[i]); |
| if (o != null) { |
| reachabilityHandler.process(o, myPM, commit); |
| } |
| } |
| } |
| |
| /** Set owner on referenced SCO objects. |
| * @param o referenced object. |
| * @param field the field number. |
| * @param set true if owner field should be set, false if unset. |
| */ |
| private void resetOwner(Object o, int field, boolean set) { |
| if (o == null) { |
| return; |
| |
| } else if(org.apache.jdo.sco.SCO.class.isInstance(o)) { |
| resetOwner((SCO)o, field, set); |
| |
| } else { // check for elements of Arrays. |
| Class c = o.getClass(); |
| if (c.isArray() && !c.getComponentType().isPrimitive()) { |
| resetOwner((Object[])o, field, set); |
| } // else do nothing |
| } |
| } |
| |
| /** Set owner on referenced SCO objects. |
| * @param sco referenced SCO object. |
| * @param field the field number. |
| * @param set true if owner field should be set, false if unset. |
| */ |
| private void resetOwner(SCO sco, int field, boolean set) { |
| if (set) { |
| sco.setOwner(this, field); |
| } else { |
| sco.unsetOwner(this, field); |
| } |
| |
| // Verify elements of an SCO Collection: |
| if (org.apache.jdo.sco.SCOCollection.class.isInstance(sco)) { |
| SCOCollection scoCollection = (SCOCollection)sco; |
| if (set) { |
| resetOwner(scoCollection.iterator(), field, set); |
| } else { |
| // if collection is frozen, don't thaw it to unset owner. |
| resetOwner(scoCollection.eitherIterator(), field, set); |
| } |
| |
| // Verify elements and keys of an SCO Map: |
| } else if (org.apache.jdo.sco.SCOMap.class.isInstance(sco)) { |
| SCOMap scoMap = (SCOMap)sco; |
| if (set) { |
| resetOwner(scoMap.entrySet().iterator(), field, set); |
| } else { |
| // if map is frozen, don't thaw it to unset owner. |
| resetOwner(scoMap.eitherIterator(), field, set); |
| } |
| |
| } // else do nothing |
| } |
| |
| /** Load field value if necessary |
| * @param field the field number |
| */ |
| private void loadField (int field) { |
| myPM.assertReadAllowed(); |
| LifeCycleState st = myLC; |
| if (debugging()) |
| debug("loadField " + myPCClass.getName() + "." // NOI18N |
| + getFieldName(field) + " " + myLC); // NOI18N |
| |
| try { |
| if (!loadedFields.get(field)) { |
| StoreManager srm = myPM.getStoreManager(); |
| fetch (srm, getFields(field)); |
| } |
| myLC = myLC.transitionReadField(this, tx); |
| |
| } catch (JDOException e) { |
| if (!st.isTransactional() && myLC.isTransactional()) { |
| registerNonTransactional(); |
| } |
| myLC = st; |
| throw e; |
| } |
| if (debugging()) |
| debug("Done: loadField " + myPCClass.getName() + "." + // NOI18N |
| getFieldName(field) + " " + myLC); // NOI18N |
| } |
| |
| /** Preparation steps for replacingXXXField operation |
| * @param pc the calling PersistenceCapable instance |
| * @param field the field number |
| */ |
| private void loadingField(Object pc, int field) { |
| if (myPC == pc && !inAfterCompletion) { |
| if (debugging()) |
| debug("loadingField " + myPCClass.getName() + "." + // NOI18N |
| getFieldName(field)); |
| |
| loadedFields.set(field); |
| } |
| } |
| |
| /** Preparation steps for setXXXField operation for non-Object type field. |
| * @param pc the calling PersistenceCapable instance |
| * @param field the field number |
| * @param fieldManager the FieldManager that handles double-dispatch |
| */ |
| private void prepareSetField(PersistenceCapable pc, int field, |
| FieldManager fieldManager) { |
| // Check if it is attempt to change PrimaryKey value: |
| boolean isPrimaryKey = jdoClass.getField(field).isPrimaryKey(); |
| if (!allowedChangeApplicationIdentity && isPrimaryKey) { |
| throw new JDOUnsupportedOptionException( |
| ChangeApplicationIdentityOption); |
| } |
| prepareSetField1(pc, field); |
| prepareSetField2(field, fieldManager); |
| } |
| |
| /** Preparation steps for setXXXField operation for Object type field. |
| * @param pc the calling PersistenceCapable instance |
| * @param field the field number |
| * @param fieldManager the FieldManager that handles double-dispatch |
| * @param currentValue current value of the field. |
| * @param newValue the new value of the field. |
| */ |
| private void prepareSetField(PersistenceCapable pc, int field, |
| FieldManager fieldManager, Object currentValue, Object newValue) { |
| |
| boolean present = loadedFields.get(field); |
| prepareSetField1(pc, field); |
| |
| // now the value is populated, if it was not: |
| if (!present) { |
| currentValue = fetchObjectField(field); |
| } |
| |
| boolean replace = (newValue != currentValue); |
| |
| // Verify elementType of a new SCO before proceeding further: |
| if (replace) { |
| assertSCOElementType(newValue, field); |
| } |
| |
| prepareSetField2(field, fieldManager); |
| |
| // Everything is fine, adjust the ownership on SCO objects: |
| if (replace) { |
| if (currentValue != null && |
| org.apache.jdo.sco.SCO.class.isInstance(currentValue)) { |
| // Unset owner on SCO instance that is not referenced any more. |
| resetOwner(currentValue, field, false); |
| } |
| if (newValue != null && |
| org.apache.jdo.sco.SCO.class.isInstance(newValue)) { |
| // This is the first time we set it: |
| resetOwner(newValue, field, true); |
| } |
| } |
| } |
| |
| /** Verification and load part of the preparation steps for |
| * setXXXField operation. |
| * @param pc the calling PersistenceCapable instance |
| * @param field the field number |
| */ |
| private void prepareSetField1(PersistenceCapable pc, int field) { |
| if (myPC != pc) { |
| // It is clone that we will disconnect. But before set the |
| // field value: |
| expectedProvider = pc; // Save for verification. |
| pc.jdoReplaceField(field) ; //getFields(field)); |
| expectedProvider = null; // No expected request. |
| |
| disconnectClone(pc); |
| } |
| |
| // Reload field if necessary: |
| if(myLC.isPersistent()) { |
| loadField(field); |
| } |
| } |
| |
| /** Transtion write access and replace value step for setXXXField operation. |
| * @param field the field number |
| * @param fieldManager the FieldManager that handles double-dispatch |
| */ |
| private void prepareSetField2(int field, FieldManager fieldManager) { |
| LifeCycleState st = myLC; |
| |
| if (debugging()) |
| debug("prepareSetField2 " + myLC); // NOI18N |
| |
| myLC = myLC.transitionWriteField(this, tx); |
| |
| if (debugging()) |
| debug("prepareSetField2 " + myLC); // NOI18N |
| |
| this.fieldManager = fieldManager; // Save for callback in giveXXXField |
| expectedProvider = myPC; // Save for verification. |
| myPC.jdoReplaceField(field) ; //getFields(field)); |
| expectedProvider = null; // No expected request. |
| |
| dirtyFields.set(field); |
| } |
| |
| /** |
| * Update existing beforeImage in a transaction. |
| */ |
| private void updateBeforeImage(int[] fields) { |
| //Do NOT create beforeImage here - this is update only. |
| if (beforeImage != null) { |
| fields = getUnloaded(fields, biFields); |
| if (fields != null && fields.length > 0) { |
| if (debugging()) { |
| debug("updateBeforeImage ["); // NOI18N |
| |
| for (int i = 0; i < fields.length; i++) |
| logger.debug (fields[i] + " "); // NOI18N |
| logger.debug("]"); // NOI18N |
| } |
| beforeImage.jdoCopyFields(myPC, fields); |
| replaceSCOWithClones(fields); |
| } |
| biFields.or(loadedFields); |
| } |
| } |
| |
| /** |
| * Replace field value with tracked SCO. |
| * @param sco tracked SCO instance to be replaced. |
| * @param field the field number. |
| */ |
| private void replaceSCO(SCO sco, int field) { |
| this.fieldManager = objectFieldManager; |
| |
| if (sco != null) { |
| resetOwner(sco, field, true); |
| |
| // Replace the field |
| fieldManager.storeObjectField(field, sco); |
| expectedProvider = myPC; // Save for verification. |
| myPC.jdoReplaceField(field) ; //getFields(field)); |
| expectedProvider = null; // No expected request. |
| } |
| } |
| |
| /** |
| * Change owner of all SCO fields. |
| * |
| * @param set true if owner should be set, false if references |
| * to this SCO instance will be nullified and owner to be set to null. |
| */ |
| private void setSCOOwner(boolean set) { |
| Object o = null; |
| Class cls = null; |
| JDOField jdoField = null; |
| int[] nonpkfields = jdoClass.getPersistentNonPrimaryKeyFieldNumbers(); |
| |
| Throwable[] err = new Throwable[nonpkfields.length]; |
| int l = 0; |
| for (int i = 0; i < nonpkfields.length; i++) { |
| int field = nonpkfields[i]; |
| |
| jdoField = jdoClass.getField(field); |
| if (isSCOType(javaModelFactory.getJavaClass(jdoField.getType()))) { |
| o = fetchObjectField(field); |
| try { |
| if (set) { |
| scoProcessor.assertSCOElementType(o, jdoField); |
| } |
| resetOwner(o, field, set); |
| } catch (Throwable e) { |
| err[l++] = e; |
| } |
| } // else not an Object field - do nothing |
| } |
| |
| if (l > 0) { |
| Throwable[] t = new Throwable[l]; |
| System.arraycopy(err, 0, t, 0, l); |
| throw new JDOUserException(msg.msg( |
| "EXC_FailedToProcessAll"), t); // NOI18N |
| } |
| } |
| |
| /** Assert element type of an SCO Collection or key and value types |
| * of an SCO Map. |
| * @param o Object to be tested. |
| * @param field the corresponding field number. |
| * @throws JDOUserException if assertion fails. |
| */ |
| private void assertSCOElementType(Object o, int field) { |
| scoProcessor.assertSCOElementType(o, jdoClass.getField(field)); |
| } |
| |
| /** Returns external representation of the transactional object id |
| * that can be used by the client |
| */ |
| private Object getTransactionalObjectId () { |
| StoreManager srm = myPM.getStoreManager(); |
| Object oid = null; |
| |
| if (flushedImage != null) { |
| oid = srm.getExternalObjectId(txObjectId, flushedImage); |
| } else if (beforeImage != null) { |
| oid = srm.getExternalObjectId(txObjectId, beforeImage); |
| } else { |
| oid = srm.getExternalObjectId(txObjectId, myPC); |
| } |
| return oid; |
| } |
| |
| /** Create beforeImage for all fields - called by transition from TRANSIENT |
| * to P_NEW |
| */ |
| private void createAllBeforeImage() { |
| markAllDirty(); |
| if (debugging()) |
| debug("createBeforeImage"); // NOI18N |
| |
| if (isBeforeImageRequired()) { |
| beforeImage = jdoImplHelper.newInstance (myPCClass, this); |
| beforeImage.jdoCopyFields(myPC, getFieldNums(loadedFields)); |
| biFields.or(loadedFields); |
| } |
| } |
| |
| /** Mark all fields as loaded and dirty - called by transition from |
| * TRANSIENT to P_NEW and T_CLEAN |
| */ |
| private void markAllDirty() { |
| for (int i = 0; i < numFields; i++) { |
| loadedFields.set(i); |
| dirtyFields.set(i); |
| } |
| } |
| |
| /** Initialize SM reference in PC and Oid |
| */ |
| private void initializeSM(int newState) { |
| myLC = LifeCycleState.getLifeCycleState(newState); |
| final StateManagerImpl thisSM = this; |
| |
| try { |
| if (myLC.isPersistent()) { |
| StoreManager srm = myPM.getStoreManager(); |
| objectId = srm.createObjectId(this, myPM); |
| |
| myPM.register(this, objectId, true, true); |
| this.txObjectId = this.objectId; |
| |
| } else { |
| myPM.registerTransient(this); |
| } |
| |
| // Everything OK so far. Now we can set SM reference in PC |
| // It can be done only after myLC is set to deligate validation |
| // to the LC and objectId verified for uniqueness |
| AccessController.doPrivileged ( |
| // Need to have privileges to perform jdoReplaceStateManager. |
| new PrivilegedAction () { |
| public Object run () { |
| try { |
| myPC.jdoReplaceStateManager(thisSM); |
| return null; |
| } |
| catch (SecurityException e) { |
| throw new JDOFatalUserException (msg.msg( |
| "EXC_CannotSetStateManager"), e); // NOI18N |
| } |
| } |
| } |
| ); |
| |
| } catch (SecurityException e) { |
| throw new JDOUserException(e.getMessage()); |
| |
| } catch (JDOException e1) { |
| if (myPM.getStateManager(objectId, myPCClass) == this) { |
| deregister(); |
| } |
| resetRef(); |
| throw e1; |
| } |
| } |
| |
| /** Clear dirtyFields list on flush |
| */ |
| private void resetDirtyFields() { |
| // RESOLVE: flushed Oid |
| dirtyFields.andNot(dirtyFields); |
| } |
| |
| /** Reset all references to null |
| */ |
| private void resetRef() { |
| if (debugging()) |
| debug("resetRef"); // NOI18N |
| |
| myPC = null; |
| myPM = null; |
| myLC = null; |
| jdoClass = null; |
| myPCClass = null; |
| beforeImage = null; |
| flushedImage = null; |
| this.txObjectId = null; |
| this.objectId = null; |
| } |
| |
| /** Desconnects clone instance. |
| * @return true if it was clone. |
| */ |
| private boolean disconnectClone(PersistenceCapable pc) { |
| if (pc != myPC) { |
| // Replace jdoFlags. It will be set to |
| // PersistenceCapable.READ_WRITE_OK |
| // by replacingFlags(). |
| pc.jdoReplaceFlags(); |
| |
| // Reset StateManager: |
| pc.jdoReplaceStateManager(null); |
| |
| return true; |
| } |
| return false; |
| } |
| |
| /** Verifies field provider |
| * @throws JDOUserException if provider is not the one expected. |
| */ |
| private boolean verifyProvider(PersistenceCapable pc) { |
| if (pc != expectedProvider) { |
| if (pc == myPC || pc == beforeImage || pc == flushedImage) { |
| throw new JDOFatalInternalException( |
| msg.msg("EXC_WrongProvider")); // NOI18N |
| } |
| disconnectClone(pc); |
| return false; |
| } |
| return true; |
| } |
| |
| /** Fetches instance from the data store |
| */ |
| private void fetch(StoreManager srm) { |
| fetch(srm, null); |
| } |
| |
| /** Fetches specific fields in the instance from the data store |
| */ |
| private void fetch(StoreManager srm, int[] fetchFields) { |
| srm.fetch(this, fetchFields); |
| } |
| |
| /** |
| * Create a new PC instance with key fields copied from objectId |
| */ |
| private void initializePC(StoreManager srm) { |
| initializePCInfo(); |
| if(srm.isMediationRequiredToCopyOid()) { |
| myPC = jdoImplHelper.newInstance (myPCClass, this); |
| srm.copyKeyFieldsFromObjectId(this, myPCClass); |
| } else { |
| myPC = jdoImplHelper.newInstance (myPCClass, this, objectId); |
| } |
| markPKFieldsAsLoaded(); |
| } |
| |
| /** |
| * Helper method to define the list of fields to be loaded |
| * together with this field |
| */ |
| private int[] getFields(int field) { |
| // RESOLVE: SRM.dosomething(field) |
| fieldArr[0] = field; |
| return fieldArr; |
| } |
| |
| /** |
| * Helper method to convert not loaded bits to field numbers. |
| */ |
| private int[] getUnloaded(int[] newfields, BitSet set) { |
| int l = 0; |
| int tmp[] = new int[newfields.length]; |
| |
| for (int i = 0; i < newfields.length; i++) { |
| if (set.get(newfields[i]) == false) { |
| tmp[l] = newfields[i]; |
| l++; |
| } |
| } |
| |
| int[] fields = new int[l]; |
| System.arraycopy(tmp, 0, fields, 0, l); |
| |
| return fields; |
| } |
| |
| /** |
| * Helper method to convert set bits in a BitSet to field numbers. |
| */ |
| private int[] getFieldNums(BitSet bs) { |
| int length = 0; |
| int tmp[] = new int[numFields]; |
| |
| for (int i = 0; i < numFields; i++) { |
| if (bs.get(i) == true) { |
| tmp[length] = i; |
| length++; |
| } |
| } |
| |
| int[] fields = new int[length]; |
| System.arraycopy(tmp, 0, fields, 0, length); |
| |
| return fields; |
| } |
| |
| // |
| // ------------ End methods for state transitions ------------ |
| // |
| |
| /** The owning StateManager uses this method to supply the |
| * value of the flags to the PersistenceCapable instance. |
| * @param pc the calling PersistenceCapable instance |
| * @return the value of jdoFlags to be stored in the |
| * PersistenceCapable instance |
| */ |
| public byte replacingFlags(PersistenceCapable pc) { |
| if (myPC != pc) { |
| // This is clone - set flags as in a transient instance: |
| return PersistenceCapable.READ_WRITE_OK; |
| } |
| return jdoFlags; |
| } |
| |
| /** Replace the current value of jdoStateManager. |
| * This method is called by the PersistenceCapable whenever |
| * jdoReplaceStateManager is called and there is already |
| * an owning StateManager. This is a security precaution |
| * to ensure that the owning StateManager is the only |
| * source of any change to itself. |
| * @param pc the calling PersistenceCapable instance |
| * @return the new value for the jdoStateManager |
| */ |
| public StateManager replacingStateManager (PersistenceCapable pc, |
| StateManager sm) { |
| if (myLC == null) { |
| // This should never happen. LifeCycle is set the first |
| // thing on makePersistent and makeTransactional. |
| throw new JDOFatalInternalException(msg.msg( |
| "EXC_NullLifeCycle")); // NOI18N |
| } |
| |
| // This is the same PC - not beforeImage or clone. |
| if (myPC == pc) { |
| |
| // This call back should happen only when LifeCycle is |
| // transitioning to Transient |
| if (sm == null) { // transitioning to transient... |
| if (!transitionTransient) { // we are NOT transitioning to transient |
| throw new JDOFatalInternalException(msg.msg( |
| "EXC_NotTransitionTransient")); // NOI18N |
| } |
| return null; // OK. |
| |
| } else if (sm == this) { // should not happen |
| throw new JDOFatalInternalException(msg.msg( |
| "EXC_SameStateManager")); // NOI18N |
| |
| } else if (this.myPM == ((StateManagerImpl)sm).myPM) { |
| // same PM && sm != null && sm != this |
| // This is a race condition when makePersistent or |
| // makeTransactional is called on the same PC instance |
| // for the same PM. It has been already set to this SM |
| // - just disconnect the other one. Return this SM so |
| // it won't be replaced. |
| ((StateManagerImpl)sm).disconnect(); |
| return this; |
| |
| } else { // another PM && sm != null && sm != this |
| // This is race condition when makePersistent or |
| // makeTransactional is called on the same PC instance |
| // for different PM |
| throw new JDOUserException(msg.msg( |
| "EXC_PersistentInAnotherPersistenceManager"));// NOI18N |
| } |
| |
| } else if (pc != beforeImage) { |
| /* This indicates that the clone is calling the method. |
| * Either the clone is trying to become persistent or we told it |
| * to become transient. |
| */ |
| if (sm != null) { |
| // It is not becoming transient - force it: |
| ((StateManagerImpl)sm).disconnect(); |
| disconnectClone(pc); |
| } |
| return null; |
| } |
| return null; |
| } |
| |
| /** Return the PersistenceManager that owns this instance. |
| * Called from internal methods. No validation performed. |
| * @return the PersistenceManager that owns this instance |
| */ |
| public PersistenceManagerInternal getPersistenceManager () { |
| if (debugging()) |
| debug("getPersistenceManager " + myPM); // NOI18N |
| |
| return myPM; |
| } |
| |
| /** Return the PersistenceManager that owns this instance as |
| * PersistenceManager wrapper. If called by PersistenceManagerImpl, it |
| * will perform validation during this call. |
| * @param pc the calling PersistenceCapable instance |
| * @return the PersistenceManager that owns this instance |
| */ |
| public PersistenceManager getPersistenceManager (PersistenceCapable pc) { |
| if (disconnectClone(pc)) { |
| // This was clone. It should be transient now: |
| return null; |
| } else { |
| myPM.hereIsStateManager(this, myPC); |
| return myPM.getCurrentWrapper(); |
| } |
| } |
| |
| /** Mark the associated PersistenceCapable field dirty. |
| * <P> The StateManager will make a copy of the field |
| * so it can be restored if needed later, and then mark |
| * the field as modified in the current transaction. |
| * @param pc the calling PersistenceCapable instance |
| * @param fieldName the name of the field |
| */ |
| public void makeDirty (PersistenceCapable pc, String fieldName) { |
| if (debugging()) |
| debug("makeDirty " + fieldName); // NOI18N |
| |
| if (disconnectClone(pc)) { |
| // This was clone. It should be transient now: |
| return; |
| } |
| JDOField f = jdoClass.getManagedField(fieldName); |
| if (f != null) { |
| this.makeDirty(f.getFieldNumber()); |
| } // else non-managed field - do nothing. |
| } |
| |
| /** Return the object representing the JDO identity |
| * of the calling instance. If the JDO identity is being changed in |
| * the current transaction, this method returns the identity as of |
| * the beginning of the transaction. |
| * @param pc the calling PersistenceCapable instance |
| * @return the object representing the JDO identity of the calling instance |
| */ |
| public Object getObjectId (PersistenceCapable pc) { |
| if(disconnectClone(pc)) { |
| // This was clone. It should be transient now: |
| return null; |
| } |
| return getExternalObjectId(); |
| } |
| |
| /** Return the object representing the JDO identity |
| * of the calling instance. If the JDO identity is being changed in |
| * the current transaction, this method returns the current identity as |
| * changed in the transaction. |
| * @param pc the calling PersistenceCapable instance |
| * @return the object representing the JDO identity of the calling instance |
| */ |
| public Object getTransactionalObjectId (PersistenceCapable pc){ |
| if (disconnectClone(pc)) { |
| // This was clone. It should be transient now: |
| return null; |
| } |
| return getTransactionalObjectId(); |
| } |
| |
| /** Return the object representing the version |
| * of the calling instance. |
| * @param pc the calling <code>PersistenceCapable</code> instance |
| * @return the object representing the version of the calling instance |
| * @since 2.0 |
| */ |
| public Object getVersion (PersistenceCapable pc) { |
| throw new UnsupportedOperationException( |
| "Method getVersion(PersistenceCapable) not yet implemented"); |
| } |
| |
| /** Tests whether this object is dirty. |
| * |
| * Instances that have been modified, deleted, or newly |
| * made persistent in the current transaction return true. |
| * |
| *<P>Transient instances return false. |
| *<P> |
| * @see javax.jdo.spi.PersistenceCapable#jdoMakeDirty(String fieldName) |
| * @param pc the calling PersistenceCapable instance |
| * @return true if this instance has been modified in the current |
| * transaction. |
| */ |
| public boolean isDirty(PersistenceCapable pc) { |
| if (disconnectClone(pc) || myLC == null) |
| return false; |
| |
| return myLC.isDirty(); |
| } |
| |
| /** Tests whether this object is transactional. |
| * |
| * Instances that respect transaction boundaries return true. |
| * These instances include transient instances made transactional |
| * as a result of being the target of a makeTransactional method |
| * call; newly made persistent or deleted persistent instances; |
| * persistent instances read in data store transactions; and |
| * persistent instances modified in optimistic transactions. |
| * |
| *<P>Transient instances return false. |
| *<P> |
| * @param pc the calling PersistenceCapable instance |
| * @return true if this instance is transactional. |
| */ |
| public boolean isTransactional(PersistenceCapable pc) { |
| if (disconnectClone(pc) || myLC == null) |
| return false; |
| |
| return myLC.isTransactional(); |
| } |
| |
| |
| /** Tests whether this object is persistent. |
| * |
| * Instances whose state is stored in the data store return true. |
| * |
| *<P>Transient instances return false. |
| *<P> |
| * @see PersistenceManager#makePersistent(Object pc) |
| * @param pc the calling PersistenceCapable instance |
| * @return true if this instance is persistent. |
| */ |
| public boolean isPersistent(PersistenceCapable pc) { |
| if (disconnectClone(pc) || myLC == null) |
| return false; |
| |
| return myLC.isPersistent(); |
| } |
| |
| /** Tests whether this object has been newly made persistent. |
| * |
| * Instances that have been made persistent in the current transaction |
| * return true. |
| * |
| *<P>Transient instances return false. |
| *<P> |
| * @see PersistenceManager#makePersistent(Object pc) |
| * @param pc the calling PersistenceCapable instance |
| * @return true if this instance was made persistent |
| * in the current transaction. |
| */ |
| public boolean isNew(PersistenceCapable pc) { |
| if (disconnectClone(pc) || myLC == null) |
| return false; |
| |
| return myLC.isNew(); |
| } |
| |
| /** Tests whether this object has been deleted. |
| * |
| * Instances that have been deleted in the current transaction return true. |
| * |
| *<P>Transient instances return false. |
| *<P> |
| * @see PersistenceManager#deletePersistent(Object pc) |
| * @param pc the calling PersistenceCapable instance |
| * @return true if this instance was deleted |
| * in the current transaction. |
| */ |
| public boolean isDeleted(PersistenceCapable pc) { |
| if (disconnectClone(pc) || myLC == null) |
| return false; |
| |
| return myLC.isDeleted(); |
| } |
| |
| /** Guarantee that the serializable transactional and persistent fields |
| * are loaded into the instance. This method is called by the generated |
| * or user-written writeObject method prior to serialization of the |
| * instance. |
| * @param pc the calling PersistenceCapable instance |
| */ |
| public void preSerialize (PersistenceCapable pc) { |
| if (disconnectClone(pc)) { |
| // It was clone that we disconnected. Return as |
| // for any transient instance. |
| return ; |
| } |
| |
| if (debugging()) |
| debug("preSerialize " + myLC); // NOI18N |
| |
| myLC = myLC.transitionReload(this, tx); |
| |
| if (debugging()) |
| debug("preSerialize " + myLC); // NOI18N |
| |
| // Check if some fields were not loaded yet: |
| int[] fields = getUnloaded( |
| jdoClass.getPersistentSerializableFieldNumbers(), loadedFields); |
| |
| // RESOLVE: how to skip java transient fields: |
| if (fields != null && fields.length > 0) { |
| StoreManager srm = myPM.getStoreManager(); |
| fetch (myPM.getStoreManager(), fields); |
| } |
| } |
| |
| /** This implementation of isLoaded will always return true. |
| * So the getXXXField methods do not ever need to be implemented. |
| * @param pc the calling PersistenceCapable instance |
| * @param field the field number |
| * @return true |
| */ |
| public boolean isLoaded (PersistenceCapable pc, int field) { |
| if (disconnectClone(pc)) { |
| // It was clone that we disconnected. Return true as |
| // for any transient instance. |
| return true; |
| } |
| |
| loadField(field); |
| |
| return loadedFields.get(field); |
| } |
| |
| // |
| // getXXXField methods |
| // |
| // In the RI, these methods all throw a JDOFatalInternalException, since |
| // their implementation is not needed. See StateManagerImpl.isLoaded |
| // |
| |
| /** |
| * @see javax.jdo.spi.StateManager#getBooleanField( |
| * PersistenceCapable pc, int field, boolean currentValue) |
| */ |
| public boolean getBooleanField(PersistenceCapable pc, int field, |
| boolean currentValue) { |
| notNeededByRI("getBooleanField"); // NOI18N |
| return false; |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#getCharField(PersistenceCapable |
| * pc, int field, char currentValue) |
| */ |
| public char getCharField(PersistenceCapable pc, int field, |
| char currentValue) { |
| notNeededByRI("getCharField"); // NOI18N |
| return 'a'; |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#getByteField( |
| * PersistenceCapable pc, int field, byte currentValue) |
| */ |
| public byte getByteField(PersistenceCapable pc, int field, |
| byte currentValue) { |
| notNeededByRI("getByteField"); // NOI18N |
| return 0; |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#getShortField( |
| * PersistenceCapable pc, int field, short currentValue) |
| */ |
| public short getShortField(PersistenceCapable pc, int field, |
| short currentValue) { |
| notNeededByRI("getShortField"); // NOI18N |
| return 0; |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#getIntField( |
| * PersistenceCapable pc, int field, int currentValue) |
| */ |
| public int getIntField(PersistenceCapable pc, int field, |
| int currentValue) { |
| notNeededByRI("getIntField"); // NOI18N |
| return 0; |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#getLongField( |
| * PersistenceCapable pc, int field, long currentValue) |
| */ |
| public long getLongField(PersistenceCapable pc, int field, |
| long currentValue) { |
| notNeededByRI("getLongField"); // NOI18N |
| return 0; |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#getFloatField( |
| * PersistenceCapable pc, int field, float currentValue) |
| */ |
| public float getFloatField(PersistenceCapable pc, int field, |
| float currentValue) { |
| notNeededByRI("getFloatField"); // NOI18N |
| return 0.0F; |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#getDoubleField( |
| * PersistenceCapable pc, int field, double currentValue) |
| */ |
| public double getDoubleField(PersistenceCapable pc, int field, |
| double currentValue) { |
| notNeededByRI("getDoubleField"); // NOI18N |
| return 0.0; |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#getStringField( |
| * PersistenceCapable pc, int field, String currentValue) |
| */ |
| public String getStringField(PersistenceCapable pc, int field, |
| String currentValue) { |
| notNeededByRI("getStringField"); // NOI18N |
| return null; |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#getObjectField( |
| * PersistenceCapable pc, int field, Object currentValue) |
| */ |
| public Object getObjectField(PersistenceCapable pc, int field, |
| Object currentValue) { |
| notNeededByRI("getObjectField"); // NOI18N |
| return null; |
| } |
| |
| private void notNeededByRI(String s) { |
| throw new JDOFatalInternalException(msg.msg( |
| "EXC_NotNeededByRI", s)); // NOI18N |
| } |
| |
| // |
| // setXXXField methods |
| // |
| |
| /** |
| * @see javax.jdo.spi.StateManager#setBooleanField( |
| * PersistenceCapable pc, int field, boolean currentValue, boolean newValue) |
| */ |
| public void setBooleanField(PersistenceCapable pc, int field, |
| boolean currentValue, boolean newValue) { |
| StateFieldManager sfm = new StateFieldManager(); |
| sfm.storeBooleanField(field, newValue); |
| prepareSetField(pc, field, sfm); |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#setCharField( |
| * PersistenceCapable pc, int field, char currentValue, char newValue) |
| */ |
| public void setCharField(PersistenceCapable pc, int field, |
| char currentValue, char newValue) { |
| StateFieldManager sfm = new StateFieldManager(); |
| sfm.storeCharField(field, newValue); |
| prepareSetField(pc, field, sfm); |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#setByteField( |
| * PersistenceCapable pc, int field, byte currentValue, byte newValue) |
| */ |
| public void setByteField(PersistenceCapable pc, int field, |
| byte currentValue, byte newValue) { |
| StateFieldManager sfm = new StateFieldManager(); |
| sfm.storeByteField(field, newValue); |
| prepareSetField(pc, field, sfm); |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#setShortField( |
| * PersistenceCapable pc, int field, short currentValue, short newValue) |
| */ |
| public void setShortField(PersistenceCapable pc, int field, |
| short currentValue, short newValue) { |
| StateFieldManager sfm = new StateFieldManager(); |
| sfm.storeShortField(field, newValue); |
| prepareSetField(pc, field, sfm); |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#setIntField( |
| * PersistenceCapable pc, int field, int currentValue, int newValue) |
| */ |
| public void setIntField(PersistenceCapable pc, int field, |
| int currentValue, int newValue) { |
| StateFieldManager sfm = new StateFieldManager(); |
| sfm.storeIntField(field, newValue); |
| prepareSetField(pc, field, sfm); |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#setLongField( |
| * PersistenceCapable pc, int field, long currentValue, long newValue) |
| */ |
| public void setLongField(PersistenceCapable pc, int field, |
| long currentValue, long newValue) { |
| StateFieldManager sfm = new StateFieldManager(); |
| sfm.storeLongField(field, newValue); |
| prepareSetField(pc, field, sfm); |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#setFloatField( |
| * PersistenceCapable pc, int field, float currentValue, float newValue) |
| */ |
| public void setFloatField(PersistenceCapable pc, int field, |
| float currentValue, float newValue) { |
| StateFieldManager sfm = new StateFieldManager(); |
| sfm.storeFloatField(field, newValue); |
| prepareSetField(pc, field, sfm); |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#setDoubleField( |
| * PersistenceCapable pc, int field, double currentValue, double newValue) |
| */ |
| public void setDoubleField(PersistenceCapable pc, int field, |
| double currentValue, double newValue) { |
| StateFieldManager sfm = new StateFieldManager(); |
| sfm.storeDoubleField(field, newValue); |
| prepareSetField(pc, field, sfm); |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#setStringField( |
| * PersistenceCapable pc, int field, String currentValue, String newValue) |
| */ |
| public void setStringField(PersistenceCapable pc, int field, |
| String currentValue, String newValue) { |
| StateFieldManager sfm = new StateFieldManager(); |
| sfm.storeStringField(field, newValue); |
| prepareSetField(pc, field, sfm); |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#setObjectField( |
| * PersistenceCapable pc, int field, Object currentValue, Object newValue) |
| */ |
| public void setObjectField(PersistenceCapable pc, int field, |
| Object currentValue, Object newValue) { |
| StateFieldManager sfm = new StateFieldManager(); |
| sfm.storeObjectField(field, newValue); |
| prepareSetField(pc, field, sfm, currentValue, newValue); |
| } |
| |
| |
| // |
| // providedXXXField methods |
| // |
| |
| /** |
| * @see javax.jdo.spi.StateManager#providedBooleanField( |
| * PersistenceCapable pc, int field, boolean currentValue) |
| */ |
| public void providedBooleanField(PersistenceCapable pc, int field, |
| boolean currentValue) { |
| if (verifyProvider(pc)) { |
| fieldManager.storeBooleanField(field, currentValue); |
| } |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#providedCharField( |
| * PersistenceCapable pc, int field, char currentValue) |
| */ |
| public void providedCharField(PersistenceCapable pc, int field, |
| char currentValue) { |
| if (verifyProvider(pc)) { |
| fieldManager.storeCharField(field, currentValue); |
| } |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#providedByteField( |
| * PersistenceCapable pc, int field, byte currentValue) |
| */ |
| public void providedByteField(PersistenceCapable pc, int field, |
| byte currentValue) { |
| if (verifyProvider(pc)) { |
| fieldManager.storeByteField(field, currentValue); |
| } |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#providedShortField( |
| * PersistenceCapable pc, int field, short currentValue) |
| */ |
| public void providedShortField(PersistenceCapable pc, int field, |
| short currentValue) { |
| if (verifyProvider(pc)) { |
| fieldManager.storeShortField(field, currentValue); |
| } |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#providedIntField( |
| * PersistenceCapable pc, int field, int currentValue) |
| */ |
| public void providedIntField(PersistenceCapable pc, int field, |
| int currentValue) { |
| if (verifyProvider(pc)) { |
| fieldManager.storeIntField(field, currentValue); |
| } |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#providedLongField( |
| * PersistenceCapable pc, int field, long currentValue) |
| */ |
| public void providedLongField(PersistenceCapable pc, int field, |
| long currentValue) { |
| if (verifyProvider(pc)) { |
| fieldManager.storeLongField(field, currentValue); |
| } |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#providedFloatField( |
| * PersistenceCapable pc, int field, float currentValue) |
| */ |
| public void providedFloatField(PersistenceCapable pc, int field, |
| float currentValue) { |
| if (verifyProvider(pc)) { |
| fieldManager.storeFloatField(field, currentValue); |
| } |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#providedDoubleField( |
| * PersistenceCapable pc, int field, double currentValue) |
| */ |
| public void providedDoubleField(PersistenceCapable pc, int field, |
| double currentValue) { |
| if (verifyProvider(pc)) { |
| fieldManager.storeDoubleField(field, currentValue); |
| } |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#providedStringField( |
| * PersistenceCapable pc, int field, String currentValue) |
| */ |
| public void providedStringField(PersistenceCapable pc, int field, |
| String currentValue) { |
| if (verifyProvider(pc)) { |
| fieldManager.storeStringField(field, currentValue); |
| } |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#providedObjectField( |
| * PersistenceCapable pc, int field, Object currentValue) |
| */ |
| public void providedObjectField(PersistenceCapable pc, int field, |
| Object currentValue) { |
| if (verifyProvider(pc)) { |
| fieldManager.storeObjectField(field, currentValue); |
| } |
| } |
| |
| |
| // |
| // replacingXXXField methods |
| // |
| |
| /** |
| * @see javax.jdo.spi.StateManager#replacingBooleanField( |
| * PersistenceCapable pc, int field) |
| */ |
| public boolean replacingBooleanField(PersistenceCapable pc, int field) { |
| loadingField(pc, field); |
| return fieldManager.fetchBooleanField(field); |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#replacingCharField( |
| * PersistenceCapable pc, int field) |
| */ |
| public char replacingCharField(PersistenceCapable pc, int field) { |
| loadingField(pc, field); |
| return fieldManager.fetchCharField(field); |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#replacingByteField( |
| * PersistenceCapable pc, int field) |
| */ |
| public byte replacingByteField(PersistenceCapable pc, int field) { |
| loadingField(pc, field); |
| return fieldManager.fetchByteField(field); |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#replacingShortField( |
| * PersistenceCapable pc, int field) |
| */ |
| public short replacingShortField(PersistenceCapable pc, int field) { |
| loadingField(pc, field); |
| return fieldManager.fetchShortField(field); |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#replacingIntField( |
| * PersistenceCapable pc, int field) |
| */ |
| public int replacingIntField(PersistenceCapable pc, int field) { |
| loadingField(pc, field); |
| return fieldManager.fetchIntField(field); |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#replacingLongField( |
| * PersistenceCapable pc, int field) |
| */ |
| public long replacingLongField(PersistenceCapable pc, int field) { |
| loadingField(pc, field); |
| return fieldManager.fetchLongField(field); |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#replacingFloatField( |
| * PersistenceCapable pc, int field) |
| */ |
| public float replacingFloatField(PersistenceCapable pc, int field) { |
| loadingField(pc, field); |
| return fieldManager.fetchFloatField(field); |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#replacingDoubleField( |
| * PersistenceCapable pc, int field) |
| */ |
| public double replacingDoubleField(PersistenceCapable pc, int field) { |
| loadingField(pc, field); |
| return fieldManager.fetchDoubleField(field); |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#replacingStringField( |
| * PersistenceCapable pc, int field) |
| */ |
| public String replacingStringField(PersistenceCapable pc, int field) { |
| loadingField(pc, field); |
| return fieldManager.fetchStringField(field); |
| } |
| |
| /** |
| * @see javax.jdo.spi.StateManager#replacingObjectField( |
| * PersistenceCapable pc, int field) |
| */ |
| public Object replacingObjectField(PersistenceCapable pc, int field) { |
| loadingField(pc, field); |
| return fieldManager.fetchObjectField(field); |
| } |
| |
| /** The replacing value of the object id in the calling instance. |
| * @param pc the calling <code>PersistenceCapable</code> instance |
| * @param oid the current value of the oid |
| * @return the new value for the oid |
| * @since 2.0 |
| */ |
| public Object replacingObjectId (PersistenceCapable pc, Object oid) { |
| throw new UnsupportedOperationException( |
| "Method replacingObjectId(PersistenceCapable, Object) not yet implemented"); |
| } |
| |
| /** The replacing value of the version in the calling instance. |
| * @param pc the calling <code>PersistenceCapable</code> instance |
| * @param version the current value of the version |
| * @return the new value for the version |
| * @since 2.0 |
| */ |
| public Object replacingVersion (PersistenceCapable pc, Object version) { |
| throw new UnsupportedOperationException( |
| "Method replacingVersion(PersistenceCapable, Object) not yet implemented"); |
| } |
| |
| /** The provided value of the loaded field list in the calling instance. |
| * @param pc the calling <code>PersistenceCapable</code> instance |
| * @param loaded the current value of the loaded field list |
| * @since 2.0 |
| */ |
| public void providedLoadedFieldList (PersistenceCapable pc, BitSet loaded) { |
| throw new UnsupportedOperationException( |
| "Method providedLoadedFieldList(PersistenceCapable, BitSet) not yet implemented"); |
| } |
| |
| /** The replacing value of the loaded field list in the calling instance. |
| * @param pc the calling <code>PersistenceCapable</code> instance |
| * @param loaded the current value of the loaded field list |
| * @return the replacement value for the loaded field list |
| * @since 2.0 |
| */ |
| public BitSet replacingLoadedFieldList (PersistenceCapable pc, BitSet loaded) { |
| throw new UnsupportedOperationException( |
| "Method replacingLoadedFieldList(PersistenceCapable, BitSet) not yet implemented"); |
| } |
| |
| /** The provided value of the modified field list in the calling instance. |
| * @param pc the calling <code>PersistenceCapable</code> instance |
| * @param modified the current value of the modified field list |
| * @since 2.0 |
| */ |
| public void providedModifiedFieldList (PersistenceCapable pc, BitSet modified) { |
| throw new UnsupportedOperationException( |
| "Method providedModifiedFieldList(PersistenceCapable, BitSet) not yet implemented"); |
| } |
| |
| /** The replacing value of the modified field list in the calling instance. |
| * @param pc the calling <code>PersistenceCapable</code> instance |
| * @param modified the current value of the modified field list |
| * @return the replacement value for the modified field list |
| * @since 2.0 |
| */ |
| public BitSet replacingModifiedFieldList (PersistenceCapable pc, BitSet modified) { |
| throw new UnsupportedOperationException( |
| "Method replacingModifiedFieldList(PersistenceCapable, BitSet) not yet implemented"); |
| } |
| |
| // |
| // Implemention of other StateManagerInternal methods |
| // |
| |
| /** |
| * Returns true if current state is present in the datastore. |
| */ |
| public boolean isStored() { |
| return myLC.isStored(); |
| } |
| |
| /** |
| * Returns true if current state is flushed. |
| */ |
| public boolean isFlushed() { |
| return myLC.isFlushed(); |
| } |
| |
| /** |
| * @see org.apache.jdo.state.StateManagerInternal#setDependency( |
| * Object dependency) |
| */ |
| public Object setDependency(Object dependency) { |
| return this.dependency = dependency; |
| } |
| |
| /** |
| * @see org.apache.jdo.state.StateManagerInternal#getDependency() |
| */ |
| public Object getDependency() { |
| return dependency; |
| } |
| /** |
| * @see org.apache.jdo.state.StateManagerInternal#getObject() |
| */ |
| public PersistenceCapable getObject() { |
| return myPC; |
| } |
| |
| /** |
| * @see org.apache.jdo.state.StateManagerInternal#setObjectId(Object objectId) |
| */ |
| public void setObjectId(Object objectId) { |
| myPM.replaceObjectId(this.objectId, objectId); |
| this.objectId = objectId; |
| // RESOLVE: what will happen if we support PK updates? |
| this.txObjectId = objectId; |
| } |
| |
| /** Return the object representing the JDO identity |
| * of the associated instance |
| * @return the object representing the JDO identity of the associated |
| * instance. |
| */ |
| public Object getInternalObjectId () { |
| if (null == objectId) { |
| if (debugging()) |
| debug("getInternalObjectId"); // NOI18N |
| |
| StoreManager srm = myPM.getStoreManager(); |
| objectId = srm.createObjectId(this, myPM); |
| txObjectId = this.objectId; |
| } |
| return objectId; |
| } |
| |
| /** Returns external representation of the object id that can be used |
| * by the client |
| */ |
| public Object getExternalObjectId () { |
| StoreManager srm = myPM.getStoreManager(); |
| return srm.getExternalObjectId(objectId, myPC); |
| } |
| |
| /** |
| * @see org.apache.jdo.state.StateManagerInternal#provideField( |
| * int fieldNumber, |
| * FieldManager fieldManager, boolean identifying) |
| */ |
| // Synchronized to avoid conflicts w.r.t. fieldManager. |
| public synchronized void provideField(int fieldNumber, |
| FieldManager fieldManager, |
| boolean identifying) { |
| |
| this.fieldManager = fieldManager; // Save for callback in giveXXXField |
| if (identifying) { |
| if (flushedImage != null) { |
| expectedProvider = flushedImage; // Save for verification. |
| flushedImage.jdoProvideField(fieldNumber); |
| } else { |
| expectedProvider = beforeImage; // Save for verification. |
| beforeImage.jdoProvideField(fieldNumber); |
| } |
| |
| } else { |
| expectedProvider = myPC; // Save for verification. |
| myPC.jdoProvideField(fieldNumber); |
| } |
| expectedProvider = null; // No expected request. |
| } |
| |
| /** |
| * @see org.apache.jdo.state.StateManagerInternal#provideFields(int[] fields, |
| * FieldManager fieldManager, boolean identifying) |
| */ |
| // Synchronized to avoid conflicts w.r.t. fieldManager. |
| public synchronized void provideFields(int fields[], |
| FieldManager fieldManager, |
| boolean identifying) { |
| |
| this.fieldManager = fieldManager; // Save for callback in giveXXXField |
| if (identifying) { |
| if (flushedImage != null) { |
| expectedProvider = flushedImage; // Save for verification. |
| flushedImage.jdoProvideFields(fields); |
| } else { |
| expectedProvider = beforeImage; // Save for verification. |
| beforeImage.jdoProvideFields(fields); |
| } |
| |
| } else { |
| expectedProvider = myPC; // Save for verification. |
| myPC.jdoProvideFields(fields); |
| } |
| expectedProvider = null; // No expected request. |
| } |
| |
| /** |
| * @see org.apache.jdo.state.StateManagerInternal#replaceFields(int[] fields, |
| * FieldManager fieldManager) |
| */ |
| // Synchronized to avoid conflicts w.r.t. fieldManager. |
| public synchronized void replaceFields(int[] fields, |
| FieldManager fieldManager) { |
| this.fieldManager = fieldManager; // Save for callback in giveXXXField |
| if (fields != null && fields.length > 0) { |
| expectedProvider = myPC; // Save for verification. |
| myPC.jdoReplaceFields(fields); |
| expectedProvider = null; // No expected request. |
| |
| // Merge BeforeImage |
| updateBeforeImage(fields); |
| } |
| |
| this.fieldManager = null; |
| } |
| |
| /** |
| * Replace the detached state of the caller with the return value. |
| * This method is called only in response to this StateManager |
| * calling jdoReplaceDetachedState(). |
| * <P>This method performs two functions: |
| * <ul><li>it gets the detached state from |
| * a Detachable instance when attaching it. In this case, after |
| * this call, the detachedState in the StateManager instance will |
| * have the value from the Detachable instance. |
| * </li><li>it sets the detached state in a Detachable instance |
| * prior to detaching (or serializing) it. In this case, |
| * the caller of the replaceDetachedState method must first set |
| * the detachedState in the StateManager instance to the value to be |
| * replaced in the Detachable instance. |
| * </li></ul> |
| */ |
| public Object[] replacingDetachedState(Detachable pc, Object[] detachedState) { |
| if (detachedState == null) { |
| // replace the null value in Detachable |
| return this.detachedState; |
| } else { |
| // replace this value with the value from Detachable |
| this.detachedState = detachedState; |
| return detachedState; |
| } |
| } |
| /** |
| * For replacing field values in a PC with one that is provided by |
| * the FieldManager. This method does not replace fields that are |
| * already loaded, even if their field number are included in the |
| * specified field number array. |
| * @param fields Indicates which fields should be replaced in the PC. |
| * @param fieldManager FieldManager from which the field values should |
| * be obtained. |
| */ |
| protected void replaceUnloadedFields(int[] fields, |
| FieldManager fieldManager) { |
| replaceFields(getUnloaded(fields, loadedFields), fieldManager); |
| } |
| |
| /* |
| * @see org.apache.jdo.state.StateManagerInternal#preStore() |
| */ |
| public void preStore() { |
| if (myLC.isDeleted) { |
| // Don't call jdoPreStore for deleted instances. |
| return; |
| } else if (javax.jdo.InstanceCallbacks.class.isInstance(myPC)) { |
| ((InstanceCallbacks)myPC).jdoPreStore(); |
| } |
| |
| } |
| |
| /** |
| * Tracing method |
| * @param msg String to display |
| */ |
| private void debug(String msg) { |
| logger.debug("In StateManagerImpl " + msg); // NOI18N |
| } |
| |
| /** |
| * Verifies if debugging is enabled. |
| * @return true if debugging is enabled. |
| */ |
| private boolean debugging() { |
| return logger.isDebugEnabled(); |
| } |
| } |