0001: /**
0002: * Copyright (C) 2001-2004 France Telecom R&D
0003: *
0004: * This library is free software; you can redistribute it and/or
0005: * modify it under the terms of the GNU Lesser General Public
0006: * License as published by the Free Software Foundation; either
0007: * version 2 of the License, or (at your option) any later version.
0008: *
0009: * This library is distributed in the hope that it will be useful,
0010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0012: * Lesser General Public License for more details.
0013: *
0014: * You should have received a copy of the GNU Lesser General Public
0015: * License along with this library; if not, write to the Free Software
0016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0017: */package org.objectweb.speedo.runtime.tck;
0018:
0019: import java.util.Iterator;
0020:
0021: import javax.jdo.Extent;
0022: import javax.jdo.JDOHelper;
0023: import javax.jdo.PersistenceManager;
0024: import javax.jdo.Transaction;
0025:
0026: import org.objectweb.speedo.pobjects.tck.StateTransitionObj;
0027: import org.objectweb.speedo.SpeedoTestHelper;
0028: import org.objectweb.util.monolog.api.BasicLevel;
0029:
0030: public class JdoLifecycleTck extends SpeedoTestHelper {
0031:
0032: public static final int TRANSIENT = 0;
0033: public static final int PERSISTENT_NEW = 1;
0034: public static final int PERSISTENT_CLEAN = 2;
0035: public static final int PERSISTENT_DIRTY = 3;
0036: public static final int HOLLOW = 4;
0037: public static final int TRANSIENT_CLEAN = 5;
0038: public static final int TRANSIENT_DIRTY = 6;
0039: public static final int PERSISTENT_NEW_DELETED = 7;
0040: public static final int PERSISTENT_DELETED = 8;
0041: public static final int PERSISTENT_NONTRANSACTIONAL = 9;
0042: public static final int NUM_STATES = 10;
0043: public static final int ILLEGAL_STATE = 10;
0044:
0045: public static final String[] states = { "transient",
0046: "persistent-new", "persistent-clean", "persistent-dirty",
0047: "hollow", "transient-clean", "transient-dirty",
0048: "persistent-new-deleted", "persistent-deleted",
0049: "persistent-nontransactional", "illegal" };
0050: private static final int IS_PERSISTENT = 0;
0051: private static final int IS_TRANSACTIONAL = 1;
0052: private static final int IS_DIRTY = 2;
0053: private static final int IS_NEW = 3;
0054: private static final int IS_DELETED = 4;
0055: private static final int NUM_STATUSES = 5;
0056:
0057: /*
0058: * This table indicates the values returned by the status interrogation
0059: * methods for each state. This is used to determine the current lifecycle
0060: * state of an object.
0061: */
0062: private static final boolean state_statuses[][] = {
0063: // IS_PERSISTENT IS_TRANSACTIONAL IS_DIRTY IS_NEW IS_DELETED
0064: // transient
0065: { false, false, false, false, false },
0066:
0067: // persistent-new
0068: { true, true, true, true, false },
0069:
0070: // persistent-clean
0071: { true, true, false, false, false },
0072:
0073: // persistent-dirty
0074: { true, true, true, false, false },
0075:
0076: // hollow
0077: { true, false, false, false, false },
0078:
0079: // transient-clean
0080: { false, true, false, false, false },
0081:
0082: // transient-dirty
0083: { false, true, true, false, false },
0084:
0085: // persistent-new-deleted
0086: { true, true, true, true, true },
0087:
0088: // persistent-deleted
0089: { true, true, true, false, true },
0090:
0091: // persistent-nontransactional
0092: { true, false, false, false, false } };
0093:
0094: // These values MUST correspond to index in sorted array below.
0095: private static final int OPTION_APPLICATIONIDENTITY = 0;
0096: private static final int OPTION_ARRAY = 1;
0097: private static final int OPTION_ARRAYLIST = 2;
0098: private static final int OPTION_CHANGEAPPLICATIONIDENTITY = 3;
0099: private static final int OPTION_DATASTOREIDENTITY = 4;
0100: private static final int OPTION_HASHMAP = 5;
0101: private static final int OPTION_HASHTABLE = 6;
0102: private static final int OPTION_LINKEDLIST = 7;
0103: private static final int OPTION_LIST = 8;
0104: private static final int OPTION_MAP = 9;
0105: private static final int OPTION_NONDURABLEIDENTITY = 10;
0106: private static final int OPTION_NONTRANSACTIONALREAD = 11;
0107: private static final int OPTION_NONTRANSACTIONALWRITE = 12;
0108: private static final int OPTION_NULLCOLLECTION = 13;
0109: private static final int OPTION_OPTIMISTIC = 14;
0110: private static final int OPTION_RETAINVALUES = 15;
0111: private static final int OPTION_TRANSIENTTRANSACTIONAL = 16;
0112: private static final int OPTION_TREEMAP = 17;
0113: private static final int OPTION_TREESET = 18;
0114: private static final int OPTION_VECTOR = 19;
0115:
0116: private static boolean[] options = new boolean[OPTION_VECTOR + 1];
0117: private static Boolean syncObj = new Boolean(false);
0118: private static boolean syncFlag = false;
0119:
0120: private static String[] optionNames = { // MUST be in "natural sorted order"
0121: "-ApplicationIdentity", "-Array", "-ArrayList",
0122: "-ChangeApplicationIdentity", "-DatastoreIdentity",
0123: "-HashMap", "-Hashtable", "-LinkedList", "-List", "-Map",
0124: "-NonDurableIdentity", "-NontransactionalRead",
0125: "-NontransactionalWrite", "-NullCollection", "-Optimistic",
0126: "-RetainValues", "-TransientTransactional", "-TreeMap",
0127: "-TreeSet", "-Vector" };
0128:
0129: private PersistenceManager pm;
0130: private Transaction transaction;
0131: private int scenario;
0132: private int operation;
0133: private int current_state;
0134: private int expected_state;
0135: private int new_state;
0136: private String pmfName;
0137: private String contextFactory;
0138: private String providerURL;
0139: private String connectionUserName;
0140: private String connectionPassword;
0141: private String connectionURL;
0142:
0143: private static final String PMFNAME = "pmfName";
0144: private static final String JNDICONTEXTFACTORY = "PMFProperties";
0145:
0146: /**
0147: * Operations that cause state changes
0148: */
0149: private static final int MAKEPERSISTENT = 0;
0150: private static final int DELETEPERSISTENT = 1;
0151: private static final int MAKETRANSACTIONAL = 2;
0152: private static final int MAKENONTRANSACTIONAL = 3;
0153: private static final int MAKETRANSIENT = 4;
0154: private static final int COMMITNORETAINVALUES = 5;
0155: private static final int COMMITRETAINVALUES = 6;
0156: private static final int ROLLBACKNORETAINVALUES = 7;
0157: private static final int ROLLBACKRETAINVALUES = 8;
0158: private static final int REFRESHDATASTORE = 9;
0159: private static final int REFRESHOPTIMISTIC = 10;
0160: private static final int EVICT = 11;
0161: private static final int READOUTSIDETX = 12;
0162: private static final int READOPTIMISTIC = 13;
0163: private static final int READDATASTORE = 14;
0164: private static final int WRITEOUTSIDETX = 15;
0165: private static final int WRITEINSIDETX = 16;
0166:
0167: private static final String[] operations = { "makePersistent",
0168: "deletePersistent", "makeTransactional",
0169: "makeNontransactional", "makeTransient",
0170: "commit, retainValues=false", "commit, retainValues=true",
0171: "rollback, retainValues=false",
0172: "rollback, retainValues=true",
0173: "refresh with active datastore tx",
0174: "refresh with active optimistic tx", "evict",
0175: "read field outside tx",
0176: "read field with active optimistic tx",
0177: "read field with active datastore tx",
0178: "write field outside tx", "write field with active tx" };
0179: private static final int NUM_OPERATIONS = 17;
0180:
0181: private static final boolean[] closes_transaction = { false, false,
0182: false, false, false, true, true, true, true, false, false,
0183: false, false, false, false, false, false };
0184:
0185: /**
0186: * Illegal state transitions
0187: */
0188: private static final int UNCHANGED = -1;
0189: private static final int ERROR = -2;
0190: private static final int IMPOSSIBLE = -3;
0191: private static final int NOT_APPLICABLE = -4;
0192:
0193: /**
0194: * StateItf transitions
0195: */
0196:
0197: public static final int[][] transitions = { // [operation] [current state] = new state
0198: // makePersistent
0199: { PERSISTENT_NEW, UNCHANGED, UNCHANGED, UNCHANGED,
0200: UNCHANGED, PERSISTENT_NEW, PERSISTENT_NEW,
0201: UNCHANGED, UNCHANGED, UNCHANGED },
0202:
0203: // deletePersistent
0204: { ERROR, PERSISTENT_NEW_DELETED, PERSISTENT_DELETED,
0205: PERSISTENT_DELETED, PERSISTENT_DELETED, ERROR,
0206: ERROR, UNCHANGED, UNCHANGED, PERSISTENT_DELETED },
0207:
0208: // makeTransactional
0209: { TRANSIENT_CLEAN, UNCHANGED, UNCHANGED, UNCHANGED,
0210: PERSISTENT_CLEAN, UNCHANGED, UNCHANGED, UNCHANGED,
0211: UNCHANGED, PERSISTENT_CLEAN },
0212:
0213: // makeNontransactional
0214: { ERROR, ERROR, PERSISTENT_NONTRANSACTIONAL, ERROR,
0215: UNCHANGED, TRANSIENT, ERROR, ERROR, ERROR,
0216: UNCHANGED },
0217:
0218: // makeTransient
0219: { UNCHANGED, ERROR, TRANSIENT, ERROR, TRANSIENT, UNCHANGED,
0220: UNCHANGED, ERROR, ERROR, TRANSIENT },
0221:
0222: // commit, retainValues = false
0223: { UNCHANGED, HOLLOW, HOLLOW, HOLLOW, UNCHANGED, UNCHANGED,
0224: TRANSIENT_CLEAN, TRANSIENT, TRANSIENT, UNCHANGED },
0225:
0226: // commit, retainValues = true
0227: { UNCHANGED, PERSISTENT_NONTRANSACTIONAL,
0228: PERSISTENT_NONTRANSACTIONAL,
0229: PERSISTENT_NONTRANSACTIONAL, UNCHANGED, UNCHANGED,
0230: TRANSIENT_CLEAN, TRANSIENT, TRANSIENT, UNCHANGED },
0231:
0232: // rollback, retainValues = false
0233: { UNCHANGED, TRANSIENT, HOLLOW, HOLLOW, UNCHANGED,
0234: UNCHANGED, TRANSIENT_CLEAN, TRANSIENT, HOLLOW,
0235: UNCHANGED },
0236:
0237: // rollback, retainValues = true
0238: { UNCHANGED, TRANSIENT, PERSISTENT_NONTRANSACTIONAL,
0239: PERSISTENT_NONTRANSACTIONAL, UNCHANGED, UNCHANGED,
0240: TRANSIENT_CLEAN, TRANSIENT,
0241: PERSISTENT_NONTRANSACTIONAL, UNCHANGED },
0242:
0243: // refresh with active datastore transaction
0244: { UNCHANGED, UNCHANGED, UNCHANGED, PERSISTENT_CLEAN,
0245: UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED,
0246: UNCHANGED, UNCHANGED },
0247:
0248: // refresh with active optimistic transaction
0249: { UNCHANGED, UNCHANGED, UNCHANGED,
0250: PERSISTENT_NONTRANSACTIONAL, UNCHANGED, UNCHANGED,
0251: UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED },
0252:
0253: // evict
0254: { UNCHANGED, UNCHANGED, HOLLOW, UNCHANGED, UNCHANGED,
0255: UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED, HOLLOW },
0256:
0257: // read field outside transaction
0258: { UNCHANGED, IMPOSSIBLE, IMPOSSIBLE, IMPOSSIBLE,
0259: PERSISTENT_NONTRANSACTIONAL, UNCHANGED, IMPOSSIBLE,
0260: IMPOSSIBLE, IMPOSSIBLE, UNCHANGED },
0261:
0262: // read field with active optimistic transaction
0263: { UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED,
0264: PERSISTENT_NONTRANSACTIONAL, UNCHANGED, UNCHANGED,
0265: ERROR, ERROR, UNCHANGED },
0266:
0267: // read field with active datastore transaction
0268: { UNCHANGED, UNCHANGED, UNCHANGED, UNCHANGED,
0269: PERSISTENT_CLEAN, UNCHANGED, UNCHANGED, ERROR,
0270: ERROR, PERSISTENT_CLEAN },
0271:
0272: // write field outside transaction
0273: { UNCHANGED, IMPOSSIBLE, IMPOSSIBLE, IMPOSSIBLE,
0274: PERSISTENT_NONTRANSACTIONAL, UNCHANGED, IMPOSSIBLE,
0275: IMPOSSIBLE, IMPOSSIBLE, UNCHANGED },
0276:
0277: // write field with active transaction
0278: { UNCHANGED, UNCHANGED, PERSISTENT_DIRTY, UNCHANGED,
0279: PERSISTENT_DIRTY, TRANSIENT_DIRTY, UNCHANGED,
0280: ERROR, ERROR, PERSISTENT_DIRTY } };
0281:
0282: private static final int DATASTORE_TX = 0;
0283: private static final int OPTIMISTIC_TX = 1;
0284: private static final int NO_TX = 2;
0285:
0286: private static final String[] scenario_string = {
0287: "datastore transaction", "optimistic transaction",
0288: "no transaction" };
0289:
0290: private static final boolean[][] applies_to_scenario = {
0291: // Datastore Optimistic No tx
0292: { true, true, false }, // makePersistent
0293: { true, true, false }, // deletePersistent
0294: { true, true, false }, // makeTransactional
0295: { true, true, false }, // makeNontransactional
0296: { true, true, false }, // makeTransient
0297: { true, true, false }, // commit RetainValues = false
0298: { true, true, false }, // commit RetainValues = true
0299: { true, true, false }, // rollback RetainValues = false
0300: { true, true, false }, // rollback RetainValues = true
0301: { true, false, false }, // refresh with active datastore
0302: { false, true, false }, // refresh with active optimistic
0303: { true, true, false }, // evict
0304: { false, false, true }, // read field outside transaction
0305: { false, true, false }, // read field with optimistic
0306: { true, false, false }, // read field with datastore
0307: { false, false, true }, // write field outside transaction
0308: { true, true, false } // write field with active transaction
0309: };
0310:
0311: /**
0312: *Reports whether TransientTransactional is supported.
0313: */
0314: public static boolean isTransientTransactionalSupported() {
0315: return options[OPTION_TRANSIENTTRANSACTIONAL];
0316: }
0317:
0318: /**
0319: *Reports whether NontransactionalRead is supported.
0320: */
0321: public static boolean isNontransactionalReadSupported() {
0322: return options[OPTION_NONTRANSACTIONALREAD];
0323: }
0324:
0325: /**
0326: *Reports whether NontransactionalWrite is supported.
0327: */
0328: public static boolean isNontransactionalWriteSupported() {
0329: return options[OPTION_NONTRANSACTIONALWRITE];
0330: }
0331:
0332: /**
0333: *Reports whether RetainValues is supported.
0334: */
0335: public static boolean isRetainValuesSupported() {
0336: return options[OPTION_RETAINVALUES];
0337: }
0338:
0339: /**
0340: *Reports whether Optimistic is supported.
0341: */
0342: public static boolean isOptimisticSupported() {
0343: return options[OPTION_OPTIMISTIC];
0344: }
0345:
0346: /**
0347: *Reports whether Application Identity is supported.
0348: */
0349: public static boolean isApplicationIdentitySupported() {
0350: return options[OPTION_APPLICATIONIDENTITY];
0351: }
0352:
0353: /**
0354: * Reports whether Changing Application Identity is supported.
0355: */
0356: public static boolean isChangeApplicationIdentitySupported() {
0357: return options[OPTION_CHANGEAPPLICATIONIDENTITY];
0358: }
0359:
0360: /**
0361: *Reports whether Datastore Identity is supported.
0362: */
0363: public static boolean isDatastoreIdentitySupported() {
0364: return options[OPTION_DATASTOREIDENTITY];
0365: }
0366:
0367: /**
0368: *Reports whether Non-Durable Identity is supported.
0369: */
0370: public static boolean isNonDurableIdentitySupported() {
0371: return options[OPTION_NONDURABLEIDENTITY];
0372: }
0373:
0374: /**
0375: *Reports whether an <code>ArrayList</code> collection is supported.
0376: */
0377: public static boolean isArrayListSupported() {
0378: return options[OPTION_ARRAYLIST];
0379: }
0380:
0381: /**
0382: *Reports whether a <code>HashMap</code> collection is supported.
0383: */
0384: public static boolean isHashMapSupported() {
0385: return options[OPTION_HASHMAP];
0386: }
0387:
0388: /**
0389: *Reports whether a <code>Hashtable</code> collection is supported.
0390: */
0391: public static boolean isHashtableSupported() {
0392: return options[OPTION_HASHTABLE];
0393: }
0394:
0395: /**
0396: *Reports whether a <code>LinkedList</code> collection is supported.
0397: */
0398: public static boolean isLinkedListSupported() {
0399: return options[OPTION_LINKEDLIST];
0400: }
0401:
0402: /**
0403: *Reports whether a <code>TreeMap</code> collection is supported.
0404: */
0405: public static boolean isTreeMapSupported() {
0406: return options[OPTION_TREEMAP];
0407: }
0408:
0409: /**
0410: *Reports whether a <code>TreeSet</code> collection is supported.
0411: */
0412: public static boolean isTreeSetSupported() {
0413: return options[OPTION_TREESET];
0414: }
0415:
0416: /**
0417: *Reports whether a <code>Vector</code> collection is supported.
0418: */
0419: public static boolean isVectorSupported() {
0420: return options[OPTION_VECTOR];
0421: }
0422:
0423: /**
0424: *Reports whether a <code>Map</code> collection is supported.
0425: */
0426: public static boolean isMapSupported() {
0427: return options[OPTION_MAP];
0428: }
0429:
0430: /**
0431: *Reports whether a <code>List</code> collection is supported.
0432: */
0433: public static boolean isListSupported() {
0434: return options[OPTION_LIST];
0435: }
0436:
0437: /**
0438: *Reports whether arrays are supported.
0439: */
0440: public static boolean isArraySupported() {
0441: return options[OPTION_ARRAY];
0442: }
0443:
0444: /**
0445: *Reports whether a null collection is supported.
0446: */
0447: public static boolean isNullCollectionSupported() {
0448: return options[OPTION_NULLCOLLECTION];
0449: }
0450:
0451: /**
0452: * This method will return the current lifecycle state of an instance.
0453: */
0454: public static int currentState(Object o) {
0455: boolean[] status = new boolean[5];
0456: status[IS_PERSISTENT] = JDOHelper.isPersistent(o);
0457: status[IS_TRANSACTIONAL] = JDOHelper.isTransactional(o);
0458: status[IS_DIRTY] = JDOHelper.isDirty(o);
0459: status[IS_NEW] = JDOHelper.isNew(o);
0460: status[IS_DELETED] = JDOHelper.isDeleted(o);
0461: int i, j;
0462: outerloop: for (i = 0; i < NUM_STATES; ++i) {
0463: for (j = 0; j < NUM_STATUSES; ++j) {
0464: if (status[j] != state_statuses[i][j])
0465: continue outerloop;
0466: }
0467: return i;
0468: }
0469: return NUM_STATES;
0470: }
0471:
0472: public JdoLifecycleTck(String s) {
0473: super (s);
0474:
0475: }
0476:
0477: protected String getLoggerName() {
0478: return LOG_NAME + ".rt.tck.JdoLifecycleTck";
0479: }
0480:
0481: public void testStateTransitions() {
0482: logger.log(BasicLevel.INFO, "testStateTransitions");
0483: try {
0484: pmf = getPMF();
0485: if (pmf == null) {
0486: fail("StateTransitions: Unable to acquire a PMF");
0487: }
0488: pm = pmf.getPersistenceManager();
0489: generatePersistentInstances();
0490:
0491: scenario = DATASTORE_TX;
0492: logger
0493: .log(BasicLevel.INFO,
0494: "###scenario = DATASTORE_TX###");
0495: checkTransitions();
0496: if (isOptimisticSupported()) {
0497: scenario = OPTIMISTIC_TX;
0498: logger.log(BasicLevel.INFO,
0499: "###scenario = OPTIMISTIC_TX###");
0500: checkTransitions();
0501: }
0502: if (isNontransactionalReadSupported()
0503: || isNontransactionalWriteSupported()) {
0504: scenario = NO_TX;
0505: logger.log(BasicLevel.INFO, "###scenario = NO_TX###");
0506: checkTransitions();
0507: }
0508: } catch (Exception e) {
0509: logger.log(BasicLevel.ERROR,
0510: "Unexception caught in testStateTransitions", e);
0511: fail(e.getMessage());
0512: } finally {
0513: Transaction tx = pm.currentTransaction();
0514: if (tx.isActive()) {
0515: tx.rollback();
0516: }
0517: pm.close();
0518: }
0519: /*
0520: int errCnt = getErrorCount();
0521: if( errCnt == 0 ){
0522: return Status.passed("StateTransitions passed");
0523: } else{
0524: return Status.failed("StateTransitions failed, number of errors detected is " + errCnt);
0525: }
0526: */
0527: }
0528:
0529: private void generatePersistentInstances() {
0530: if (doPersistentInstancesExist())
0531: return;
0532: int i;
0533: Transaction t = pm.currentTransaction();
0534: t.begin();
0535: for (i = 0; i < 50; ++i) {
0536: StateTransitionObj sto = new StateTransitionObj(i);
0537: sto.writeField(i);
0538: pm.makePersistent(sto);
0539: }
0540: t.commit();
0541: if (!doPersistentInstancesExist())
0542: logger
0543: .log(BasicLevel.INFO,
0544: "StateTransitions unable to create instances of StateTransitionsObj");
0545: }
0546:
0547: private boolean doPersistentInstancesExist() {
0548: boolean ret;
0549: Transaction t = pm.currentTransaction();
0550: t.begin();
0551: Extent e = pm.getExtent(StateTransitionObj.class, false);
0552: Iterator iter = e.iterator();
0553: ret = iter.hasNext();
0554: t.rollback();
0555: return ret;
0556: }
0557:
0558: void checkTransitions() {
0559: for (operation = 0; operation < NUM_OPERATIONS; ++operation) {
0560:
0561: // rule out situations that do not apply
0562: if (!applies_to_scenario[operation][scenario])
0563: continue;
0564: if (operation == READOUTSIDETX
0565: && !isNontransactionalReadSupported())
0566: continue;
0567: if (operation == WRITEOUTSIDETX
0568: && !isNontransactionalWriteSupported())
0569: continue;
0570: if ((operation == COMMITRETAINVALUES || operation == ROLLBACKRETAINVALUES)
0571: && !isRetainValuesSupported())
0572: continue;
0573: if (operation == MAKENONTRANSACTIONAL
0574: && !(isNontransactionalReadSupported() || isNontransactionalWriteSupported()))
0575: continue;
0576:
0577: for (current_state = 0; current_state < NUM_STATES; ++current_state) {
0578: if (scenario == OPTIMISTIC_TX
0579: && current_state == PERSISTENT_CLEAN)
0580: continue;
0581: if ((current_state == TRANSIENT_CLEAN || current_state == TRANSIENT_DIRTY)
0582: && !isTransientTransactionalSupported())
0583: continue; // this state is not supported by implementation
0584: if (current_state == PERSISTENT_NONTRANSACTIONAL
0585: && !(isNontransactionalReadSupported() || isNontransactionalWriteSupported()))
0586: continue; // this state is not supported by implementation
0587: expected_state = transitions[operation][current_state];
0588: if (expected_state == IMPOSSIBLE)
0589: continue;
0590: if (expected_state == UNCHANGED)
0591: expected_state = current_state;
0592: try {
0593: transaction = pm.currentTransaction();
0594: if (transaction.isActive()) {
0595: logger
0596: .log(BasicLevel.INFO,
0597: "JDOTransactionItf is active (but should not be), rolling back");
0598: transaction.rollback();
0599: }
0600: if (scenario != NO_TX) {
0601:
0602: if (operation == COMMITNORETAINVALUES
0603: || operation == ROLLBACKNORETAINVALUES)
0604: transaction.setRetainValues(false);
0605: if (operation == COMMITRETAINVALUES
0606: || operation == ROLLBACKRETAINVALUES)
0607: transaction.setRetainValues(true);
0608: /* possibly switch above 4 lines to the following line
0609: transaction.setRetainValues( operation == COMMITRETAINVALUES || operation == ROLLBACKRETAINVALUES );
0610: */
0611: transaction
0612: .setOptimistic(scenario == OPTIMISTIC_TX);
0613: transaction.begin();
0614: if (!transaction.isActive())
0615: logger
0616: .log(BasicLevel.INFO,
0617: "StateTransitions: JDOTransactionItf should be active, but it is not");
0618: }
0619:
0620: // get and verify object is in right initial state
0621: StateTransitionObj obj = getInstanceInState(current_state);
0622: if (obj == null) { // could not get object in state
0623: if (transaction.isActive())
0624: transaction.rollback();
0625: continue;
0626: }
0627:
0628: // Apply operation, catching possible exception
0629: Exception e = null;
0630: try {
0631: logger.log(BasicLevel.DEBUG, "##initial state="
0632: + states[current_state]);
0633: logger.log(BasicLevel.DEBUG, "##operation="
0634: + operations[operation]);
0635:
0636: applyOperation(operation, obj);
0637: } catch (Exception excep) {
0638: if (excep instanceof javax.jdo.JDOUserException) {
0639: e = excep;
0640: } else {
0641: logger.log(BasicLevel.ERROR,
0642: "StateTransitions: Unexpected exception:"
0643: + excep);
0644: printSituation();
0645: //incrementErrorCount();
0646: continue;
0647: }
0648: }
0649:
0650: // Get new state, verify correct transition and exceptions occurred
0651: logger.log(BasicLevel.DEBUG, "##expected state="
0652: + states[new_state]);
0653: new_state = currentState(obj);
0654: logger.log(BasicLevel.DEBUG, "##new state ="
0655: + states[expected_state]);
0656: if (expected_state == ERROR
0657: || expected_state == NOT_APPLICABLE) {
0658: if (e == null) {
0659: logger
0660: .log(BasicLevel.ERROR,
0661: "StateTransitions: JDOUserException should have been thrown");
0662: printSituation();
0663: //incrementErrorCount();
0664: } else {
0665: if (new_state != current_state) {
0666: logger
0667: .log(
0668: BasicLevel.ERROR,
0669: "JDOUserException properly thrown, but instance should remain in current state, instance changed state to "
0670: + states[new_state]);
0671: printSituation();
0672: //incrementErrorCount();
0673: }
0674: }
0675: }
0676: if (expected_state >= 0
0677: && new_state != expected_state
0678: && !((new_state == HOLLOW && expected_state == PERSISTENT_NONTRANSACTIONAL) || (new_state == PERSISTENT_NONTRANSACTIONAL && expected_state == HOLLOW))) {
0679: logger.log(BasicLevel.ERROR,
0680: "StateTransitions: Invalid state transition to "
0681: + states[new_state]
0682: + ", new state should be "
0683: + states[expected_state]);
0684: printSituation();
0685: //incrementErrorCount();
0686: }
0687: if (transaction.isActive())
0688: transaction.rollback();
0689: } catch (Exception unexpected_exception) {
0690: logger.log(BasicLevel.ERROR,
0691: "Unexpected exception caught in StateTransitions "
0692: + unexpected_exception);
0693: printSituation();
0694: //unexpected_exception.printStackTrace(out);
0695: //incrementErrorCount();
0696: if (transaction.isActive())
0697: transaction.rollback();
0698: }
0699: }
0700: }
0701:
0702: }
0703:
0704: void printSituation() {
0705: logger.log(BasicLevel.INFO, "========================");
0706: logger.log(BasicLevel.INFO, scenario_string[scenario]);
0707: logger.log(BasicLevel.INFO, "initial state="
0708: + states[current_state]);
0709: logger.log(BasicLevel.INFO, "operation="
0710: + operations[operation]);
0711: logger.log(BasicLevel.INFO, "========================");
0712: }
0713:
0714: void applyOperation(int operation, StateTransitionObj stobj) {
0715: StateTransitionObj obj = (StateTransitionObj) stobj;
0716: switch (operation) {
0717: case MAKEPERSISTENT: {
0718: pm.makePersistent(obj);
0719: break;
0720: }
0721: case DELETEPERSISTENT: {
0722: pm.deletePersistent(obj);
0723: break;
0724: }
0725: case MAKETRANSACTIONAL: {
0726: pm.makeTransactional(obj);
0727: break;
0728: }
0729: case MAKENONTRANSACTIONAL: {
0730: pm.makeNontransactional(obj);
0731: break;
0732: }
0733: case MAKETRANSIENT: {
0734: pm.makeTransient(obj);
0735: break;
0736: }
0737: case COMMITNORETAINVALUES: {
0738: pm.currentTransaction().commit();
0739: break;
0740: }
0741: case COMMITRETAINVALUES: {
0742: pm.currentTransaction().commit();
0743: break;
0744: }
0745: case ROLLBACKNORETAINVALUES: {
0746: pm.currentTransaction().rollback();
0747: break;
0748: }
0749: case ROLLBACKRETAINVALUES: {
0750: pm.currentTransaction().rollback();
0751: break;
0752: }
0753: case REFRESHDATASTORE: {
0754: pm.refresh(obj);
0755: break;
0756: }
0757: case REFRESHOPTIMISTIC: {
0758: pm.refresh(obj);
0759: break;
0760: }
0761: case EVICT: {
0762: pm.evict(obj);
0763: break;
0764: }
0765: case READOUTSIDETX: {
0766: int val = obj.readField();
0767: break;
0768: }
0769: case READOPTIMISTIC: {
0770: int val = obj.readField();
0771: break;
0772: }
0773: case READDATASTORE: {
0774: int val = obj.readField();
0775: break;
0776: }
0777: case WRITEOUTSIDETX: {
0778: obj.writeField(42);
0779: break;
0780: }
0781: case WRITEINSIDETX: {
0782: obj.writeField(42);
0783: break;
0784: }
0785: default: {
0786: logger.log(BasicLevel.ERROR,
0787: "StateTransitions internal error, illegal operation "
0788: + operation);
0789: }
0790: }
0791: }
0792:
0793: /**
0794: * Get an instance in the specified state.
0795: */
0796: private StateTransitionObj getInstanceInState(int state) {
0797: switch (state) {
0798: case TRANSIENT:
0799: return getTransientInstance();
0800: case PERSISTENT_NEW:
0801: return getPersistentNewInstance();
0802: case PERSISTENT_CLEAN:
0803: return getPersistentCleanInstance();
0804: case PERSISTENT_DIRTY:
0805: return getPersistentDirtyInstance();
0806: case HOLLOW:
0807: return getHollowInstance();
0808: case TRANSIENT_CLEAN:
0809: return getTransientCleanInstance();
0810: case TRANSIENT_DIRTY:
0811: return getTransientDirtyInstance();
0812: case PERSISTENT_NEW_DELETED:
0813: return getPersistentNewDeletedInstance();
0814: case PERSISTENT_DELETED:
0815: return getPersistentDeletedInstance();
0816: case PERSISTENT_NONTRANSACTIONAL:
0817: return getPersistentNontransactionalInstance();
0818: default: {
0819: return null;
0820: }
0821: }
0822: }
0823:
0824: private StateTransitionObj getTransientInstance() {
0825: StateTransitionObj obj = new StateTransitionObj(23);
0826: int curr = currentState(obj);
0827: if (curr != TRANSIENT) {
0828: logger.log(BasicLevel.INFO,
0829: "StateTransitions: Unable to create transient instance, state is "
0830: + states[curr]);
0831: printSituation();
0832: return null;
0833: }
0834: return obj;
0835: }
0836:
0837: private StateTransitionObj getPersistentNewInstance() {
0838: StateTransitionObj obj = getTransientInstance();
0839: if (obj == null)
0840: return null;
0841: pm.makePersistent(obj); // should transition to persistent-new
0842: int curr = currentState(obj);
0843: if (curr != PERSISTENT_NEW) {
0844: logger
0845: .log(BasicLevel.INFO,
0846: "StateTransitions: Unable to create persistent-new instance");
0847: logger.log(BasicLevel.INFO,
0848: " from transient instance via makePersistent(), state is "
0849: + states[curr]);
0850: printSituation();
0851: return null;
0852: }
0853: return obj;
0854: }
0855:
0856: public StateTransitionObj getPersistentCleanInstance() {
0857: StateTransitionObj obj = getHollowInstance();
0858: if (obj == null)
0859: return null;
0860: StateTransitionObj sto = (StateTransitionObj) obj;
0861: int val = sto.readField();
0862: int curr = currentState(sto);
0863: if (curr != PERSISTENT_CLEAN) {
0864: logger
0865: .log(BasicLevel.INFO,
0866: "StateTransitions: Unable to create persistent-clean instance");
0867: logger.log(BasicLevel.INFO,
0868: " from a hollow instance by reading a field, state is "
0869: + states[curr]);
0870: printSituation();
0871: return null;
0872: }
0873: return obj;
0874: }
0875:
0876: public StateTransitionObj getPersistentDirtyInstance() {
0877: StateTransitionObj obj = getHollowInstance();
0878: if (obj == null)
0879: return null;
0880: StateTransitionObj pcobj = (StateTransitionObj) obj;
0881: pcobj.writeField(23);
0882: int curr = currentState(obj);
0883: if (curr != PERSISTENT_DIRTY) {
0884: logger
0885: .log(BasicLevel.INFO,
0886: "StateTransitions: Unable to create persistent-dirty instance");
0887: logger.log(BasicLevel.INFO,
0888: " from a hollow instance by writing a field, state is "
0889: + states[curr]);
0890: printSituation();
0891: return null;
0892: }
0893: return obj;
0894: }
0895:
0896: public StateTransitionObj getHollowInstance() {
0897: Extent extent = pm.getExtent(StateTransitionObj.class, false);
0898: Iterator iter = extent.iterator();
0899: if (!iter.hasNext()) {
0900: logger
0901: .log(BasicLevel.INFO,
0902: "Extent for StateTransitionObj should not be empty");
0903: return null;
0904: }
0905: StateTransitionObj obj = (StateTransitionObj) iter.next();
0906: int curr = currentState(obj);
0907: if (curr != HOLLOW && curr != PERSISTENT_NONTRANSACTIONAL) {
0908: logger
0909: .log(
0910: BasicLevel.INFO,
0911: "StateTransition: Attempt to get hollow instance via accessing extent failed, state is "
0912: + states[curr]);
0913: printSituation();
0914: return null;
0915: }
0916: return obj;
0917: }
0918:
0919: public StateTransitionObj getTransientCleanInstance() {
0920: StateTransitionObj obj = getTransientInstance();
0921: if (obj == null)
0922: return null;
0923: pm.makeTransactional(obj);
0924: int curr = currentState(obj);
0925: if (curr != TRANSIENT_CLEAN) {
0926: logger
0927: .log(BasicLevel.INFO,
0928: "StateTransitions: Unable to create transient-clean instance");
0929: logger.log(BasicLevel.INFO,
0930: " from a transient instance via makeTransactional(), state is "
0931: + states[curr]);
0932: printSituation();
0933: return null;
0934: }
0935: return obj;
0936: }
0937:
0938: public StateTransitionObj getTransientDirtyInstance() {
0939: StateTransitionObj obj = getTransientCleanInstance();
0940: if (obj == null)
0941: return null;
0942: StateTransitionObj pcobj = (StateTransitionObj) obj;
0943: pcobj.writeField(23);
0944: int curr = currentState(obj);
0945: if (curr != TRANSIENT_DIRTY) {
0946: logger
0947: .log(BasicLevel.INFO,
0948: "StateTransitions: Unable to create transient-dirty instance");
0949: logger.log(BasicLevel.INFO,
0950: " from a transient clean instance via modifying a field, state is "
0951: + states[curr]);
0952: printSituation();
0953: return null;
0954: }
0955: return obj;
0956: }
0957:
0958: public StateTransitionObj getPersistentNewDeletedInstance() {
0959: StateTransitionObj obj = getPersistentNewInstance();
0960: if (obj == null)
0961: return null;
0962: pm.deletePersistent(obj); // should transition to persistent-new-deleted
0963: int curr = currentState(obj);
0964: if (curr != PERSISTENT_NEW_DELETED) {
0965: logger
0966: .log(BasicLevel.INFO,
0967: "StateTransitions: Unable to create transient-new-deleted instance");
0968: logger.log(BasicLevel.INFO,
0969: " from a persistent-new instance via deletePersistent, state is "
0970: + states[curr]);
0971: printSituation();
0972: return null;
0973: }
0974: return obj;
0975: }
0976:
0977: public StateTransitionObj getPersistentDeletedInstance() {
0978: StateTransitionObj obj = getHollowInstance();
0979: if (obj == null)
0980: return null;
0981: pm.deletePersistent(obj);
0982: int curr = currentState(obj);
0983: if (curr != PERSISTENT_DELETED) {
0984: logger
0985: .log(BasicLevel.INFO,
0986: "StateTransitions: Unable to create persistent-deleted instance");
0987: logger.log(BasicLevel.INFO,
0988: " from a persistent instance via deletePersistent(), state is "
0989: + states[curr]);
0990: printSituation();
0991: return null;
0992: }
0993: return obj;
0994: }
0995:
0996: public StateTransitionObj getPersistentNontransactionalInstance() {
0997: StateTransitionObj obj = getHollowInstance();
0998: if (obj == null)
0999: return null;
1000: pm.makeNontransactional(obj);
1001: int curr = currentState(obj);
1002: if (curr != PERSISTENT_NONTRANSACTIONAL && curr != HOLLOW) {
1003: logger
1004: .log(BasicLevel.INFO,
1005: "StateTransitions: Unable to create persistent-nontransactional instance");
1006: logger.log(BasicLevel.INFO,
1007: " from a persistent clean instance via makeNontransactional(), state is "
1008: + states[curr]);
1009: printSituation();
1010: return null;
1011: }
1012: return null;
1013: }
1014: }
|