/**********************************************************************
 * Copyright (c) 2003 Hyades project.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 *
 * Contributors:
 * IBM - Initial API and implementation
 **********************************************************************/

package org.eclipse.hyades.execution.trace.sample;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.rmi.RemoteException;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import javax.rmi.CORBA.Util;

import org.eclipse.hyades.collection.correlation.BaseApplicationImpl;
import org.eclipse.hyades.collection.correlation.ServiceRegistry;
import org.eclipse.hyades.execution.trace.IiopProfiler;
import org.eclipse.hyades.execution.trace.ThreadComparator;
import org.eclipse.hyades.execution.trace.TraceCorrelator;
import org.eclipse.hyades.execution.trace.TraceHandler;
import org.omg.CORBA.ORB;
import org.omg.PortableServer.POA;
import org.omg.PortableServer.Servant;


/**
 * This is the server providing two simple services: saying hello and adding two integers.
 * 
 * @author Richard Duggan, Qiayn Li
 */
public class Server extends PortableRemoteObject implements IService {

    // BEGIN INSTRUMENTED STATIC BLOCK
    static {
        IiopProfiler app = IiopProfiler.getInstance();
        app.initialize();
        app.registerHandler(new TraceHandler());
        ServiceRegistry.getRegistry().registerApplication(app);

        /* Pause for the user to attach to the agent if need be. */
        System.out.println("Please attach to the server agent and press [Enter] to start profiling...");
        try {
            (new BufferedReader(new InputStreamReader(System.in))).readLine();
        } catch (Exception e) {
            e.printStackTrace();
        }
    } // END INSTRUMENTED STATIC BLOCK


    /**
     * Creates an instance of the server.
     */
    public Server() throws RemoteException {

        // BEGIN ENTRY INSTRUMENTATION
        BaseApplicationImpl app = (BaseApplicationImpl) ServiceRegistry.getRegistry().getApplicationById(IiopProfiler.ID);
        TraceCorrelator correlator = (TraceCorrelator) app.createCorrelatorData();
        correlator.setInvocation(this.hashCode(), this.getClass(), "Server", new Class[0], new Object[0], null);
        app.pushChild(new ThreadComparator(), correlator);
        // END ENTRY INSTRUMENTATION

        /* Print out the message as an indicator. */
        System.out.println("RMI-IIOP Sample Server ready...");

        // BEGIN EXIT INSTRUMENTATION
        app = (BaseApplicationImpl) ServiceRegistry.getRegistry().getApplicationById(IiopProfiler.ID);
        app.returnCorrelatorData(app.popChild(new ThreadComparator()).getChild());
        // END EXIT INSTRUMENTATION
    }


    /**
     * @see org.eclipse.hyades.execution.trace.sample.IService#hello(java.lang.String)
     */
    public String hello(String name) throws RemoteException {

        // BEGIN ENTRY INSTRUMENTATION
        BaseApplicationImpl app = (BaseApplicationImpl) ServiceRegistry.getRegistry().getApplicationById(IiopProfiler.ID);
        TraceCorrelator correlator = (TraceCorrelator) app.createCorrelatorData();
        correlator.setInvocation(this.hashCode(), this.getClass(), "hello",
            new Class[] {String.class}, new Object[] {name}, String.class);
        correlator.setParmNames(new String[] {"name"});
        app.pushChild(new ThreadComparator(), correlator);
        // END ENTRY INSTRUMENTATION

        /* Create the message according to the name. */
        String helloMessage = "Hello " + (name == null ? "there" : name) + "!";

        // BEGIN EXIT INSTRUMENTATION
        app = (BaseApplicationImpl) ServiceRegistry.getRegistry().getApplicationById(IiopProfiler.ID);
        correlator = (TraceCorrelator) app.getActiveCorrelatorByKey(new ThreadComparator());
        correlator.setReturnValue(helloMessage);
        app.returnCorrelatorData(app.popChild(new ThreadComparator()).getChild());
        // END EXIT INSTRUMENTATION

        return helloMessage;
    }


    /**
     * @see org.eclipse.hyades.execution.trace.sample.IService#add(int, int)
     */
    public Long add(int x, int y) throws RemoteException {

        // BEGIN ENTRY INSTRUMENTATION
        BaseApplicationImpl app = (BaseApplicationImpl) ServiceRegistry.getRegistry().getApplicationById(IiopProfiler.ID);
        TraceCorrelator correlator = (TraceCorrelator) app.createCorrelatorData();
        correlator.setInvocation(this.hashCode(), this.getClass(), "add",
            new Class[] {int.class, int.class}, new Object[] {new Integer(x), new Integer(y)}, Long.class);
        correlator.setParmNames(new String[] {"x", "y"});
        app.pushChild(new ThreadComparator(), correlator);
        // END ENTRY INSTRUMENTATION

        /* Add the integers. */
        Long z = new Long((long) x + y);

        // BEGIN EXIT INSTRUMENTATION
        app = (BaseApplicationImpl) ServiceRegistry.getRegistry().getApplicationById(IiopProfiler.ID);
        correlator = (TraceCorrelator) app.getActiveCorrelatorByKey(new ThreadComparator());
        correlator.setReturnValue(z);
        app.returnCorrelatorData(app.popChild(new ThreadComparator()).getChild());
        // END EXIT INSTRUMENTATION

        return z;
    }


    /**
     * This is the server entry point.
     * 
     * @param args  the parameters from the command line
     */
    public static void main(String[] args) {

        //BEGIN ENTRY INSTRUMENTATION
        BaseApplicationImpl app = (BaseApplicationImpl) ServiceRegistry.getRegistry().getApplicationById(IiopProfiler.ID);
        TraceCorrelator correlator = (TraceCorrelator) app.createCorrelatorData();
        correlator.setInvocation(Server.class.hashCode(), Server.class, "main",
            new Class[] {String[].class}, new Object[] {args}, void.class);
        correlator.setParmNames(new String[] {"args"});
        app.pushChild(new ThreadComparator(), correlator);
        // END ENTRY INSTRUMENATION

        try {

            /* Prepare the server object. */
            ORB orb = ORB.init(new String[0], null);
            POA rootPoa = (POA) orb.resolve_initial_references("RootPOA");
            POA childPoa = rootPoa.create_POA("SamplePOA", null, null);
            childPoa.the_POAManager().activate();

            /* Initialize the server. */
            Server svr = new Server();
            Servant svrTie = (Servant) Util.getTie(svr);
            byte[] svrId = (svr.hashCode() + "@" + InetAddress.getLocalHost().getHostAddress() +
                    "#" + Util.getTie(svr).getClass().getName()).getBytes();
            childPoa.activate_object_with_id(svrId, svrTie);

            /* Register the server, and wait for requests to arrive. */
            Context initialNamingContext = new InitialContext();
            String service = "RMI-IIOPSampleServer";
            org.omg.CORBA.Object servant = childPoa.create_reference_with_id(svrId,
                svrTie._all_interfaces(childPoa, svrId)[0]);

            //BEGIN ENTRY INSTRUMENTATION
            app = (BaseApplicationImpl) ServiceRegistry.getRegistry().getApplicationById(IiopProfiler.ID);
            correlator = (TraceCorrelator) app.createCorrelatorData();
            correlator.setInvocation(initialNamingContext.hashCode(), initialNamingContext.getClass(),
                "rebind", new Class[] {service.getClass(), servant.getClass()},
                new Object[] {service, servant}, void.class);
            correlator.setParmNames(new String[2]);
            app.pushChild(new ThreadComparator(), correlator);
            // END ENTRY INSTRUMENATION

            initialNamingContext.rebind(service, servant);

            //BEGIN EXIT INSTRUMENTATION
            app.returnCorrelatorData(app.popChild(new ThreadComparator()).getChild());
            // END EXIT INSTRUMENATION

            orb.run();

        } catch (Exception e) {
            e.printStackTrace();
        }

        // BEGIN EXIT INSTRUMENTATION
        app.returnCorrelatorData(app.popChild(new ThreadComparator()).getChild());
        // END EXIT INSTRUMENTATION
    }
}