### Eclipse Workspace Patch 1.0 #P jdo-tck Index: src/java/org/apache/jdo/tck/lifecycle/StateTransitions.java =================================================================== --- src/java/org/apache/jdo/tck/lifecycle/StateTransitions.java (revision 1740768) +++ src/java/org/apache/jdo/tck/lifecycle/StateTransitions.java (working copy) @@ -24,6 +24,9 @@ import javax.jdo.Extent; import javax.jdo.JDOFatalException; +import javax.jdo.JDOHelper; +import javax.jdo.ObjectState; +import javax.jdo.PersistenceManager; import javax.jdo.Transaction; import org.apache.jdo.tck.JDO_Test; @@ -37,7 +40,7 @@ *
*Assertion IDs: A5.9-1 through A5.9-190 *Assertion Description: - All possible state transistions are being tested in this test. + * All possible state transitions are being tested in this test. */ public class StateTransitions extends JDO_Test { @@ -92,8 +95,13 @@ private static final int SERIALIZEOUTSIDETX = 24; private static final int SERIALIZEDATASTORE = 25; private static final int SERIALIZEOPTIMISTIC = 26; + private static final int REFRESH_REMOTELY_MODIFIED = 27; + private static final int REFRESH_REMOTELY_DELETED = 28; + //The optimistic test allows additional scenarios without causing locking problems + private static final int REFRESH_REMOTELY_MODIFIED_OPT = 29; + private static final int REFRESH_REMOTELY_DELETED_OPT = 30; - private static final int NUM_OPERATIONS = 27; + private static final int NUM_OPERATIONS = 31; private static final String[] operations = { "makePersistent", @@ -122,7 +130,11 @@ "detachCopy with active optimistic tx", "serialize outside tx", "serialize with active datastore tx", - "serialize with active optimistic tx" + "serialize with active optimistic tx", + "refresh remotely modified, datastore tx", + "refresh remotely deleted, datastore tx", + "refresh remotely modified, optimistic tx", + "refresh remotely deleted, optimistic tx" }; /** @@ -350,6 +362,40 @@ UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED}, + + // TRANSIENT, PERSISTENT_NEW, PERSISTENT_CLEAN, + // PERSISTENT_DIRTY, HOLLOW, TRANSIENT_CLEAN, + // TRANSIENT_DIRTY, PERSISTENT_NEW_DELETED, PERSISTENT_DELETED, + // PERSISTENT_NONTRANSACTIONAL, PERSISTENT_NONTRANSACTIONAL_DIRTY, DETACHED_CLEAN, + // DETACHED_DIRTY + + // refresh after remote modification - normal tx + { UNCHANGED, PERSISTENT_CLEAN, UNCHANGED, + PERSISTENT_CLEAN, UNCHANGED, UNCHANGED, + UNCHANGED, PERSISTENT_CLEAN, UNCHANGED, + UNCHANGED, PERSISTENT_NONTRANSACTIONAL, ERROR, + ERROR}, + + // refresh after remote deletion - normal tx + { UNCHANGED, UNCHANGED, TRANSIENT, + TRANSIENT, UNCHANGED, UNCHANGED, + UNCHANGED, TRANSIENT, TRANSIENT, + TRANSIENT, TRANSIENT, ERROR, + ERROR}, + + // refresh after remote modification - optimistic + { UNCHANGED, PERSISTENT_NONTRANSACTIONAL, UNCHANGED, + PERSISTENT_NONTRANSACTIONAL, UNCHANGED, UNCHANGED, + UNCHANGED, PERSISTENT_NONTRANSACTIONAL, UNCHANGED, + UNCHANGED, PERSISTENT_NONTRANSACTIONAL, ERROR, + ERROR}, + + // refresh after remote deletion - optimistic + { UNCHANGED, UNCHANGED, TRANSIENT, + TRANSIENT, UNCHANGED, UNCHANGED, + UNCHANGED, TRANSIENT, TRANSIENT, + TRANSIENT, TRANSIENT, ERROR, + ERROR}, }; private static final int DATASTORE_TX = 0; @@ -388,12 +434,17 @@ { false, true, false }, // detachCopy with active optimistic tx { false, false, true }, // serialize outside tx { true, false, false }, // serialize with active datastore tx - { false, true, false } // serialize with active optimistic tx + { false, true, false }, // serialize with active optimistic tx + { true, false, false }, // refresh remotely modified, datastore tx + { true, false, false }, // refresh remotely deleted, datastore tx + { false, true, false }, // refresh remotely modified, optimistic tx + { false, true, false } // refresh remotely deleted, optimistix tx }; /** * @see JDO_Test#localSetUp() */ + @Override protected void localSetUp() { pm = getPM(); addTearDownClass(StateTransitionObj.class); @@ -487,6 +538,7 @@ { for( operation = 0; operation < NUM_OPERATIONS; ++operation ){ // rule out situations that do not apply + appendMessage("TZ-Checking: " + scenario + " / " + operation); //TODO if( !applies_to_scenario[operation][scenario] ) continue; if( (operation == READOUTSIDETX || operation == RETRIEVEOUTSIDETX || @@ -586,6 +638,8 @@ if( transaction.isActive() ) transaction.rollback(); } catch(Exception unexpected_exception) { + appendMessage("TZ-Failing: " + scenario + " / " + operation); //TODO + unexpected_exception.printStackTrace(); //TODO if (debug) { unexpected_exception.printStackTrace(); } @@ -776,6 +830,26 @@ } break; } + case REFRESH_REMOTELY_MODIFIED: + case REFRESH_REMOTELY_MODIFIED_OPT: + { + //This test only applies to persistent objects + if (JDOHelper.isPersistent(obj)) { + modifyRemotely(obj, false); + pm.refresh(obj); + } + break; + } + case REFRESH_REMOTELY_DELETED: + case REFRESH_REMOTELY_DELETED_OPT: + { + //This test only applies to persistent objects + if (JDOHelper.isPersistent(obj)) { + modifyRemotely(obj, true); + pm.refresh(obj); + } + break; + } default: { appendMessage(ASSERTION_FAILED + NL + @@ -1079,4 +1153,82 @@ } return obj; } + + /** Modify or delete an object in a separate PM. */ + private void modifyRemotely(StateTransitionObj objLocal, boolean deleteRemotely) + { + //First ensure that the object is in the DB and PERSISTENT_CLEAN (has no locks in DB) + ObjectState state = JDOHelper.getObjectState(objLocal); + if (ObjectState.TRANSIENT == state + || ObjectState.TRANSIENT_CLEAN == state + || ObjectState.TRANSIENT_DIRTY == state) { + pm.makePersistent(objLocal); + } + if (JDOHelper.isNew(objLocal)) { + boolean isRV = pm.currentTransaction().getRetainValues(); + //ensure non-hollow after commit + pm.currentTransaction().setRetainValues(true); + pm.currentTransaction().commit(); + pm.currentTransaction().begin(); + pm.currentTransaction().setRetainValues(isRV); + } else { + pm.refresh(objLocal); + } + + //apply changes in concurrent transaction + Object oid = pm.getObjectId(objLocal); + PersistenceManager pm = getPMF().getPersistenceManager(); + pm.currentTransaction().begin(); + StateTransitionObj objRemote = (StateTransitionObj) pm.getObjectById(oid); + if (deleteRemotely) { + pm.deletePersistent(objRemote); + } else { + objRemote.writeField(objRemote.readField() + 1); + } + pm.currentTransaction().commit(); + pm.close(); + + //recreate desired object state + switch (state) { + case DETACHED_CLEAN: + case DETACHED_DIRTY: + case HOLLOW_PERSISTENT_NONTRANSACTIONAL: + throw new IllegalStateException("State is not applicable: " + state); + case PERSISTENT_CLEAN: + break; + case PERSISTENT_DELETED: + pm.deletePersistent(objLocal); + break; + case PERSISTENT_DIRTY: + objLocal.writeField(objLocal.readField() + 23); + break; + case PERSISTENT_NEW: + pm.makeTransient(objLocal); //make it TRANSIENT + pm.makePersistent(objLocal); // make it p-new + break; + case PERSISTENT_NEW_DELETED: + pm.makeTransient(objLocal); //make it TRANSIENT + pm.makePersistent(objLocal); // make it p-new + pm.deletePersistent(objLocal); + break; + case PERSISTENT_NONTRANSACTIONAL_DIRTY: + pm.makeNontransactional(objLocal); + objLocal.writeField(objLocal.readField() + 23); + break; + case TRANSIENT: + pm.makeTransient(objLocal); + break; + case TRANSIENT_CLEAN: + pm.makeTransient(objLocal); + pm.makeTransactional(objLocal); + break; + case TRANSIENT_DIRTY: + pm.makeTransient(objLocal); + pm.makeTransactional(objLocal); + objLocal.writeField(objLocal.readField() + 23); + break; + default: + throw new IllegalStateException("State is not applicable: " + state); + } + } }