/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * This software is the proprietary information of Sun Microsystems, Inc.
 * Use is subject to license terms.
 * 
 * Copyright 2004 Sun Microsystems, Inc.  Tous droits r?serv?s.
 * Ce logiciel est propri?t? de Sun Microsystems, Inc.
 * Distribu? par des licences qui en restreignent l'utilisation.
 *
 * ident        "@(#)SubTransaction2.java 1.7     04/06/30 SMI"
 *
 */

package com.sun.mfwk.examples.instrum;

// java imports
//

import java.util.*;
import java.io.IOException;
import java.net.UnknownHostException;

// JDMK import
import com.sun.jdmk.comm.*;
import com.sun.jdmk.*;

// JMX RI imports
import javax.management.*;
import javax.management.remote.*;
import javax.management.remote.jmxmp.*;

// JESMA APIs
import com.sun.mfwk.trans.*;
import com.sun.mfwk.util.instrum.*;
import com.sun.mfwk.util.log.MfLogService;

/*
 *
 * Example of MfTransaction API usage using the Option 2 (MfTranReport report)
 * and sub-transactions
 *
 */

public class SubTransaction2 { 

    public static void main(String[] args) {

	SubTransaction2 mySubTransaction2 = new SubTransaction2();

	if (args.length == 1) {
	    mySubTransaction2.nbLoop = new Integer(args[0]).intValue();
	} else {
	    System.out.println("Usage: java SubTransaction2 nbLoop");
	    System.exit(1);
	}


	// Initialization: traces, connectors
	mySubTransaction2.init();

	// MfTransaction example
	mySubTransaction2.manageTransactions();
    }


    public void init() {

        // Parse system properties to check if LEVEL_TRACE and/or
	// LEVEL_DEBUG are set and enable the TRACE level accordingly
        try {
            TraceManager.parseTraceProperties();
        }
        catch (IOException e) {
            e.printStackTrace();
        }

	
	/*
        ** Create the MBean server
	*/
	mbs = MBeanServerFactory.createMBeanServer();

	/*
        ** Create JDMK HTML adaptor for debug 
	*/
	HtmlAdaptorServer htmlAdaptor = new HtmlAdaptorServer(8083);
        try {
            ObjectName oName =
                new ObjectName("jmx", "type", "htmlAdaptor");
            mbs.registerMBean(htmlAdaptor, oName);
	    htmlAdaptor.start();
        } catch(Exception e) {
            e.printStackTrace();
        }
	// waiting to leave starting state...
        while (htmlAdaptor.getState() == CommunicatorServer.STARTING) {
	    System.out.println("sleeping on htmlAdaptor");
            sleep(500);
        }
        System.out.println("\nHTML protocol adaptor started on port "+ htmlAdaptor.getPort());

	/*
        ** Create JSR 160 JMXMP connector 
	*/
	JMXConnectorServer cs = null;
	try {
	    JMXServiceURL url = new JMXServiceURL("jmxmp", null, 0);
	    cs = new JMXMPConnectorServer(url, null);
	    ObjectName csName =
		new ObjectName("jmx:type=cserver,name=jmxmpConnectorServer"); 
	    mbs.registerMBean(cs, csName);
	    cs.start();
	} catch (Exception e) {
	    e.printStackTrace();
	    System.exit(1);
	}
	System.out.println("\nJMXMP connector started.");

	// logging init
        MfLogService l = new MfLogService("sdk_transaction1");
    }


    void manageTransactions() {
	// Instanciate transaction factory
	MfTransactionFactory tranFactory = new MfTransactionFactoryImpl();

	// Instanciate the Metrics MBean
	MfTransactionMetrics transMetricsParent = new MfTransactionMetrics();
	MfTransactionMetrics transMetricsSubTrans = new MfTransactionMetrics();
	// Register it in the MBeanServer
	try {
	    ObjectName oName = MfObjectNameFactory.getTransactionMetricsName("parent_uri_name");
	    mbs.registerMBean(transMetricsParent, oName);
	    oName = MfObjectNameFactory.getTransactionMetricsName("subTrans_uri_name");
	    mbs.registerMBean(transMetricsSubTrans, oName);
	} catch (Exception e) {
	    e.printStackTrace();
	}

	// Instanciate the MfInstrumManagement MBean
	MfInstrumManagement instrumManagement = new MfInstrumManagement();
	// Register it in the MBeanServer
	try {
	    ObjectName oName = MfObjectNameFactory.getInstrumManagementName();
	    mbs.registerMBean(instrumManagement, oName);
	} catch (Exception e) {
	    e.printStackTrace();
	}

	// Define the MfTransaction types
	MfTransactionDefinition tranDefParent =
	    tranFactory.newTransactionDefinition("MfTransaction type parent", "hello:/xx.xx", transMetricsParent);

	MfTransactionDefinition tranDefSubTrans =
	    tranFactory.newTransactionDefinition("MfTransaction type subTrans", "hello:/xx.xx/yyy", transMetricsSubTrans);

	if (isCpuTimeSupported()) {
	    cpuTimeSupported = true;
	}

	// Define the MfTransaction instances (start/stop mode)
	MfTranReport tranParent = tranFactory.newTranReport(tranDefParent, null);
	MfTranReport subTrans = tranFactory.newTranReport(tranDefSubTrans, tranParent);

	for (int ii=0; ii < nbLoop; ii++, sleep(500)) {

	    int ret = 0;	    
	    long parentStartTime = java.lang.System.currentTimeMillis();

	    long parentStartCpuTime = 0;
	    if (cpuTimeSupported)
		parentStartCpuTime = threadMBean.getCurrentThreadCpuTime();
	

	    // MfTransaction processing
	    System.out.println("Hello world1!");

	    math_proc();

	    sleep(4000);


	    ////////////////////////////////////////////////////////////////////////////////
	    // Sub-transaction starting
	    long subTransStartTime = java.lang.System.currentTimeMillis();

	    long subTransStartCpuTime = 0;
	    if (cpuTimeSupported)
		subTransStartCpuTime = threadMBean.getCurrentThreadCpuTime();

	    math_proc();

	    sleep(1000);

	    // The sub-transaction is finished: report the info
	    long subTransStopTime = java.lang.System.currentTimeMillis();
	    long subTransResponseTime = subTransStopTime - subTransStartTime;

	    long subTransStopCpuTime = threadMBean.getCurrentThreadCpuTime();
	    long subTransCpuTime = subTransStopCpuTime - subTransStartCpuTime;
	    // transform cpu time from nanoseconds to milliseconds
	    subTransCpuTime = subTransCpuTime / 1000000;

	    System.out.println("Sub-transaction report...");
	    System.out.println("subTransResponseTime = " + subTransResponseTime + " subTransCpuTime = " + subTransCpuTime);
	    ret = subTrans.report(MfConstants.STATUS_GOOD, subTransResponseTime, subTransCpuTime, subTransStopTime);
	    if (ret != MfConstants.OK)
		System.out.println(subTrans.getErrorMessage(subTrans.getErrorCode()));
	    ////////////////////////////////////////////////////////////////////////////////

	    // The parent transaction is finished: report the info

	    long parentStopTime = java.lang.System.currentTimeMillis();
	    long parentResponseTime = parentStopTime - parentStartTime;

	    long parentStopCpuTime = threadMBean.getCurrentThreadCpuTime();
	    long parentCpuTime = parentStopCpuTime - parentStartCpuTime;
	    // transform cpu time from nanoseconds to milliseconds
	    parentCpuTime = parentCpuTime / 1000000;

	    System.out.println("Parent transaction report...");
	    System.out.println("parentResponseTime = " + parentResponseTime + " parentCpuTime = " + parentCpuTime);
	    ret = tranParent.report(MfConstants.STATUS_GOOD, parentResponseTime, parentCpuTime, parentStopTime);
	    if (ret != MfConstants.OK)
		System.out.println(tranParent.getErrorMessage(tranParent.getErrorCode()));

	    System.out.println("\n\n\n");
	}

    }

    private static void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            return;
        }
    }

    private static void math_proc() {
	    double sum = 0;
	    for (int i = 0; i < 50000; i++) {
		double r = 0.543;
		double x = Math.pow(30, r);
		sum += x - r;
	    }	  
    } 

    private boolean isCpuTimeSupported() {
        // Check and set thread cpuTime instrumentation
        try {
            threadMBean = new MfCpuTime(null);
	    
            if (threadMBean.isCurrentThreadCpuTimeSupported()) {
                if (!threadMBean.isThreadCpuTimeEnabled()) {
                    threadMBean.setThreadCpuTimeEnabled(true);
                    System.out.println("ThreadCpuTime Enabled.");
                } else {
                    System.out.println("ThreadCpuTime was already enabled.");
                }
                return true;
            } else {
                System.out.println("WARNING: CurrentThreadCpuTime not supported.");
                return false;
            }
        } catch(Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    private MBeanServer mbs = null;
    private int nbLoop = 0;
    private MfCpuTime threadMBean = null;
    private boolean cpuTimeSupported = false;

}
