/**
 * 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 any 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.jtests.clients.mbeans;

import java.util.Properties;

import javax.management.ObjectName;
import javax.management.j2ee.Management;
import javax.management.j2ee.ManagementHome;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.callback.CallbackHandler;

import junit.framework.Test;
import junit.framework.TestSuite;

import org.objectweb.jonas.jtests.util.JWebServicesTestCase;
import org.ow2.jonas.security.auth.callback.NoInputCallbackHandler;

/**
 * Test WebServices MBeans (WebServices, Service, PortComponent and Handler).
 *
 * @author Guillaume Sauthier
 */
public class F_WebServicesMBeans extends JWebServicesTestCase {

    /**
     * MEJB instance
     */
    private Management mejb = null;

    /**
     * Service of Time Sample's ObjectName
     */
    private static final String SERVICE_MBEAN_ON = "jonas:type=WebService,name=TimeWebService,J2EEServer=jonas,J2EEApplication=time-test,EJBModule=time";

    /**
     * PortComponent of Time Sample's ObjectName
     */
    private static final String PC_MBEAN_ON = "jonas:type=WebServicePortComponent,name=TimePort,WebService=TimeWebService,J2EEServer=jonas,EJBModule=time,J2EEApplication=time-test";

    /**
     * Handler of Time Sample's ObjectName
     */
    private static final String HANDLER_MBEAN_ON = "jonas:type=WebServiceHandler,name=TimeBeanHandler,WebServicePortComponent=TimePort,EJBModule=time,J2EEServer=jonas,J2EEApplication=time-test,WebService=TimeWebService";

    /**
     * SessionBean realizing the Time Service
     */
    private static final String SSB_MBEAN_ON = "jonas:j2eeType=StatelessSessionBean,name=TimeBeanSLR,EJBModule=time,J2EEApplication=time-test,J2EEServer=jonas";

    // =================== Attributes pre-filling ======================================

    /**
     * Service.portComponents
     */
    private static final String[] SERVICE_PCS_ATT = new String[] { PC_MBEAN_ON };

    /**
     * PortComponent.handlers
     */
    private static final String[] PC_HANDLERS_ATT = new String[] { HANDLER_MBEAN_ON };

    /**
     * Handler.soapHeaders
     */
    private static final String[] SOAP_HEADERS = new String[] { };

    /**
     * Handler.soapRoles
     */
    private static final String[] SOAP_ROLES = new String[] { };

    /**
     * Handler.initParams
     */
    private static Properties INIT_PARAMS = null;

    /**
     * Inner static class used to store tests expected results
     *
     * @author Guillaume Sauthier
     */
    private static class WsTest {
        /**
         * MBean attribute name
         */
        public String name;

        /**
         * MBean attribute type
         */
        public Class type;

        /**
         * Expected result
         */
        public Object expected;

        /**
         * does the String represents an ObjectName ?
         */
        public boolean isObjectName;

        /**
         * WsTest Constructor
         * @param name att name
         * @param type att type
         * @param expected att value
         */
        public WsTest(String name, Class type, Object expected) {
            this(name, type, expected, false);
        }

        /**
         * WsTest Constructor
         * @param name att name
         * @param type att type
         * @param expected att value
         */
        public WsTest(String name, Class type, Object expected, boolean on) {
            super();
            this.name = name;
            this.type = type;
            this.expected = expected;
            this.isObjectName = on;
        }
    }

    /**
     * Tests values for Service MBean
     */
    private WsTest[] SERVICE_TEST = null;

    /**
     * Tests values for PortComponent MBean
     */
    private WsTest[] PORT_TEST = null;

    /**
     * Tests values for Handler MBean
     */
    private WsTest[] HANDLER_TEST = null;

    /**
     * Are the tables init ?
     */
    private boolean initialized = false;
    
    /**
     * The LoginContext to be used for security.
     */
    private LoginContext context;

    public F_WebServicesMBeans(String s) {
        super(s);
    }

    public static Test suite() {
        return new TestSuite(F_WebServicesMBeans.class);
    }

    public void setUp() throws Exception {
        super.setUp();
        useEar("time-test");
        CallbackHandler handler = new NoInputCallbackHandler("jonas", "jonas");
        context = new LoginContext("test", handler);
        context.login();
        
        mejb = getMEJB();
        if (!initialized) {
            initTestsTables();
            initialized = true;
        }
    }

    /**
     * init tables
     */
    private void initTestsTables() {

        INIT_PARAMS = new Properties();
        INIT_PARAMS.put("jonas.test.server.handler", "JOnAS");

        SERVICE_TEST = new WsTest[] {
                new WsTest("name", java.lang.String.class, "TimeWebService"),
                new WsTest("portComponents", java.lang.String[].class, SERVICE_PCS_ATT, true),
                new WsTest("wsdlURL", java.lang.String.class, getAbsoluteUrl("/time/TimePort/TimePort?JWSDL")),
                new WsTest("mappingFilename", java.lang.String.class, "META-INF/mapping.xml"),
                new WsTest("wsdlFilename", java.lang.String.class, "META-INF/wsdl/TimePort.wsdl") };

        PORT_TEST = new WsTest[] {
                new WsTest("name", java.lang.String.class, "TimePort"),
                new WsTest("handlers", java.lang.String[].class, PC_HANDLERS_ATT, true),
                new WsTest("wsdlPort", java.lang.String.class, "{jonas:Time}TimePort"),
                new WsTest("serviceEndpointInterface", java.lang.String.class, "org.objectweb.jonas.jtests.beans.time.TimeEndpoint"),
                new WsTest("endpoint", java.lang.String.class, getAbsoluteUrl("/time/TimePort/TimePort")),
                new WsTest("implementationBean", java.lang.String.class, SSB_MBEAN_ON, true) };

        HANDLER_TEST = new WsTest[] {
                new WsTest("name", java.lang.String.class, "TimeBeanHandler"),
                new WsTest("classname", java.lang.String.class, "org.objectweb.jonas.jtests.beans.time.TimeBeanHandler"),
                new WsTest("soapHeaders", java.lang.String[].class, SOAP_HEADERS),
                new WsTest("soapRoles", java.lang.String[].class, SOAP_ROLES),
                new WsTest("initParams", java.util.Properties.class, INIT_PARAMS) };

    }


    private Management getMEJB() throws Exception {
        InitialContext ic = new InitialContext();
        Object o = ic.lookup("ejb/mgmt/MEJB");
        ManagementHome home = (ManagementHome) PortableRemoteObject.narrow(o, ManagementHome.class);
        return home.create();
    }

    public void tearDown() throws Exception {
        mejb = null;
        context.logout();
        super.tearDown();
    }

    public void testWebServiceMBean() throws Exception {
        checkMBean(SERVICE_MBEAN_ON, SERVICE_TEST);
    }

    public void testPortComponentMBean() throws Exception {
        checkMBean(PC_MBEAN_ON, PORT_TEST);
        // check that the implementationBean is live
        String se = (String) mejb.getAttribute(new ObjectName(PC_MBEAN_ON), "implementationBean");
        assertTrue("implementationBean MBean must be registered", mejb.isRegistered(new ObjectName(se)));
    }

    public void testHandlerMBean() throws Exception {
        checkMBean(HANDLER_MBEAN_ON, HANDLER_TEST);
    }

    private void checkMBean(String onStr, WsTest[] tests) throws Exception {
        ObjectName on = ObjectName.getInstance(onStr);
        assertTrue("ObjectName not registered " + on, mejb.isRegistered(on));

        for (int i = 0; i < tests.length; i++) {

            boolean isObjectName = tests[i].isObjectName;

            Object o = mejb.getAttribute(on, tests[i].name);
            assertNotNull("Cannot retrieve attribute '" + tests[i].name
                    + "' from " + on, o);
            assertEquals("Expecting type " + tests[i].type + " for attribute "
                    + tests[i].name, tests[i].type, o.getClass());
            if (tests[i].type.isArray()) {
                Object[] a1 = (Object[]) o;
                Object[] a2 = (Object[]) tests[i].expected;
                assertEquals("'" + tests[i].name + "' Array size error", a2.length, a1.length);

                for (int j = 0; j < a1.length; j++) {
                    if (isObjectName) {
                        assertEquals("'" + tests[i].name + "[" + j + "]'  mismatch", new ObjectName((String) a2[j]), new ObjectName((String) a1[j]));
                    } else {
                        assertEquals("'" + tests[i].name + "[" + j + "]'  mismatch", a2[j], a1[j]);
                    }
                }
            } else {
                if (isObjectName) {
                    assertEquals("'" + tests[i].name + "' mismatch", new ObjectName((String) tests[i].expected), new ObjectName((String) o));
                } else {
                    assertEquals("'" + tests[i].name + "' mismatch", tests[i].expected, o);
                }
            }
        }
    }

}
