/**
 * 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.catalina;

import java.util.Iterator;

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;

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.xml.sax.SAXException;

import com.meterware.httpunit.HTMLElement;
import com.meterware.httpunit.HttpUnitOptions;
import com.meterware.httpunit.TableCell;
import com.meterware.httpunit.WebConversation;
import com.meterware.httpunit.WebForm;
import com.meterware.httpunit.WebLink;
import com.meterware.httpunit.WebResponse;
import com.meterware.httpunit.WebTable;

/**
 * Define a class to test the JOnAS Admin console Test connectors
 * @author Paul Kemler
 */
public class F_JonasAdminConnector extends JonasAdminTestCase {

    /**
     * URL of Jonas Logger
     */
    private static final String URL_JONASADMIN_JONAS_LOGGER = "/EditLoggingJonas.do";

    /**
     * URL to modify a connector
     */
    private static final String URL_JONASADMIN_MODIFY_CONNECTOR = "EditCatalinaConnector.do?select=jonas%3Atype%3DConnector%2Cport%3D";

    /**
     * URL of connectors
     */
    private static final String URL_JONASADMIN_CONNECTORS = "ListCatalinaConnectors.do";

    /**
     * INPUT Checkbox
     */
    private static final String INPUT_CHECKBOX = "input type=\"checkbox\"";

    /**
     * Title port
     */
    private static final String TITLE_PORT = "Port";

    /**
     * Title address
     */
    private static final String TITLE_ADDRESS = "Address";

    /**
     * Title type
     */
    private static final String TITLE_TYPE = "Type";

    /**
     * Button 'Save'
     */
    private static final String BUTTON_SAVE = "/EditServletServer.do?forward=ActionListCatalinaConnectors";

    /**
     * SUCCESS CODE
     */
    private static final int HTTP_SUCCESS_CODE = 200;

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


    /**
     * Port of the http connector
     */
    String portHttp;

    /**
     * Port of the https connector
     */
    String portHttps;

    /**
     * Port of the ajp connector
     */
    String portAjp;

    /**
     * Accept Count
     */
    private static final String acceptCount = "128";
    /**
     * Allow Trace
     */
    private static final String allowTrace = "true";
    /**
     * Empty Session Path
     */
    private static final String emptySessionPath = "true";
    /**
     * Enable DNS Lookups
     */
    private static final String enableLookups = "true";
    /**
     * Max Bytes in a Post
     */
    private static final String maxPostSize = "1048576";
    /**
     * Connection Timeout
     */
    private static final String connTimeOut = "10000";
    /**
     * URI Encoding
     */
    private static final String URIEncoding = "";
    /**
     * Use Body Encoding for URI
     */
    private static final String useBodyEncodingForURI = "true";
    /**
     * X-Powered-By Generation Enabled
     */
    private static final String xpoweredBy = "true";
    /**
     * Should we use TCP no delay
     */
    private static final String tcpNoDelay = "false";
    /**
     * Default Buffer Size
     */
    private static final String bufferSize = "2048";
    /**
     * IP Address
     */
    private static final String address = "";
    /**
     * Redirect Port Number
     */
    private static final String redirectPort = "9043";
    /**
     * Maximum Threads
     */
    private static final String maxThreads = "50";
    /**
     * Minimum Spare Threads
     */
    private static final String minSpareThreads = "10";
    /**
     * Maximum Spare Threads
     */
    private static final String maxSpareThreads = "25";
    /**
     * Proxy Name
     */
    private static final String proxyName = "";
    /**
     * Proxy Port Number
     */
    private static final String proxyPort = "0";

    /**
     * Constructor with a specified name
     * @param s name
     */
    public F_JonasAdminConnector(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_JonasAdminConnector(testtorun));
        }
    }

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

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

        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);
                }
            }
        }
        undeployAllEar();
        undeployAllJar();

        useEar("autoload/mejb");
    }

    /**
     * Test connectors
     * @throws Exception if error occurs
     */
    public void testConnectors() throws Exception {

        WebResponse wr;
        WebLink link;
        WebTable table;
        WebForm form;

        int row;
        int portColumn;
        int addressColumn;
        int typeColumn;
        int rowHttp;
        int rowHttps;
        int rowAjp;
        String testUrl;
        JonasAdminUtils utils = new JonasAdminUtils();

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

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

        if (jProp.isCatalina()) {
            wr = ConnectorUtils.getConnectorPage(wc);
            table = utils.getTable(wr, 3);
            portColumn = utils.getColumn(TITLE_PORT, table).intValue();
            if (portColumn == -1) {
                throw new IllegalThreadStateException("There is no column, which contains '" + TITLE_PORT + "'. ");
            }
            addressColumn = utils.getColumn(TITLE_ADDRESS, table).intValue();
            if (portColumn == -1) {
                throw new IllegalThreadStateException("There is no column, which contains '" + TITLE_ADDRESS + "'. ");
            }
            typeColumn = utils.getColumn(TITLE_TYPE, table).intValue();
            if (portColumn == -1) {
                throw new IllegalThreadStateException("There is no column, which contains '" + TITLE_TYPE + "'. ");
            }

            // Verify 'remove' button
            if (table.getRowCount() == 2) {
                assertFalse("There is a checkbox. ", wr.getText().indexOf(INPUT_CHECKBOX) != -1);

                // Choose remove action
                link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, "remove");
                link.click();
                wr = wc.getFrameContents(FRAME_CONTENT);
                // ERROR: "No connector found !"
                assertTrue("There is no error message. ", wr.getText().indexOf("<tr class=\"errors\">") != -1);
                link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_CONNECTORS);
                link.click();
                wr = wc.getFrameContents(FRAME_CONTENT);
            } else {
                assertTrue("There is no remove button but there is no one and only one connector. ", wr.getText()
                        .indexOf("'remove'") != -1);
                assertTrue("There is no checkbox but there is no one and only one connector. ", wr.getText().indexOf(
                        INPUT_CHECKBOX) != -1);
            }

            // Open connectors branch in the tree to verify if a connector is
            // well added.
            wr = wc.getFrameContents(FRAME_TREE);
            table = wr.getTables()[0];
            int rowConnectors = utils.getFirstRow("Connectors", table, 6).intValue();
            if (rowConnectors == -1) {
                throw new IllegalThreadStateException("Connectors was not found in the tree. ");
            }
            TableCell cell = table.getTableCell(rowConnectors, 4);
            HTMLElement[] elements = cell.getElementsWithAttribute("src", "images/tree/node_close_last.gif");
            if (elements.length == 1) {
                if (elements[0].getAttribute("src").indexOf("node_close") != -1) {
                    link = cell.getLinks()[0];
                    link.click();
                }
            }

            // 1-Create new connectors
            portHttp = ConnectorUtils.createNewConnector(wc, "http");
            // Verify
            wr = wc.getFrameContents(FRAME_TREE);
            assertTrue("The port " + portHttp + " is not found in the tree. ", wr.getText().indexOf(portHttp) != -1);
            wr = wc.getFrameContents(FRAME_CONTENT);
            assertTrue("It is not the connectors.jsp page. ", wr.getText().indexOf("catalina/connectors.jsp") != -1);

            wr = ConnectorUtils.getConnectorPage(wc);
            table = utils.getTable(wr, 3);
            form = wr.getForms()[0];
            row = utils.getFirstRow(port, table, portColumn).intValue();
            if (row == -1) {
                throw new IllegalThreadStateException("There is no row, which contains '" + port
                        + "' in the 'Port' column. ");
            }
            rowHttp = utils.getFirstRow(portHttp, table, portColumn).intValue();
            if (rowHttp == -1) {
                throw new IllegalThreadStateException("There is no row, which contains '" + portHttp
                        + "' in the 'Port' column. ");
            }
            assertEquals("There is no the correct number of connectors. ", 3, table.getRowCount());
            assertTrue("There is no remove button. ", wr.getText().indexOf("'remove'") != -1);
            assertEquals("There is no the correct number of parameters in the form. ", 2,
                    form.getParameterNames().length);
            assertTrue("There is a checkbox for " + port + "port. ", table.getTableCell(row, 0).getElementsWithName(
                    "selectedItems").length == 0);
            assertEquals("There is no checkbox for " + portHttp + "port. ", 1, table.getTableCell(rowHttp, 0)
                    .getElementsWithName("selectedItems").length);
            assertEquals("The connector address is not null. ", "", table.getTableCell(rowHttp, addressColumn)
                    .getText());
            assertEquals("The connector type is not 'HTTP'. ", "HTTP", table.getTableCell(rowHttp, typeColumn)
                    .getText());
            testUrl = "http://localhost:" + portHttp + "/jonasAdmin/";
            wr = wc2.getResponse(testUrl);
            assertEquals("A code of 200 (success) should be returned. ", HTTP_SUCCESS_CODE, wr.getResponseCode());

            portHttps = ConnectorUtils.createNewConnector(wc, "https");
            // Verify
            wr = ConnectorUtils.getConnectorPage(wc);
            table = utils.getTable(wr, 3);
            form = wr.getForms()[0];
            row = utils.getFirstRow(port, table, portColumn).intValue();
            if (row == -1) {
                throw new IllegalThreadStateException("There is no row, which contains '" + port
                        + "' in the 'Port' column. ");
            }
            rowHttps = utils.getFirstRow(portHttps, table, portColumn).intValue();
            if (rowHttps == -1) {
                throw new IllegalThreadStateException("There is no row, which contains '" + portHttps
                        + "' in the 'Port' column. ");
            }
            assertEquals("There is no the correct number of connectors. ", 4, table.getRowCount());
            assertTrue("There is no remove button. ", wr.getText().indexOf("'remove'") != -1);
            assertEquals("There is no the correct number of parameters in the form. ", 2,
                    form.getParameterNames().length);
            assertEquals("There is no checkbox for " + portHttps + "port. ", 1, table.getTableCell(rowHttps, 0)
                    .getElementsWithName("selectedItems").length);
            assertEquals("The connector address is not null. ", "", table.getTableCell(rowHttps, addressColumn)
                    .getText());
            assertEquals("The connector type is not 'HTTPS'. ", "HTTPS", table.getTableCell(rowHttps, typeColumn)
                    .getText());

            portAjp = ConnectorUtils.createNewConnector(wc, "ajp");
            // Verify
            wr = ConnectorUtils.getConnectorPage(wc);
            table = utils.getTable(wr, 3);
            form = wr.getForms()[0];
            row = utils.getFirstRow(port, table, portColumn).intValue();
            if (row == -1) {
                throw new IllegalThreadStateException("There is no row, which contains '" + port
                        + "' in the 'Port' column. ");
            }
            rowAjp = utils.getFirstRow(portAjp, table, portColumn).intValue();
            if (rowAjp == -1) {
                throw new IllegalThreadStateException("There is no row, which contains '" + portAjp
                        + "' in the 'Port' column. ");
            }
            assertEquals("There is no the correct number of connectors. ", 5, table.getRowCount());
            assertTrue("There is no remove button. ", wr.getText().indexOf("'remove'") != -1);
            assertEquals("There is no the correct number of parameters in the form. ", 2,
                    form.getParameterNames().length);
            assertEquals("There is no checkbox for " + portAjp + "port. ", 1, table.getTableCell(rowAjp, 0)
                    .getElementsWithName("selectedItems").length);
            assertEquals("The connector address is not null. ", "", table.getTableCell(rowAjp, addressColumn).getText());
            assertEquals("The connector type is not 'AJP'. ", "AJP", table.getTableCell(rowAjp, typeColumn).getText());

            // 2-Modify connectors
            // Get form
            wr = ConnectorUtils.getConnectorPage(wc);
            link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_MODIFY_CONNECTOR + portHttp);
            if (link != null) {
                link.click();
            } else {
                throw new IllegalThreadStateException("The link " + URL_JONASADMIN_MODIFY_CONNECTOR + portHttp
                        + " is not found. ");
            }
            wr = wc.getFrameContents(FRAME_CONTENT);

            table = utils.getTable(wr, 1);
            // Verify
            assertTrue("The value of 'Type' row is not 'HTTP'", table.getTableCell(0, 2).getText().indexOf("HTTP") != -1);
            assertTrue("The value of 'Scheme' row is not 'http'", table.getTableCell(1, 2).getText().indexOf("http") != -1);
            assertTrue("The value of 'Coyote Protocol Handler' row is not 'HTTP/1.1'", table.getTableCell(2, 2).getText().indexOf("HTTP/1.1") != -1);
            assertTrue("The value of 'Secure (SSL) Connector' row is not 'false'", table.getTableCell(3, 2).getText().indexOf("false") != -1);

            table = utils.getTable(wr, 4);
            // Verify
            assertTrue("The value of 'Port Number' row is not '"+ portHttp +"'", table.getTableCell(0, 2).getText().indexOf(portHttp) != -1);

            table = utils.getTable(wr, 10);

            form = wr.getForms()[0];
            ConnectorUtils.modifyHttpConnector(form, acceptCount, maxPostSize, connTimeOut, URIEncoding, bufferSize, address, redirectPort, maxThreads,
                    minSpareThreads, maxSpareThreads, proxyName, proxyPort, allowTrace, emptySessionPath, enableLookups, useBodyEncodingForURI, xpoweredBy, tcpNoDelay);

            // Verify
            // Add Go back to the Editor page
            // -------------------------------
            wr = ConnectorUtils.getConnectorPage(wc);
            link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_MODIFY_CONNECTOR + portHttp);
            if (link != null) {
                link.click();
            } else {
                throw new IllegalThreadStateException("The link " + URL_JONASADMIN_MODIFY_CONNECTOR + portHttp
                        + " is not found. ");
            }
            wr = wc.getFrameContents(FRAME_CONTENT);
            verifyConnector(wr, acceptCount, maxPostSize, connTimeOut, URIEncoding, bufferSize, address, redirectPort, maxThreads,
            		minSpareThreads, maxSpareThreads, proxyName, proxyPort, allowTrace, emptySessionPath, enableLookups, useBodyEncodingForURI, xpoweredBy, tcpNoDelay);

            // 3-Remove connectors
            String[] tabPort = {portHttp, portHttps, portAjp};
            ConnectorUtils.deleteConnectors(wc, tabPort);
            // Verify
            wr = ConnectorUtils.getConnectorPage(wc);
            table = utils.getTable(wr, 3);
            assertEquals("The number of connectors is not 1. ", 2, table.getRowCount());

            // 4-Button 'Save'
            wr = wc.getFrameContents(FRAME_CONTENT);
            link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, BUTTON_SAVE);
            if (link == null) {
                throw new IllegalStateException("No link found for button : '" + BUTTON_SAVE + "'.");
            }
            wr = link.click();
            assertTrue("It is not the servletServer.jsp page. ",
                    wr.getText().indexOf("jonasserver/servletServer.jsp") != -1);
        }
    }

    /**
     * Verify value of parameters in connector form
     * @param wr the content frame
     * @param acceptCountText value of the acceptCountText param
     * @param maxPostSizeText value of the maxPostSizeText param
     * @param connTimeOutText value of the connTimeOutText param
     * @param URIEncoding value of the URIEncoding param
     * @param bufferSizeText value of the bufferSizeText param
     * @param address value of the address param
     * @param redirectPortText value of the redirectPortText param
     * @param maxThreadsText value of the maxThreadsText param
     * @param minSpareThreadsText value of the minSpareThreadsText param
     * @param maxSpareThreadsText value of the maxSpareThreadsText param
     * @param proxyName value of the proxyName param
     * @param proxyPortText value of the proxyPortText param
     * @param allowTrace value of the allowTrace param
     * @param emptySessionPath value of the emptySessionPath param
     * @param enableLookups value of the enableLookups param
     * @param useBodyEncodingForURI value of the useBodyEncodingForURI param
     * @param xpoweredBy value of the xpoweredBy param
     * @param tcpNoDelay value of the tcpNoDelay param
     * @throws SAXException if there is not a form.
     */
    private void verifyConnector(WebResponse wr, String acceptCountText,
            String maxPostSizeText, String connTimeOutText, String URIEncoding, String bufferSizeText, String address,
            String redirectPortText, String maxThreadsText, String minSpareThreadsText, String maxSpareThreadsText,
            String proxyName, String proxyPortText, String allowTrace, String emptySessionPath, String enableLookups,
            String useBodyEncodingForURI, String xpoweredBy, String tcpNoDelay) throws SAXException {
        WebForm form = wr.getForms()[0];
        assertEquals("Accept count value is not " + acceptCountText + ". ", acceptCountText, form.getParameterValue("acceptCountText"));
        assertEquals("Max Bytes in a Post value is not " + maxPostSizeText + ". ", maxPostSizeText, form.getParameterValue("maxPostSizeText"));
        assertEquals("Connection Timeout value is not " + connTimeOutText + ". ", connTimeOutText, form.getParameterValue("connTimeOutText"));
        assertEquals("URI Encoding value is not " + URIEncoding + ". ", URIEncoding, form.getParameterValue("URIEncoding"));
        assertEquals("Default Buffer Size value is not " + bufferSizeText + ". ", bufferSizeText, form.getParameterValue("bufferSizeText"));
        assertEquals("IP Address value is not " + address + ". ", address, form.getParameterValue("address"));
        assertEquals("Redirect Port Number value is not " + redirectPortText + ". ", redirectPortText, form.getParameterValue("redirectPortText"));
        assertEquals("Maximum Threads value is not " + maxThreadsText + ". ", maxThreadsText, form.getParameterValue("maxThreadsText"));
        assertEquals("Minimum Spare Threads value is not " + minSpareThreadsText + ". ", minSpareThreadsText, form.getParameterValue("minSpareThreadsText"));
        assertEquals("Maximum Spare Threads value is not " + maxSpareThreadsText + ". ", maxSpareThreadsText, form.getParameterValue("maxSpareThreadsText"));
        assertEquals("Proxy Name value is not " + proxyName + ". ", proxyName, form.getParameterValue("proxyName"));
        assertEquals("Proxy Port Number value is not " + proxyPortText + ". ", proxyPortText, form.getParameterValue("proxyPortText"));
        assertEquals("Allow Trace value is not " + allowTrace + ". ", allowTrace, form.getParameterValue("allowTrace"));
        assertEquals("Empty Session Path value is not " + emptySessionPath + ". ", emptySessionPath, form.getParameterValue("emptySessionPath"));
        assertEquals("Enable DNS Lookups value is not " + enableLookups + ". ", enableLookups, form.getParameterValue("enableLookups"));
        assertEquals("Use Body Encoding for URI value is not " + useBodyEncodingForURI + ". ", useBodyEncodingForURI, form.getParameterValue("useBodyEncodingForURI"));
        assertEquals("X-Powered-By Generation Enabled value is not " + xpoweredBy + ". ", xpoweredBy, form.getParameterValue("xpoweredBy"));
        assertEquals("Should we use TCP no delay value is not " + tcpNoDelay + ". ", tcpNoDelay, form.getParameterValue("tcpNoDelay"));
    }

    /**
     * Tear Down
     * cleanUp action: remove all connectors except default port connector
     */
    public void tearDown() throws Exception {
        MBeanServerConnection server = getMBeanServer();
        ObjectName on = ObjectName.getInstance("jonas:type=Connector,*");

        Iterator connectorList = server.queryNames(on, null).iterator();

        while (connectorList.hasNext()) {
            ObjectName connectorON = (ObjectName) connectorList.next();
            String connectorPort = connectorON.getKeyProperty("port");
            if (!connectorPort.equals(port)) {
                server.invoke(connectorON, "destroy", new Object[] {}, new String[] {});
            }
        }
        super.tearDown();
    }
}
