// PerfsClient.java

package applis.ejb.perfs;

import java.util.Date;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import javax.transaction.UserTransaction;

import util.Trace;


class PerfsClientThread extends Thread {

    static private int trace = Trace.DB_1;

    private int m_loops;
    private int m_reads;
    private int m_writes;
    private int m_reqsize;
    private int m_beans;
    private int m_tx;
    private long m_time;
    private int m_perfnb;

    public PerfsClientThread(int b, int r, int w, int s, int n, int t, int perfnb) {
        m_loops     = b;
        m_reads     = r;
        m_writes    = w;
        m_reqsize   = s;
        m_beans   = n;
        m_tx = t;
        m_perfnb = perfnb;
    }

    public void run() {
			
        Trace.outln(trace, "Running a PerfsClientThread...");

        UserTransaction ut = null;
        Context initialContext = null;
        try {
            initialContext = new InitialContext();
            ut = Transaction.getUserTransaction();
        } catch (Exception e) {
            Trace.errln("ERROR: Cannot lookup UserTransaction:\n"+e);
            System.exit(2);
        }
        if (ut == null) {
            Trace.errln("ERROR: Cannot get UserTransaction");
            System.exit(2);
        }
        if (m_beans == 0) {
            Trace.outln(trace, "No bean");
            return;
        }

        // Connecting to each Perfs_X Home, and get the Perfs object
        Perfs t_objPerfs [] = new Perfs [m_beans];
        for (int i = 1; i <= m_beans; i++) {
            String beanName = "";
            switch (m_perfnb) {
            case 1:
                beanName = "PerfsHome_";
                break;
            case 2:
                beanName = "Perfs2Home_";
                break;
            case 3:
                beanName = "Perfs3Home_";
                break;
            }
            beanName += i;
            PerfsHome home = null;
            try {
                home = (PerfsHome) PortableRemoteObject.narrow(initialContext.lookup(beanName), PerfsHome.class);
            } catch (Exception e) {
                Trace.errln("ERROR: Cannot lookup "+beanName+":\n"+e);
                System.exit(2);
            }
            Trace.outln(trace, "Connected to the '"+beanName+"' Object");

            try {
                t_objPerfs[i-1] = home.findByCode(m_reqsize/100);
            } catch (Exception e) {
                Trace.errln("ERROR: Cannot find the object " + m_reqsize/100 + " of "+beanName+":\n"+e);
                System.exit(2);
            }
        }
		
        // Build the message used for the write request
        String s_writeMsg = new String();
        String s_date     = (new Date().toString());
        while ((s_writeMsg.length() + s_date.length() + 1) <= m_reqsize) {
            s_writeMsg = s_writeMsg.concat(s_date);
            s_writeMsg = s_writeMsg.concat(";");
        }
        for (int i = s_writeMsg.length(); i < m_reqsize; i++) {
            s_writeMsg = s_writeMsg.concat(".");
        }

        Trace.outln(trace, "Start loop for " + m_loops + " transactions on " + m_beans + " servers");
        Trace.outln(trace, "Each transaction does " + m_reads + " read and " + m_writes + " write requests");
        Trace.outln(trace, "Request size is " + m_reqsize);

        // Loop on transactions
        long d_begin = System.currentTimeMillis();

        for (int l = 0; l < m_loops; l++) {
            // Begin the transaction
            if (m_tx == PerfsClient.TX_CLIENT) {
                try {
                    ut.begin();
                } catch (Exception e) {
                    Trace.errln("ERROR: Problem during begin:\n"+e);
                    System.exit(2);
                }
            }

            // Requests in the transaction
            try {
                for (int r = 0; r < m_reads + m_writes; r++) {
                    if (r < m_reads) {
                        if (m_tx == PerfsClient.TX_CONTAINER) {
                            t_objPerfs[r%m_beans].txread();
                        } else {
                            t_objPerfs[r%m_beans].read();
                        }
                    } else {
                        if (m_tx == PerfsClient.TX_CONTAINER) {
                            t_objPerfs[r%m_beans].txwrite(s_writeMsg);
                        } else {
                            t_objPerfs[r%m_beans].write(s_writeMsg);
                        }
                    }
                }
            } catch (Exception e) {
                Trace.errln("ERROR: Problem during a bussiness method:\n"+e);
                System.exit(2);
            }

            // Commit the transaction
            if (m_tx == PerfsClient.TX_CLIENT) {
                try {
                    ut.commit();
                } catch (Exception e) {
                    Trace.errln("ERROR: Problem during a commit:\n"+e);
                    System.exit(2);
                }
            }

            Trace.outln(trace, "End of loop " + (l+1) + " OK");
        }
		
        long d_end = System.currentTimeMillis();
        m_time = (d_end - d_begin) / (m_loops);
        Trace.outln(trace,"Time per transaction in millisec: " + m_time);
    }	
    public long getTime(){
        return m_time;
    }
}


public class PerfsClient {

    static private int trace = Trace.DB_1;

    static public int TX_CLIENT = 0;
    static public int TX_CONTAINER = 1;
    static public int TX_NONE = 2;

    private static final int m_MAXBEANS = 3;
    private static final int m_MAXTHREADS = 50;
    private static final int m_MAXREQSIZE = 800;

    private static int m_loops = 1;
    private static int m_poolsize = 1;
    private static int m_reads = 0;
    private static int m_writes = 0;
    private static int m_beans = 0;
    private static int m_reqsize = 100;
    private static boolean m_recreate = false;
    private static boolean m_cmp2 = false;
    private static boolean m_irc = false;
    private static int m_tx = TX_CLIENT;


    private static void usage() {
        Trace.errln("Usage: java applis.ejb.perfs.PerfsClient <args>");
        Trace.errln("  -i              re-create the data-base tables");
        Trace.errln("  -2              use beans cmp2");
        Trace.errln("  -b <loop>       number of loops (transactions) per thread");
        Trace.errln("  -p <thread>     number of client threads");
        Trace.errln("  -r <read>       number of read requests per transaction");
        Trace.errln("  -w <write>      number of write requests per transaction");
        Trace.errln("  -s <size>       request data size in bytes");
        Trace.errln("  -n <beans>    number of Perfs beans used");
        Trace.errln("  -h              no tx");
        Trace.errln("  -c              container tx");
        Trace.errln("default args:");
        Trace.errln(" -b " + m_loops +
                    " -p " + m_poolsize +
                    " -r " + m_reads +
                    " -w " + m_writes +
                    " -s " + m_reqsize +
                    " -n " + m_beans
                    );
    }

    public static void main(String args[]) {

        Trace.configure();

        // Get command args
        for (int argn = 0; argn < args.length; argn++) {
            String s_arg = args[argn];
            Integer i_arg;
            if ((s_arg.equals("-b") == true)) {
                s_arg = args[++argn];
                i_arg = java.lang.Integer.valueOf(s_arg);
                m_loops = i_arg.intValue();
            } else if ((s_arg.equals("-p") == true)) {
                s_arg = args[++argn];
                i_arg = java.lang.Integer.valueOf(s_arg);
                m_poolsize = i_arg.intValue();
            } else if ((s_arg.equals("-r") == true)) {
                s_arg = args[++argn];
                i_arg = java.lang.Integer.valueOf(s_arg);
                m_reads = i_arg.intValue();
            } else if ((s_arg.equals("-w") == true)) {
                s_arg = args[++argn];
                i_arg = java.lang.Integer.valueOf(s_arg);
                m_writes = i_arg.intValue();
            } else if ((s_arg.equals("-s") == true)) {
                s_arg = args[++argn];
                i_arg = java.lang.Integer.valueOf(s_arg);
                m_reqsize = i_arg.intValue();
            } else if ((s_arg.equals("-n") == true)) {
                s_arg = args[++argn];
                i_arg = java.lang.Integer.valueOf(s_arg);
                m_beans = i_arg.intValue();
            } else if (s_arg.equals("-i") == true) {
                m_recreate = true;
            } else if (s_arg.equals("-cmp2") == true) {
                m_cmp2 = true;
            } else if (s_arg.equals("-irc") == true) {
                m_irc = true;
            } else if (s_arg.equals("-h") == true) {
                m_tx = TX_NONE;
            } else if (s_arg.equals("-c") == true) {
                m_tx = TX_CONTAINER;
            } else if (s_arg.equals("-?") == true) {
                usage();
                System.exit(0);
            } else {
                usage();
                System.exit(2);
            }
        }

        // Check command args
        if (m_loops < 1) {
            usage();
            System.exit(2);
        }
        if ((m_poolsize < 1) || (m_poolsize > m_MAXTHREADS)) {
            usage();
            System.exit(2);
        }
        if (m_reads < 0) {
            usage();
            System.exit(2);
        }
        if (m_writes < 0) {
            usage();
            System.exit(2);
        }
        if ((m_reqsize < 1) || (m_reqsize > m_MAXREQSIZE)) {
            usage();
            System.exit(2);
        }
        if ((m_reqsize%100) != 0) {
            usage();
            System.exit(2);
        }
        if (m_beans > m_MAXBEANS) {
            usage();
            System.exit(2);
        }
        if (m_reads + m_writes < m_beans) {
            Trace.errln("All beans will not be used. You must have r+w>=n");
            System.exit(2);
        }
	
        Trace.outln(trace,
                    "PerfsClient" +
                    " -b " + m_loops + " -p " + m_poolsize +
                    " -r " + m_reads + " -w " + m_writes +
                    " -s " + m_reqsize + " -n " + m_beans
                    );


        if (m_recreate) {
            // Connecting to the DBHome object to create the Perfs_X tables
            DBHome dbhome  = null;
            DB     session = null;
            String sName   = "PerfsDBHome";
            try {
                Context initialContext = new InitialContext();
                dbhome = (DBHome) PortableRemoteObject.narrow(initialContext.lookup(sName), DBHome.class);
            } catch (Exception e) {
                Trace.errln("ERROR: Cannot bind to PerfsDBHome:\n"+e);
                System.exit(2);
            }
            Trace.outln(trace, "Connected to the PerfsDBHome Object");
 
            try {
                session = dbhome.create();
                for (int i = 1; i <= 3; i++) {
                    if (m_cmp2) {
                        session.initTable(i, m_irc);
                        Trace.outln(trace, "Table "+i+" initialized");
                    } else {
                        session.createTable("Perfs_"+i);
                        Trace.outln(trace, "Table Perfs_"+i+" created");
                    }
                }
            } catch (Exception e) {
                Trace.errln("ERROR: Problem during the creation of the tables:\n"+e);
                System.exit(2);
            }
        }

        // Start pool of client threads
        PerfsClientThread t_thr[] = new PerfsClientThread [m_MAXTHREADS];
        long ttime[]  = new long[m_MAXTHREADS];
        for (int p = 0; p < m_poolsize; p++) {
            int pnb;
            if (m_cmp2) {
                if (m_irc) {
                    pnb = 3;
                } else {
                    pnb = 2;
                }
            } else {
                pnb = 1;
            }
            t_thr[p] = new PerfsClientThread(m_loops, m_reads, m_writes, m_reqsize, m_beans, m_tx, pnb);
            t_thr[p].start();
        }
        for (int p = 0; p < m_poolsize; p++) {
            try {
                t_thr[p].join();
                ttime[p] = t_thr[p].getTime();

            } catch (InterruptedException e) {
                Trace.errln("ERROR: Problem in PerfsClientThread.join():\n"+e);
                System.exit(2);
            }
        }
        String txtype = " - no tx";
        if (m_tx == TX_CONTAINER) txtype = " - container tx";
        if (m_tx == TX_CLIENT) txtype = " - client tx";

        Trace.out("PerfsClient " +
                  " -b " + m_loops + 
                  " -p " + m_poolsize +
                  " -r " + m_reads + 
                  " -w " + m_writes +
                  " -n " + m_beans +  
                  " -s " + m_reqsize + 
                  txtype);
        for (int p = 0; p < m_poolsize; p++) {
            Trace.out(" "+ ttime[p]);   
        }
        Trace.outln("");
    }

}
