Package org.apache.jdo.tck.lifecycle

Source Code of org.apache.jdo.tck.lifecycle.StateTransitionsReturnedObjects

/*
* 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;

/**
*<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 StateTransitionsReturnedObjects extends JDO_Test {

    /** */
    private static final String ASSERTION_FAILED =
        "Assertions A5.9-1 through A5.5.8 (serialization, detachment, attachment) 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(StateTransitionsReturnedObjects.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,                          PERSISTENT_CLEAN,    
            PERSISTENT_DIRTY},

        // detachCopy outside tx
        {   ERROR,                          IMPOSSIBLE,                         IMPOSSIBLE,
            IMPOSSIBLE,                     DETACHED_CLEAN,                     IMPOSSIBLE,
            IMPOSSIBLE,                     IMPOSSIBLE,                         IMPOSSIBLE,
            DETACHED_CLEAN,                 ERROR,                              UNCHANGED,
            DETACHED_CLEAN},

        // detachCopy with active tx
        {   DETACHED_CLEAN,                 DETACHED_CLEAN,                     DETACHED_CLEAN,
            DETACHED_CLEAN,                 DETACHED_CLEAN,                     DETACHED_CLEAN,
            DETACHED_CLEAN,                 ERROR,                              ERROR,
            DETACHED_CLEAN,                 ERROR,                              UNCHANGED,
            DETACHED_CLEAN},

        // serialize outside tx
        {   UNCHANGED,                      IMPOSSIBLE,                         IMPOSSIBLE,
            IMPOSSIBLE,                     DETACHED_CLEAN,                     IMPOSSIBLE,
            IMPOSSIBLE,                     IMPOSSIBLE,                         IMPOSSIBLE,
            DETACHED_CLEAN,                 TRANSIENT,                          UNCHANGED,
            UNCHANGED},

        // serialize with active tx
        {   UNCHANGED,                      DETACHED_CLEAN,                     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
        // since the spec leaves detachCopy outside tx a bit underspecified,
        // we decided to disable this scanario for now
        //{   false,         false,       true },   // detachCopy outside tx
        {   false,         false,       false },   // 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();
        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("StateTransitionsReturnedObjects 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("StateTransitionsReturnedObjects: 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 {
                            appendMessage(ASSERTION_FAILED + NL +
                                          "StateTransitionsReturnedObjects: " +
                                          scenario_string[scenario] +
                                          "; current state " + states[current_state] + NL +
                                          operations[operation] +
                                          "; unexpected exception: " + excep);
                            continue;
                        }
                    }

                    if( expected_state == ERROR ){
                        if( e == null ){
                            appendMessage(ASSERTION_FAILED + NL +
                                          "StateTransitionsReturnedObjects: " +
                                          scenario_string[scenario] +
                                          "; current state " + states[current_state] + NL +
                                          operations[operation] +
                                          "; JDOUserException should have been thrown");
                        } else {
                            int stateOfObj = currentState(obj);
                            if( stateOfObj != current_state ){
                                appendMessage(ASSERTION_FAILED + NL +
                                              "StateTransitionsReturnedObjects: " +
                                              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[stateOfObj]);
                            }
                        }
                    } else {
                        // Get new state, verify correct transition and exceptions occurred
                        new_state = currentState(returnedObject);
                        if( !compareStates(new_state, expected_state) ) {
                            appendMessage(ASSERTION_FAILED + NL +
                                          "StateTransitionsReturnedObjects: " +
                                          scenario_string[scenario] +
                                          "; current state " + states[current_state] + NL +
                                          operations[operation] +
                                          " returned instance in 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 +
                                  "StateTransitionsReturnedObjects: " +
                                  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] +
                         ", " + 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:
                appendMessage(ASSERTION_FAILED + NL +
                              "StateTransitionsReturnedObjects: " +
                              scenario_string[scenario] +
                              "; 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("StateTransitionsReturnedObjects: 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("StateTransitionsReturnedObjects: 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("StateTransitionsReturnedObjects: 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("StateTransitionsReturnedObjects: 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("StateTransitionsReturnedObjects: 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("StateTransitionsReturnedObjects: 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("StateTransitionsReturnedObjects: 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("StateTransitionsReturnedObjects: 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("StateTransitionsReturnedObjects: 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("StateTransitionsReturnedObjects: 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("StateTransitionsReturnedObjects: 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("StateTransitionsReturnedObjects: 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("StateTransitionsReturnedObjects: Unable to create detached-dirty instance" +
                             " from a persistent-clean instance via detachCopy/persistent field modification," +
                             " state is " + states[curr]);
            }
            return null;
        }
        return obj;
    }
}
TOP

Related Classes of org.apache.jdo.tck.lifecycle.StateTransitionsReturnedObjects

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.