/*
 * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

/*
 * $Id: ServiceEETest.java 70876 2013-03-20 15:28:50Z kgrucci $
 */


package  com.sun.ts.lib.harness;

import  java.io.*;
import  java.rmi.Remote;
import  java.rmi.RemoteException;
import  com.sun.ts.lib.util.*;
import  java.util.*;
import  com.sun.javatest.Status;
import  com.sun.ts.tests.common.vehicle.*;
import  com.sun.ts.lib.util.*;
import  com.sun.ts.lib.porting.*;
import  com.sun.ts.lib.deliverable.*;
import  java.net.*;


/**
 * This abstract class must be extended by all clients of tests of
 * J2EE service apis; for example, JDBC, RMI-IIOP, JavaMail, JMS,
 * etc.  When a service test is encountered by the JavaTest Client,
 * the instance is passed to a J2EE server component and run from
 * that remote location.  Using this model to develop tests allows
 * the same test to be run from different locations within the scope
 * of the J2EE Application Programming Model.
 *
 * @author	Kyle Grucci
 */
public abstract class ServiceEETest extends EETest
{


    /*
     * Please do NOT change this class in an incompatible manner with respect to serialization.
     * Please see the serialization specification to determine what is a compatible change
     * versus incompatible.  If you do need to change this class in an incompatible manner you will
     * need to rebuild the compat tests.  You should also increment the serialVersionUID field to
     * denote that this class is incompatible with older versions.
     */
    //static final long serialVersionUID = -1396452037848185296L;

    String[] sVehicles;
    
    private Object theSharedObject;
    private Object theSharedObjectArray[];

    /**
     * Returns any additional properties that may need to be set 
     * by a subclass of ServiceEETest for use by a specific vehicle.
     * This method was created due to a need for clients of the
     * JBIVehicle to set the name of the object to lookup in the
     * rmiregistry.  By rule, this value should match the id name
     * for the component specified in the JBI installation
     * descriptor.  This impl returns an empty properties object
     * by default.
     * 
     * @param  p	   user configured properties used by the test
     * @return Properties  Additional properties that may need to 
     *                     be set by a subclass of ServiceEETest
     *                     for use by a specific vehicle.  
     */
    public Properties getVehicleSpecificClientProps(Properties p)
    {
        return new Properties();
    }

    /**
     * When called within the harness VM, this method passes an instance
     * of itself to the appropriate J2EE server component.  When
     * called from within that server component, EETest's run method
     * is called and the test is run.
     *
     * @param	argv	an array of arguments that a test may use
     * @param	p	user configured properties used by this test
     * @return		a Javatest Status object (passed or failed)
     */
    public Status run (String[] argv, Properties p) {
        Status status = null;
        if (TestUtil.iWhereAreWe == TestUtil.VM_HARNESS  &&
            this instanceof com.sun.ts.tests.common.vehicle.VehicleClient) {
            TestUtil.logTrace("in ServiceEETest.run() method");
            String sVehicle = p.getProperty("vehicle");
            String className = this.getClass().getName();
            //use this name for the context root or jndi name to eliminate
            //naming conflicts for apps deployed at the same time
            String sVehicleEarName = p.getProperty("vehicle_ear_name");
            TestUtil.logTrace("Vehicle to be used for this test is:  " + sVehicle);
            //call to the Deliverable to run in deliverable specific vehicles
            //This should never be called on the server, so there is
            //no need to pass in the deliverable.class system property
            try {
                VehicleRunnable runner = VehicleRunnerFactory.getVehicleRunner(sVehicle);
                p.putAll((Map)getVehicleSpecificClientProps(p));
                status = runner.run(argv, p);
            } catch (Throwable e) {
                e.printStackTrace();
                return  Status.failed("Vehicle runner failed.");
            }
            
            return  status;
        }
        else {
            //we're on the server in a custom vehicle, so just call on EETest
            TestUtil.logTrace("in custom vehicle so call on EETest.");
            return  super.run(argv, p);
        }
    }

    protected Properties getTestPropsFromArgs (String[] argv) {
        Properties p = new Properties();
        Properties ap = new Properties();
        String sProp = null;
        String sVal = null;
        boolean bRunIndividualTest = false;
        vLeftOverTestArgs = new Vector();

	if(TestUtil.harnessDebug)
            TestUtil.logHarnessDebug("ServiceEETest: " + argv.length + " args: "
		+ Arrays.asList(argv).toString());
        //load a props object if used with -p
        boolean tFound = false;
        String argItem = null;
        for (int ii = 0; ii < argv.length; ii++) {
            argItem = argv[ii];
            if (argItem.equals("-p") || argItem.equals("-ap")) {
                ap = initializeProperties(argv[++ii]);
                //add additional props to "p"
                Enumeration e = ap.propertyNames();
                String key = null;
                while (e.hasMoreElements()) {
                    key = (String)e.nextElement();
                    p.put(key, (String)ap.getProperty(key));
                }
            }
            else if (argItem.startsWith("-d") && argItem.indexOf('=') != -1) {
                int equalSign = argItem.indexOf('=');
                sProp = argItem.substring(2, equalSign);
                sVal = argItem.substring(equalSign + 1);
                p.put(sProp, sVal);
            }
            // the first -t specifies test name and should be consumed by harness.
            // Any subsequent -t is to be passed along to test.
            else if (argItem.equalsIgnoreCase("-t") && !tFound) {
                sTestCase = argv[++ii];
                tFound = true;
                bRunIndividualTest = true;
            }
            else if (argItem.equalsIgnoreCase("-vehicle")) {
                sVehicles = new String[1];
                sVehicles[0] = argv[++ii];
            }
            else {
                //there must be args that the test needs,
                //so pass these on
                vLeftOverTestArgs.addElement(argItem);
            }
        }
        if (bRunIndividualTest)
            p.setProperty("testName", sTestCase);
        return  p;
    }

    public Status run (String[] argv, PrintWriter log, PrintWriter err) {
        Status s = Status.passed("OK");
        Properties props;
        props = getTestPropsFromArgs(argv);
        //get the # of secs we should delay to allow reporting to finish
        try {
            iLogDelaySeconds = Integer.parseInt(props.getProperty("harness.log.delayseconds",
                    "1"))*1000;
        } catch (NumberFormatException e) {
            //set the default if a number was not set
            iLogDelaySeconds = 1000;
        }
        if (sVehicles == null) {
	    if(TestUtil.harnessDebug)
                TestUtil.logHarnessDebug("ServiceEETest.run(): vehicles = null");
            sVehicles = getVehicles(props);
        }
        if (props.isEmpty())
            return  Status.failed("FAILED:  An error occurred while trying to load the test properties");
        //copy leftover args to an array and pass them on
        int iSize = vLeftOverTestArgs.size();
        if (iSize == 0) {
            argv = null;
        }
        else {
            argv = new String[iSize];
            for (int ii = 0; ii < iSize; ii++) {
                argv[ii] = (String)vLeftOverTestArgs.elementAt(ii);
            }
        }
        if (sTestCase == null)
            return  runAllTestCases(argv, props, log, err);
        else {
            for (int ii = 0; ii < sVehicles.length; ii++) {
                props.put("vehicle", sVehicles[ii]);
                //need to pass these streams to the Local Reporter
                TestUtil.setCurrentTest(sTestCase, new PrintWriter(log, true), new PrintWriter(err,
                        true));
                TestUtil.initClient(props);
                s = getPropsReady(argv, props);
                try {
                    Thread.sleep(iLogDelaySeconds);
                    TestUtil.logTrace("SLEPT FOR:  " + iLogDelaySeconds);
                } catch (InterruptedException e) {
                    logErr("Exception: " + e);
                }
            }
        }
        return  s;
    }

    //overridden to allow service tests to run in standalone
    //mode outside of javatest
    protected Status runAllTestCases (String[] argv, Properties p, PrintStream log,
            PrintStream err) {
        if (sVehicles == null) {
	    if(TestUtil.harnessDebug)
                TestUtil.logHarnessDebug("ServiceEETest.runAllTestCases(): vehicles = null");
            sVehicles = getVehicles(p);
        }
        Status s = Status.passed("OK");
        for (int ii = 0; ii < sVehicles.length; ii++) {
            p.put("vehicle", sVehicles[ii]);
            s = super.runAllTestCases(argv, p, new PrintWriter(log, true), new PrintWriter(err, true));
            log.println("Completed running tests in " + sVehicles[ii] + " vehicle.");
        }
        return  s;
    }

    private String[] getVehicles (Properties p) {
        String[] sReturn = null;
        String sVal = null;
        String sVehiclesToUse = null;
        StringTokenizer st = null;
        try {
            //get vehicles property (DEFAULT to all)
            sVal = p.getProperty("service_eetest.vehicles");
        } catch (Exception e) {
            //got an exception looking up the prop, so set defaults
            sVal = "";
            sVal = "ejb servlet jsp";
        }
        if (sVal == null || sVal.equals("")) {
            sVehiclesToUse = "ejb servlet jsp";
	    if(TestUtil.harnessDebug)
                TestUtil.logHarnessDebug("getVehicles:  " + "Using default - all vehicles");
        }
        else {
            sVehiclesToUse = sVal;
	    if(TestUtil.harnessDebug)
                TestUtil.logHarnessDebug("getVehicles: using vehicle(s) - " + sVehiclesToUse);
        }
        st = new StringTokenizer(sVehiclesToUse);
        int iCount = st.countTokens();
        sReturn = new String[iCount];
        for (int ii = 0; ii < iCount; ii++) {
            //create 1 desc for each vehicle to be tested
            sReturn[ii] = st.nextToken().trim();
        }
        return  sReturn;
    }

    /*
     * Set shared object
     */
    public void setSharedObject(Object o) {
     theSharedObject = o;
    }

    /*
     * Get shared object
     */
    public Object getSharedObject() {
      return theSharedObject;
    }
}
