/*
 * CallETPFromJava
 * Example of invoking an Heirloom Computing Elastic 
 * Transaction Platform transaction from Java.
 * 
 * This does not have to be contained in an Elastic COBOL project,
 * a standard Java project will suffice with the Java Build Path:
 * including 3 additional JARs:
 * - openejb-client-4.5.2.jar (http://tomee.apache.org/downloads.html)
 * - javaee-api-6.0.5.jar (http://tomee.apache.org/downloads.html)
 * - ecobol.jar (part of Elastic COBOL)
 * 
 * EJB Context Properties (using OpenEJB factory objects):
 * - java.naming.factory.initial=org.openejb.client.RemoteInitialContextFactory
 * - java.naming.provider.url=ejbd://localhost:4201
 * - java.naming.security.principal=userid
 * - java.naming.security.credentials=password
 * 
 * By Heirloom convention, the lookup for the remote interface object for
 * ETP SYSID 'ABCD' (i.e., "CICS region" ABCD) is "ETPSYSL_etp2Remote"
 * 
 * Different property names will be required for JBOSS JNP,
 * Oracle WebLogics and IBM WebSphere client libraries.  security 
 * principal and credentials are required only if the JEE server is
 * running under control of a Security Manager and the client library
 * doesn't convey the local security context to the server.
 * 
 * Setup Required:  Start JEE server with an Elastic COBOL ETP
 * Deployment Project deployed to it as SYSID 'ETP2'  In this example,
 * the requested transaction ID is 'ELNK' and associated with 
 * the COBOL Program ID 'ETPELNK'.  It is a non-BMS transaction.
 * Upon completion, the program should execute the following: 
 *      EXEC CICS RETURN COMMAREA('something') END-EXEC
 *      
 */

import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import com.heirloomcomputing.etp.transaction.env.ejb.LinkDispatcherRemote;
import com.heirloomcomputing.etp.transaction.link.CommArea;

public class ETPCallFromJava {

    public static void main(String[] args) throws Exception {
    	final Properties props = new Properties();
    	String contextFactoryClass = "org.openejb.client.RemoteInitialContextFactory";
    	String sysID = "etp1";	// the SYSID (i.e., CICS REGION) to connect
        String transID = null;
        String programID = "etpetrn";
        String hostURL = "ejbd://localhost:4201";
        String userID = null;
        String password = null;
        int    sleep = 0;
        String msg = null;
        String defaultMsg = "Hello from ETPCallFromJava                                       ";
        CommArea sendCommArea = null, returnCommArea = null;
        boolean syncOnReturn = false, doCommit = false, 
        		doRollback = false, doPrepare = false,
        		doAbort = false, quiet = false;
        boolean eatIterations = false, eatSysID = false, eatHostID = false,
        		eatProgramID = false, eatTransID = false, eatUserID = false,
        		eatPassword = false, eatSleep = false, eatBeans = false;
        String resultString = null;
        Object AnyThing = null;
        int iterations = 1;
        int beans = 1;
        
        // do sync-on-return if -sr is specified on the command line
        for (String arg : args) {
        	if (arg.equals("-sr")) {
        		syncOnReturn = true;
        	} else if (arg.equals("-sys")) {
        		eatSysID = true;
        	} else if (eatSysID) {
        		eatSysID = false;
        		sysID = arg;
        	} else if (arg.equals("-prog")) {
        		eatProgramID = true;
        	} else if (eatProgramID) {
        		eatProgramID = false;
        		programID = arg;
        	} else if (arg.equals("-tran")) {
        		eatTransID = true;
        	} else if (eatTransID) {
        		eatTransID = false;
        		transID = arg;
        	} else if (arg.equals("-host")) {
        		eatHostID = true;
        	} else if (eatHostID) {
        		eatHostID = false;
        		hostURL = arg;
        	} else if (arg.equals("-user")) {
        		eatUserID = true;
        	} else if (eatUserID) {
        		eatUserID = false;
        		userID = arg;
        	} else if (arg.equals("-password")) {
        		eatPassword = true;
        	} else if (eatPassword) {
        		eatPassword = false;
        		password = arg;
        	} else if (arg.equals("-s")) {
        		eatSleep = true;
        	} else if (eatSleep) {
        		eatSleep = false;
        		sleep = Integer.parseInt(arg);
        	} else if (arg.equals("-c")) {
        		doCommit = true;
        	} else if (arg.equals("-p")) {
        		doPrepare = true;
        	} else if (arg.equals("-a")) {
        		doAbort = true;
        	} else if (arg.equals("-r")) {
        		doRollback= true;
        	} else if (arg.equals("-q")) {
        		quiet= true;
        	} else if (arg.equals("-i")) {
        		eatIterations= true;
        	} else if (eatIterations) {
        		eatIterations = false;
        		try {
        			iterations = Integer.parseInt(arg);
        		} catch (NumberFormatException e) {
        			// ignore, keep iterations at 1
        		}
        	} else if (arg.equals("-b")) {
        		eatBeans= true;
        	} else if (eatBeans) {
        		eatBeans = false;
        		try {
        			beans = Integer.parseInt(arg);
        		} catch (NumberFormatException e) {
        			// ignore, keep iterations at 1
        		}
        	} else if ((arg.length() > 0) && arg.charAt(0) == '-') {
        		System.out.println("Usage:  java ETPCallFromJava [-sr] [-r] [-c] [-p] [-a] [-q]");
        		System.out.println("             [-s milli] [-sys sysid] [-trans transid] [-prog progid]");
        		System.out.println("             [-host hostid] [-user userid] [-password pw]");
        		System.out.println("             [-i iterations] [-b beans] [msg]");
        		System.out.println("            -sr - pass syncOnReturn to transaction link");
        		System.out.println("             -p - prepare a commit");
        		System.out.println("             -a - abort the prepare");
        		System.out.println("             -c - commit");
        		System.out.println("             -r - rollback");
        		System.out.println("             -q - do not print messages");
        		System.out.println("       -s milli - wait milliseconds between each transaction (default:" + sleep + ")");
        		System.out.println("     -sys sysid - system id to contact (default:" + sysID + ")");
        		System.out.println("  -tran transid - transaction to invoke (default:<none>)");
        		System.out.println("   -prog progid - program name to invoke (default:" + programID + ")");
        		System.out.println("  -host hosturl - ETP connection host (default:" + hostURL + ")");
        		System.out.println("   -user userid - ETP connection user (default:<none>)");
        		System.out.println("   -password pw - ETP connection password (default:<none>)");
        		System.out.println("  -i iterations - perform n transactions per bean, default 1");
        		System.out.println("       -b beans - start beans sessions n transactions per bean, default 1");
        		System.out.println("           msg  - COMMAREA msg to send");
        		System.out.println("");
        		System.out.println("When invoking ETPETRN program or the ETRN transaction");
        		System.out.println("the 'msg' may be:");
        		System.out.println("'INSERT'        - ETRN SQL INSERTs current time into table T");
        		System.out.println("'SYNC'          - ETRN issues EXEC CICS SYNC");
        		System.out.println("'COMMIT'        - ETRN issues EXEC SQL COMMIT");
        		System.out.println("'COUNT'         - ETRN increments a working-storage counter");
        		System.out.println("'INIT'          - ETRN INITIALIZEs the working-storage counter");
        		System.out.println("'POINTER'       - ETRN assigns a POINTER");
        		System.out.println("'CALL ETPETRN'  - COBOL call to ETPETRN, then GOBACK");
        		System.out.println("'TRAN ETRN'     - EXEC LINK to TRAN ETRN, then EXEC RETURN");
        		System.out.println("'PROG ETPETRN'  - EXEC LINK to PROGRAM ETPETRN, then EXEC RETURN");
        		System.out.println("'GOBACK'        - after finishing other commands GOBACK");
        		System.out.println("'RETURN'        - after finishing other commands EXEC RETURN");
        		System.out.println("'TRAN ETRN INSERT GOBACK'- EXEC LINK to ETRN, then insert,");
        		System.out.println("                  then GOBACK instead of EXEC RETURN");
        		System.out.println("'TRAN ETRN CALL ETPETRN INSERT'- EXEC LINK to ETRN, then");
        		System.out.println("                  recursivly call it again, then insert");
        		System.out.println("'TRAN ETRN CALL ETPETRN PROG ETPETRN GOBACK INSERT POINTER'");
        		System.out.println("                  4-level call, insert, assign a ptr in 3rd level");
        		System.exit(1);
        	} else {
        		if (msg == null) msg = "";
        		msg += arg + " ";
        	}
        }
        if (msg == null) msg = defaultMsg;
        else msg += "                                                     ";
        if (msg.length() > 80) {
        	msg = msg.substring(0, 80);
        }

    	props.setProperty(Context.INITIAL_CONTEXT_FACTORY, contextFactoryClass);
    	props.setProperty(Context.PROVIDER_URL, hostURL);
    	if (userID != null) {
    		props.setProperty(Context.SECURITY_PRINCIPAL, userID);
    	}
    	if (password != null) {
    		props.setProperty(Context.SECURITY_CREDENTIALS, password);
    	}

    	System.out.println("ETP call From Java example");
    	System.out.println();
    	
    	System.out.println("EJB Context Lookup properties:");
    	System.out.println(props.toString());
        final Context context = new InitialContext(props);

        // create a number of sessions
        for (int b = 1; b <= beans; b++) {
	        // Get a new EJB Context to the ETP with SYSID "ETP2"
	        try {
		        AnyThing = context.lookup("ETPSYSL_" + sysID + "Remote");
	        } catch (NamingException e) {
	        	System.err.println("ETP server not started or region name '" + sysID + "' not deployed and started.");
	        	e.printStackTrace(System.err);
	        	return;
	        }
	 
	        // the object returned must be a com.heirloomcomputing.etp.transaction.env.ejb.LinkDispatcherRemote
	        // or this cast generates an error.
	        LinkDispatcherRemote ETPSystem = (LinkDispatcherRemote) AnyThing;
	
	        // invoke an ETP transaction from Java
	        sendCommArea = new CommArea(msg.getBytes()); // note:  Default CODE Page
	        
	        for(int i = 1; i <= iterations; i++) {
	        	if (!quiet) System.out.println("linking to " + ((programID == null)?transID:programID) + " #" + b + ":" + i);
	        	returnCommArea = ETPSystem.link(transID, programID, sendCommArea, 
	        			syncOnReturn);
	            if ((returnCommArea.getLength() >  0) && (!quiet)) {
	            	// the transaction returned something
	            	System.out.println("ETP program " + programID + " #" + i + " returned " + returnCommArea.getLength() + " bytes.");
	
	            	// resultString = new String(returnCommArea.toString()); // default code page conversion
	            	resultString = new String(returnCommArea.toByteArray(), "UTF-8"); // specific code page conversion
	            	System.out.println("    commarea:" + resultString);
	            }
	            if (doRollback) {
	            	if (!quiet) System.out.println("Issuing transaction rollback");
	            	ETPSystem.rollback(); // rollback() transaction
	            }
	            if (doPrepare) {
	            	if (!quiet) System.out.println("Issuing transaction prepare");
	            	ETPSystem.prepare(); // prepare a 2-phase commit() transaction
	            }
	            if (doAbort) {
	            	if (!quiet) System.out.println("Issuing transaction abort");
	            	ETPSystem.abort(); // undo the prepare
	            }
	            if (doCommit) {
	            	if (!quiet) System.out.println("Issuing transaction commit");
	            	ETPSystem.commit(); // 1-phase or 2-phase commit() transaction
	            }
	            
	            // sleep between transactions
	            if (sleep > 0) {
	            	Thread.sleep(sleep);
	            }
	        }
        }
        if (!quiet) System.out.println("ETPCallFromJava - finished");
    }
}
