/**
 * 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
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.objectweb.jonas.jonasadmin.test.jonasserver;

import java.io.IOException;
import java.net.MalformedURLException;

import junit.framework.TestSuite;

import org.objectweb.jonas.jonasadmin.test.util.JonasAdminAuth;
import org.objectweb.jonas.jonasadmin.test.util.JonasAdminTestCase;
import org.objectweb.jonas.jonasadmin.test.util.JonasAdminUtils;
import org.objectweb.jonas_lib.version.Version;
import org.xml.sax.SAXException;

import com.meterware.httpunit.HttpUnitOptions;
import com.meterware.httpunit.WebConversation;
import com.meterware.httpunit.WebLink;
import com.meterware.httpunit.WebResponse;
import com.meterware.httpunit.WebTable;

/**
 * Class for testing server infos in jonasAdmin
 * @author kemlerp
 *
 */
public class F_JonasAdminInfoServer extends JonasAdminTestCase {

    /**
     * URL of the Server Management
     */
    private static final String URL_JONASADMIN_SERVER = "EditJonasServer.do";

    /**
     * URL of the JMX SERVER
     */
    private static final String URL_JONASADMIN_JMX_SERVER = "EditJmxServer.do";

    /**
     * URL of the server registry
     */
    private static final String URL_JONASADMIN_SERVER_REGISTRY = "ListRegistry.do";

    /**
     * URL of the SERVLET SERVER
     */
    private static final String URL_JONASADMIN_SERVLET_SERVER = "EditServletServer.do";

    /**
     * URL of the JVM
     */
    private static final String URL_JONASADMIN_JVM = "EditJvm.do";

    /**
     * URL of owner mbeans
     */
    private static final String URL_JONASADMIN_OWNER = "/jonasAdmin/ListOwnerMBeans.do";

    /**
     * RMI PROTOCOL
     */
    private static final String RMI_PROTOCOL = "rmi/";

    /**
     * Value of select parameter for JVM
     */
    private static final String SELECT_JVM_MBEAN = "jonas%3Aj2eeType%3DJVM%2Cname%3Djonas%2CJ2EEServer%3Djonas";

    /**
     * Value of select parameter for MBEAN Server
     */
    private static final String SELECT_MBEAN_SERVER_MBEAN = "JMImplementation%3Atype%3DMBeanServerDelegate";

    /**
     * Value of select parameter for Servlet Server
     */
    private static final String SELECT_SERVLET_SERVER_MBEAN = "jonas%3Atype%3Dservice%2Cname%3DwebContainers";

    /**
     * Value of select parameter for Catalina Server
     */
    private static final String SELECT_CATALINA_SERVER = "Catalina%3Atype%3DServer";

    /**
     * URL of the MBean attributs
     */
    private static final String URL_MBEAN_ATTRIBUTS = "/jonasAdmin/ListMBeanAttributes.do?select=";

    /**
     * Balise HTML
     */
    private static final String END_OF_COLUMN = "</td>";

    /**
     * A 2nd connection to jonasAdmin
     */
    private static WebConversation wc2 = new WebConversation();

    /**
     * Constructor with a specified name
     * @param s name
     */
    public F_JonasAdminInfoServer(String s) {
        super(s, URL_JONASADMIN);
    }

    /**
     * Main method
     * @param args the arguments
     */
    public static void main(String[] args) {

        String testtorun = null;
        // Get args
        for (int argn = 0; argn < args.length; argn++) {
            String sArg = args[argn];
            if (sArg.equals("-n")) {
                testtorun = args[++argn];
            }
        }
        if (testtorun == null) {
            junit.textui.TestRunner.run(suite());
        } else {
            junit.textui.TestRunner.run(new F_JonasAdminInfoServer(testtorun));
        }
    }

    /**
     * Get a new TestSuite for this class
     * @return a new TestSuite for this class
     */
    public static TestSuite suite() {
        return new TestSuite(F_JonasAdminInfoServer.class);
    }

    /**
     * Setup need for these tests
     * jonasAdmin is required
     * @throws Exception if it fails
     */
    protected void setUp() throws Exception {
        super.setUp();

        unUseEar("earsample");

        if (wc.getCurrentPage().getURL() == null) {
            useWar("jonasAdmin");
            // login to jonas admin
            try {
                JonasAdminAuth.doValidAuth(wc, url);
            } catch (Exception e) {
                fail("authentification failed :  " + e);
            }
        } else {
            // if there was an error, the connection must be restablished
            try {
                wc.getFrameContents(FRAME_TREE);
            } catch (Exception e) {
                wc.getResponse(urlLogOut);
                // login to jonas admin
                try {
                    JonasAdminAuth.doValidAuth(wc, url);
                } catch (Exception auth) {
                    fail("authentification failed :  " + auth);
                }
            }
        }
    }

    /**
     * Test JOnAS server infos
     * @throws Exception if error occurs
     *
     */
    public void testInfos() throws Exception {

        WebResponse wr;
        WebLink link;
        WebTable table;
        JonasAdminUtils utils = new JonasAdminUtils();

        // Disable errors of javascript
        HttpUnitOptions.setExceptionsThrownOnScriptError(false);
        // Disable exception thrown on error status
        HttpUnitOptions.setExceptionsThrownOnErrorStatus(false);

        String jonasName = null;
        String jonasVersion = Version.NUMBER;
        String jonasProtocol = RMI_PROTOCOL + jProp.getRegistryProtocol();

        String mbeanId = null;
        String mbeanSpecification = null;
        String mbeanSpecVersion = null;
        String mbeanSpecVendor = null;
        String mbeanImplementation = null;
        String mbeanImplVersion = null;
        String mbeanImplVendor = null;

        String registryProtocol = jProp.getRegistryProtocol();
        String registryUrl = jProp.getRegistryUrl();
        int jndiNb = 0;

        String servletName = null;
        String servletVersion = null;
        String servletService = null;
        String servletEngine = null;
        String servletHost = null;

        String jvmVersion = jProp.getJvmVersion();
        String jvmVendor = jProp.getJvmVendor();
        String jvmNode = null;


        // OPEN A SECOND CONNECTION
        // login to jonas admin
        try {
            JonasAdminAuth.doValidAuth(wc2, url);
        } catch (Exception e) {
            fail("authentification failed :  " + e);
        }

        // TEST JONAS SERVER
        // Go to jonas server management
        wr = wc.getFrameContents(FRAME_TREE);
        link = wr.getFirstMatchingLink( WebLink.MATCH_URL_STRING, URL_JONASADMIN_SERVER);
        link.click();
        wr = wc.getFrameContents(FRAME_CONTENT);

        // Get jonas server name
        String text;
        text = wr.getText();
        int beginIndex = text.indexOf("Server JOnAS ( ");
        int endIndex = text.indexOf(" )", beginIndex);
        jonasName = text.substring(beginIndex + "Server JOnAS ( ".length(), endIndex);

        try {
            // Get table
            table = utils.getTable(wr, 0);

            // Verify
            assertEquals("It is not the jonas name. ", jonasName, table.getTableCell(0, 2).getText());
            assertEquals("It is not the jonas version. ", jonasVersion, table.getTableCell(1, 2).getText());
            assertEquals("It is not the jonas protocol. ", jonasProtocol, table.getTableCell(2, 2).getText());
        } catch (SAXException e) {
            fail("The jonas table is incorrect.");
        }


        // TEST JMX SERVER
        link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_JMX_SERVER);
        link.click();
        wr = wc.getFrameContents(FRAME_CONTENT);

        mbeanId = getMBeanAttribut(SELECT_MBEAN_SERVER_MBEAN, "MBeanServerId");
        mbeanSpecification = getMBeanAttribut(SELECT_MBEAN_SERVER_MBEAN, "SpecificationName");
        mbeanSpecVersion = getMBeanAttribut(SELECT_MBEAN_SERVER_MBEAN, "SpecificationVersion");
        mbeanSpecVendor = getMBeanAttribut(SELECT_MBEAN_SERVER_MBEAN, "SpecificationVendor");
        mbeanImplementation = getMBeanAttribut(SELECT_MBEAN_SERVER_MBEAN, "ImplementationName");
        mbeanImplVersion = getMBeanAttribut(SELECT_MBEAN_SERVER_MBEAN, "ImplementationVersion");
        mbeanImplVendor = getMBeanAttribut(SELECT_MBEAN_SERVER_MBEAN, "ImplementationVendor");

        try {
            // Get table
            table = utils.getTable(wr, 0);

            // Verify
            assertEquals("It is not the mbean server id. ", mbeanId, table.getTableCell(0, 2).getText());
            assertEquals("It is not the mbean server specification name. ", mbeanSpecification, table.getTableCell(1, 2).getText());
            assertEquals("It is not the mbean server specification version. ", mbeanSpecVersion, table.getTableCell(2, 2).getText());
            assertEquals("It is not the mbean server specification vendor. ", mbeanSpecVendor, table.getTableCell(3, 2).getText());
            assertEquals("It is not the mbean server implementation name. ", mbeanImplementation, table.getTableCell(4, 2).getText());
            assertEquals("It is not the mbean server implementation version. ", mbeanImplVersion, table.getTableCell(5, 2).getText());
            assertEquals("It is not the mbean server implementation vendor. ", mbeanImplVendor, table.getTableCell(6, 2).getText());
        } catch (SAXException e) {
            fail("The jmx server table is incorrect.");
        }


        // TEST REGISTRY INFOS
        link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_SERVER_REGISTRY);
        link.click();
        wr = wc.getFrameContents(FRAME_CONTENT);

        try {
            // Get table
            table = utils.getTable(wr, 0);

            // Verify
            assertEquals("It is not the registry protocol. ", registryProtocol, table.getTableCell(1, 0).getText());
            assertEquals("It is not the registry url. ", registryUrl, table.getTableCell(1, 1).getText());
        } catch (SAXException e) {
            fail("The registry table is incorrect.");
        }

        try {
            //Get table
            table = utils.getTable(wr, 3);
            int rowNb = table.getRowCount();
            jndiNb = getJndiNb(wr);
            text = table.getText();

            // Verify
            if (jndiNb > 0) {
                assertEquals("The number of jndi names is not " + jndiNb, rowNb, jndiNb);
            }
            assertFalse("'EarOpHome' is found. ", text.indexOf("EarOpHome") > -1);
            assertFalse("'EarOpHome_L' is found. ", text.indexOf("EarOpHome_L") > -1);
            assertFalse("'eisName' is found. ", text.indexOf("eisName") > -1);
        } catch (SAXException e) {
            fail("The jndi name table is incorrect.");
        }

        // Deploy earsample.ear
        useEar("earsample");

        // Refresh
        link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_JVM);
        link.click();
        wr = wc.getFrameContents(FRAME_CONTENT);
        link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_SERVER_REGISTRY);
        link.click();
        wr = wc.getFrameContents(FRAME_CONTENT);

        try {
            //Get table
            table = utils.getTable(wr, 3);
            int jndiNb2 = getJndiNb(wr);
            text = table.getText();

            // Verify
            if (jProp.isResource()) {
                // 3 JNDI NAMES are added: EarOpHome, EarOpHome_L, eisName
                assertEquals("The number of JNDI names has not been updated: ", jndiNb + 3, jndiNb2);
                assertTrue("'eisName' is not found. ", text.indexOf("eisName") > -1);
            } else {
                // 2 JNDI NAMES are added: EarOpHome, EarOpHome_L
                assertEquals("The number of JNDI names has not been updated: ", jndiNb + 2, jndiNb2);
            }
            assertTrue("'EarOpHome' is not found. ", text.indexOf("EarOpHome") > -1);
            assertTrue("'EarOpHome_L' is not found. ", text.indexOf("EarOpHome_L") > -1);
        } catch (SAXException e) {
            fail("The jndi name table is incorrect.");
        }


        // TEST SERVLET SERVER
        link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_SERVLET_SERVER);
        link.click();
        wr = wc.getFrameContents(FRAME_CONTENT);

        servletName = getMBeanAttribut(SELECT_SERVLET_SERVER_MBEAN, "ServerName");
        servletVersion = getMBeanAttribut(SELECT_SERVLET_SERVER_MBEAN, "ServerVersion");
        // if CATALINA
        if (jProp.isCatalina()) {
            String selectService = getMBeanAttribut(SELECT_CATALINA_SERVER, "serviceNames");
            if (selectService.indexOf("[ ") == 0) {
                if (selectService.indexOf(" ]") == selectService.length()-2) {
                    selectService = selectService.substring(2, selectService.length()-2);
                } else {
                    selectService = selectService.substring(2);
                }
            }
            servletService = getMBeanAttribut(selectService, "name");
            String selectContainer = getMBeanAttribut(selectService, "containerName");
            servletEngine = getMBeanAttribut(selectContainer, "name");
            servletHost = getMBeanAttribut(selectContainer, "defaultHost");
        }

        try {
            // Get table
            table = utils.getTable(wr, 0);

            // Verify
            assertEquals("It is not the servlet server name. ", servletName, table.getTableCell(0, 2).getText());
            assertEquals("It is not the servlet server version. ", servletVersion, table.getTableCell(1, 2).getText());
            if (jProp.isCatalina()) {
                assertEquals("It is not the servlet server service. ", servletService, table.getTableCell(2, 2).getText());
                assertEquals("It is not the servlet server engine. ", servletEngine, table.getTableCell(3, 2).getText());
                assertEquals("It is not the servlet server host. ", servletHost, table.getTableCell(4, 2).getText());
            }
        } catch (SAXException e) {
            fail("The jmx server table is incorrect.");
        }


        // TEST JVM INFOS
        link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_JVM);
        link.click();
        wr = wc.getFrameContents(FRAME_CONTENT);

        jvmNode = getMBeanAttribut(SELECT_JVM_MBEAN, "node");
        try {
            // Get table
            table = utils.getTable(wr, 0);

            // Verify
            assertEquals("It is not the jvm version. ", jvmVersion, table.getTableCell(0, 2).getText());
            assertEquals("It is not the jvm vendor. ", jvmVendor, table.getTableCell(1, 2).getText());
            assertEquals("It is not the jvm node. ", jvmNode, table.getTableCell(2, 2).getText());
        } catch (SAXException e) {
            fail("The jvm table is incorrect.");
        }

    }

    /**
     * Get the number of JNDI object
     * @param contentFrame the content frame
     * @return number of JNDI objects
     * @throws SAXException if a table or cell doesn't match.
     */
    private int getJndiNb(WebResponse contentFrame) throws SAXException {
        JonasAdminUtils utils = new JonasAdminUtils();
        WebTable table = utils.getTable(contentFrame, 2);

        String text = table.getTableCell(0, 0).getText();
        int beginIndex = text.indexOf("(");
        int endIndex = text.indexOf(")", beginIndex);
        String nb = text.substring(beginIndex + "(".length(), endIndex);

        return Integer.parseInt(nb);
    }

    /**
     * Get MBean attribut
     * @param select value of select param to indicate the chosen MBean
     * @param attribut name of attribut
     * @return value of the attribut
     * @throws MalformedURLException if url is invalid
     * @throws IOException if url is not correct
     * @throws SAXException if an error is found
     */
    private String getMBeanAttribut(String select, String attribut) {
        WebResponse wr;
        String urlAttributs = prefixUrl + URL_MBEAN_ATTRIBUTS + select;

        try {
            wr = wc2.getResponse(urlAttributs);
            String attributs = wr.getText();
            int position = attributs.indexOf("<b>" + attribut + "</b>");
            int beginIndex = attributs.indexOf("== ", position);
            int endIndex = attributs.indexOf(END_OF_COLUMN, beginIndex);
            return attributs.substring(beginIndex + "== ".length(), endIndex);
        } catch (MalformedURLException e) {
            throw new IllegalStateException("Invalid URL: " + url + ". " + e);
        } catch (IOException e) {
            throw new IllegalStateException("No response from: " + url + ". " + e);
        } catch (SAXException e) {
            throw new IllegalStateException("No text found. " + e);
        }
    }

    /**
     * Tear Down cleanUp action
     * @throws Exception if an error occurs
     */
    public void tearDown() throws Exception {
        super.tearDown();
    }
}
