You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jdo-commits@db.apache.org by mc...@apache.org on 2007/01/12 22:56:27 UTC

svn commit: r495751 [2/3] - in /db/jdo/trunk/tck20/src/java/org/apache/jdo/tck/lifecycle: StateTransitions.java StateTransitionsReturnedObjects.java

Modified: db/jdo/trunk/tck20/src/java/org/apache/jdo/tck/lifecycle/StateTransitions.java
URL: http://svn.apache.org/viewvc/db/jdo/trunk/tck20/src/java/org/apache/jdo/tck/lifecycle/StateTransitions.java?view=diff&rev=495751&r1=495750&r2=495751
==============================================================================
--- db/jdo/trunk/tck20/src/java/org/apache/jdo/tck/lifecycle/StateTransitions.java (original)
+++ db/jdo/trunk/tck20/src/java/org/apache/jdo/tck/lifecycle/StateTransitions.java Fri Jan 12 13:56:26 2007
@@ -1,1044 +1,1074 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.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;
-import org.apache.jdo.tck.pc.lifecycle.StateTransitionObj;
-import org.apache.jdo.tck.util.BatchTestRunner;
-
-/**
- *<B>Title:</B> Test State Transitions
- *<BR>
- *<B>Keywords:</B> lifecycle
- *<BR>
- *<B>Assertion IDs:</B> A5.9-1 through A5.9-190
- *<B>Assertion Description: </B>
- All possible state transistions are being tested in this test.
- */
-
-public class StateTransitions extends JDO_Test {
-
-    /** */
-    private static final String ASSERTION_FAILED = 
-        "Assertions A5.9-1 through A5.9-190 (StateTransitions) failed: ";
-    
-    /**
-     * The <code>main</code> 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(StateTransitions.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 DELETEPERSISTENT        = 1;
-    private static final int MAKETRANSACTIONAL       = 2;
-    private static final int MAKENONTRANSACTIONAL    = 3;
-    private static final int MAKETRANSIENT           = 4;
-    private static final int COMMITNORETAINVALUES    = 5;
-    private static final int COMMITRETAINVALUES      = 6;
-    private static final int ROLLBACKNORESTOREVALUES = 7;
-    private static final int ROLLBACKRESTOREVALUES   = 8;
-    private static final int REFRESHDATASTORE        = 9;
-    private static final int REFRESHOPTIMISTIC       = 10;
-    private static final int EVICT                   = 11;
-    private static final int READOUTSIDETX           = 12;
-    private static final int READOPTIMISTIC          = 13;
-    private static final int READDATASTORE           = 14;
-    private static final int WRITEOUTSIDETX          = 15;
-    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 SERIALIZEDATASTORE      = 23;
-    private static final int SERIALIZEOPTIMISTIC     = 24;
-    
-    private static final int NUM_OPERATIONS          = 25;
-    
-    private static final String[] operations = {
-        "makePersistent",
-        "deletePersistent",
-        "makeTransactional",
-        "makeNontransactional",
-        "makeTransient",
-        "commit, retainValues=false",
-        "commit, retainValues=true",
-        "rollback, restoreValues=false",
-        "rollback, restoreValues=true",
-        "refresh with active datastore tx",
-        "refresh with active optimistic tx",
-        "evict",
-        "read field outside tx",
-        "read field with active optimistic tx",
-        "read field with active datastore tx",
-        "write field outside tx",
-        "write field with active tx",
-        "retrieve outside tx",
-        "retrieve with active tx",
-        "commit, detachAllOnCommit=true",
-        "detachCopy outside tx",
-        "detachCopy with active tx",
-        "serialize outside tx",
-        "serialize with active datastore tx",
-        "serialize with active optimistic 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;
-    private static final int UNSPECIFIED                 = -5;
-
-    /**
-     * 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,                      UNCHANGED,                          DETACHED_CLEAN,     
-            DETACHED_DIRTY},
-
-        // deletePersistent
-        {   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,               PERSISTENT_DIRTY,                   ERROR,
-            ERROR},
-    
-        // makeNontransactional
-        {   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,                      ERROR,                              ERROR,
-            ERROR},
-
-        // commit, retainValues = false
-        {   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,                      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,                      HOLLOW,                             UNCHANGED,  
-            UNCHANGED},
-
-        // rollback, restoreValues = true
-        {   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,                      PERSISTENT_NONTRANSACTIONAL,        UNCHANGED,
-            UNCHANGED},
-
-        // refresh with active optimistic transaction
-        {   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,                         HOLLOW,                             UNCHANGED,
-            UNCHANGED},
-
-        // read field outside transaction
-        {   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,                      UNSPECIFIED,                        UNSPECIFIED,
-            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,                      UNSPECIFIED,                        UNSPECIFIED,
-            PERSISTENT_CLEAN,               UNCHANGED,                          UNCHANGED,
-            UNCHANGED},
-
-        // write field outside transaction
-        {   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,                          DETACHED_DIRTY,
-            UNCHANGED},
-      
-        // retrieve outside transaction
-        {   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},
-
-        // commit, detachAllOnCommit = true
-        {   UNCHANGED,                      DETACHED_CLEAN,                     DETACHED_CLEAN,
-            DETACHED_CLEAN,                 DETACHED_CLEAN,                     UNCHANGED,
-            TRANSIENT_CLEAN,                TRANSIENT,                          TRANSIENT,
-            DETACHED_CLEAN,                 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
-        {   UNSPECIFIED,                    IMPOSSIBLE,                         IMPOSSIBLE,
-            IMPOSSIBLE,                     UNSPECIFIED,                        IMPOSSIBLE,
-            IMPOSSIBLE,                     IMPOSSIBLE,                         IMPOSSIBLE,
-            UNCHANGED,                      ERROR,                              UNCHANGED,
-            UNCHANGED},
-
-        // detachCopy with active tx
-        {   PERSISTENT_NEW,                 UNCHANGED,                          UNCHANGED,
-            UNCHANGED,                      UNSPECIFIED,                        PERSISTENT_NEW,
-            PERSISTENT_NEW,                 ERROR,                              ERROR,
-            UNSPECIFIED,                    ERROR,                              UNSPECIFIED,
-            UNSPECIFIED},
-
-        // serialize outside tx
-        {   UNCHANGED,                      IMPOSSIBLE,                         IMPOSSIBLE,
-            IMPOSSIBLE,                     UNCHANGED,                          IMPOSSIBLE,
-            IMPOSSIBLE,                     IMPOSSIBLE,                         IMPOSSIBLE,
-            UNCHANGED,                      UNCHANGED,                          UNCHANGED,
-            UNCHANGED},
-
-        // serialize with active datastore tx
-        {   UNCHANGED,                      UNCHANGED,                          UNCHANGED,
-            UNCHANGED,                      PERSISTENT_CLEAN,                   UNCHANGED,
-            UNCHANGED,                      UNCHANGED,                          UNCHANGED,
-            PERSISTENT_CLEAN,               UNCHANGED,                          UNCHANGED,
-            UNCHANGED},
-
-        // serialize with active optimistic tx
-        {   UNCHANGED,                      UNCHANGED,                          UNCHANGED,
-            UNCHANGED,                      UNCHANGED,                          UNCHANGED,
-            UNCHANGED,                      UNCHANGED,                          UNCHANGED,
-            UNCHANGED,                      UNCHANGED,                          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
-        {   true,          true,        false },  // deletePersistent
-        {   true,          true,        false },  // makeTransactional
-        {   true,          true,        false },  // makeNontransactional
-        {   true,          true,        false },  // makeTransient
-        {   true,          true,        false },  // commit RetainValues = false
-        {   true,          true,        false },  // commit RetainValues = true
-        {   true,          true,        false },  // rollback RestoreValues = false
-        {   true,          true,        false },  // rollback RestoreValues = true
-        {   true,          false,       false },  // refresh with active datastore transaction
-        {   false,         true,        false },  // refresh with active optimistic transaction
-        {   true,          true,        false },  // evict
-        {   false,         false,       true  },  // read field outside of a transaction
-        {   false,         true,        false },  // read field with active optimistic transaction
-        {   true,          false,       false },  // read field with active datastore transaction
-        {   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,          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,          false,       false },  // serialize with active datastore tx
-        {   false,         true,        false }   // serialize with active optimistic 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();
-        failOnError();
-    }
-
-    /** */
-    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("StateTransitions 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);
-            
-            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 ||
-                 operation == RETRIEVEOUTSIDETX ||
-                 operation == DETACHCOPYOUTSIDETX ||
-                 operation == SERIALIZEOUTSIDETX) && 
-                 !isNontransactionalReadSupported() ) continue;
-            if( operation == WRITEOUTSIDETX && !isNontransactionalWriteSupported() ) continue;
-            if( operation == COMMITRETAINVALUES && !isRetainValuesSupported() ) continue;
-            if( operation == MAKENONTRANSACTIONAL &&
-                !(isNontransactionalReadSupported() || isNontransactionalWriteSupported()) )
-                continue;
-            int NUM_JDO1_STATES = NUM_STATES - 2; // JDO1 is tested so far here.
-            for( current_state = 0; current_state < NUM_JDO1_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 = transitions[operation][current_state];
-                if( expected_state == IMPOSSIBLE ) continue;
-                if( expected_state == NOT_APPLICABLE ) continue;
-                if( expected_state == UNSPECIFIED ) 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;
-                    try {
-                        applyOperation(operation, obj);
-                    } catch( Exception excep ){
-                        if( excep instanceof javax.jdo.JDOUserException ){
-                            e = excep;
-                        } else {
-                            appendMessage(ASSERTION_FAILED + NL +
-                                          "StateTransitions: " +
-                                          scenario_string[scenario] +
-                                          "; current state " + states[current_state] + NL +
-                                          operations[operation] +
-                                          "; unexpected exception:" + excep);
-                            continue;
-                        }
-                    }
-
-                    // Get new state, verify correct transition and exceptions occurred
-                    new_state = currentState(obj);
-                    if( expected_state == ERROR ){
-                        if( e == null ){
-                            appendMessage(ASSERTION_FAILED + NL +
-                                          "StateTransitions: " +
-                                          scenario_string[scenario] +
-                                          "; current state " + states[current_state] + NL +
-                                          operations[operation] +
-                                          "; JDOUserException should have been thrown");
-                        } else {
-                            if( new_state != current_state ){
-                                appendMessage(ASSERTION_FAILED + NL +
-                                              "StateTransitions: " +
-                                              scenario_string[scenario] +
-                                              "; current state " + states[current_state] + NL +
-                                              operations[operation] +
-                                              "; JDOUserException properly thrown, but instance should remain in current state," +
-                                              "instance changed state to " + states[new_state]);
-                            }
-                        }
-                    }
-                    if( !compareStates(new_state, expected_state) ) { 
-                        appendMessage(ASSERTION_FAILED + NL +
-                                      "StateTransitions: " +
-                                      scenario_string[scenario] +
-                                      "; current state " + states[current_state] + NL +
-                                      operations[operation] +
-                                      " transitioned instance to invalid state " + states[new_state] + 
-                                      "; expected state " + states[expected_state]);
-                    }
-                    if( transaction.isActive() ) transaction.rollback();
-                } 
-                catch(Exception unexpected_exception) {
-                    if (transaction.isActive()) 
-                        transaction.rollback();
-                    appendMessage(ASSERTION_FAILED + NL +
-                                  "StateTransitions: " +
-                                  scenario_string[scenario] +
-                                  "; current state " + states[current_state] + NL +
-                                  operations[operation] +
-                                  "; unexpected exception caught: " + unexpected_exception);
-                }
-            }
-        }
-    }
-
-    /** */
-    void printSituation()
-    {
-        if (debug) {
-            logger.debug(" (" + scenario_string[scenario] +
-                         ", initial state=" + states[current_state] + 
-                         ", operation=" + operations[operation] + ")");
-        }
-    }
-
-    /** */
-    void applyOperation(int operation, StateTransitionObj stobj)
-    {
-        StateTransitionObj obj = (StateTransitionObj) stobj;
-        switch( operation ){
-        case MAKEPERSISTENT:
-        {
-            pm.makePersistent(obj);
-            break;
-        }
-        case DELETEPERSISTENT:
-        {
-            pm.deletePersistent(obj);
-            break;
-        }
-        case MAKETRANSACTIONAL:
-        {
-            pm.makeTransactional(obj);
-            break;
-        }
-        case MAKENONTRANSACTIONAL:
-        {
-            pm.makeNontransactional(obj);
-            break;
-        }
-        case MAKETRANSIENT:
-        {
-            pm.makeTransient(obj);
-            break;
-        }
-        case COMMITNORETAINVALUES:
-        {
-            pm.currentTransaction().commit();
-            break;
-        }
-        case COMMITRETAINVALUES:
-        {
-            pm.currentTransaction().commit();
-            break;
-        }
-        case ROLLBACKNORESTOREVALUES:
-        {
-            pm.currentTransaction().rollback();
-            break;
-        }
-        case ROLLBACKRESTOREVALUES:
-        {
-            pm.currentTransaction().rollback();
-            break;
-        }
-        case REFRESHDATASTORE:
-        {
-            pm.refresh(obj);
-            break;
-        }
-        case REFRESHOPTIMISTIC:
-        {
-            pm.refresh(obj);
-            break;
-        }
-        case EVICT:
-        {
-            pm.evict(obj);
-            break;
-        }
-        case READOUTSIDETX:
-        {
-            obj.readField();
-            break;
-        }
-        case READOPTIMISTIC:
-        {
-            obj.readField();
-            break;
-        }
-        case READDATASTORE:
-        {
-            obj.readField();
-            break;
-        }
-        case WRITEOUTSIDETX:
-        {
-            obj.writeField(42);
-            break;
-        }
-        case WRITEINSIDETX:
-        {
-            obj.writeField(42);
-            break;
-        }
-        case RETRIEVEOUTSIDETX:
-        {
-            pm.retrieve(obj);
-            break;
-        }
-        case RETRIEVEINSIDETX:
-        {
-            pm.retrieve(obj);
-            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 SERIALIZEDATASTORE:
-        case SERIALIZEOPTIMISTIC:
-        {
-            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:
-        {
-            appendMessage(ASSERTION_FAILED + NL +
-                          "StateTransitions: " +
-                          scenario_string[scenario] +
-                          "; internal error, illegal operation: " + operation);
-        }
-        }
-    }
-
-    /**
-     * 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("StateTransitions: 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("StateTransitions: 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;
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.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;
+import org.apache.jdo.tck.pc.lifecycle.StateTransitionObj;
+import org.apache.jdo.tck.util.BatchTestRunner;
+
+/**
+ *<B>Title:</B> Test State Transitions
+ *<BR>
+ *<B>Keywords:</B> lifecycle
+ *<BR>
+ *<B>Assertion IDs:</B> A5.9-1 through A5.9-190
+ *<B>Assertion Description: </B>
+ All possible state transistions are being tested in this test.
+ */
+
+public class StateTransitions extends JDO_Test {
+
+    /** */
+    private static final String ASSERTION_FAILED = 
+        "Assertions A5.9-1 through A5.9-190 (StateTransitions) failed: ";
+    
+    /**
+     * The <code>main</code> 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(StateTransitions.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 DELETEPERSISTENT        = 1;
+    private static final int MAKETRANSACTIONAL       = 2;
+    private static final int MAKENONTRANSACTIONAL    = 3;
+    private static final int MAKETRANSIENT           = 4;
+    private static final int COMMITNORETAINVALUES    = 5;
+    private static final int COMMITRETAINVALUES      = 6;
+    private static final int ROLLBACKNORESTOREVALUES = 7;
+    private static final int ROLLBACKRESTOREVALUES   = 8;
+    private static final int REFRESHDATASTORE        = 9;
+    private static final int REFRESHOPTIMISTIC       = 10;
+    private static final int EVICT                   = 11;
+    private static final int READOUTSIDETX           = 12;
+    private static final int READOPTIMISTIC          = 13;
+    private static final int READDATASTORE           = 14;
+    private static final int WRITEOUTSIDETX          = 15;
+    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 DETACHCOPYOUTSIDETXNTRTRU     = 20;
+    private static final int DETACHCOPYOUTSIDETXNTRFLS     = 21;
+    private static final int DETACHCOPYINSIDEDATASTORETX      = 22;
+    private static final int DETACHCOPYINSIDEOPTIMISTICTX      = 23;
+    private static final int SERIALIZEOUTSIDETX      = 24;
+    private static final int SERIALIZEDATASTORE      = 25;
+    private static final int SERIALIZEOPTIMISTIC     = 26;
+    
+    private static final int NUM_OPERATIONS          = 27;
+    
+    private static final String[] operations = {
+        "makePersistent",
+        "deletePersistent",
+        "makeTransactional",
+        "makeNontransactional",
+        "makeTransient",
+        "commit, retainValues=false",
+        "commit, retainValues=true",
+        "rollback, restoreValues=false",
+        "rollback, restoreValues=true",
+        "refresh with active datastore tx",
+        "refresh with active optimistic tx",
+        "evict",
+        "read field outside tx",
+        "read field with active optimistic tx",
+        "read field with active datastore tx",
+        "write field outside tx",
+        "write field with active tx",
+        "retrieve outside tx",
+        "retrieve with active tx",
+        "commit, detachAllOnCommit=true",
+        "detachCopy outside tx with NontransactionalRead=true",
+        "detachCopy outside tx with NontransactionalRead=false",
+        "detachCopy with active datastore tx",
+        "detachCopy with active optimistic tx",
+        "serialize outside tx",
+        "serialize with active datastore tx",
+        "serialize with active optimistic 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;
+    private static final int UNSPECIFIED                 = -5;
+
+    /**
+     * 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,                      UNCHANGED,                          DETACHED_CLEAN,     
+            DETACHED_DIRTY},
+
+        // deletePersistent
+        {   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,               PERSISTENT_DIRTY,                   ERROR,
+            ERROR},
+    
+        // makeNontransactional
+        {   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,                      ERROR,                              ERROR,
+            ERROR},
+
+        // commit, retainValues = false
+        {   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,                      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,                      HOLLOW,                             UNCHANGED,  
+            UNCHANGED},
+
+        // rollback, restoreValues = true
+        {   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,                      PERSISTENT_NONTRANSACTIONAL,        UNCHANGED,
+            UNCHANGED},
+
+        // refresh with active optimistic transaction
+        {   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,                         HOLLOW,                             UNCHANGED,
+            UNCHANGED},
+
+        // read field outside transaction
+        {   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,                      UNSPECIFIED,                        UNSPECIFIED,
+            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,                      UNSPECIFIED,                        UNSPECIFIED,
+            PERSISTENT_CLEAN,               UNCHANGED,                          UNCHANGED,
+            UNCHANGED},
+
+        // write field outside transaction
+        {   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,                          DETACHED_DIRTY,
+            UNCHANGED},
+      
+        // retrieve outside transaction
+        {   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},
+
+        // commit, detachAllOnCommit = true
+        {   UNCHANGED,                      DETACHED_CLEAN,                     DETACHED_CLEAN,
+            DETACHED_CLEAN,                 DETACHED_CLEAN,                     UNCHANGED,
+            TRANSIENT_CLEAN,                TRANSIENT,                          TRANSIENT,
+            DETACHED_CLEAN,                 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 with NontransactionalRead=true
+        {   ERROR,                          IMPOSSIBLE,                         IMPOSSIBLE,
+            IMPOSSIBLE,                     PERSISTENT_NONTRANSACTIONAL,        ERROR,
+            IMPOSSIBLE,                     IMPOSSIBLE,                         IMPOSSIBLE,
+            UNCHANGED,                      UNSPECIFIED,                        UNCHANGED,
+            UNSPECIFIED},
+
+        // detachCopy outside tx with NontransactionalRead=false
+        {   ERROR,                          IMPOSSIBLE,                         IMPOSSIBLE,
+            IMPOSSIBLE,                     ERROR,                              ERROR,
+            IMPOSSIBLE,                     IMPOSSIBLE,                         IMPOSSIBLE,
+            ERROR,                          ERROR,                              ERROR,
+            ERROR},
+
+        // detachCopy with active datastore tx
+        {   PERSISTENT_NEW,                 UNCHANGED,                          UNCHANGED,
+            UNCHANGED,                      PERSISTENT_CLEAN,                   PERSISTENT_NEW,
+            PERSISTENT_NEW,                 ERROR,                              ERROR,
+            UNCHANGED,                      IMPOSSIBLE,                         UNCHANGED,
+            UNCHANGED},
+
+        // detachCopy with active optimistic tx
+        {   PERSISTENT_NEW,                 UNCHANGED,                          UNCHANGED,
+            UNCHANGED,                      PERSISTENT_NONTRANSACTIONAL,        PERSISTENT_NEW,
+            PERSISTENT_NEW,                 ERROR,                              ERROR,
+            UNCHANGED,                      IMPOSSIBLE,                         UNCHANGED,
+            UNCHANGED},
+
+        // serialize outside tx
+        {   UNCHANGED,                      IMPOSSIBLE,                         IMPOSSIBLE,
+            IMPOSSIBLE,                     UNCHANGED,                          IMPOSSIBLE,
+            IMPOSSIBLE,                     IMPOSSIBLE,                         IMPOSSIBLE,
+            UNCHANGED,                      UNCHANGED,                          UNCHANGED,
+            UNCHANGED},
+
+        // serialize with active datastore tx
+        {   UNCHANGED,                      UNCHANGED,                          UNCHANGED,
+            UNCHANGED,                      PERSISTENT_CLEAN,                   UNCHANGED,
+            UNCHANGED,                      UNCHANGED,                          UNCHANGED,
+            PERSISTENT_CLEAN,               UNCHANGED,                          UNCHANGED,
+            UNCHANGED},
+
+        // serialize with active optimistic tx
+        {   UNCHANGED,                      UNCHANGED,                          UNCHANGED,
+            UNCHANGED,                      UNCHANGED,                          UNCHANGED,
+            UNCHANGED,                      UNCHANGED,                          UNCHANGED,
+            UNCHANGED,                      UNCHANGED,                          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
+        {   true,          true,        false },  // deletePersistent
+        {   true,          true,        false },  // makeTransactional
+        {   true,          true,        false },  // makeNontransactional
+        {   true,          true,        false },  // makeTransient
+        {   true,          true,        false },  // commit RetainValues = false
+        {   true,          true,        false },  // commit RetainValues = true
+        {   true,          true,        false },  // rollback RestoreValues = false
+        {   true,          true,        false },  // rollback RestoreValues = true
+        {   true,          false,       false },  // refresh with active datastore transaction
+        {   false,         true,        false },  // refresh with active optimistic transaction
+        {   true,          true,        false },  // evict
+        {   false,         false,       true  },  // read field outside of a transaction
+        {   false,         true,        false },  // read field with active optimistic transaction
+        {   true,          false,       false },  // read field with active datastore transaction
+        {   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,          true,        false },  // commit, DetachAllOnCommit = true
+        {   false,         false,       true },   // detachCopy outside tx with NonTransactionaRead=true
+        {   false,         false,       true },   // detachCopy outside tx with NonTransactionaRead=false
+        {   true,          false,        false },  // detachCopy with active datastore tx
+        {   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
+    };
+
+    /**
+     * @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();
+        failOnError();
+    }
+
+    /** */
+    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("StateTransitions 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);
+            
+            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 == DETACHCOPYOUTSIDETXNTRTRU ||
+                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 ||
+                 operation == RETRIEVEOUTSIDETX ||
+                 operation == DETACHCOPYOUTSIDETXNTRTRU ||
+                 operation == SERIALIZEOUTSIDETX) && 
+                 !isNontransactionalReadSupported() ) continue;
+            if( operation == WRITEOUTSIDETX && !isNontransactionalWriteSupported() ) continue;
+            if( operation == COMMITRETAINVALUES && !isRetainValuesSupported() ) continue;
+            if( operation == MAKENONTRANSACTIONAL &&
+                !(isNontransactionalReadSupported() || isNontransactionalWriteSupported()) )
+                continue;
+            int NUM_JDO1_STATES = NUM_STATES - 2; // JDO1 is tested so far here.
+            for( current_state = 0; current_state < NUM_JDO1_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 = transitions[operation][current_state];
+                if( expected_state == IMPOSSIBLE ) continue;
+                if( expected_state == NOT_APPLICABLE ) continue;
+                if( expected_state == UNSPECIFIED ) 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;
+                    try {
+                        applyOperation(operation, obj);
+                    } catch( Exception excep ){
+                        if( excep instanceof javax.jdo.JDOUserException ){
+                            e = excep;
+                        } else {
+                            appendMessage(ASSERTION_FAILED + NL +
+                                          "StateTransitions: " +
+                                          scenario_string[scenario] +
+                                          "; current state " + states[current_state] + NL +
+                                          operations[operation] +
+                                          "; unexpected exception:" + excep);
+                            continue;
+                        }
+                    }
+
+                    // Get new state, verify correct transition and exceptions occurred
+                    new_state = currentState(obj);
+                    if( expected_state == ERROR ){
+                        if( e == null ){
+                            appendMessage(ASSERTION_FAILED + NL +
+                                          "StateTransitions: " +
+                                          scenario_string[scenario] +
+                                          "; current state " + states[current_state] + NL +
+                                          operations[operation] +
+                                          "; JDOUserException should have been thrown");
+                        } else {
+                            if( new_state != current_state ){
+                                appendMessage(ASSERTION_FAILED + NL +
+                                              "StateTransitions: " +
+                                              scenario_string[scenario] +
+                                              "; current state " + states[current_state] + NL +
+                                              operations[operation] +
+                                              "; JDOUserException properly thrown, but instance should remain in current state," +
+                                              "instance changed state to " + states[new_state]);
+                            }
+                        }
+                    }
+                    if( !compareStates(new_state, expected_state) ) { 
+                        appendMessage(ASSERTION_FAILED + NL +
+                                      "StateTransitions: " +
+                                      scenario_string[scenario] +
+                                      "; current state " + states[current_state] + NL +
+                                      operations[operation] +
+                                      " transitioned instance to invalid state " + states[new_state] + 
+                                      "; expected state " + states[expected_state]);
+                    }
+                    if( transaction.isActive() ) transaction.rollback();
+                } 
+                catch(Exception unexpected_exception) {
+                    if (transaction.isActive()) 
+                        transaction.rollback();
+                    appendMessage(ASSERTION_FAILED + NL +
+                                  "StateTransitions: " +
+                                  scenario_string[scenario] +
+                                  "; current state " + states[current_state] + NL +
+                                  operations[operation] +
+                                  "; unexpected exception caught: " + unexpected_exception);
+                }
+            }
+        }
+    }
+
+    /** */
+    void printSituation()
+    {
+        if (debug) {
+            logger.debug(" (" + scenario_string[scenario] +
+                         ", initial state=" + states[current_state] + 
+                         ", operation=" + operations[operation] + ")");
+        }
+    }
+
+    /** */
+    void applyOperation(int operation, StateTransitionObj stobj)
+    {
+        StateTransitionObj obj = (StateTransitionObj) stobj;
+        switch( operation ){
+        case MAKEPERSISTENT:
+        {
+            pm.makePersistent(obj);
+            break;
+        }
+        case DELETEPERSISTENT:
+        {
+            pm.deletePersistent(obj);
+            break;
+        }
+        case MAKETRANSACTIONAL:
+        {
+            pm.makeTransactional(obj);
+            break;
+        }
+        case MAKENONTRANSACTIONAL:
+        {
+            pm.makeNontransactional(obj);
+            break;
+        }
+        case MAKETRANSIENT:
+        {
+            pm.makeTransient(obj);
+            break;
+        }
+        case COMMITNORETAINVALUES:
+        {
+            pm.currentTransaction().commit();
+            break;
+        }
+        case COMMITRETAINVALUES:
+        {
+            pm.currentTransaction().commit();
+            break;
+        }
+        case ROLLBACKNORESTOREVALUES:
+        {
+            pm.currentTransaction().rollback();
+            break;
+        }
+        case ROLLBACKRESTOREVALUES:
+        {
+            pm.currentTransaction().rollback();
+            break;
+        }
+        case REFRESHDATASTORE:
+        {
+            pm.refresh(obj);
+            break;
+        }
+        case REFRESHOPTIMISTIC:
+        {
+            pm.refresh(obj);
+            break;
+        }
+        case EVICT:
+        {
+            pm.evict(obj);
+            break;
+        }
+        case READOUTSIDETX:
+        {
+            obj.readField();
+            break;
+        }
+        case READOPTIMISTIC:
+        {
+            obj.readField();
+            break;
+        }
+        case READDATASTORE:
+        {
+            obj.readField();
+            break;
+        }
+        case WRITEOUTSIDETX:
+        {
+            obj.writeField(42);
+            break;
+        }
+        case WRITEINSIDETX:
+        {
+            obj.writeField(42);
+            break;
+        }
+        case RETRIEVEOUTSIDETX:
+        {
+            pm.retrieve(obj);
+            break;
+        }
+        case RETRIEVEINSIDETX:
+        {
+            pm.retrieve(obj);
+            break;      
+        }
+        case DETACHALLONCOMMIT:
+        {
+            pm.currentTransaction().commit();
+            break;      
+        }
+        case DETACHCOPYOUTSIDETXNTRTRU:
+        {
+            pm.detachCopy(obj);
+            break;      
+        }
+        case DETACHCOPYOUTSIDETXNTRFLS:
+        {
+            pm.detachCopy(obj);
+            break;      
+        }
+        case DETACHCOPYINSIDEDATASTORETX:
+        {
+            pm.detachCopy(obj);
+            break;      
+        }
+        case DETACHCOPYINSIDEOPTIMISTICTX:
+        {
+            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 SERIALIZEDATASTORE:
+        case SERIALIZEOPTIMISTIC:
+        {
+            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:
+        {
+            appendMessage(ASSERTION_FAILED + NL +
+                          "StateTransitions: " +
+                          scenario_string[scenario] +
+                          "; internal error, illegal operation: " + operation);
+        }
+        }
+    }
+
+    /**
+     * 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("StateTransitions: 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("StateTransitions: 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;

[... 123 lines stripped ...]