/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999~2009 Bull S.A.S.
 * Contact: jonas-team@ow2.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 1any 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.ws.jaxws.test.util;

import java.io.IOException;
import java.util.Set;

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.meterware.httpunit.WebConversation;

/**
 * Define a class to add useful methods for test the webservices
 *  - Deploy ear, war and beans
 *  - Retrieve initial context
 * @author Florent Benoit
 */
public class JWebServicesTestCase {

    /**
     * Name of the JOnAS server used for tests
     */
    private static String jonasName = "jonas";

    /**
     *  JONAS_BASE
     */
    protected static String jb = null;

    /**
     * Initial context used for lookup
     */
    protected static Context ictx = null;

    /**
     * Connection to the MBeanServer
     */
    private static MBeanServerConnection cnx = null;

    /**
     * Conversation used for HttpUnit
     */
    protected WebConversation wc = null;

    /**
     * URL used for the constructor
     */
    protected String url = null;

    /**
     * Prefix for build URLs
     */
    private String prefixUrl = null;

    /**
     * Add to the specified url the prefix
     * @param url relative URL
     * @return absolute path of URL
     */
    protected String getAbsoluteUrl (String url) {
        return (this.prefixUrl + url);
    }


    /**
     * Make an absolute path with the filename.
     */
    public String absPath(String name, String extension) {

        String ret = "";
        if ( extension.equals(".jar")) {
            ret = jb + "/ejbjars/" + name + ".jar";
        } else if ( extension.equals(".war")) {
            ret = jb + "/webapps/" + name + ".war";
        } else if (extension.equals(".ear")) {
            ret = jb + "/apps/" + name + ".ear";
        }
        return ret;
    }
    private static JMXServiceURL jmxServerUrl = null;
    private static String urlSuffix = "service:jmx:";
    private static String registry = null;
    private static String defaultRegistry = "rmi://localhost:19099";
    private static String protocol = null;
    private static String defaultProtocol = "jrmp";

    /*
     * Get Connection to the MBean server
     * Set the static cnx variable
     */
    private void getJmxCnx() {
        if (cnx == null) {
            try {
                if (registry == null) {
                    registry = defaultRegistry;
                }
                registry = registry + "/";
                int  indx = registry.lastIndexOf(":");
                String st = registry.substring(0, indx);
                String serverUrl = urlSuffix + st +"/jndi/"+registry;
                
                if (protocol == null) {
                    protocol = defaultProtocol;
                }
                
                String connectorName = protocol.concat("connector_");
                
                connectorName = connectorName.concat(jonasName);
                serverUrl = serverUrl.concat(connectorName);

                jmxServerUrl = new JMXServiceURL(serverUrl);
                JMXConnector cntor = JMXConnectorFactory.connect(jmxServerUrl, null);
                cnx = cntor.getMBeanServerConnection(null);
                System.out.println("server reached via: "+serverUrl);
            } catch (IOException e) {
                System.err.println("Can't reach server " + jonasName
                        + " as couldn't create JMXConnector (" + e.getMessage()
                        + ")");
                System.err.println("Check name, registry and protocol options.");
                System.exit(2);
            }
        }
    }

    /*
     * ObjectName of y=the J2eeServerMBean
     */
    private static ObjectName j2eeserver = null;

    /*
     * Get the ObjectName of the J2eeServerMBean
     * @return the ObjectName
     */
    private ObjectName getJ2eeServer() {
        if (j2eeserver == null) {
            try {       	
                ObjectName on = ObjectName.getInstance("*:j2eeType=J2EEServer,name=" + jonasName);
                Set<?> j2eeservers = cnx.queryNames(on, null);
                if (j2eeservers.isEmpty()) {
                    System.err.println("Can't admin server " + jonasName + ": didn't found J2EEServer MBean");
                    System.exit(2);
                }
                j2eeserver = (ObjectName) j2eeservers.iterator().next();
            } catch (Exception e) {
                System.err.println("Can't invoke mbeanServer: " + e);
            }
        }
        return j2eeserver;
    }

    /**
     * Initialize the port used by tests and the prefix
     * @throws Exception 
     */
    private void init() throws Exception {
        String port = System.getProperty("http.port");    
        if (port == null) {
            port = "9000";
        }
        prefixUrl = "http://localhost:" + port;
        setUpProperties();
    }

    /**
     * Constructor with a specified name
     * @param s the name
     * @throws Exception 
     */
    public JWebServicesTestCase(String s) throws Exception {   
        init();
    }
    /**
     * Constructor with a specified name and url
     * @param s the name
     * @param url the url which can be used
     * @throws Exception 
     */
    public JWebServicesTestCase(String s, String url) throws Exception {      
        wc = new WebConversation();
        init();
        this.url = getAbsoluteUrl(url);
    }

    /**
     * Get initialContext
     * @return the initialContext
     * @throws NamingException if the initial context can't be retrieved
     */
    private Context getInitialContext() throws NamingException {
        return new InitialContext();
    }

    /**
     * Common setUp routine, used for every test.
     * @throws Exception if an error occurs
     */

    protected void setUpProperties() throws Exception {
        try {
            // get InitialContext
            if (ictx == null) {
                ictx = getInitialContext();
            }
            jb = System.getProperty("jonas.base");

            registry = System.getProperty("registry");
            protocol = System.getProperty("protocol");
            getJmxCnx();

        } catch (NamingException e) {
            System.err.println("Cannot setup test: " + e);
            e.printStackTrace();
        }
    }


    /**
     * Load an ear file in the jonas server
     * @param filename ear file, without ".ear" extension
     * @throws Exception if an error occurs
     */
    public void useEar(String fname) throws Exception {
        String filename = absPath(fname, ".ear");
        try {
            // Load ear in JOnAS if not already loaded.
            if (!isEarLoaded(filename)) {
                loadEar(filename);
            }

        } catch (Exception e) {
            throw new Exception("Cannot load Ear : " + e.getMessage());
        }

    }

    /**
     * Unload an ear file in the jonas server
     * @param filename ear file, without ".ear" extension
     * @throws Exception if an error occurs
     */
    public void unUseEar(String fname) throws Exception {
        String filename = absPath(fname, ".ear");
         try {

             if (isEarLoaded(filename)) {
                 unloadEar(filename);
             }
         } catch (Exception e) {
             throw new Exception("Cannot unload Ear : " + e.getMessage());
         }
     }

    /**
     * Load a war file in the jonas server
     * @param filename war file, without ".war" extension
     * @throws Exception if an error occurs
     */

    public void useWar(String fname) throws Exception {
        String filename = absPath(fname, ".war");
        try {
            // Load war in JOnAS if not already loaded.
            if (!isWarLoaded(filename)) {
                loadWar(filename);
            }
        } catch (Exception e) {
            throw new Exception("Cannot load War : " + e.getMessage());
        }
    }
    
    /**
     * Unload an ear file in the jonas server
     * @param filename ear file, without ".ear" extension
     * @throws Exception if an error occurs
     */
    public void unUseWar(String fname) throws Exception {
        String filename = absPath(fname, ".war");
         try {

             if (isWarLoaded(filename)) {
                 unloadEar(filename);
             }
         } catch (Exception e) {
             throw new Exception("Cannot unload war : " + e.getMessage());
         }
     }


    /**
     * Load a bean jar file in the jonas server
     * @param filename jar file, without ".jar" extension
     * @throws Exception if an error occurs
     */
    public void useBeans(String fname) throws Exception {
        try {
            String filename = absPath(fname, ".jar");
            // Load bean in EJBServer if not already loaded.
            
            if (!isJarLoaded(filename)) {
                addBeans(filename);
            }
        } catch (Exception e) {
            throw new Exception("Cannot load Bean : " + e.getMessage());
        }
    }



    /**
     * Unload a bean jar file in the jonas server
     * @param filename jar file, without ".jar" extension
     * @throws Exception if an error occurs
     */
    public void unUseBeans(String filename) throws Exception {
        String fname = absPath(filename, ".jar");

         try {

             //if (isJarLoaded(fname)) {
                 unloadBeans(fname);
             //}
         } catch (Exception e) {
             throw new Exception("Cannot unload Bean : " + e.getMessage());
         }
     }



    /*
     * isLoaded remote operation
     */
     private boolean isLoaded(String filename) {
         boolean ret = false;
         String[] params = {filename};
         String[] signature = {"java.lang.String"};
         try {
             Boolean r = (Boolean) cnx.invoke(getJ2eeServer(), "isDeployed", params, signature);
             ret = r.booleanValue();
         } catch (Exception e) {
             System.err.println("Cannot deploy " + filename + ": " + e);
         }
         return ret;
     }

    /**
     * isJarLoaded remote operation
     * @param filename jar file, with ".jar" extension
     */
    private boolean isJarLoaded(String filename) {
        boolean ret = false;
        try {
            return isLoaded(filename);
        } catch (Exception e) {
            System.err.println("Cannot test bean: " + e);
        }

        return ret;
    }
    public void addBeans(String filename) {

        try {
            String[] params = {filename};
            String[] signature = {"java.lang.String"};
            try {
                cnx.invoke(getJ2eeServer(), "deploy", params, signature);
            } catch (Exception e) {
                System.err.println("Cannot deploy " + filename + ": " + e);
            }

        } catch (Exception e) {
            System.err.println("Cannot load bean: " + e);
        }
    }

    /**
     * loadEar remote operation
     * @param filename war file, with ".war" extension
     */
    public void loadWar(String filename) {
        try {

            String[] params = {filename};
            String[] signature = {"java.lang.String"};
            try {
                cnx.invoke(getJ2eeServer(), "deploy", params, signature);
            } catch (Exception e) {
                System.err.println("Cannot deploy " + filename + ": " + e);
            }

        } catch (Exception e) {
            System.err.println("Cannot load bean: " + e);
        }
    }

    /**
     * isWarLoaded remote operation
     * @param filename war file, with ".war" extension
     */
    private boolean isWarLoaded(String filename) {
        boolean ret = false;
        try {
            return isLoaded(filename);
        } catch (Exception e) {
            System.err.println("Cannot test bean: " + e);
        }

        return ret;
    }
    /**
     * isEarLoaded remote operation
     * @param filename ear file, with ".ear" extension
     */
    private boolean isEarLoaded(String filename) {
        boolean ret = false;
        try {
            return isLoaded(filename);

        } catch (Exception e) {
            System.err.println("Cannot test bean: " + e);
        }

        return ret;
    }
    /**
     * loadEar remote operation
     * @param filename ear file, with ".ear" extension
     */
    public void loadEar(String filename) {
        try {

            String[] params = {filename};
            String[] signature = {"java.lang.String"};
            try {
                cnx.invoke(getJ2eeServer(), "deploy", params, signature);
            } catch (Exception e) {
                System.err.println("Cannot deploy " + filename + ": " + e);
            }

        } catch (Exception e) {
            System.err.println("Cannot load bean: " + e);
        }
    }

    /**
     * unloadBean remote operation
     * @param filename ear file, with ".ear" extension
     */
    public void unloadEar(String filename) {
        try {
            String[] params = {filename};
            String[] signature = {"java.lang.String"};
            try {
                cnx.invoke(getJ2eeServer(), "undeploy", params, signature);
            } catch (Exception e) {
                System.err.println("Cannot undeploy " + filename + ": " + e);
            }

        } catch (Exception e) {
            System.err.println("Cannot unload ear: " + e);
        }
    }

    /**
     * unloadBean remote operation
     * @param filename jar file, with ".jar" extension
     */
    public void unloadBeans(String filename) {
        try {
            String[] params = {filename};
            String[] signature = {"java.lang.String"};
            try {
                cnx.invoke(getJ2eeServer(), "undeploy", params, signature);
            } catch (Exception e) {
                System.err.println("Cannot undeploy " + filename + ": " + e);
            }

        } catch (Exception e) {
            System.err.println("Cannot unload bean: " + e);
        }
    }
}
