/**
 * Protocols test
 * Copyright (C) 2007 Bull S.A.S.
 * Contact: jonas-team@objectweb.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */
package org.ow2.jonas.protocols.test.ejbs;

import java.lang.reflect.InvocationTargetException;
import java.rmi.RemoteException;

import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.EJBHome;
import javax.ejb.EJBMetaData;
import javax.ejb.EJBObject;
import javax.ejb.Handle;
import javax.ejb.RemoveException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;


/**
 * @author Francois Waeselynck
 */
public class MyServiceEJB implements SessionBean, MyService {

	/**
     *
     */
    private static final long serialVersionUID = 0L;


    public void ejbActivate() throws EJBException, RemoteException {
		// TODO Auto-generated method stub

	}

	public void ejbPassivate() throws EJBException, RemoteException {
		// TODO Auto-generated method stub

	}

	public void ejbRemove() throws EJBException, RemoteException {
		// TODO Auto-generated method stub

	}

	public void setSessionContext(SessionContext sessionContext)
			throws EJBException, RemoteException {
		ejbContext = sessionContext;

	}

	public long call(String s) throws RemoteException {
		long tb = System.currentTimeMillis();
		/*
		 * Find the EJBs ten call them
		 */
		//long t = ba1.call(s);

		long t;

		try {

			InitialContext ctx = new InitialContext();

			/*
			 * find BackA1
			 */
			BackAHome aHome = (BackAHome) PortableRemoteObject.narrow(
					ctx.lookup("java:comp/env/ejb/backA1"),
					BackAHome.class);
			BackServiceA ba = aHome.create();
			t = ba.call(s);
			ba.remove();

			/*
			 * find BackA2
			 */
			aHome = (BackAHome) PortableRemoteObject.narrow(
					ctx.lookup("java:comp/env/ejb/backA2"),
					BackAHome.class);
			ba = aHome.create();
			t = ba.call(s);
			ba.remove();

		} catch (NamingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoveException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return System.currentTimeMillis() - tb;
	}

    private long callBackHome(BackAHome aHome, String s)  throws RemoteException{
        Object im = null;
        EJBMetaData meta=null;

        long t;

        try {

            try {
                meta = aHome.getEJBMetaData();
            } catch (RemoteException e) {
                e.printStackTrace(System.err);
            }

            // Do a narrow on the right type
            Class homeClass = meta.getHomeInterfaceClass();
            Object imHome = PortableRemoteObject.narrow(aHome, homeClass);

            // Invoke create method
            try {
                im = homeClass.getMethod("create", (java.lang.Class[]) null).invoke(imHome, (java.lang.Object[]) null);
            } catch (IllegalArgumentException e) {
                e.printStackTrace(System.err);
            } catch (SecurityException e) {
                e.printStackTrace(System.err);
            } catch (IllegalAccessException e) {
                e.printStackTrace(System.err);
            } catch (InvocationTargetException e) {
                e.printStackTrace(System.err);
            } catch (NoSuchMethodException e) {
                e.printStackTrace(System.err);
            }

            // Try a narrow on the "remoteAble" method
            Class remoteClass = meta.getRemoteInterfaceClass();
            String imAbleClassName = remoteClass.getName() + "Able";

            ClassLoader cloader = Thread.currentThread().getContextClassLoader();
            try {
                Class imAbleClass = cloader.loadClass(imAbleClassName);
                if (!imAbleClass.isAssignableFrom(im.getClass())) {
                    im = PortableRemoteObject.narrow(im, imAbleClass);

                }
            } catch (Exception ex) {
                //ex.printStackTrace(System.err);
            }
            BackServiceA ba = (BackServiceA) im;

            t = ba.call(s);
            ba.remove();
            return t;

        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return 0;
        } catch (RemoveException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return 0;
        }
    }
    public long callMetaData(String s) throws RemoteException {
        long tb = System.currentTimeMillis();
        /*
         * Find the EJBs ten call them
         */
        //long t = ba1.call(s);

        long t;

        try {

            InitialContext ctx = new InitialContext();


            /*
             * find BackA1
             */
            BackAHome aHome = (BackAHome) PortableRemoteObject.narrow(
                    ctx.lookup("java:comp/env/ejb/backA1"),
                    BackAHome.class);

            t = callBackHome(aHome, s);



            /*
             * find BackA2
             */
            aHome = (BackAHome) PortableRemoteObject.narrow(
                    ctx.lookup("java:comp/env/ejb/backA2"),
                    BackAHome.class);

            t = callBackHome(aHome, s);



        } catch (NamingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return System.currentTimeMillis() - tb;
    }

	public long optCall(String s) throws RemoteException {
		long tb = System.currentTimeMillis();
		/*
		 * Use the cached ba1 and ba2 EJBs
		 */
		long t = ba1.call(s);
		t = ba2.call(s);
		return System.currentTimeMillis() - tb;
	}


	public long optHomeCall(String s) throws RemoteException {
		long tb = System.currentTimeMillis();
		long t = 0;
		try {

			BackServiceA ba = ha1.create();
			t = ba.call(s);
			ba.remove();

			/*
			 * find BackA2
			 */
			ba = ha2.create();
			t = ba.call(s);
			ba.remove();

		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoveException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return System.currentTimeMillis() - tb;
	}

	public EJBHome getEJBHome() throws RemoteException {
		// TODO Auto-generated method stub
		return null;
	}

	public Handle getHandle() throws RemoteException {
		// TODO Auto-generated method stub
		return null;
	}

	public Object getPrimaryKey() throws RemoteException {
		// TODO Auto-generated method stub
		return null;
	}

	public boolean isIdentical(EJBObject arg0) throws RemoteException {
		// TODO Auto-generated method stub
		return false;
	}

	public void remove() throws RemoteException, RemoveException {
		// TODO Auto-generated method stub

	}

	public void ejbCreate() throws CreateException {
		try {

			InitialContext ctx = new InitialContext();
			String tag = (String) ctx.lookup("java:comp/env/params/myTag");
			id = (tag == null ? id : tag);
		} catch (NamingException e) {
			e.printStackTrace();
		}
		initForOptCall();
	}

	public void initForOptCall() {
		try {
			ictx = new InitialContext();

			/*
			 * find BackA1
			 */
			ha1 = (BackAHome) PortableRemoteObject.narrow(
					ictx.lookup("java:comp/env/ejb/backA1"),
					BackAHome.class);
			ba1 = ha1.create();

			/*
			 * find BackA2
			 */
			ha2 = (BackAHome) PortableRemoteObject.narrow(
					ictx.lookup("java:comp/env/ejb/backA2"),
					BackAHome.class);
			ba2 = ha2.create();

		} catch (NamingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {

		}
		System.out.println("FWA - ba1 : " + ba1 + " ; ba2 : " + ba2);
	}

	private SessionContext ejbContext = null;
	private String id = "MyService";

	/*
	 * Fields for
	 */
	private InitialContext ictx = null;
	private BackAHome ha1 = null;
	private BackAHome ha2 = null;
	private BackServiceA ba1 = null;
	private BackServiceA ba2 = null;


	public Request call(Request r) throws RemoteException {
		/*
		 * Find the EJBs ten call them
		 */
		r.addStamp(id, "IN call");
		try {

			InitialContext ctx = new InitialContext();

			/*
			 * find BackA1
			 */
			BackAHome aHome = (BackAHome) PortableRemoteObject.narrow(
					ctx.lookup("java:comp/env/ejb/backA1"),
					BackAHome.class);
			r.addStamp(id, "A1 LOOKUP");
			BackServiceA ba = aHome.create();
			r.addStamp(id, "A1 CREATE");
			r = ba.call(r);
			r.addStamp(id, "A1 call");
			ba.remove();
			r.addStamp(id, "A1 REMOVE");

			/*
			 * find BackA2
			 */
			aHome = (BackAHome) PortableRemoteObject.narrow(
					ctx.lookup("java:comp/env/ejb/backA2"),
					BackAHome.class);
			r.addStamp(id, "A2 LOOKUP");
			ba = aHome.create();
			r.addStamp(id, "A2 CREATE");
			r = ba.call(r);
			r.addStamp(id, "A2 call");
			ba.remove();
			r.addStamp(id, "A2 REMOVE");

		} catch (NamingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoveException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		r.addStamp(id, "OUT call");
		return r;
	}


	public Request optCall(Request r) throws RemoteException {

		/*
		 * Use the cached ba1 and ba2 EJBs
		 */
		r.addStamp(id, "IN optCall");
		r = ba1.call(r);
		r.addStamp(id, "A1 < x < A2");
		r = ba2.call(r);
		r.addStamp(id, "OUT optCall");
		return r;
	}

	public Request optHomeCall(Request r) throws RemoteException {
		/*
		 * Find the EJBs ten call them
		 */
		r.addStamp(id, "IN optHomeCall");
		try {

			BackServiceA ba = ha1.create();
			r.addStamp(id, "A1 CREATE");
			r = ba.call(r);
			r.addStamp(id, "A1 call");
			ba.remove();
			r.addStamp(id, "A1 REMOVE");

			/*
			 * find BackA2
			 */
			ba = ha2.create();
			r.addStamp(id, "A2 CREATE");
			r = ba.call(r);
			r.addStamp(id, "A2 call");
			ba.remove();
			r.addStamp(id, "A2 REMOVE");

		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoveException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		r.addStamp(id, "OUT optHomeCall");
		return r;
	}
}
