/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2005 Bull S.A.
 * 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 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
 *
 * Initial developer: Matt Wringe
 * --------------------------------------------------------------------------
 * $Id: 
 * --------------------------------------------------------------------------
 */

package org.objectweb.jonas.applications.util;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;

import junit.framework.TestCase;

import org.ow2.jonas.adm.AdmInterface;

import com.meterware.httpunit.WebConversation;

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

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

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

    /**
     * JOnAS admin used for communicate via JMX to JOnAS
     */
    private static AdmInterface admI = 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);
    }

    /**
     * Initialize the port used by tests and the prefix
     */
    private void init() {
        String port = System.getProperty("http.port");
        if (port == null) {
            port = "9000";
        }

        prefixUrl = "http://localhost:" + port;
    }

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

    /**
     * Constructor with a specific name and url
     * This constructor is to be used when Basic Authentication 
     * is required.
     * 
     * @param s the name
     * @param url the url which can be used
     * @param username the username
     * @param password the password
     */
    public JApplicationsTestCase(String s, String url, String username, String password) {
    	super(s);
    	wc = new WebConversation();
    	wc.setAuthorization(username, password);
    	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 setUp() throws Exception {
        try {
            // get InitialContext
            if (ictx == null) {
                ictx = getInitialContext();
            }
            if (admI == null) {
                admI = (AdmInterface) PortableRemoteObject.narrow(ictx.lookup(jonasName + "_Adm"), AdmInterface.class);
            }

            
        } 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 filename) throws Exception {
        
        try {
            // Load ear in JOnAS if not already loaded.
            if (ictx == null) {
                ictx = getInitialContext();
            }

            if (admI == null) {
                admI = (AdmInterface) ictx.lookup(jonasName + "_Adm");
            }

            //Test in both directories (apps/ and apps/autoload)
            String appsFileName = filename + ".ear";
            String autoloadAppsFileName = "autoload" + File.separator + filename + ".ear";
            if (!admI.isEarLoaded(appsFileName) && !admI.isEarLoaded(autoloadAppsFileName)) {
                //if the file was in autoload, it was loaded
                admI.addEar(appsFileName);
            }

        } catch (Exception e) {
            throw new Exception("Cannot load 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 filename) throws Exception {
        
        try {
            // Load war in JOnAS if not already loaded.
            if (ictx == null) {
                ictx = getInitialContext();
            }

            if (admI == null) {
                admI = (AdmInterface) ictx.lookup(jonasName + "_Adm");
            }

            //Test in both directories (apps/ and apps/autoload)
            String webappsFileName = filename + ".war";
            String autoloadWebappsFileName = "autoload" + File.separator + filename + ".war";
            if (!admI.isWarLoaded(webappsFileName) && !admI.isWarLoaded(autoloadWebappsFileName)) {
                //if the file was in autoload, it was loaded
                admI.addWar(webappsFileName);
            }

        } catch (Exception e) {
            throw new Exception("Cannot load 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 filename) throws Exception {
        try {
            // Load bean in EJBServer if not already loaded.
            if (ictx == null) {
                ictx = getInitialContext();
            }
            if (admI == null) {
                admI = (AdmInterface) ictx.lookup(jonasName + "_Adm");
            }
            if (!admI.isLoaded(filename + ".jar")) {
                admI.addBeans(filename + ".jar");
            }
        } 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 {
        try {
            // Load bean in EJBServer if not already loaded.
            if (ictx == null) {
                ictx = getInitialContext();
            }
            if (admI == null) {
                admI = (AdmInterface) ictx.lookup(jonasName + "_Adm");
            }
            if (admI.isLoaded(filename + ".jar")) {
                admI.removeBeans(filename + ".jar");
            }
        } catch (Exception e) {
            throw new Exception("Cannot unload Bean : " + e.getMessage());
        }
    }


    /**
     * Call the main method of a specific class with empty args
     * @param classToLoad name of class which contains the main method
     * @throws Exception if it fails
     */
    protected void callMainMethod(String classToLoad) throws Exception {
        callMainMethod(classToLoad, new String[]{});
    }


    /**
     * Call the main method of a specific class and the specific args
     * @param classToLoad name of class which contains the main method
     * @param args args to give to the main method
     * @throws Exception if it fails
     */
    protected void callMainMethod(String classToLoad, String[] args) throws Exception {
        //Build classloader
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        URL[] urls = new URL[1];
        urls[0] = new File(System.getProperty("jonas.root") + File.separator + "examples" + File.separator + "classes").toURL();
        URLClassLoader loader = new URLClassLoader(urls);
        Thread.currentThread().setContextClassLoader(loader);
        Class clazz = loader.loadClass(classToLoad);
        Class[] argList = new Class[] {args.getClass()};
        Method meth = clazz.getMethod("main", argList);
        Object appli = meth.invoke(null, new Object[]{args});
    }





}
