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

import javax.jdo.Constants;
import javax.jdo.JDOUnsupportedOptionException;
import javax.jdo.Transaction;
import org.apache.jdo.tck.JDO_Test;
import org.apache.jdo.tck.util.BatchTestRunner;


/**
 *<B>Title:</B>Set  isolation level of transaction  
 *<BR>
 *<B>Keywords:</B> persistencemanagerfactory
 *<BR>
 *<B>Assertion IDs:</B> A11.1-xxxx, A11.1-xxxx.
 *<BR>
 *<B>Assertion Description: </B>
 * Transaction.getIsolationLevel() returns the value
 * of the  isolation level.
 * Transaction.setIsolationLevel(String) sets the value
 * of the  isolation level.
 */

public class SetIsolationLevel extends JDO_Test 
        implements Constants {
    
    /** */
    private static final String ASSERTION_29_FAILED = 
        "Assertion A13.4.2-29 (setIsolationLevel) failed: ";
    /** */
    private static final String ASSERTION_25_FAILED = 
        "Assertion A13.4.2-25 (setIsolationLevel) failed: ";

    /** All specified  isolation levels */
    private static final String[] isolationLevels = new String[] {
        TX_READ_UNCOMMITTED,
        TX_READ_COMMITTED, 
        TX_REPEATABLE_READ,
        TX_SNAPSHOT,
        TX_SERIALIZABLE
    };

    /**
     * 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(SetIsolationLevel.class);
    }

    /** */
    protected void localSetUp() {
        pm = getPM();
    }

    /** Set IsolationLevel to all values. */ 
    public void testSetIsolationLevelOutsideTransaction() {
        // iterate through all possible IsolationLevels
        for (int i = 0; i < isolationLevels.length; ++i) {
            String isolationLevel = isolationLevels[i];
            setIsolationLevel(isolationLevel);
        }
        closePMF(pmf);
        failOnError();
    }

    /** Set IsolationLevel to all values within datastore transaction. */ 
    public void testSetIsolationLevelWithActiveDataStoreTransaction() {
        pm.currentTransaction().setOptimistic(false);
        pm.currentTransaction().begin();
        // iterate through all possible IsolationLevels
        for (int i = 0; i < isolationLevels.length; ++i) {
            String isolationLevel = isolationLevels[i];
            try {
                pm.currentTransaction().setIsolationLevel(isolationLevel);
                appendMessage(ASSERTION_25_FAILED + 
                        "active datastore transaction; no exception thrown for "
                        + "setIsolationLevel(" + isolationLevel + ").");
            } catch (JDOUnsupportedOptionException ex) {
                // good catch
            } catch (Throwable t) {
                appendMessage(ASSERTION_25_FAILED + 
                        "active datastore transaction; " +
                        "JDOUnsupportedOptionException not thrown for " +
                        "setIsolationLevel(" + isolationLevel +
                        "). Unexpected exception: \n" + t);
                
            }
        }
        pm.currentTransaction().commit();
        closePMF(pmf);
        failOnError();
    }

    /** Set IsolationLevel to all values within optimistic transaction. */ 
    public void testSetIsolationLevelWithActiveOptimisticTransaction() {
        if (!isOptimisticSupported()) {
            printUnsupportedOptionalFeatureNotTested(
                    "testSetIsolationLevelWithActiveOptimisticTransaction",
                    "Optimistic");
            return;
        }
        pm.currentTransaction().setOptimistic(true);
        pm.currentTransaction().begin();
        // iterate through all possible IsolationLevels
        for (int i = 0; i < isolationLevels.length; ++i) {
            String isolationLevel = isolationLevels[i];
            setIsolationLevel(isolationLevel);
        }
        pm.currentTransaction().commit();
        closePMF(pmf);
        failOnError();
    }

    /** */
    private void setIsolationLevel(String level) {
        Transaction tx = pm.currentTransaction();
        String property = PROPERTY_TRANSACTION_ISOLATION_LEVEL + "." + level;
        if (isSupported(property)) {
            tx.setIsolationLevel(level);
            String actual = tx.getIsolationLevel();
            if (!validLevelSubstitution(level, actual)) {
                appendMessage(ASSERTION_29_FAILED
                        + "\nIsolationLevel set to "
                        + level
                        + "; value returned by Transaction is "
                        + actual);
            }
        } else {
            try {
                tx.setIsolationLevel(level);
                // no exception thrown; bad
                appendMessage(ASSERTION_29_FAILED
                        + "\nThe expected JDOUserException was not thrown.");            
            } catch (JDOUnsupportedOptionException ex) {
                // good catch
                return;
            } catch (Throwable t) {
                // wrong exception thrown; bad
                appendMessage(ASSERTION_29_FAILED +
                        "active datastore transaction; " +
                        "JDOUnsupportedOptionException not thrown for " +
                        "setIsolationLevel(" + level +
                        "). Unexpected exception: \n" + t);
                return;
            }
        }
    }
}
