Index: src/java/org/apache/jdo/tck/lifecycle/CheckStatesOfReturnedObjects.java
===================================================================
--- src/java/org/apache/jdo/tck/lifecycle/CheckStatesOfReturnedObjects.java (revision 0)
+++ src/java/org/apache/jdo/tck/lifecycle/CheckStatesOfReturnedObjects.java (revision 0)
@@ -0,0 +1,679 @@
+/*
+ * 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.
+ */
+
+package org.apache.jdo.tck.lifecycle;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Iterator;
+
+import javax.jdo.Extent;
+import javax.jdo.JDOFatalException;
+import javax.jdo.Transaction;
+
+import org.apache.jdo.tck.JDO_Test;
+import org.apache.jdo.tck.pc.lifecycle.StateTransitionObj;
+import org.apache.jdo.tck.util.BatchTestRunner;
+
+/**
+ *Title: Test State Transitions
+ *
+ *Keywords: lifecycle
+ *
+ *Assertion IDs: A5.9-1 through A5.9-190
+ *Assertion Description:
+ All possible state transistions are being tested in this test.
+ */
+
+public class CheckStatesOfReturnedObjects extends JDO_Test {
+
+ /** */
+ private static final String ASSERTION_FAILED =
+ "Assertions A5.9-1 through A5.5.8 (serialization, detachment, attachment) failed: ";
+
+ /**
+ * The main is called when the class
+ * is directly executed from the command line.
+ * @param args The arguments passed to the program.
+ */
+ public static void main(String[] args) {
+ BatchTestRunner.run(CheckStatesOfReturnedObjects.class);
+ }
+
+ private Transaction transaction;
+ private int scenario;
+ private int operation;
+ private int current_state;
+ private int expected_state;
+ private int new_state;
+
+/**
+ * Operations that cause state changes
+ */
+ private static final int MAKEPERSISTENT = 0;
+ private static final int DETACHCOPYOUTSIDETX = 1;
+ private static final int DETACHCOPYINSIDETX = 2;
+ private static final int SERIALIZEOUTSIDETX = 3;
+ private static final int SERIALIZEINSIDETX = 4;
+
+ private static final int NUM_OPERATIONS = 5;
+
+ private static final String[] operations = {
+ "makePersistent",
+ "detachCopy outside tx",
+ "detachCopy with active tx",
+ "serialize outside tx",
+ "serialize with active tx"
+ };
+
+ /**
+ * Illegal state transitions
+ */
+ private static final int UNCHANGED = -1;
+ private static final int ERROR = -2;
+ private static final int IMPOSSIBLE = -3;
+ private static final int NOT_APPLICABLE = -4;
+
+ /**
+ * State transitions
+ */
+ public static final int[][] statesOfReturnedObjects = { // [operation] [current state] = new state
+ // 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
+
+ // makePersistent
+ { PERSISTENT_NEW, UNCHANGED, UNCHANGED,
+ UNCHANGED, UNCHANGED, PERSISTENT_NEW,
+ PERSISTENT_NEW, UNCHANGED, UNCHANGED,
+ UNCHANGED, UNCHANGED, /*Bug: PERSISTENT_CLEAN*/PERSISTENT_DIRTY,
+ PERSISTENT_DIRTY},
+
+ // detachCopy outside tx
+ { ERROR, IMPOSSIBLE, IMPOSSIBLE,
+ IMPOSSIBLE, DETACHED_CLEAN, IMPOSSIBLE,
+ IMPOSSIBLE, IMPOSSIBLE, IMPOSSIBLE,
+ DETACHED_CLEAN, ERROR, UNCHANGED,
+ UNCHANGED},
+
+ // detachCopy with active tx
+ { /*Bug: DETACHED_CLEAN*/UNCHANGED,DETACHED_CLEAN, DETACHED_CLEAN,
+ DETACHED_CLEAN, DETACHED_CLEAN, /*Bug: DETACHED_CLEAN*/TRANSIENT,
+ /*Bug: DETACHED_CLEAN*/TRANSIENT,ERROR, ERROR,
+ DETACHED_CLEAN, ERROR, UNCHANGED,
+ UNCHANGED},
+
+ // serialize outside tx
+ { UNCHANGED, IMPOSSIBLE, IMPOSSIBLE,
+ IMPOSSIBLE, DETACHED_CLEAN, IMPOSSIBLE,
+ IMPOSSIBLE, IMPOSSIBLE, IMPOSSIBLE,
+ DETACHED_CLEAN, TRANSIENT, UNCHANGED,
+ UNCHANGED},
+
+ // serialize with active tx
+ { UNCHANGED, /*Bug: DETACHED_CLEAN*/TRANSIENT, DETACHED_CLEAN,
+ DETACHED_CLEAN, DETACHED_CLEAN, TRANSIENT,
+ TRANSIENT, TRANSIENT, TRANSIENT,
+ DETACHED_CLEAN, TRANSIENT, UNCHANGED,
+ UNCHANGED},
+ };
+
+ private static final int DATASTORE_TX = 0;
+ private static final int OPTIMISTIC_TX = 1;
+ private static final int NO_TX = 2;
+
+ private static final String[] scenario_string = {
+ "datastore transaction", "optimistic transaction", "no transaction"
+ };
+
+ private static final boolean[][] applies_to_scenario = {
+ // Datastore Optimistic No tx
+ { true, true, false }, // makePersistent
+ { false, false, true }, // detachCopy outside tx
+ { true, true, false }, // detachCopy with active tx
+ { false, false, true }, // serialize outside tx
+ { true, true, false } // serialize with active tx
+ };
+
+ /**
+ * @see JDO_Test#localSetUp()
+ */
+ protected void localSetUp() {
+ pm = getPM();
+ addTearDownClass(StateTransitionObj.class);
+ generatePersistentInstances();
+ }
+
+ public void test() {
+ scenario = DATASTORE_TX;
+ checkTransitions();
+
+ if( isOptimisticSupported() ){
+ scenario = OPTIMISTIC_TX;
+ checkTransitions();
+ }
+
+ scenario = NO_TX;
+ checkTransitions();
+ }
+
+ /** */
+ private void generatePersistentInstances()
+ {
+ if( doPersistentInstancesExist() ) return;
+ int i;
+ Transaction t = pm.currentTransaction();
+ t.begin();
+ for( i = 0; i < 50; ++i ){
+ StateTransitionObj sto = new StateTransitionObj(i);
+ sto.writeField(i);
+ pm.makePersistent(sto);
+ }
+ t.commit();
+ if( !doPersistentInstancesExist() )
+ if (debug)
+ logger.debug("CheckStatesOfReturnedObjects unable to create instances of StateTransitionsObj");
+ }
+
+ /** */
+ private boolean doPersistentInstancesExist()
+ {
+ boolean ret;
+ Transaction t = pm.currentTransaction();
+ t.begin();
+ Extent e = pm.getExtent(StateTransitionObj.class, false);
+ Iterator iter = e.iterator();
+ ret = iter.hasNext();
+ t.rollback();
+ return ret;
+ }
+
+ /** */
+ public void prepareTransactionAndJDOSettings(Transaction transaction) {
+ if( scenario != NO_TX ) {
+ transaction.setNontransactionalRead(false);
+ transaction.setNontransactionalWrite(false);
+ pm.setDetachAllOnCommit(false);
+
+ transaction.setOptimistic(scenario == OPTIMISTIC_TX);
+ transaction.begin();
+ if( !transaction.isActive() )
+ if (debug)
+ logger.debug("CheckStatesOfReturnedObjects: Transaction should be active, but it is not");
+ } else {
+ if( operation == DETACHCOPYOUTSIDETX ||
+ operation == SERIALIZEOUTSIDETX ) {
+ transaction.setNontransactionalRead(true);
+ }
+ if( current_state == PERSISTENT_NONTRANSACTIONAL_DIRTY) {
+ transaction.setNontransactionalRead(true);
+ }
+ }
+ }
+
+ /** */
+ void checkTransitions()
+ {
+ for( operation = 0; operation < NUM_OPERATIONS; ++operation ){
+ // rule out situations that do not apply
+ if( !applies_to_scenario[operation][scenario] ) continue;
+ if( (operation == DETACHCOPYOUTSIDETX ||
+ operation == SERIALIZEOUTSIDETX) &&
+ !isNontransactionalReadSupported() ) continue;
+
+ for( current_state = 0; current_state < NUM_STATES; ++current_state){
+ if( scenario == OPTIMISTIC_TX && current_state == PERSISTENT_CLEAN ) continue;
+ if( (current_state == TRANSIENT_CLEAN || current_state == TRANSIENT_DIRTY) &&
+ !isTransientTransactionalSupported() )
+ continue; // this state is not supported by implementation
+ if( current_state == PERSISTENT_NONTRANSACTIONAL &&
+ !(isNontransactionalReadSupported() || isNontransactionalWriteSupported()) )
+ continue; // this state is not supported by implementation
+ if( current_state == PERSISTENT_NONTRANSACTIONAL_DIRTY &&
+ !isNontransactionalWriteSupported() )
+ continue;
+
+ expected_state = statesOfReturnedObjects[operation][current_state];
+ if( expected_state == IMPOSSIBLE ) continue;
+ if( expected_state == NOT_APPLICABLE ) continue;
+ if( expected_state == UNCHANGED ) expected_state = current_state;
+ try {
+ transaction = pm.currentTransaction();
+ if( transaction.isActive()){
+ if (debug)
+ logger.debug("Transaction is active (but should not be), rolling back");
+ transaction.rollback();
+ }
+
+ prepareTransactionAndJDOSettings(transaction);
+
+ printSituation();
+
+ StateTransitionObj obj = getInstanceInState(current_state);
+ if( obj == null ){ // could not get object in state
+ if( transaction.isActive() ) transaction.rollback();
+ continue;
+ }
+
+ // Apply operation, catching possible exception
+ Exception e = null;
+ Object returnedObject = null;
+ try {
+ returnedObject = applyOperation(operation, obj);
+ } catch( Exception excep ){
+ if( excep instanceof javax.jdo.JDOUserException ){
+ e = excep;
+ } else {
+ fail(ASSERTION_FAILED,
+ "CheckStatesOfReturnedObjects: Unexpected exception:" + excep);
+ continue;
+ }
+ }
+
+ if( expected_state == ERROR ){
+ if( e == null ){
+ fail(ASSERTION_FAILED,
+ "CheckStatesOfReturnedObjects: JDOUserException should have been thrown");
+ } else {
+ int stateOfObj = currentState(obj);
+ if( stateOfObj != current_state ){
+ fail(ASSERTION_FAILED,
+ "CheckStatesOfReturnedObjects: " +
+ " JDOUserException properly thrown, but instance should remain in current state," +
+ " instance changed state to " + states[stateOfObj]);
+ }
+ }
+ } else {
+ // Get new state, verify correct transition and exceptions occurred
+ new_state = currentState(returnedObject);
+ if( expected_state >= 0 && new_state != expected_state &&
+ !((new_state == HOLLOW && expected_state == PERSISTENT_NONTRANSACTIONAL) ||
+ (new_state == PERSISTENT_NONTRANSACTIONAL && expected_state == HOLLOW)) ) {
+ // status interrogation gives same values for PERSISTENT_NONTRANSACTIONAL and HOLLOW
+ fail(ASSERTION_FAILED,
+ "CheckStatesOfReturnedObjects: Invalid state " + states[new_state] +
+ ", returned by operation " + operations[operation] +
+ ", returned state should be " + states[expected_state]);
+ }
+ }
+ if( transaction.isActive() ) transaction.rollback();
+ }
+ catch(Exception unexpected_exception) {
+ if (transaction.isActive())
+ transaction.rollback();
+ fail(ASSERTION_FAILED,
+ "Unexpected exception caught in CheckStatesOfReturnedObjects " + unexpected_exception);
+ }
+ }
+ }
+ }
+
+ /** */
+ void printSituation()
+ {
+ if (debug) {
+ logger.debug(" (" + scenario_string[scenario] +
+ ", initial state=" + states[current_state] +
+ ", operation=" + operations[operation] + ")");
+ }
+ }
+
+ /** */
+ Object applyOperation(int operation, StateTransitionObj stobj)
+ {
+ Object result = null;
+ StateTransitionObj obj = (StateTransitionObj) stobj;
+ switch( operation ){
+ case MAKEPERSISTENT:
+ result = pm.makePersistent(obj);
+ break;
+
+ case DETACHCOPYOUTSIDETX:
+ case DETACHCOPYINSIDETX:
+ result = pm.detachCopy(obj);
+ break;
+
+ case SERIALIZEOUTSIDETX:
+ case SERIALIZEINSIDETX:
+ ObjectOutputStream oos = null;
+ ObjectInputStream ois = null;
+ try {
+ ByteArrayOutputStream byteArrayOutputStream =
+ new ByteArrayOutputStream();
+ oos = new ObjectOutputStream(byteArrayOutputStream);
+ oos.writeObject(obj);
+ ois = new ObjectInputStream(new ByteArrayInputStream(
+ byteArrayOutputStream.toByteArray()));
+ result = ois.readObject();
+ } catch (IOException e) {
+ throw new JDOFatalException(e.getMessage(), e);
+ } catch (ClassNotFoundException e) {
+ throw new JDOFatalException(e.getMessage(), e);
+ } finally {
+ try {
+ if (oos != null) {
+ oos.close();
+ }
+ if (ois != null) {
+ ois.close();
+ }
+ } catch (IOException e) {
+ throw new JDOFatalException(e.getMessage(), e);
+ }
+ }
+ break;
+
+ default:
+ fail(ASSERTION_FAILED,
+ "CheckStatesOfReturnedObjects internal error, illegal operation " + operation);
+ }
+ return result;
+ }
+
+ /**
+ * Get an instance in the specified state.
+ */
+ public StateTransitionObj getInstanceInState(int state)
+ {
+ switch(state) {
+ case TRANSIENT:
+ return getTransientInstance();
+ case PERSISTENT_NEW:
+ return getPersistentNewInstance();
+ case PERSISTENT_CLEAN:
+ return getPersistentCleanInstance();
+ case PERSISTENT_DIRTY:
+ return getPersistentDirtyInstance();
+ case HOLLOW:
+ return getHollowInstance();
+ case TRANSIENT_CLEAN:
+ return getTransientCleanInstance();
+ case TRANSIENT_DIRTY:
+ return getTransientDirtyInstance();
+ case PERSISTENT_NEW_DELETED:
+ return getPersistentNewDeletedInstance();
+ case PERSISTENT_DELETED:
+ return getPersistentDeletedInstance();
+ case PERSISTENT_NONTRANSACTIONAL:
+ return getPersistentNontransactionalInstance();
+ case PERSISTENT_NONTRANSACTIONAL_DIRTY:
+ return getPersistentNontransactionalDirtyInstance();
+ case DETACHED_CLEAN:
+ return getDetachedCleanInstance();
+ case DETACHED_DIRTY:
+ return getDetachedDirtyInstance();
+ default:
+ return null;
+ }
+ }
+
+ /** */
+ public StateTransitionObj getTransientInstance()
+ {
+ StateTransitionObj obj = new StateTransitionObj(23);
+ int curr = currentState(obj);
+ if( curr != TRANSIENT ) {
+ if (debug) {
+ logger.debug("CheckStatesOfReturnedObjects: Unable to create transient instance, state is " +
+ states[curr]);
+ }
+ return null;
+ }
+ return obj;
+ }
+
+ /** */
+ public StateTransitionObj getPersistentNewInstance()
+ {
+ StateTransitionObj obj = getTransientInstance();
+ if( obj == null ) return null;
+ pm.makePersistent(obj); // should transition to persistent-new
+ int curr = currentState(obj);
+ if( curr != PERSISTENT_NEW ) {
+ if (debug) {
+ logger.debug("CheckStatesOfReturnedObjects: Unable to create persistent-new instance" +
+ " from transient instance via makePersistent(), state is " +
+ states[curr]);
+ }
+ return null;
+ }
+ return obj;
+ }
+
+ /** */
+ public StateTransitionObj getPersistentCleanInstance()
+ {
+ StateTransitionObj obj = getHollowInstance();
+ if( obj == null ) return null;
+ StateTransitionObj sto = (StateTransitionObj) obj;
+ sto.readField();
+ int curr = currentState(sto);
+ if( curr != PERSISTENT_CLEAN ) {
+ if (debug) {
+ logger.debug("StateTransition: Unable to create persistent-clean instance" +
+ " from a hollow instance by reading a field, state is " +
+ states[curr]);
+ }
+ return null;
+ }
+ return obj;
+ }
+
+ /** */
+ public StateTransitionObj getPersistentDirtyInstance()
+ {
+ StateTransitionObj obj = getHollowInstance();
+ if( obj == null ) return null;
+ StateTransitionObj pcobj = (StateTransitionObj) obj;
+ pcobj.writeField(23);
+ int curr = currentState(obj);
+ if( curr != PERSISTENT_DIRTY ) {
+ if (debug) {
+ logger.debug("StateTransition: Unable to create persistent-dirty instance" +
+ " from a hollow instance by writing a field, state is " +
+ states[curr]);
+ }
+ return null;
+ }
+ return obj;
+ }
+
+ /** */
+ public StateTransitionObj getHollowInstance()
+ {
+ Extent extent = pm.getExtent(StateTransitionObj.class, false);
+ Iterator iter = extent.iterator();
+ if( !iter.hasNext() ){
+ if (debug)
+ logger.debug("Extent for StateTransitionObj should not be empty");
+ return null;
+ }
+ StateTransitionObj obj = (StateTransitionObj) iter.next();
+
+ transaction.setRetainValues(false);
+ if ( !transaction.isActive() )
+ transaction.begin();
+ if( !transaction.isActive() )
+ if (debug)
+ logger.debug("getHollowInstance: Transaction should be active, but it is not");
+
+ transaction.commit(); // This should put the instance in the HOLLOW state
+
+ prepareTransactionAndJDOSettings(transaction);
+
+ int curr = currentState(obj);
+ if( curr != HOLLOW && curr != PERSISTENT_NONTRANSACTIONAL ){
+ if (debug) {
+ logger.debug("StateTransition: Attempt to get hollow instance via accessing extent failed, state is " +
+ states[curr]);
+ }
+ return null;
+ }
+ return obj;
+ }
+
+ /** */
+ public StateTransitionObj getTransientCleanInstance()
+ {
+ StateTransitionObj obj = getTransientInstance();
+ if( obj == null ) return null;
+ pm.makeTransactional(obj);
+ int curr = currentState(obj);
+ if( curr != TRANSIENT_CLEAN ) {
+ if (debug) {
+ logger.debug("StateTransition: Unable to create transient-clean instance" +
+ " from a transient instance via makeTransactional(), state is " +
+ states[curr]);
+ }
+ return null;
+ }
+ return obj;
+ }
+
+ /** */
+ public StateTransitionObj getTransientDirtyInstance()
+ {
+ StateTransitionObj obj = getTransientCleanInstance();
+ if( obj == null ) return null;
+ StateTransitionObj pcobj = (StateTransitionObj) obj;
+ pcobj.writeField(23);
+ int curr = currentState(obj);
+ if( curr != TRANSIENT_DIRTY ) {
+ if (debug) {
+ logger.debug("StateTransition: Unable to create transient-dirty instance" +
+ " from a transient-clean instance via modifying a field, state is " +
+ states[curr]);
+ }
+ return null;
+ }
+ return obj;
+ }
+
+ /** */
+ public StateTransitionObj getPersistentNewDeletedInstance()
+ {
+ StateTransitionObj obj = getPersistentNewInstance();
+ if( obj == null ) return null;
+ pm.deletePersistent(obj); // should transition to persistent-new-deleted
+ int curr = currentState(obj);
+ if( curr != PERSISTENT_NEW_DELETED) {
+ if (debug) {
+ logger.debug("StateTransition: Unable to create persistent-new-deleted instance" +
+ " from a persistent-new instance via deletePersistent, state is " +
+ states[curr]);
+ }
+ return null;
+ }
+ return obj;
+ }
+
+ /** */
+ public StateTransitionObj getPersistentDeletedInstance()
+ {
+ StateTransitionObj obj = getHollowInstance();
+ if( obj == null ) return null;
+ pm.deletePersistent(obj);
+ int curr = currentState(obj);
+ if( curr != PERSISTENT_DELETED ) {
+ if (debug) {
+ logger.debug("StateTransition: Unable to create persistent-deleted instance" +
+ " from a persistent instance via deletePersistent(), state is " +
+ states[curr]);
+ }
+ return null;
+ }
+ return obj;
+ }
+
+ /** */
+ public StateTransitionObj getPersistentNontransactionalInstance()
+ {
+ StateTransitionObj obj = getHollowInstance();
+ if( obj == null ) return null;
+ pm.makeNontransactional(obj);
+ int curr = currentState(obj);
+ if( curr != PERSISTENT_NONTRANSACTIONAL && curr != HOLLOW ) {
+ if (debug) {
+ logger.debug("StateTransition: Unable to create persistent-nontransactional instance" +
+ " from a persistent-clean instance via makeNontransactional(), state is " +
+ states[curr]);
+ }
+ return null;
+ }
+ return obj;
+ }
+
+ /** */
+ public StateTransitionObj getPersistentNontransactionalDirtyInstance()
+ {
+ StateTransitionObj obj = getPersistentNontransactionalInstance();
+ if( obj == null ) return null;
+ obj.writeField(10000);
+ int curr = currentState(obj);
+ if( curr != PERSISTENT_NONTRANSACTIONAL_DIRTY ) {
+ if (debug) {
+ logger.debug("StateTransition: Unable to create persistent-nontransactional-dirty instance" +
+ " from a persistent-clean instance via makeNontransactional()/JDOHelper.makeDirty," +
+ " state is " + states[curr]);
+ }
+ return null;
+ }
+ return obj;
+ }
+
+ /** */
+ public StateTransitionObj getDetachedCleanInstance()
+ {
+ StateTransitionObj obj = getHollowInstance();
+ if( obj == null ) return null;
+ obj = (StateTransitionObj) pm.detachCopy(obj);
+ int curr = currentState(obj);
+ if( curr != DETACHED_CLEAN ) {
+ if (debug) {
+ logger.debug("StateTransition: Unable to create detached-clean instance" +
+ " from a persistent-clean instance via detachCopy," +
+ " state is " + states[curr]);
+ }
+ return null;
+ }
+ return obj;
+ }
+
+ /** */
+ public StateTransitionObj getDetachedDirtyInstance()
+ {
+ StateTransitionObj obj = getHollowInstance();
+ if( obj == null ) return null;
+ obj = (StateTransitionObj) pm.detachCopy(obj);
+ obj.writeField(1000);
+ int curr = currentState(obj);
+ if( curr != DETACHED_DIRTY ) {
+ if (debug) {
+ logger.debug("StateTransition: Unable to create detached-dirty instance" +
+ " from a persistent-clean instance via detachCopy/persistent field modification," +
+ " state is " + states[curr]);
+ }
+ return null;
+ }
+ return obj;
+ }
+
+}
Index: src/java/org/apache/jdo/tck/lifecycle/StateTransitions.java
===================================================================
--- src/java/org/apache/jdo/tck/lifecycle/StateTransitions.java (revision 371522)
+++ src/java/org/apache/jdo/tck/lifecycle/StateTransitions.java (working copy)
@@ -16,9 +16,13 @@
package org.apache.jdo.tck.lifecycle;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
import java.util.Iterator;
import javax.jdo.Extent;
+import javax.jdo.JDOFatalException;
import javax.jdo.Transaction;
import org.apache.jdo.tck.JDO_Test;
@@ -79,7 +83,14 @@
private static final int WRITEINSIDETX = 16;
private static final int RETRIEVEOUTSIDETX = 17;
private static final int RETRIEVEINSIDETX = 18;
-
+ private static final int DETACHALLONCOMMIT = 19;
+ private static final int DETACHCOPYOUTSIDETX = 20;
+ private static final int DETACHCOPYINSIDETX = 21;
+ private static final int SERIALIZEOUTSIDETX = 22;
+ private static final int SERIALIZEINSIDETX = 23;
+
+ private static final int NUM_OPERATIONS = 24;
+
private static final String[] operations = {
"makePersistent",
"deletePersistent",
@@ -99,14 +110,14 @@
"write field outside tx",
"write field with active tx",
"retrieve outside tx",
- "retrieve with active tx"
+ "retrieve with active tx",
+ "commit, detachAllOnCommit=true",
+ "detachCopy outside tx",
+ "detachCopy with active tx",
+ "serialize outside tx",
+ "serialize with active tx"
};
- private static final int NUM_OPERATIONS = 19;
- private static final boolean[] closes_transaction =
- { false, false, false, false, false, true, true, true, true, false,
- false, false, false, false, false, false, false, false, false };
-
/**
* Illegal state transitions
*/
@@ -119,82 +130,197 @@
* State transitions
*/
public static final int[][] transitions = { // [operation] [current state] = new state
+ // 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
+
// makePersistent
- { PERSISTENT_NEW, UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED, PERSISTENT_NEW,
- PERSISTENT_NEW, UNCHANGED, UNCHANGED, UNCHANGED},
+ { PERSISTENT_NEW, UNCHANGED, UNCHANGED,
+ UNCHANGED, UNCHANGED, PERSISTENT_NEW,
+ PERSISTENT_NEW, UNCHANGED, UNCHANGED,
+ UNCHANGED, UNCHANGED, DETACHED_CLEAN,
+ DETACHED_DIRTY},
// deletePersistent
- { ERROR, PERSISTENT_NEW_DELETED, PERSISTENT_DELETED, PERSISTENT_DELETED,
- PERSISTENT_DELETED, ERROR, ERROR, UNCHANGED, UNCHANGED, PERSISTENT_DELETED},
+ { ERROR, PERSISTENT_NEW_DELETED, PERSISTENT_DELETED,
+ PERSISTENT_DELETED, PERSISTENT_DELETED, ERROR,
+ ERROR, UNCHANGED, UNCHANGED,
+ PERSISTENT_DELETED, PERSISTENT_DELETED, ERROR,
+ ERROR},
// makeTransactional
- { TRANSIENT_CLEAN, UNCHANGED, UNCHANGED, UNCHANGED, PERSISTENT_CLEAN,
- UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED, PERSISTENT_CLEAN},
+ { TRANSIENT_CLEAN, UNCHANGED, UNCHANGED,
+ UNCHANGED, PERSISTENT_CLEAN, UNCHANGED,
+ UNCHANGED, UNCHANGED, UNCHANGED,
+ PERSISTENT_CLEAN, PERSISTENT_DIRTY, /*Bug: ERROR*/TRANSIENT_CLEAN,
+ /*Bug: ERROR*/TRANSIENT_CLEAN},
// makeNontransactional
- { ERROR, ERROR, PERSISTENT_NONTRANSACTIONAL, ERROR, UNCHANGED,
- TRANSIENT, ERROR, ERROR, ERROR, UNCHANGED},
+ { ERROR, ERROR, PERSISTENT_NONTRANSACTIONAL,
+ ERROR, UNCHANGED, TRANSIENT,
+ ERROR, ERROR, ERROR,
+ UNCHANGED, UNCHANGED, ERROR,
+ ERROR},
// makeTransient
- { UNCHANGED, ERROR, TRANSIENT, ERROR, TRANSIENT,
- UNCHANGED, UNCHANGED, ERROR, ERROR, TRANSIENT},
+ { UNCHANGED, ERROR, TRANSIENT,
+ ERROR, TRANSIENT, UNCHANGED,
+ UNCHANGED, ERROR, ERROR,
+ TRANSIENT, /*Bug: ERROR*/TRANSIENT, /*Bug: ERROR*/UNCHANGED,
+ /*Bug: ERROR*/UNCHANGED},
// commit, retainValues = false
- { UNCHANGED, HOLLOW, HOLLOW, HOLLOW, UNCHANGED, UNCHANGED,
- TRANSIENT_CLEAN, TRANSIENT, TRANSIENT, UNCHANGED},
+ { UNCHANGED, HOLLOW, HOLLOW,
+ HOLLOW, UNCHANGED, UNCHANGED,
+ TRANSIENT_CLEAN, TRANSIENT, TRANSIENT,
+ UNCHANGED, HOLLOW, UNCHANGED,
+ UNCHANGED},
// commit, retainValues = true
- { UNCHANGED, PERSISTENT_NONTRANSACTIONAL, PERSISTENT_NONTRANSACTIONAL,
- PERSISTENT_NONTRANSACTIONAL, UNCHANGED, UNCHANGED, TRANSIENT_CLEAN,
- TRANSIENT, TRANSIENT, UNCHANGED},
+ { UNCHANGED, PERSISTENT_NONTRANSACTIONAL, PERSISTENT_NONTRANSACTIONAL,
+ PERSISTENT_NONTRANSACTIONAL, UNCHANGED, UNCHANGED,
+ TRANSIENT_CLEAN, TRANSIENT, TRANSIENT,
+ UNCHANGED, PERSISTENT_NONTRANSACTIONAL, 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
+
// rollback, restoreValues = false
- { UNCHANGED, TRANSIENT, HOLLOW, HOLLOW, UNCHANGED, UNCHANGED,
- TRANSIENT_CLEAN, TRANSIENT, HOLLOW, UNCHANGED},
+ { UNCHANGED, TRANSIENT, HOLLOW,
+ HOLLOW, UNCHANGED, UNCHANGED,
+ TRANSIENT_CLEAN, TRANSIENT, HOLLOW,
+ UNCHANGED, HOLLOW, UNCHANGED,
+ UNCHANGED},
// rollback, restoreValues = true
- { UNCHANGED, TRANSIENT, PERSISTENT_NONTRANSACTIONAL, PERSISTENT_NONTRANSACTIONAL,
- UNCHANGED, UNCHANGED, TRANSIENT_CLEAN, TRANSIENT, PERSISTENT_NONTRANSACTIONAL, UNCHANGED},
+ { UNCHANGED, TRANSIENT, PERSISTENT_NONTRANSACTIONAL,
+ PERSISTENT_NONTRANSACTIONAL, UNCHANGED, UNCHANGED,
+ TRANSIENT_CLEAN, TRANSIENT, PERSISTENT_NONTRANSACTIONAL,
+ UNCHANGED, UNCHANGED, UNCHANGED,
+ UNCHANGED},
// refresh with active datastore transaction
- { UNCHANGED, UNCHANGED, UNCHANGED, PERSISTENT_CLEAN, UNCHANGED,
- UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED},
+ { UNCHANGED, UNCHANGED, UNCHANGED,
+ PERSISTENT_CLEAN, UNCHANGED, UNCHANGED,
+ UNCHANGED, UNCHANGED, UNCHANGED,
+ UNCHANGED, PERSISTENT_NONTRANSACTIONAL, UNCHANGED,
+ UNCHANGED},
// refresh with active optimistic transaction
- { UNCHANGED, UNCHANGED, UNCHANGED, PERSISTENT_NONTRANSACTIONAL, UNCHANGED,
- UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED},
+ { UNCHANGED, UNCHANGED, UNCHANGED,
+ PERSISTENT_NONTRANSACTIONAL, UNCHANGED, UNCHANGED,
+ UNCHANGED, UNCHANGED, UNCHANGED,
+ UNCHANGED, PERSISTENT_NONTRANSACTIONAL, UNCHANGED,
+ UNCHANGED},
// evict
- { NOT_APPLICABLE, UNCHANGED, HOLLOW, UNCHANGED, UNCHANGED,
- UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED, HOLLOW},
+ { NOT_APPLICABLE, UNCHANGED, HOLLOW,
+ UNCHANGED, UNCHANGED, UNCHANGED,
+ UNCHANGED, UNCHANGED, UNCHANGED,
+ HOLLOW, HOLLOW, UNCHANGED,
+ UNCHANGED},
// read field outside transaction
- { UNCHANGED, IMPOSSIBLE, IMPOSSIBLE, IMPOSSIBLE, PERSISTENT_NONTRANSACTIONAL,
- UNCHANGED, IMPOSSIBLE, IMPOSSIBLE, IMPOSSIBLE, UNCHANGED},
+ { UNCHANGED, IMPOSSIBLE, IMPOSSIBLE,
+ IMPOSSIBLE, PERSISTENT_NONTRANSACTIONAL, IMPOSSIBLE,
+ IMPOSSIBLE, IMPOSSIBLE, IMPOSSIBLE,
+ UNCHANGED, UNCHANGED, UNCHANGED,
+ UNCHANGED},
// read field with active optimistic transaction
- { UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED, PERSISTENT_NONTRANSACTIONAL,
- UNCHANGED, UNCHANGED, ERROR, ERROR, UNCHANGED},
+ { UNCHANGED, UNCHANGED, UNCHANGED,
+ UNCHANGED, PERSISTENT_NONTRANSACTIONAL, UNCHANGED,
+ UNCHANGED, ERROR, ERROR,
+ 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
+
// read field with active datastore transaction
- { UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED, PERSISTENT_CLEAN,
- UNCHANGED, UNCHANGED, ERROR, ERROR, PERSISTENT_CLEAN},
+ { UNCHANGED, UNCHANGED, UNCHANGED,
+ UNCHANGED, PERSISTENT_CLEAN, UNCHANGED,
+ UNCHANGED, ERROR, ERROR,
+ PERSISTENT_CLEAN, UNCHANGED, UNCHANGED,
+ UNCHANGED},
// write field outside transaction
- { UNCHANGED, IMPOSSIBLE, IMPOSSIBLE, IMPOSSIBLE, PERSISTENT_NONTRANSACTIONAL,
- UNCHANGED, IMPOSSIBLE, IMPOSSIBLE, IMPOSSIBLE, UNCHANGED},
+ { UNCHANGED, IMPOSSIBLE, IMPOSSIBLE,
+ IMPOSSIBLE, PERSISTENT_NONTRANSACTIONAL, IMPOSSIBLE,
+ IMPOSSIBLE, IMPOSSIBLE, IMPOSSIBLE,
+ UNCHANGED, UNCHANGED, DETACHED_DIRTY,
+ UNCHANGED},
// write field with active transaction
- { UNCHANGED, UNCHANGED, PERSISTENT_DIRTY, UNCHANGED, PERSISTENT_DIRTY,
- TRANSIENT_DIRTY, UNCHANGED, ERROR, ERROR, PERSISTENT_DIRTY},
-
+ { UNCHANGED, UNCHANGED, PERSISTENT_DIRTY,
+ UNCHANGED, PERSISTENT_DIRTY, TRANSIENT_DIRTY,
+ UNCHANGED, ERROR, ERROR,
+ PERSISTENT_DIRTY, UNCHANGED, DETACHED_DIRTY,
+ UNCHANGED},
+
// retrieve outside transaction
- { UNCHANGED, IMPOSSIBLE, IMPOSSIBLE, IMPOSSIBLE, PERSISTENT_NONTRANSACTIONAL,
- UNCHANGED, IMPOSSIBLE, IMPOSSIBLE, IMPOSSIBLE, UNCHANGED},
-
+ { UNCHANGED, IMPOSSIBLE, IMPOSSIBLE,
+ IMPOSSIBLE, PERSISTENT_NONTRANSACTIONAL, IMPOSSIBLE,
+ IMPOSSIBLE, IMPOSSIBLE, IMPOSSIBLE,
+ UNCHANGED, UNCHANGED, UNCHANGED,
+ UNCHANGED},
+
// retrieve with active transaction
- { UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED, PERSISTENT_CLEAN,
- UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED, PERSISTENT_CLEAN}
+ { UNCHANGED, UNCHANGED, UNCHANGED,
+ UNCHANGED, PERSISTENT_CLEAN, UNCHANGED,
+ UNCHANGED, UNCHANGED, UNCHANGED,
+ PERSISTENT_CLEAN, UNCHANGED, UNCHANGED,
+ UNCHANGED},
+
+ // commit, detachAllOnCommit = true
+ { UNCHANGED, DETACHED_CLEAN, DETACHED_CLEAN,
+ DETACHED_CLEAN, /*Bug: DETACHED_CLEAN*/UNCHANGED, UNCHANGED,
+ TRANSIENT_CLEAN, /*Bug: TRANSIENT*/NOT_APPLICABLE, /*Bug: TRANSIENT*/NOT_APPLICABLE,
+ /*Bug: DETACHED_CLEAN*/HOLLOW, DETACHED_CLEAN, 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
+
+ // detachCopy outside tx
+ { ERROR, IMPOSSIBLE, IMPOSSIBLE,
+ IMPOSSIBLE, UNCHANGED, IMPOSSIBLE,
+ IMPOSSIBLE, IMPOSSIBLE, IMPOSSIBLE,
+ UNCHANGED, ERROR, UNCHANGED,
+ UNCHANGED},
+
+ // detachCopy with active tx
+ { /*Bug: PERSISTENT_NEW*/UNCHANGED,UNCHANGED, UNCHANGED,
+ UNCHANGED, UNCHANGED, /*Bug: PERSISTENT_NEW*/UNCHANGED,
+ /*Bug: PERSISTENT_NEW*/UNCHANGED,ERROR, ERROR,
+ UNCHANGED, ERROR, UNCHANGED,
+ UNCHANGED},
+
+ // serialize outside tx
+ { UNCHANGED, IMPOSSIBLE, IMPOSSIBLE,
+ IMPOSSIBLE, UNCHANGED, IMPOSSIBLE,
+ IMPOSSIBLE, IMPOSSIBLE, IMPOSSIBLE,
+ UNCHANGED, UNCHANGED, UNCHANGED,
+ UNCHANGED},
+
+ // serialize with active tx
+ { UNCHANGED, UNCHANGED, UNCHANGED,
+ UNCHANGED, UNCHANGED, UNCHANGED,
+ UNCHANGED, UNCHANGED, UNCHANGED,
+ UNCHANGED, UNCHANGED, UNCHANGED,
+ UNCHANGED},
};
private static final int DATASTORE_TX = 0;
@@ -225,7 +351,12 @@
{ false, false, true }, // write field or makeDirty outside of a transaction
{ true, true, false }, // write field or makeDirty with active transaction
{ false, true, true }, // retrieve outside of a transaction or with active optimistic transaction
- { true, false, false } // retrieve with active datastore transaction
+ { true, false, false }, // retrieve with active datastore transaction
+ { true, true, false }, // commit, DetachAllOnCommit = true
+ { false, false, true }, // detachCopy outside tx
+ { true, true, false }, // detachCopy with active tx
+ { false, false, true }, // serialize outside tx
+ { true, true, false } // serialize with active tx
};
/**
@@ -282,12 +413,54 @@
}
/** */
+ public void prepareTransactionAndJDOSettings(Transaction transaction) {
+ if( scenario != NO_TX ) {
+ transaction.setNontransactionalRead(false);
+ transaction.setNontransactionalWrite(false);
+
+ if( operation == COMMITNORETAINVALUES )
+ transaction.setRetainValues(false);
+ if( operation == COMMITRETAINVALUES )
+ transaction.setRetainValues(true);
+ if( operation == ROLLBACKNORESTOREVALUES )
+ transaction.setRestoreValues(false);
+ if( operation == ROLLBACKRESTOREVALUES )
+ transaction.setRestoreValues(true);
+ if( operation == DETACHALLONCOMMIT )
+ pm.setDetachAllOnCommit(true);
+ else
+ pm.setDetachAllOnCommit(false);
+
+ transaction.setOptimistic(scenario == OPTIMISTIC_TX);
+ transaction.begin();
+ if( !transaction.isActive() )
+ if (debug)
+ logger.debug("StateTransitions: Transaction should be active, but it is not");
+ } else {
+ if( operation == READOUTSIDETX ||
+ operation == RETRIEVEOUTSIDETX ||
+ operation == DETACHCOPYOUTSIDETX ||
+ operation == SERIALIZEOUTSIDETX ) {
+ transaction.setNontransactionalRead(true);
+ }
+ if( operation == WRITEOUTSIDETX ||
+ current_state == PERSISTENT_NONTRANSACTIONAL_DIRTY) {
+ transaction.setNontransactionalWrite(true);
+ }
+ }
+ }
+
+ /** */
void checkTransitions()
{
for( operation = 0; operation < NUM_OPERATIONS; ++operation ){
// rule out situations that do not apply
- if( ! applies_to_scenario[operation][scenario] ) continue;
- if( operation == READOUTSIDETX && !isNontransactionalReadSupported() ) continue;
+ if( !applies_to_scenario[operation][scenario] ) continue;
+ if( (operation == READOUTSIDETX ||
+ operation == RETRIEVEOUTSIDETX ||
+ operation == DETACHCOPYOUTSIDETX ||
+ operation == SERIALIZEOUTSIDETX) &&
+ !isNontransactionalReadSupported() ) continue;
if( operation == WRITEOUTSIDETX && !isNontransactionalWriteSupported() ) continue;
if( operation == COMMITRETAINVALUES && !isRetainValuesSupported() ) continue;
if( operation == MAKENONTRANSACTIONAL &&
@@ -302,6 +475,9 @@
if( current_state == PERSISTENT_NONTRANSACTIONAL &&
!(isNontransactionalReadSupported() || isNontransactionalWriteSupported()) )
continue; // this state is not supported by implementation
+ if( current_state == PERSISTENT_NONTRANSACTIONAL_DIRTY &&
+ !isNontransactionalWriteSupported() )
+ continue;
expected_state = transitions[operation][current_state];
if( expected_state == IMPOSSIBLE ) continue;
@@ -315,23 +491,10 @@
transaction.rollback();
}
- if( scenario != NO_TX ){
- if( operation == COMMITNORETAINVALUES )
- transaction.setRetainValues(false);
- if( operation == COMMITRETAINVALUES )
- transaction.setRetainValues(true);
- if( operation == ROLLBACKNORESTOREVALUES )
- transaction.setRestoreValues(false);
- if( operation == ROLLBACKRESTOREVALUES )
- transaction.setRestoreValues(true);
+ prepareTransactionAndJDOSettings(transaction);
- transaction.setOptimistic(scenario == OPTIMISTIC_TX);
- transaction.begin();
- if( !transaction.isActive() )
- if (debug)
- logger.debug("StateTransitions: Transaction should be active, but it is not");
- }
-
+ printSituation();
+
StateTransitionObj obj = getInstanceInState(current_state);
if( obj == null ){ // could not get object in state
if( transaction.isActive() ) transaction.rollback();
@@ -346,7 +509,6 @@
if( excep instanceof javax.jdo.JDOUserException ){
e = excep;
} else {
- printSituation();
fail(ASSERTION_FAILED,
"StateTransitions: Unexpected exception:" + excep);
continue;
@@ -357,12 +519,10 @@
new_state = currentState(obj);
if( expected_state == ERROR ){
if( e == null ){
- printSituation();
fail(ASSERTION_FAILED,
"StateTransitions: JDOUserException should have been thrown");
} else {
if( new_state != current_state ){
- printSituation();
fail(ASSERTION_FAILED,
"StateTransitions: " +
" JDOUserException properly thrown, but instance should remain in current state," +
@@ -374,7 +534,6 @@
!((new_state == HOLLOW && expected_state == PERSISTENT_NONTRANSACTIONAL) ||
(new_state == PERSISTENT_NONTRANSACTIONAL && expected_state == HOLLOW)) ) {
// status interrogation gives same values for PERSISTENT_NONTRANSACTIONAL and HOLLOW
- printSituation();
fail(ASSERTION_FAILED,
"StateTransitions: Invalid state transition to " +
states[new_state] + ", new state should be " +
@@ -383,7 +542,6 @@
if( transaction.isActive() ) transaction.rollback();
}
catch(Exception unexpected_exception) {
- printSituation();
if (transaction.isActive())
transaction.rollback();
fail(ASSERTION_FAILED,
@@ -470,17 +628,17 @@
}
case READOUTSIDETX:
{
- int val = obj.readField();
+ obj.readField();
break;
}
case READOPTIMISTIC:
{
- int val = obj.readField();
+ obj.readField();
break;
}
case READDATASTORE:
{
- int val = obj.readField();
+ obj.readField();
break;
}
case WRITEOUTSIDETX:
@@ -501,8 +659,61 @@
case RETRIEVEINSIDETX:
{
pm.retrieve(obj);
- break;
+ break;
}
+ case DETACHALLONCOMMIT:
+ {
+ pm.currentTransaction().commit();
+ break;
+ }
+ case DETACHCOPYOUTSIDETX:
+ {
+ pm.detachCopy(obj);
+ break;
+ }
+ case DETACHCOPYINSIDETX:
+ {
+ pm.detachCopy(obj);
+ break;
+ }
+ case SERIALIZEOUTSIDETX:
+ {
+ ObjectOutputStream oos = null;
+ try {
+ oos = new ObjectOutputStream(new ByteArrayOutputStream());
+ oos.writeObject(obj);
+ } catch (IOException e) {
+ throw new JDOFatalException(e.getMessage(), e);
+ } finally {
+ if (oos != null) {
+ try {
+ oos.close();
+ } catch (IOException e) {
+ throw new JDOFatalException(e.getMessage(), e);
+ }
+ }
+ }
+ break;
+ }
+ case SERIALIZEINSIDETX:
+ {
+ ObjectOutputStream oos = null;
+ try {
+ oos = new ObjectOutputStream(new ByteArrayOutputStream());
+ oos.writeObject(obj);
+ } catch (IOException e) {
+ throw new JDOFatalException(e.getMessage(), e);
+ } finally {
+ if (oos != null) {
+ try {
+ oos.close();
+ } catch (IOException e) {
+ throw new JDOFatalException(e.getMessage(), e);
+ }
+ }
+ }
+ break;
+ }
default:
{
fail(ASSERTION_FAILED,
@@ -514,7 +725,7 @@
/**
* Get an instance in the specified state.
*/
- private StateTransitionObj getInstanceInState(int state)
+ public StateTransitionObj getInstanceInState(int state)
{
switch(state) {
case TRANSIENT:
@@ -537,15 +748,19 @@
return getPersistentDeletedInstance();
case PERSISTENT_NONTRANSACTIONAL:
return getPersistentNontransactionalInstance();
+ case PERSISTENT_NONTRANSACTIONAL_DIRTY:
+ return getPersistentNontransactionalDirtyInstance();
+ case DETACHED_CLEAN:
+ return getDetachedCleanInstance();
+ case DETACHED_DIRTY:
+ return getDetachedDirtyInstance();
default:
- {
return null;
}
- }
}
/** */
- private StateTransitionObj getTransientInstance()
+ public StateTransitionObj getTransientInstance()
{
StateTransitionObj obj = new StateTransitionObj(23);
int curr = currentState(obj);
@@ -554,14 +769,13 @@
logger.debug("StateTransitions: Unable to create transient instance, state is " +
states[curr]);
}
- printSituation();
return null;
}
return obj;
}
/** */
- private StateTransitionObj getPersistentNewInstance()
+ public StateTransitionObj getPersistentNewInstance()
{
StateTransitionObj obj = getTransientInstance();
if( obj == null ) return null;
@@ -573,7 +787,6 @@
" from transient instance via makePersistent(), state is " +
states[curr]);
}
- printSituation();
return null;
}
return obj;
@@ -585,7 +798,7 @@
StateTransitionObj obj = getHollowInstance();
if( obj == null ) return null;
StateTransitionObj sto = (StateTransitionObj) obj;
- int val = sto.readField();
+ sto.readField();
int curr = currentState(sto);
if( curr != PERSISTENT_CLEAN ) {
if (debug) {
@@ -593,7 +806,6 @@
" from a hollow instance by reading a field, state is " +
states[curr]);
}
- printSituation();
return null;
}
return obj;
@@ -613,7 +825,6 @@
" from a hollow instance by writing a field, state is " +
states[curr]);
}
- printSituation();
return null;
}
return obj;
@@ -637,33 +848,17 @@
if( !transaction.isActive() )
if (debug)
logger.debug("getHollowInstance: Transaction should be active, but it is not");
-
+
transaction.commit(); // This should put the instance in the HOLLOW state
- if( scenario != NO_TX ){
- if( operation == COMMITNORETAINVALUES )
- transaction.setRetainValues(false);
- if( operation == COMMITRETAINVALUES )
- transaction.setRetainValues(true);
- if( operation == ROLLBACKNORESTOREVALUES )
- transaction.setRestoreValues(false);
- if( operation == ROLLBACKRESTOREVALUES )
- transaction.setRestoreValues(true);
+ prepareTransactionAndJDOSettings(transaction);
- transaction.setOptimistic(scenario == OPTIMISTIC_TX);
- transaction.begin();
- if( !transaction.isActive() )
- if (debug)
- logger.debug("getHollowInstance: Transaction should be active, but it is not");
- }
-
int curr = currentState(obj);
if( curr != HOLLOW && curr != PERSISTENT_NONTRANSACTIONAL ){
if (debug) {
logger.debug("StateTransition: Attempt to get hollow instance via accessing extent failed, state is " +
states[curr]);
}
- printSituation();
return null;
}
return obj;
@@ -682,7 +877,6 @@
" from a transient instance via makeTransactional(), state is " +
states[curr]);
}
- printSituation();
return null;
}
return obj;
@@ -702,7 +896,6 @@
" from a transient-clean instance via modifying a field, state is " +
states[curr]);
}
- printSituation();
return null;
}
return obj;
@@ -721,7 +914,6 @@
" from a persistent-new instance via deletePersistent, state is " +
states[curr]);
}
- printSituation();
return null;
}
return obj;
@@ -740,7 +932,6 @@
" from a persistent instance via deletePersistent(), state is " +
states[curr]);
}
- printSituation();
return null;
}
return obj;
@@ -759,10 +950,64 @@
" from a persistent-clean instance via makeNontransactional(), state is " +
states[curr]);
}
- printSituation();
return null;
}
- return null;
+ return obj;
}
+ /** */
+ public StateTransitionObj getPersistentNontransactionalDirtyInstance()
+ {
+ StateTransitionObj obj = getPersistentNontransactionalInstance();
+ if( obj == null ) return null;
+ obj.writeField(10000);
+ int curr = currentState(obj);
+ if( curr != PERSISTENT_NONTRANSACTIONAL_DIRTY ) {
+ if (debug) {
+ logger.debug("StateTransition: Unable to create persistent-nontransactional-dirty instance" +
+ " from a persistent-clean instance via makeNontransactional()/JDOHelper.makeDirty," +
+ " state is " + states[curr]);
+ }
+ return null;
+ }
+ return obj;
+ }
+
+ /** */
+ public StateTransitionObj getDetachedCleanInstance()
+ {
+ StateTransitionObj obj = getHollowInstance();
+ if( obj == null ) return null;
+ obj = (StateTransitionObj) pm.detachCopy(obj);
+ int curr = currentState(obj);
+ if( curr != DETACHED_CLEAN ) {
+ if (debug) {
+ logger.debug("StateTransition: Unable to create detached-clean instance" +
+ " from a persistent-clean instance via detachCopy," +
+ " state is " + states[curr]);
+ }
+ return null;
+ }
+ return obj;
+ }
+
+ /** */
+ public StateTransitionObj getDetachedDirtyInstance()
+ {
+ StateTransitionObj obj = getHollowInstance();
+ if( obj == null ) return null;
+ obj = (StateTransitionObj) pm.detachCopy(obj);
+ obj.writeField(1000);
+ int curr = currentState(obj);
+ if( curr != DETACHED_DIRTY ) {
+ if (debug) {
+ logger.debug("StateTransition: Unable to create detached-dirty instance" +
+ " from a persistent-clean instance via detachCopy/persistent field modification," +
+ " state is " + states[curr]);
+ }
+ return null;
+ }
+ return obj;
+ }
+
}
Index: src/java/org/apache/jdo/tck/pc/lifecycle/StateTransitionObj.java
===================================================================
--- src/java/org/apache/jdo/tck/pc/lifecycle/StateTransitionObj.java (revision 371522)
+++ src/java/org/apache/jdo/tck/pc/lifecycle/StateTransitionObj.java (working copy)
@@ -19,7 +19,7 @@
import java.io.Serializable;
-public class StateTransitionObj {
+public class StateTransitionObj implements Serializable {
private static int counter = 0;
private int id;
Index: src/java/org/apache/jdo/tck/JDO_Test.java
===================================================================
--- src/java/org/apache/jdo/tck/JDO_Test.java (revision 371522)
+++ src/java/org/apache/jdo/tck/JDO_Test.java (working copy)
@@ -51,18 +51,21 @@
import org.apache.commons.logging.LogFactory;
public abstract class JDO_Test extends TestCase {
- public static final int TRANSIENT = 0;
- public static final int PERSISTENT_NEW = 1;
- public static final int PERSISTENT_CLEAN = 2;
- public static final int PERSISTENT_DIRTY = 3;
- public static final int HOLLOW = 4;
- public static final int TRANSIENT_CLEAN = 5;
- public static final int TRANSIENT_DIRTY = 6;
- public static final int PERSISTENT_NEW_DELETED = 7;
- public static final int PERSISTENT_DELETED = 8;
- public static final int PERSISTENT_NONTRANSACTIONAL = 9;
- public static final int NUM_STATES = 10;
- public static final int ILLEGAL_STATE = 10;
+ public static final int TRANSIENT = 0;
+ public static final int PERSISTENT_NEW = 1;
+ public static final int PERSISTENT_CLEAN = 2;
+ public static final int PERSISTENT_DIRTY = 3;
+ public static final int HOLLOW = 4;
+ public static final int TRANSIENT_CLEAN = 5;
+ public static final int TRANSIENT_DIRTY = 6;
+ public static final int PERSISTENT_NEW_DELETED = 7;
+ public static final int PERSISTENT_DELETED = 8;
+ public static final int PERSISTENT_NONTRANSACTIONAL = 9;
+ public static final int PERSISTENT_NONTRANSACTIONAL_DIRTY = 10;
+ public static final int DETACHED_CLEAN = 11;
+ public static final int DETACHED_DIRTY = 12;
+ public static final int NUM_STATES = 13;
+ public static final int ILLEGAL_STATE = 13;
public static final String[] states = {
"transient",
@@ -75,6 +78,9 @@
"persistent-new-deleted",
"persistent-deleted",
"persistent-nontransactional",
+ "persistent-nontransactional-dirty",
+ "detached-clean",
+ "detached-dirty",
"illegal"
};
private static final int IS_PERSISTENT = 0;
@@ -82,7 +88,8 @@
private static final int IS_DIRTY = 2;
private static final int IS_NEW = 3;
private static final int IS_DELETED = 4;
- private static final int NUM_STATUSES = 5;
+ private static final int IS_DETACHED = 5;
+ private static final int NUM_STATUSES = 6;
/*
* This table indicates the values returned by the status interrogation
@@ -90,36 +97,45 @@
* state of an object.
*/
private static final boolean state_statuses[][] = {
- // IS_PERSISTENT IS_TRANSACTIONAL IS_DIRTY IS_NEW IS_DELETED
+ // IS_PERSISTENT IS_TRANSACTIONAL IS_DIRTY IS_NEW IS_DELETED IS_DETACHED
// transient
- { false, false, false, false, false},
+ { false, false, false, false, false, false},
// persistent-new
- { true, true, true, true, false},
+ { true, true, true, true, false, false},
// persistent-clean
- { true, true, false, false, false},
+ { true, true, false, false, false, false},
// persistent-dirty
- { true, true, true, false, false},
+ { true, true, true, false, false, false},
// hollow
- { true, false, false, false, false},
+ { true, false, false, false, false, false},
// transient-clean
- { false, true, false, false, false},
+ { false, true, false, false, false, false},
// transient-dirty
- { false, true, true, false, false},
+ { false, true, true, false, false, false},
// persistent-new-deleted
- { true, true, true, true, true},
+ { true, true, true, true, true, false},
// persistent-deleted
- { true, true, true, false, true},
+ { true, true, true, false, true, false},
// persistent-nontransactional
- { true, false, false, false, false}
+ { true, false, false, false, false, false},
+
+ // persistent-nontransactional-dirty
+ { true, false, true, false, false, false},
+
+ // detached_clean
+ { false, false, false, false, false, true},
+
+ // detached_dirty
+ { false, false, true, false, false, true}
};
/** identitytype value for applicationidentity. */
@@ -740,6 +756,10 @@
if( existingEntries ) buff.append(", ");
buff.append("deleted");
}
+ if( JDOHelper.isDetached(o) ){
+ if( existingEntries ) buff.append(", ");
+ buff.append("detached");
+ }
buff.append("}");
return buff.toString();
}
@@ -749,12 +769,13 @@
*/
public static int currentState(Object o)
{
- boolean[] status = new boolean[5];
+ boolean[] status = new boolean[NUM_STATUSES];
status[IS_PERSISTENT] = JDOHelper.isPersistent(o);
status[IS_TRANSACTIONAL] = JDOHelper.isTransactional(o);
status[IS_DIRTY] = JDOHelper.isDirty(o);
status[IS_NEW] = JDOHelper.isNew(o);
status[IS_DELETED] = JDOHelper.isDeleted(o);
+ status[IS_DETACHED] = JDOHelper.isDetached(o);
int i, j;
outerloop:
for( i = 0; i < NUM_STATES; ++i ){
Index: src/conf/lifecycle.conf
===================================================================
--- src/conf/lifecycle.conf (revision 371522)
+++ src/conf/lifecycle.conf (working copy)
@@ -10,6 +10,7 @@
org.apache.jdo.tck.lifecycle.PMReturnsIdenticalInstancesForEqualObjIds \
org.apache.jdo.tck.lifecycle.PMsCanSharePCClassesButNotPCInstances \
org.apache.jdo.tck.lifecycle.StateTransitions \
+org.apache.jdo.tck.lifecycle.CheckStatesOfReturnedObjects \
org.apache.jdo.tck.lifecycle.TransientTransactionalStateCommit \
org.apache.jdo.tck.lifecycle.TransientTransactionalStateRollback \
org.apache.jdo.tck.lifecycle.nontransactional.ModificationOfNontransactionalInstanceOutsideTransaction
Index: src/jdo/datastoreidentity/org/apache/jdo/tck/pc/lifecycle/StateTransitionObj.jdo
===================================================================
--- src/jdo/datastoreidentity/org/apache/jdo/tck/pc/lifecycle/StateTransitionObj.jdo (revision 371522)
+++ src/jdo/datastoreidentity/org/apache/jdo/tck/pc/lifecycle/StateTransitionObj.jdo (working copy)
@@ -2,6 +2,6 @@
-
+
Index: src/jdo/applicationidentity/org/apache/jdo/tck/pc/lifecycle/StateTransitionObj.jdo
===================================================================
--- src/jdo/applicationidentity/org/apache/jdo/tck/pc/lifecycle/StateTransitionObj.jdo (revision 371522)
+++ src/jdo/applicationidentity/org/apache/jdo/tck/pc/lifecycle/StateTransitionObj.jdo (working copy)
@@ -5,7 +5,8 @@
+ objectid-class="org.apache.jdo.tck.pc.lifecycle.StateTransitionObj$Oid"
+ detachable="true">