/*BEGINPROLOGUE****************************************************************
 * @copyright(disclaimer)                                                     *
 *                                                                            *
 * DISCLAIMER OF WARRANTIES.                                                  *
 *                                                                            *
 * The following IBM Content Manager Enterprise Edition code is sample code   *
 * created by IBM Corporation. IBM grants you a nonexclusive copyright        *
 * license to use this sample code example to generate similar function       *
 * tailored to your own specific needs. This sample code is not part of any   *
 * standard IBM product and is provided to you solely for the purpose of      *
 * assisting you in the development of your applications. This example has    *
 * not been thoroughly tested under all conditions. IBM, therefore cannot     *
 * guarantee nor may you imply reliability, serviceability, or function of    *
 * these programs. The code is provided "AS IS", without warranty of any      *
 * kind. IBM shall not be liable for any damages arising out of your or any   *
 * other parties use of the sample code, even if IBM has been advised of the  *
 * possibility of such damages. If you do not agree with these terms, do not  *
 * use the sample code.                                                       *
 *                                                                            *
 * Licensed Materials - Property of IBM                                       *
 * 5724-B19, 5697-H60                                                         *
 * © Copyright IBM Corp. 1994, 2013 All Rights Reserved.                      *
 *                                                                            *
 * US Government Users Restricted Rights - Use, duplication or disclosure     *
 * restricted by GSA ADP Schedule Contract with IBM Corp.                     *
 *                                                                            *
 * @endCopyright                                                              *
 ******************************************************************************

    Refer to the STransactionsICM sample education module for information on 
    rollback behavior for Explicit Transactions.

    This sample changes the current Explicit Transaction behavior
    configured for whether or not the server will automatically rollback and
    end an open Explicit Transaction if it detects an error during a
    persistent operation.  Refer to STransactionsICM for more details.
    
    !!! WARNING !!!
    
        THIS WILL CHANGE THE EXPLICIT TRANSACTION BEHAVIOR OF ENTIRE SYSTEM
        
        Only admininstrators should run this utility since it affects the
        behavior of the APIs, affecting all applications using Explicit
        Transactions.  
        
        Changing the behavior from automatically rolling back
        and closing the explicit transaction to require the application to 
        handle can cause existing applications to stop working after an error
        occurs during an explicit transaction.
        
        Changing the behavior from requiring the application acknowledge
        the failure and explicitly end the transaction to automatic closure
        of the transaction can cause unexpected changes to data if
        applications continue to make changes that would have otherwise
        been prevented.
        
        You should invoke a behavior change very rarely and only when all
        applications using the DB2 Content Manager Version 8 system are 
        built with understanding of the configured behavior choice.

        Improper modification of the system flag in the Library Server 
        configuration can result in an unusable system.  Take note of
        your old system flag value reported by this sample tool if
        you make a change so that you can set it back to its original
        if you make a mistake.  If you are unable to return to the
        previous state, contact your IBM service representative
        with the old value printed by this sample.
    
    This sample only works with both the DB2 Content Manager Version 8.2 with
    fix pack 7 or later.

*******************************************************************************/

// Imports
import com.ibm.mm.sdk.common.*;
import com.ibm.mm.sdk.server.*;
import java.io.*;

/************************************************************************************************
 *          FILENAME: STransactionsRollbackChangeICM.java
 *                    ---------------------------------------------------------------------------
 *       DESCRIPTION: Change Rollback Behavior Configuration for When System Detects an Error
 *                    ---------------------------------------------------------------------------
 *     DEMONSTRATION: Rollback Behavior Configuration Change for System Detected Errors
 *                    ---------------------------------------------------------------------------
 * COMMANDLINE USAGE: java STransactionsRollbackChangeICM <options>
 *
 *                    Required:  Specify Exaclty One of the Following Two Options.  Refer
 *                               to the STransactionICM sample API education module for
 *                               more documentation on the choices below.  Refer to this
 *                               sample header for warnings and implications of changes.
 *
 *                               -AUTO : Changes the whole system behavior to automatically
 *                                       close the Explicit Transaction when the system 
 *                                       detects an error during a persistent operation.
 *                                       Subsequent valid operations succeed individually
 *                                       outside of the canceled transaction.
 *                               -KEEP : Changes the whole system behavior to leave the
 *                                       explicit transaction open in a failed state, 
 *                                       requiring the caller to explicitly rollback and
 *                                       end the transaction before continuing when the
 *                                       server detects an error during a persistent
 *                                       operation.  All subsequent operations fail
 *                                       until the caller explicitly ends the transaction
 *                                       by calling rollback.
 *
 *                    Optional:  If any of the following are not specified, defaults will
 *                               be used where possible.
 *
 *                               -d/database <you database name>
 *                               -u/user     <CM user id>
 *                               -p/password <CM user's password>
 *                               -o/options  <Connect String Options>
 *
 *                        Help:  Refer to the header documentation inside this file for
 *                               details on functionality.
 *
 *                               -?/help     : Display Command Line Usage
 *
 *                     Example:  java STransactionsRollbackChangeICM -AUTO -d icmnlsdb
 *                    ---------------------------------------------------------------------------
 *     PREREQUISITES: none.
 *                    ---------------------------------------------------------------------------
 *    FILES REQUIRED: SConnectDisconnectICM.java
 *                    STransactionsICM.java
 ************************************************************************************************/
public class STransactionsRollbackChangeICM{

    // Command Line Argument Usage
    private static final String  COMMANDLINE_OPTION_DATABASE          = "-d/database <you database name>";
    private static final String  COMMANDLINE_OPTION_USERNAME          = "-u/user     <CM user id>";
    private static final String  COMMANDLINE_OPTION_PASSWORD          = "-p/password <CM user's password>";
    private static final String  COMMANDLINE_OPTION_CONNECT_OPTIONS   = "-o/options  <Connect String Options>";
    private static final String  COMMANDLINE_OPTION_BEHAVIOR_AUTO     = "-AUTO";
    private static final String  COMMANDLINE_OPTION_BEHAVIOR_KEEP     = "-KEEP";
    private static final String  COMMANDLINE_OPTION_USAGE             = "-?/help";

    //-------------------------------------------------------------
    // Main
    //-------------------------------------------------------------
    /**
     * Run the Sample.
     * @param argv[] String Array containing arguments.  Optional arguments are <databse> <userName> <password>.
     */
    public static void main(String argv[]) throws DKException, Exception{

        try{
            // Parse Command Line Arguments
            String  database           = getCommandlineChoice(argv,"-d"   ,"-database" ,false,COMMANDLINE_OPTION_DATABASE);
            String  userName           = getCommandlineChoice(argv,"-u"   ,"-user"     ,false,COMMANDLINE_OPTION_USERNAME);
            String  password           = getCommandlineChoice(argv,"-p"   ,"-password" ,false,COMMANDLINE_OPTION_PASSWORD);
            String  connOpts           = getCommandlineChoice(argv,"-o"   ,"-options"  ,false,COMMANDLINE_OPTION_CONNECT_OPTIONS);
            String  requestedAutoStr   = getCommandlineChoice(argv,"-AUTO","-automatic",false,COMMANDLINE_OPTION_BEHAVIOR_AUTO);
            String  requestedKeepStr   = getCommandlineChoice(argv,"-KEEP",null        ,false,COMMANDLINE_OPTION_BEHAVIOR_KEEP);
            String  requestedUsageStr  = getCommandlineChoice(argv,"-?"   ,"-help"     ,false,COMMANDLINE_OPTION_USAGE);

            // Display Usage if Requested
            if(requestedUsageStr!=null)
                printUsage();

            // Validate Required Option Choices
            boolean requestedAutoClosure = true;
            if((requestedAutoStr!=null)&&(requestedKeepStr!=null)){
                printUsage(); // Display Usage Before Halting in Error
                throw new IllegalArgumentException("Illegal Command Line Argument Choice.  You selected both -AUTO and -KEEP.  Only select one.  Review header documentation in sample for more information on usage.");
            }else if((requestedAutoStr==null)&&(requestedKeepStr!=null))
                requestedAutoClosure = false;
            else if((requestedAutoStr!=null)&&(requestedKeepStr==null))
                requestedAutoClosure = true;
            else if((requestedAutoStr==null)&&(requestedKeepStr==null)){
                printUsage(); // Display Usage Before Halting in Error
                throw new IllegalArgumentException("You must select either -AUTO or -KEEP command line arguments to specify which behavior you choose.  Review header documentation in sample for more information on usage.");
            }else
                throw new InternalError("Internal Error:  Sample program logic fell through all expected permutations.");

            // Assume defaults for any not specified
            if(database==null) database = SConnectDisconnectICM.DEFAULT_DATABASE;
            if(userName==null) userName = SConnectDisconnectICM.DEFAULT_USERNAME;
            if(password==null) password = SConnectDisconnectICM.DEFAULT_PASSWORD;
            if(connOpts==null) connOpts = "";
            
            String ver = SConnectDisconnectICM.VERSION;
            
            System.out.println("===============================================");
            System.out.println("IBM DB2 Content Manager                    v"+ver);
            System.out.println("Sample Program:  STransactionsRollbackChangeICM");
            System.out.println("-----------------------------------------------");
            System.out.println("        Database: "+database);
            System.out.println("       User Name: "+userName);
            System.out.println("    Connect Opts: "+connOpts);
            if(requestedAutoClosure){
                System.out.println("Request Behavior: AUTO: Automatically Close Transaction   ");
                System.out.println("                        on System Error Rollback (Default)");
            }else{
                System.out.println("Request Behavior: KEEP: Keep Transaction Open / Application");
                System.out.println("                        Closure on System Error Rollback   ");
            }
            System.out.println("==============================================");
        
            //-------------------------------------------------------------
            // Connect to datastore
            //-------------------------------------------------------------
            // See Sample SConnectDisconnectICM for more information
            System.out.println("Connecting to datastore (Database '"+database+"', UserName '"+userName+"')...");

                DKDatastoreICM dsICM = new DKDatastoreICM();        // Create new datastore object.
                dsICM.connect(database,userName,password,connOpts); // Connect to the datastore.

            System.out.println("Connected to datastore (Database '"+dsICM.datastoreName()+"', UserName '"+dsICM.userName()+"').");
   
            //-------------------------------------------------------------
            // Change Transaction Rollback Behavior
            //-------------------------------------------------------------
            System.out.println("Changing Transaction Behavior...");
            
                changeTransactionRollbackBehavior(dsICM,requestedAutoClosure);
            
            System.out.println("Changed Transaction Behavior.");
            
            //-------------------------------------------------------------
            // Disconnect from datastore & Destroy Reference
            //-------------------------------------------------------------
            // See Sample SConnectDisconnectICM for more information
            System.out.println("Disconnecting from datastore & destroying reference...");            

                dsICM.disconnect();
                dsICM.destroy();

            System.out.println("Disconnected from datastore & destroying reference.");

            //-------------------------------------------------------------
            // Sample program completed without exception
            //-------------------------------------------------------------
            System.out.println("\n==========================================");
            System.out.println("Sample program completed.");
            System.out.println("==========================================\n");
        }
        //------------------------------------------------------------
        // Catch & Print Exceptions        
        //------------------------------------------------------------
        catch (DKException exc){
            SConnectDisconnectICM.printException(exc);  // Print the exception using the function listed below.
            throw(exc);
        } catch (Exception exc) {
            SConnectDisconnectICM.printException(exc);  // Print the exception using the function listed below.
            throw(exc);
        }
    }// end main

    //=================================================================
    // Private Methods
    //=================================================================
    
   /**
    * Print the command line usage for this sample tool
    **/
    private static void printUsage(){
        System.out.println("                                                                          ");
        System.out.println("USAGE: java STransactionsRollbackChangeICM <options>                      ");
        System.out.println("  Change Rollback Behavior Configuration for When System Detects an Error.");
        System.out.println("                                                                          ");
        System.out.println(" Required:  Specify Exaclty One of the Following Two Options.  Refer      ");
        System.out.println("            to the STransactionICM sample API education module for        ");
        System.out.println("            more documentation on the choices below.  Refer to this       ");
        System.out.println("            sample header for warnings and implications of changes.       ");
        System.out.println("                                                                          ");
        System.out.println("            -AUTO : Changes the whole system behavior to automatically    ");
        System.out.println("                    close the Explicit Transaction when the system        ");
        System.out.println("                    detects an error during a persistent operation.       ");
        System.out.println("                    Subsequent valid operations succeed individually      ");
        System.out.println("                    outside of the canceled transaction.                  ");
        System.out.println("            -KEEP : Changes the whole system behavior to leave the        ");
        System.out.println("                    explicit transaction open in a failed state,          ");
        System.out.println("                    requiring the caller to explicitly rollback and       ");
        System.out.println("                    end the transaction before continuing when the        ");
        System.out.println("                    server detects an error during a persistent           ");
        System.out.println("                    operation.  All subsequent operations fail            ");
        System.out.println("                    until the caller explicitly ends the transaction      ");
        System.out.println("                    by calling rollback.                                  ");
        System.out.println("                                                                          ");
        System.out.println("  Optional:  If any of the following are not specified, defaults will     ");
        System.out.println("             be used.                                                     ");
        System.out.println("                                                                          ");
        System.out.println("             -d/database <you database name>                              ");
        System.out.println("             -u/user     <CM user id>                                     ");
        System.out.println("             -p/password <CM user's password>                             ");
        System.out.println("             -o/options  <Connect String Options>                         ");
        System.out.println("                                                                          ");
        System.out.println("      Help:  Refer to the header documentation inside this file for       ");
        System.out.println("             details on functionality.                                    ");
        System.out.println("                                                                          ");
        System.out.println("             -?/help     : Display Command Line Usage                     ");
        System.out.println("                                                                          ");
        System.out.println("   Example:  java STransactionsRollbackChangeICM -AUTO -d icmnlsdb        ");
        System.out.println("                                                                          ");
    }//end printUsage()

    //=================================================================
    // Wrapper Functions
    //=================================================================
    // The following are wrapper functions for functionality covered
    // in this sample.  These functions can be used by other samples.

   /**
    * Change the behavior of Explicit Transaction closure for when the
    * system detects an error during a persistent operation and rolls
    * back persistently.  For more details, refer to the "Rollback"
    * section of the STransactionsICM sample education module.
    *
    * WARNING :  THIS AFFECTS THE BEHAVIOR OF THE ENTIRE SYSTEM,
    *            CAN BREAK EXISTING APPLICATIONS, AND MORE.  Refer
    *            to the warnings in the header of this sample.
    *
    * WARNING :  Take note of your old system flag value so that you
    *            can set it back to its original if you make a mistake.
    *            Incorrectly setting the system flag can result in a
    *            unusable system.  If you are unable to return to the
    *            previous state, contact your IBM service representative
    *            with the old value printed by this method.
    *
    * @param dsICM              - Connected DKDatastoreICM object.
    * @param requestAutoClosure - Set to 'true' if you want to set the behavior
    *                             as automatically closed when the system detects
    *                             an error during a persistent operation and rolls
    *                             back persistently, returning the system to normal
    *                             operating mode for all subsequent operations.
    *                             Set to 'false' if you want to keep the explicit
    *                             transaction open (in a failed state) until ended
    *                             explicitly by the user.  All subsequent persistent
    *                             operations and new start transaction requests fail
    *                             until the current transaction is explicitly rolled
    *                             back.
    **/
    public static void changeTransactionRollbackBehavior(DKDatastoreICM dsICM, boolean requestAutoClosure) throws DKException, Exception{
        if(dsICM==null)                throw new Exception("Invalid Parameter to STransactionsRollbackChangeICM::changeTransactionRollbackBehavior().  Parameter 'dsICM' is null.");
        if(dsICM.isConnected()==false) throw new Exception("Invalid Parameter to STransactionsRollbackChangeICM::changeTransactionRollbackBehavior().  Parameter 'dsICM' is a DKDatastoreICM that is not connected.");
        
        //-------------------------------------------------------------
        // Compare to Existing Behavior
        //-------------------------------------------------------------
        // As explained in the "Rollback" section in the header 
        // documentation in STransactionICM, the system can be
        // configured by the administrator to automatically end the
        // transaction when the system detects an error and rolls back
        // (default) or require the caller to explicitly close out the
        // transaction.
        //
        // PERFORMANCE:  This makes a call to the server and should only
        //   WARNING     be used to check the setting by an administrator
        //               Calling from your program will invoke a call to
        //               the server for each check.
        System.out.println("Comparing to Existing Configuration...");
            
            System.out.println("    Detecting Existing System Error Rollback Automatic Closure Setting...");
            System.out.println("                                                                 ");
            System.out.println("    - Sending EXISTING Setting Request to Server...              ");
            System.out.println("                                                                 ");

            boolean existingAutoClosureEnabled = STransactionsICM.isTransactionErrorRollbackAutoClosed(dsICM);
            if(existingAutoClosureEnabled)
                System.out.println("    - AUTO: Automatically Close Transaction on System Error Rollback (Default)");
            else
                System.out.println("    - KEEP: Keep Transaction Open / Application Closure on System Error Rollback");

            System.out.println("");

            // Validate if change needed
            //    If already set to the desired setting make a note to not continue.
            boolean changeNeeded = false;
            if((existingAutoClosureEnabled==true)&&(requestAutoClosure==true))
                changeNeeded = false;
            else if((existingAutoClosureEnabled==false)&&(requestAutoClosure==false))
                changeNeeded = false;
            else
                changeNeeded = true;

            // Report ot the user whether or not the change is needed
            if(changeNeeded)
                System.out.println("    - The desired setting is the opposite of existing setting.");
            else
                System.out.println("    - NO CHANGE:  The desired setting already exists.  No change is needed.");
            System.out.println("");

        System.out.println("Compared to Existing Configuration...");

        //-------------------------------------------------------------
        // Make Change If Needed
        //-------------------------------------------------------------
        // Only perform if the change is needed
        if(changeNeeded){
            System.out.println("Changing Explicit Transaction Rollback Behavior...");
                
                DKDatastoreDefICM        dsDefICM = (DKDatastoreDefICM)dsICM.datastoreDef();                     // Get the Datastore Definition Object
                DKDatastoreAdminICM      dsAdmin  = (DKDatastoreAdminICM) dsDefICM.datastoreAdmin();             // Get the Datastore Administration
                DKConfigurationMgmtICM   cfgMgmt  = (DKConfigurationMgmtICM) dsAdmin.configurationManagement();  // Get the configuration management.
                DKLSConfigurationMgmtICM lsCfg    = cfgMgmt.lsConfigurationMgmt();                               // Get the Resource Manager configuration.
                    
                // Get the Library Server configuration
                DKLSCfgDefICM lsCfgDef = lsCfg.retrieveConfigParameters();
                    
                // Get Existing System Flag for Core Behavioral Control Settings
                // WARNING:  Take note of your old system flag value so that you
                //           can set it back to its original if you make a mistake.
                //           Incorrectly setting the system flag can result in a
                //           unusable system.  If you are unable to return to the
                //           previous state, contact your IBM service representative
                //           with the old value printed by this method.
                short sysFlag = lsCfgDef.getSystemFlag();
                System.out.println("    - RECORD Original System Flag: "+sysFlag+" (base 10)");
                    
                // Calculate New System Flag
                if(requestAutoClosure==false){
	                sysFlag = (short) (sysFlag | (short) DKLSCfgDefICM.TX_EXPLICIT_AUTOROLLBACK_DOOMED);
                } else {
	                sysFlag = (short) (sysFlag & (short) ~DKLSCfgDefICM.TX_EXPLICIT_AUTOROLLBACK_DOOMED);
                }
                System.out.println("    -  NEW Calculated System Flag: "+sysFlag+" (base 10)");
   
                // Set New Value in Definition
                lsCfgDef.setSystemFlag(sysFlag);
                
                // Save Changes
                System.out.println("    - Saving...");
                lsCfg.defineConfigParameters(lsCfgDef);
                
            System.out.println("Changed Explicit Transaction Rollback Behavior.");
        }//end if(changeNeeded)

        //-------------------------------------------------------------
        // Verify Behavior Change
        //-------------------------------------------------------------
        // Only perform if the change was needed
        if(changeNeeded){
            System.out.println("Validating Change...");

                System.out.println("    Detecting Existing System Error Rollback Automatic Closure Setting...");
                System.out.println("                                                                 ");
                System.out.println("    - Sending Request to Check NEW Saved Setting...              ");
                System.out.println("                                                                 ");

                boolean newAutoClosureEnabled = STransactionsICM.isTransactionErrorRollbackAutoClosed(dsICM);
                if(newAutoClosureEnabled)
                    System.out.println("    - AUTO: Automatically Close Transaction on System Error Rollback (Default)");
                else
                    System.out.println("    - KEEP: Keep Transaction Open / Application Closure on System Error Rollback");

                System.out.println("");

                // Validating Results
                String  failureMsg = null;
                if((newAutoClosureEnabled==true)  && (requestAutoClosure==false))
                    failureMsg = "FAILED:  Behavior change from AUTO to KEEP saved without error, but was ineffective.  The setting is still configured to AUTO and not the desired value of KEEP.  Refer to header documentation in this sample for more information on the setting choices.";
                if((newAutoClosureEnabled==false) && (requestAutoClosure==true))
                    failureMsg = "FAILED:  Behavior change from KEEP to AUTO saved without error, but was ineffective.  The setting is still configured to KEEP and not the desired value of AUTO.  Refer to header documentation in this sample for more information on the setting choices.";
                    
                if(failureMsg!=null){ // report error if failed
                    System.out.println("    - "+failureMsg);
                    throw new Exception(failureMsg);
                }else
                    System.out.println("    - SUCCESS");
                    
                System.out.println("");
                    
            System.out.println("Validated Change.");
        }//end if(changeNeeded){
    }//end changeTransactionRollbackBehavior

   /**
    * Get the value of the specified command line option choice, if specified.
    * If it is specified, the String value will be returned.  If no value
    * is specified, 'null' will be returned.  If the option is found, but 
    * no following value exists, either an empty string will be returned
    * (if it is the last argument) or the next command will be returned.
    * If the option is just a flag, check for 'null' to mean it was not
    * specified, otherwise any valid string returned means that the flag
    * was found.  Note that the flag is case insensitive.  If the flag
    * is specified more than once, an error will be thrown.  Flags should
    * begin with a '-'.
    *
    * Command Line Options:
    *    <flag> <value (optional)>
    *
    * @param mainArgs       - Argument list from main function.
    * @param flag           - Flag to check for (case insensitive).
    * @param synonymFlag    - Some command line arguments have a short hand
    *                         or other synonym that can be used for the same
    *                         option.  If one exists, specify it here.
    *                         For example, if the flag is '-userId', a synonym
    *                         might be '-u' for easier usage.  A synonym flag
    *                         is optional.
    * @param valueRequired  - Whether or not this option is required, including
    *                         a value.
    * @param correctUsage   - if valueRequired, this is the correct usage.
    * @return Returns any valid string if the specified flag was found at the  
    *         command line, or 'null' if it was not found.  If it was found, the 
    *         String returned will contain the following value or the next
    *         command (to be diregarded such as in cases when only existence
    *         of flag is to be checked).
    **/
    public static String getCommandlineChoice(String mainArgs[], String flag, String synonymFlag, boolean valueRequired, String correctUsage) throws IllegalArgumentException{
        String value = null;
        
        // Validate Input
        if(flag==null)                  throw new IllegalArgumentException("Internal Tool Error: Invalid input to command line parser 'getCommandlineChoice'.  'flag' is 'null'.  Specify a valid string starting with '-'.");        
        if(flag.trim().length()==0)     throw new IllegalArgumentException("Internal Tool Error: Invalid input to command line parser 'getCommandlineChoice'.  'flag' may not be an empty string.  Specify a valid flag starting with '-'.");
        if(flag.startsWith("-")==false) throw new IllegalArgumentException("Internal Tool Error: Invalid input to command line parser 'getCommandlineChoice'.  'flag' must start with '-'.  Flag found to be '"+flag+"'.  Examples:  -UserId   or   -"+flag);
        if(flag.trim().length()==1)     throw new IllegalArgumentException("Internal Tool Error: Invalid input to command line parser 'getCommandlineChoice'.  'flag' only contains a '-'.  There must be a following name after the '-'.  Example:  -userId");
        if(synonymFlag!=null){
            if(flag.trim().length()==0)     throw new IllegalArgumentException("Internal Tool Error: Invalid input to command line parser 'getCommandlineChoice'.  'synonymFlag' may not be an empty string.  While a synonym is optional, such as '-u' for flag '-userId', if one is to be specified, it must be non-null.  Specify a valid flag starting with '-'.  To specify that there is no synonym for flag '"+flag+"', specifying 'null'.");
            if(flag.startsWith("-")==false) throw new IllegalArgumentException("Internal Tool Error: Invalid input to command line parser 'getCommandlineChoice'.  'synonymFlag' must start with '-' if any value is specified.  Synonym flag found to be '"+synonymFlag+"'.  Examples:  -UserId   or   -"+synonymFlag);
            if(flag.trim().length()==1)     throw new IllegalArgumentException("Internal Tool Error: Invalid input to command line parser 'getCommandlineChoice'.  'synonymFlag' only contains a '-'.  If any synonym is specified, there must be a following name after the '-'.  Example:  -userId.  Specify a valid flag starting with '-' or use 'null' to indicate that there is no synonym for flag '"+flag+"'.");
        }
        if(valueRequired){
            if(correctUsage==null)              throw new IllegalArgumentException("Internal Tool Error: Invalid input to command line parser 'getCommandlineChoice'.  'correctUsage' must be specified if 'valueRequired' is true.  Correct Usage is set to 'null'.");   
            if(correctUsage.trim().length()==0) throw new IllegalArgumentException("Internal Tool Error: Invalid input to command line parser 'getCommandlineChoice'.  'correctUsage' must be specified if 'valueRequired' is true.  Correct Usage is set to an empty string."); 
        }
        
        // Combine the two flags into one description for easier addition to error messages.
        StringBuffer flagInfo = new StringBuffer(flag); // Start with the required flag.
        if(synonymFlag!=null){
            flagInfo.append('/');
            flagInfo.append(synonymFlag);
        }
        
        // Loop through all arguments in main, processing input.
        for(int i=0; i < mainArgs.length; i++){
            if(                              (mainArgs[i].compareToIgnoreCase(flag)==0)
                || ((synonymFlag != null) && (mainArgs[i].compareToIgnoreCase(synonymFlag)==0)) // Only check synonym flags if one is specified.
              ){
                // If it was already specified, throw an exception
                if(value!=null){ // throw different exceptions depending on whether or not this is the last argument.
                    if((i+1)==mainArgs.length) throw new IllegalArgumentException("Command line option '"+flagInfo+"' may only be specified once.  Already accepted value '"+value+"', but also found flag specified at end of option list with no following value.");
                    else                       throw new IllegalArgumentException("Command line option '"+flagInfo+"' may only be specified once.  Already accepted value '"+value+"', but also found '"+mainArgs[i+1]+"'.");
                }
                // If at end of args, there is no following value.
                if((i+1)==mainArgs.length)
                    value = "";
                else // otherwise we found a value
                    value = mainArgs[++i];
            }
        }//end for

        //Validate if required
        if(valueRequired){
            if(value == null)     throw new IllegalArgumentException("Command line option '"+flagInfo.toString()+"' is required and was not specified.  You must specify option \""+correctUsage+"\".");   
            if(value.length()==0) throw new IllegalArgumentException("Command line option '"+flagInfo.toString()+"' is missing a required value.  You must specify a value for option \""+correctUsage+"\".");   
        }

        return(value);
    }//end getCommandlineChoice

}//end class STransactionsRollbackChangeICM