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

import java.util.Properties;

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.Query;
import javax.management.QueryExp;

import junit.framework.TestSuite;

import org.objectweb.jonas.jonasadmin.test.util.JonasAdminAuth;
import org.objectweb.jonas.jonasadmin.test.util.JonasAdminFiles;
import org.objectweb.jonas.jonasadmin.test.util.JonasAdminTestCase;
import org.objectweb.jonas.jonasadmin.test.util.JonasAdminUtils;

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

/**
 * Class for testing database service
 * @author Paul Kemler
 *
 */
public class F_JonasAdminDatabase extends JonasAdminTestCase {

    /**
     * URL of database service
     */
    private static final String URL_JONASADMIN_SERVICE_DATABASE = "ListDatabases.do";

    /**
     * URL of datasource statistics
     */
    private static final String URL_JONASADMIN_EDIT = "EditDatasource.do";

    /**
     * URL of datasource statistics
     */
    private static final String URL_JONASADMIN_STATISTICS = "EditDatasourceStat.do";

    /**
     * URL of database service
     */
    private static final String URL_JONASADMIN_USED_BY = "datasourceUsedBy.jsp";

    /**
     * number of tabs when you are in the datasource tab
     */
    private static final int NUMBER_OF_TABS_FOR_DATASOURCE = 1;

    /**
     * number of tabs when the datasource is not used
     */
    private static final int NUMBER_OF_TABS_FOR_DATASOURCE_NOT_USED = 3;

    /**
     * number of tabs when the datasource is used
     */
    private static final int NUMBER_OF_TABS_FOR_DATASOURCE_USED = 4;

    /**
     * name of the datasource
     */
    private String name = "";

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

    /**
     * Get a new TestSuite for this class
     * @return a new TestSuite for this class
     */
    public static TestSuite suite() {
        return new TestSuite(F_JonasAdminDatabase.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);
                }
            }
        }
    }

    /**
     * Test information of a JDBC
     * @throws Exception if error occurs
     *
     */
    public void testJDBCInfo() throws Exception {

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

        // Disable errors of javascript
        HttpUnitOptions.setExceptionsThrownOnScriptError(false);
        // Disable exception thrown on error status
        HttpUnitOptions.setExceptionsThrownOnErrorStatus(false);
        if (jProp.isDbm()) {
            // Add datasource
            name = "new_datasource_info";
            String datasourceName = name;
            String datasourceUrl = "jdbc:hsqldb:hsql://localhost:9001/db_jonas";
            String datasourceClassname = "org.hsqldb.jdbcDriver";
            String datasourceUsername = "jonas";
            String datasourcePassword = "jonas";
            String datasourceMapper = "rdb.hsql";
            String jdbcConnchecklevel = "0";
            String jdbcConnmaxage = "1440";
            String jdbcMaxopentime = "60";
            String jdbcConnteststmt = "select 1";
            String jdbcMinconpool = "10";
            String jdbcMaxconpool = "30";
            String jdbcSamplingperiod = "30";
            String jdbcMaxwaittime = "5";
            String jdbcMaxwaiters = "100";

            Properties properties = new Properties();
            properties.put("datasource.name", datasourceName);
            properties.put("datasource.url", datasourceUrl);
            properties.put("datasource.classname", datasourceClassname);
            properties.put("datasource.username", datasourceUsername);
            properties.put("datasource.password", datasourcePassword);
            properties.put("datasource.mapper", datasourceMapper);
            properties.put("jdbc.connchecklevel", jdbcConnchecklevel);
            properties.put("jdbc.connmaxage", jdbcConnmaxage);
            properties.put("jdbc.maxopentime", jdbcMaxopentime);
            properties.put("jdbc.connteststmt", jdbcConnteststmt);
            properties.put("jdbc.minconpool", jdbcMinconpool);
            properties.put("jdbc.maxconpool", jdbcMaxconpool);
            properties.put("jdbc.samplingperiod", jdbcSamplingperiod);
            properties.put("jdbc.maxwaittime", jdbcMaxwaittime);
            properties.put("jdbc.maxwaiters", jdbcMaxwaiters);

            useDatasource(name, properties);

            // Use alarm.ear for adding opened connections
            useEar("alarm");

            // Go to service database
            wr = wc.getFrameContents(FRAME_TREE);
            link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_SERVICE_DATABASE);
            link.click();
            wr = wc.getFrameContents(FRAME_CONTENT);
            selectedTab = 1;

            // Verify tabs
            tabTable = utils.getTabTable(wr);
            testTabs(tabTable, NUMBER_OF_TABS_FOR_DATASOURCE, selectedTab, "Problem in 'Datasources' tab.");

            // Verify JNDI Name
            table = utils.getTable(wr, 0);
            int rowNewDatasource = utils.getRow(name, table).intValue();
            if (rowNewDatasource == -1) {
                fail("'" + name + "' was not found in the table. ");
            }
            int columnJNDI = 1;
            assertEquals("It is not the JNDI name of '" + name + "'. ", datasourceName, table.getTableCell(rowNewDatasource, columnJNDI).getText());

            // Verify JDBC Connection
            int columnJDBCConnection = 2;
            int currentOpenedConnection = getCurrentOpenedConnection(datasourceName);
            assertEquals("It is not the number of opened connection for '" + name + "'. ", currentOpenedConnection, Integer.parseInt(table.getTableCell(rowNewDatasource, columnJDBCConnection).getText()));

            // Go to "new_datasource_info" database
            link = wr.getLinkWith(name);
            if (link == null) {
                fail("No link was found for '" + name + "'in the page. ");
            }
            link.click();
            wr = wc.getFrameContents(FRAME_CONTENT);
            selectedTab = 2;

            // Verify tabs
            tabTable = utils.getTabTable(wr);
            testTabs(tabTable, NUMBER_OF_TABS_FOR_DATASOURCE_NOT_USED, selectedTab, "Problem in the datasource tab.");
            // - links
            assertTrue("The link " + URL_JONASADMIN_SERVICE_DATABASE + " is not found in the first tab. ", tabTable
                    .getTableCell(0, 0).getLinks()[0].getURLString().endsWith(URL_JONASADMIN_SERVICE_DATABASE));
            assertTrue("The link " + URL_JONASADMIN_STATISTICS + " is not found in the third tab. ", tabTable
                    .getTableCell(0, 4).getLinks()[0].getURLString().endsWith(URL_JONASADMIN_STATISTICS));

            // Verify information
            // JDBC Datasource configuration
            table = utils.getTable(wr, 1);
            // JNDI name        <name>
            assertEquals("It is not the JNDI name of '" + name + "'. ", datasourceName, table.getTableCell(0, 2).getText());
            // Description      no desc
            assertEquals("It is not the description of '" + name + "'. ", "no desc", table.getTableCell(1, 2).getText());
            // URL              jdbc:hsqldb:hsql://localhost:9001/db_jonas
            assertEquals("It is not the URL of '" + name + "'. ", datasourceUrl, table.getTableCell(2, 2).getText());
            // User name        jonas
            assertEquals("It is not the user name of '" + name + "'. ", datasourceUsername, table.getTableCell(3, 2).getText());
            // User password    jonas
            assertEquals("It is not the user password of '" + name + "'. ", datasourcePassword, table.getTableCell(4, 2).getText());
            // Mapper           rdb.hsql
            assertEquals("It is not the mapper of '" + name + "'. ", datasourceMapper, table.getTableCell(5, 2).getText());

            // JDBC Driver configuration
            table = utils.getTable(wr, 4);
            // Driver class name       org.hsqldb.jdbcDriver
            assertEquals("It is not the driver class name of '" + name + "'. ", datasourceClassname, table.getTableCell(0, 2).getText());

            // JDBC connection configuration
            WebForm form = wr.getForms()[0];
            // Maximum age
            assertEquals("It is not the maximum age of '" + name + "'. ", jdbcConnmaxage, form.getParameterValue("jdbcConnMaxAge"));
            // Maximum open time
            assertEquals("It is not the maximum open time of '" + name + "'. ", jdbcMaxopentime, form.getParameterValue("jdbcMaxOpenTime"));
            // Checking level
            assertEquals("It is not the checking level of '" + name + "'. ", jdbcConnchecklevel, form.getParameterValue("jdbcConnCheckLevel"));
            // Test
            assertEquals("It is not the test of '" + name + "'. ", jdbcConnteststmt, form.getParameterValue("jdbcTestStatement"));
            // Pool minimum
            assertEquals("It is not the pool minimum of '" + name + "'. ", jdbcMinconpool, form.getParameterValue("jdbcMinConnPool"));
            // Pool maximum
            assertEquals("It is not the pool maximum time of '" + name + "'. ", jdbcMaxconpool, form.getParameterValue("jdbcMaxConnPool"));
            // Max Wait Time
            assertEquals("It is not the maximum wait time of '" + name + "'. ", jdbcMaxwaittime, form.getParameterValue("jdbcMaxWaitTime"));
            // Max Waiters
            assertEquals("It is not the maximum waiters of '" + name + "'. ", jdbcMaxwaiters, form.getParameterValue("jdbcMaxWaiters"));
            // Sampling Period
            assertEquals("It is not the sampling Period of '" + name + "'. ", jdbcSamplingperiod, form.getParameterValue("jdbcSamplingPeriod"));

         }
    }

    /**
     * Test Used By Tab of database service
     * @throws Exception if error occurs
     *
     */
    public void testJDBCUsedBy() throws Exception {

        WebResponse wr;
        WebLink link;
        WebTable table;
        WebTable tabTable;
        int selectedTab;
        String jdbc1Datasource = "";
        JonasAdminUtils utils = new JonasAdminUtils();

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

            // Go to service database
            wr = wc.getFrameContents(FRAME_TREE);
            link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_SERVICE_DATABASE);
            link.click();
            wr = wc.getFrameContents(FRAME_CONTENT);
            selectedTab = 1;

            // Search if there is a datasource with 'jdbc_1' as JNDI name
            table = utils.getTable(wr, 0);
            int columnJNDI = 1;
            int rowJDBC1 = utils.getRow("jdbc_1", table, columnJNDI).intValue();
            if (rowJDBC1 == -1) {
                // Add datasource
                name = "new_datasource_used_by";
                String datasourceName = "jdbc_1";
                String datasourceUrl = "jdbc:hsqldb:hsql://localhost:9001/db_jonas";
                String datasourceClassname = "org.hsqldb.jdbcDriver";
                String datasourceUsername = "jonas";
                String datasourcePassword = "jonas";
                String datasourceMapper = "rdb.hsql";
                String jdbcConnchecklevel = "0";
                String jdbcConnmaxage = "1440";
                String jdbcMaxopentime = "60";
                String jdbcConnteststmt = "select 1";
                String jdbcMinconpool = "10";
                String jdbcMaxconpool = "30";
                String jdbcSamplingperiod = "30";
                String jdbcMaxwaittime = "5";
                String jdbcMaxwaiters = "100";

                Properties properties = new Properties();
                properties.put("datasource.name", datasourceName);
                properties.put("datasource.url", datasourceUrl);
                properties.put("datasource.classname", datasourceClassname);
                properties.put("datasource.username", datasourceUsername);
                properties.put("datasource.password", datasourcePassword);
                properties.put("datasource.mapper", datasourceMapper);
                properties.put("jdbc.connchecklevel", jdbcConnchecklevel);
                properties.put("jdbc.connmaxage", jdbcConnmaxage);
                properties.put("jdbc.maxopentime", jdbcMaxopentime);
                properties.put("jdbc.connteststmt", jdbcConnteststmt);
                properties.put("jdbc.minconpool", jdbcMinconpool);
                properties.put("jdbc.maxconpool", jdbcMaxconpool);
                properties.put("jdbc.samplingperiod", jdbcSamplingperiod);
                properties.put("jdbc.maxwaittime", jdbcMaxwaittime);
                properties.put("jdbc.maxwaiters", jdbcMaxwaiters);

                useDatasource(name, properties);

                jdbc1Datasource = name;
            } else {
                jdbc1Datasource = table.getTableCell(rowJDBC1, 0).getText();
            }

            // Use alarm.ear
            useEar("alarm");

            // Reload service database page
            wr = wc.getFrameContents(FRAME_TREE);
            link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_SERVICE_DATABASE);
            link.click();
            wr = wc.getFrameContents(FRAME_CONTENT);
            selectedTab = 1;

            // Verify JDBC Connection is positif
            rowJDBC1 = utils.getRow("jdbc_1", table, columnJNDI).intValue();
            int columnJDBCConnection = 2;
            int currentOpenedConnection = getCurrentOpenedConnection("jdbc_1");
            assertEquals("It is not the number of opened connection for 'jdbc_1'. ", currentOpenedConnection, Integer.parseInt(table.getTableCell(rowJDBC1, columnJDBCConnection).getText()));
            assertTrue("There is no opened connection for 'jdbc_1' JNDI name. ", currentOpenedConnection > 0);

            // Go to database
            link = wr.getLinkWith(jdbc1Datasource);
            if (link == null) {
                fail("No link was found for '" + name + "'in the page. ");
            }
            link.click();
            wr = wc.getFrameContents(FRAME_CONTENT);
            selectedTab = 2;

            // Verify tabs
            tabTable = utils.getTabTable(wr);
            testTabs(tabTable, NUMBER_OF_TABS_FOR_DATASOURCE_USED, selectedTab, "Problem in the datasource tab.");
            // - links
            assertTrue("The link " + URL_JONASADMIN_SERVICE_DATABASE + " is not found in the first tab. ", tabTable
                    .getTableCell(0, 0).getLinks()[0].getURLString().endsWith(URL_JONASADMIN_SERVICE_DATABASE));
            assertTrue("The link " + URL_JONASADMIN_STATISTICS + " is not found in the third tab. ", tabTable
                    .getTableCell(0, 4).getLinks()[0].getURLString().endsWith(URL_JONASADMIN_STATISTICS));
            assertTrue("The link " + URL_JONASADMIN_USED_BY + " is not found in the third tab. ", tabTable
                    .getTableCell(0, 6).getLinks()[0].getURLString().endsWith(URL_JONASADMIN_USED_BY));

            // Go to "Used by" tab
            link = wr.getFirstMatchingLink(WebLink.MATCH_URL_STRING, URL_JONASADMIN_USED_BY);
            if (link == null) {
                fail("No link was found for '" + name + "'in the page. ");
            }
            link.click();
            wr = wc.getFrameContents(FRAME_CONTENT);
            selectedTab = 4;

            // Verify tabs
            tabTable = utils.getTabTable(wr);
            testTabs(tabTable, NUMBER_OF_TABS_FOR_DATASOURCE_USED, selectedTab, "Problem in the datasource tab.");
            // - links
            assertTrue("The link " + URL_JONASADMIN_SERVICE_DATABASE + " is not found in the first tab. ", tabTable
                    .getTableCell(0, 0).getLinks()[0].getURLString().endsWith(URL_JONASADMIN_SERVICE_DATABASE));
            assertTrue("The link " + URL_JONASADMIN_EDIT + " is not found in the third tab. ", tabTable
                    .getTableCell(0, 2).getLinks()[0].getURLString().endsWith(URL_JONASADMIN_EDIT));
            assertTrue("The link " + URL_JONASADMIN_STATISTICS + " is not found in the third tab. ", tabTable
                    .getTableCell(0, 4).getLinks()[0].getURLString().endsWith(URL_JONASADMIN_STATISTICS));

            // Verify there is Alarm Record EJB
            table = utils.getTable(wr, 0);
            int rowEJB = utils.getRow("AlarmRecord", table).intValue();
            if (rowEJB == -1) {
                fail("There is not 'Alarm Record' in the 'Used By' table. " + table.getText());
            }

            // Verify type
            assertEquals("The EJB type is not EntityBean. ", "EntityBean", table.getTableCell(rowEJB, 1).getText());

            // Verify link
            link = table.getTableCell(rowEJB, 0).getLinks()[0];
            if (link == null) {
                fail("No link was found for '" + name + "'in the page. ");
            }
            int code = wc.sendRequest(link.getRequest()).getResponseCode();
            assertEquals("Fail to go to '" + link.getURLString() + "'. ", 200, code);

         }
    }

    /**
     * Tear Down
     * cleanUp action
     */
    public void tearDown() throws Exception {

        if (jProp.isDbm()) {
            // remove created datasource file
            if (!name.equals("")) {
                // Undeploy datasource
                unUseDatasource(name);
                // Delete file
                JonasAdminFiles.deleteConfigFile(name + ".properties");
                name = "";
            }
        }
        super.tearDown();
    }

    /**
     * Get current opened connection
     * @return number of current opened connection
     * @throws Exception if an error occurs
     */
    private int getCurrentOpenedConnection(String jndiName) throws Exception {
        MBeanServerConnection server = getMBeanServer();
        ObjectName on = ObjectName.getInstance("*:j2eeType=JDBCDataSource,*");

        QueryExp exp = Query.match(Query.attr("jndiName"), Query.value(jndiName));

        ObjectName dataSourceON = (ObjectName) server.queryNames(on, exp).iterator().next();
        Integer currentOpenedConnection = (Integer) server.getAttribute(dataSourceON, "currentOpened");

        return currentOpenedConnection.intValue();
    }

}
