/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 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.service;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.xml.namespace.QName;

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

import org.custommonkey.xmlunit.Diff;
import org.custommonkey.xmlunit.XMLAssert;
import org.custommonkey.xmlunit.XMLUnit;
import org.objectweb.jonas.jtests.util.JWebServicesTestCase;
import org.ow2.jonas.deployment.common.digester.JDigester;
import org.ow2.jonas.deployment.common.rules.JonasServiceRefRuleSet;
import org.ow2.jonas.deployment.common.rules.ServiceRefRuleSet;
import org.ow2.jonas.deployment.ws.ServiceRefDesc;
import org.ow2.jonas.lib.util.JNDIUtils;
import org.ow2.jonas.ws.axis.JAxisServiceFactory;
import org.ow2.jonas.ws.jaxrpc.factory.JServiceFactory;

/**
 * test case for axis service instanciation
 */
public class F_AxisService extends JWebServicesTestCase {
    private String resources = null;

    private JServiceFactory jfactory = null;

    public F_AxisService(String name) {
        super(name);
    }

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

    public void setUp() throws Exception {
        super.setUp();
        resources = System.getProperty("ws.resources");
        jfactory = new JAxisServiceFactory();
    }

    public void tearDown() throws Exception {
        jfactory = null;
        super.tearDown();
    }

    public void testClientWSDDDefaultWhenWSDDNotSpecified() throws Exception {
        String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                + "<deployment name=\"defaultClientConfig\""
                + " xmlns=\"http://xml.apache.org/axis/wsdd/\""
                + " xmlns:java=\"http://xml.apache.org/axis/wsdd/providers/java\">\n"
                + "    <globalConfiguration>\n"
                + "        <!-- Add global configurations elements here -->\n"
                + "        <parameter name=\"disablePrettyXML\" value=\"true\"/>\n"
                + "        <parameter name=\"sendMultiRefs\" value=\"false\"/>\n"
                + "    </globalConfiguration>\n"
                + "    <transport name=\"http\" pivot=\"java:org.apache.axis.transport.http.HTTPSender\"/>\n"
                + "    <transport name=\"local\" pivot=\"java:org.apache.axis.transport.local.LocalSender\"/>\n"
                + "    <transport name=\"java\" pivot=\"java:org.apache.axis.transport.java.JavaSender\"/>\n"
                + "</deployment>\n";
        Reference ref = createServiceReference("no-wsdd-specified-j2ee.xml",
                "no-wsdd-specified-jonas.xml");
        assertNotNull("Shouldn't have a wsdd", ref.get(JAxisServiceFactory.REF_CLIENT_CONFIG));

        String returned = (String) ref.get(JAxisServiceFactory.REF_CLIENT_CONFIG).getContent();
        XMLUnit.setIgnoreWhitespace(true);
        Diff diff = XMLUnit.compareXML(expected, returned);
        XMLAssert.assertXMLEqual("WSDD are not equivalent", diff, true);
    }

    public void testClientWSDDMergingWhenWSDDSpecified() throws Exception {
        String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                + "<deployment name=\"defaultClientConfig\""
                + " xmlns=\"http://xml.apache.org/axis/wsdd/\""
                + " xmlns:java=\"http://xml.apache.org/axis/wsdd/providers/java\">\n"
                + "    <globalConfiguration>\n"
                + "        <!-- Add global configurations elements here -->\n"
                + "        <parameter name=\"disablePrettyXML\" value=\"true\"/>\n"
                + "        <parameter name=\"sendMultiRefs\" value=\"false\"/>\n"
                + "    </globalConfiguration>\n"
                + "    <transport name=\"http\" pivot=\"java:org.apache.axis.transport.http.HTTPSender\"/>\n"
                + "    <transport name=\"local\" pivot=\"java:org.apache.axis.transport.local.LocalSender\"/>\n"
                + "    <transport name=\"java\" pivot=\"java:org.apache.axis.transport.java.JavaSender\"/>\n"
                + "    <service name=\"HelloService\"/>\n" + "</deployment>\n";
        Reference ref = createServiceReference("wsdd-specified-j2ee.xml",
                "wsdd-specified-jonas.xml");

        String returned = (String) ref.get(JAxisServiceFactory.REF_CLIENT_CONFIG).getContent();
        XMLUnit.setIgnoreWhitespace(true);
        Diff diff = XMLUnit.compareXML(expected, returned);
        XMLAssert.assertXMLEqual("WSDD are not equivalent", diff, true);
    }

    public void testWSDLUrlWithNoWSDLOverride() throws Exception {
        Reference ref = createServiceReference("wsdl-url-default-j2ee.xml",
                "wsdl-url-default-jonas.xml");
        URL urlMatching = new File(new File(resources, "wsdl"), "oneService.wsdl").toURL();
        assertEquals("WSDL URL is not set appropriately",
                     urlMatching.toString(),
                     ref.get(JAxisServiceFactory.REF_SERVICE_WSDL).getContent());
    }

    public void testWSDLUrlWithWSDLOverride() throws Exception {
        Reference ref = createServiceReference("wsdl-url-override-j2ee.xml",
                "wsdl-url-override-jonas.xml");
        // create matching URL
        URL urlMatching = new File(new File(resources, "wsdl"), "twoService.wsdl").toURL();
        assertEquals(
                "WSDL URL is not set appropriately",
                urlMatching.toString(),
                ref.get(JAxisServiceFactory.REF_SERVICE_WSDL).getContent());
    }

    public void testServiceQNameWhenNotSpecified() throws Exception {
        Reference ref = createServiceReference("service-qname-auto-j2ee.xml",
                "service-qname-auto-jonas.xml");
        QName exp = new QName("http://hello.simple", "HelloWsService");
        QName auto = (QName) JNDIUtils.getObjectFromBytes((byte[]) ref.get(
                JAxisServiceFactory.REF_SERVICE_QNAME).getContent());
        assertEquals("Service QName is incorrect", exp, auto);
    }

    public void testServiceQNameWhenExplicitelySet() throws Exception {
        Reference ref = createServiceReference(
                "service-qname-explicit-j2ee.xml",
                "service-qname-explicit-jonas.xml");
        QName exp = new QName("http://hello.simple", "HelloWsService2");
        QName auto = (QName) JNDIUtils.getObjectFromBytes((byte[]) ref.get(
                JAxisServiceFactory.REF_SERVICE_QNAME).getContent());
        assertEquals("Service QName is incorrect", exp, auto);
    }

    public void testPort2WSDLMapWhenNoPortComponentRefSpecified()
            throws Exception {
        Reference ref = createServiceReference("no-port2wsdl-map-j2ee.xml",
                "no-port2wsdl-map-jonas.xml");
        assertNull("Shouldn't have a Port2WSDL Map", ref
                .get(JAxisServiceFactory.REF_SERVICE_PORT2WSDL));
    }

    public void testPort2WSDLMapWithMultiplePortComponent() throws Exception {
        Reference ref = createServiceReference("port2wsdl-map-j2ee.xml",
                "port2wsdl-map-jonas.xml");
        Map exp = new HashMap();
        exp.put("org.objectweb.jonas.jtests.hello.HelloWs", new QName(
                "http://hello.simple", "HelloPortComponent"));
        exp.put("org.objectweb.jonas.jtests.hello.HelloWs2", new QName(
                "http://hello.simple", "HelloPortComponent2"));
        Map returned = (Map) JNDIUtils.getObjectFromBytes((byte[]) ref.get(
                JAxisServiceFactory.REF_SERVICE_PORT2WSDL).getContent());
        assertEquals("Map are not identical", exp, returned);
    }

    public void testStubPropertiesNull() throws Exception {
        Reference ref = createServiceReference("stub-props-null-j2ee.xml",
                "stub-props-null-jonas.xml");
        assertNull("Stub properties should be null", ref
                .get(JAxisServiceFactory.REF_SERVICE_STUB_PROPS
                        + "_HelloPortComponent"));
    }

    public void testStubPropertiesEmpty() throws Exception {
        Reference ref = createServiceReference("stub-props-empty-j2ee.xml",
                "stub-props-empty-jonas.xml");
        RefAddr ra = ref.get(JAxisServiceFactory.REF_SERVICE_STUB_PROPS
                + "_HelloPortComponent");
        assertNull("RefAddr " + JAxisServiceFactory.REF_SERVICE_STUB_PROPS
                + "_HelloPortComponent" + " must be null", ra);
        RefAddr ra2 = ref.get(JAxisServiceFactory.REF_SERVICE_STUB_PROPS
                + "_HelloPortComponent2");
        assertNull("RefAddr " + JAxisServiceFactory.REF_SERVICE_STUB_PROPS
                + "_HelloPortComponent2" + " must be null", ra2);
    }

    public void testStubPropertiesForGivenPortName() throws Exception {
        Reference ref = createServiceReference("stub-props-j2ee.xml",
                "stub-props-jonas.xml");
        // port #1
        RefAddr ra = ref.get(JAxisServiceFactory.REF_SERVICE_STUB_PROPS
                + "_HelloPortComponent");
        assertNotNull("RefAddr " + JAxisServiceFactory.REF_SERVICE_STUB_PROPS
                + "_HelloPortComponent" + " must be not null", ra);
        Map returned = (Map) JNDIUtils.getObjectFromBytes((byte[]) ra
                .getContent());
        assertFalse("Stub properties shouldn't be empty", returned.isEmpty());
        Properties exp = new Properties();
        exp.setProperty("my.test.property", "test.value");
        exp.setProperty("my.test.property.2", "test.value.2");
        assertEquals(
                "Stub Properties for port 'HelloPortComponent' not identical",
                exp, returned);
        // port #2
        RefAddr ra2 = ref.get(JAxisServiceFactory.REF_SERVICE_STUB_PROPS
                + "_HelloPortComponent2");
        assertNotNull("RefAddr " + JAxisServiceFactory.REF_SERVICE_STUB_PROPS
                + "_HelloPortComponent2" + " must be not null", ra2);
        Map returned2 = (Map) JNDIUtils.getObjectFromBytes((byte[]) ra2
                .getContent());
        assertFalse("Stub properties shouldn't be empty", returned2.isEmpty());
        Properties exp2 = new Properties();
        exp2.setProperty("other.test.property", "test.value");
        exp2.setProperty("other.test.property.2", "test.value.2");
        assertEquals(
                "Stub Properties for port 'HelloPortComponent' not identical",
                exp2, returned2);
    }

    public void testCallPropertiesNull() throws Exception {
        Reference ref = createServiceReference("call-props-null-j2ee.xml",
                "call-props-null-jonas.xml");
        assertNull("Call properties should be null", ref
                .get(JAxisServiceFactory.REF_SERVICE_CALL_PROPS
                        + "_HelloPortComponent"));
    }

    public void testCallPropertiesEmpty() throws Exception {
        Reference ref = createServiceReference("call-props-empty-j2ee.xml",
                "call-props-empty-jonas.xml");
        RefAddr ra = ref.get(JAxisServiceFactory.REF_SERVICE_CALL_PROPS
                + "_HelloPortComponent");
        assertNull("RefAddr " + JAxisServiceFactory.REF_SERVICE_CALL_PROPS
                + "_HelloPortComponent" + " must be null", ra);
        RefAddr ra2 = ref.get(JAxisServiceFactory.REF_SERVICE_CALL_PROPS
                + "_HelloPortComponent2");
        assertNull("RefAddr " + JAxisServiceFactory.REF_SERVICE_CALL_PROPS
                + "_HelloPortComponent2" + " must be null", ra2);
    }

    public void testCallPropertiesForGivenPortName() throws Exception {
        Reference ref = createServiceReference("call-props-j2ee.xml",
                "call-props-jonas.xml");
        // port #1
        RefAddr ra = ref.get(JAxisServiceFactory.REF_SERVICE_CALL_PROPS
                + "_HelloPortComponent");
        assertNotNull("RefAddr " + JAxisServiceFactory.REF_SERVICE_CALL_PROPS
                + "_HelloPortComponent" + " must be not null", ra);
        Map returned = (Map) JNDIUtils.getObjectFromBytes((byte[]) ra
                .getContent());
        assertFalse("Stub properties shouldn't be empty", returned.isEmpty());
        Properties exp = new Properties();
        exp.setProperty("my.test.property", "test.value");
        exp.setProperty("my.test.property.2", "test.value.2");
        assertEquals(
                "Stub Properties for port 'HelloPortComponent' not identical",
                exp, returned);
        // port #2
        RefAddr ra2 = ref.get(JAxisServiceFactory.REF_SERVICE_CALL_PROPS
                + "_HelloPortComponent2");
        assertNotNull("RefAddr " + JAxisServiceFactory.REF_SERVICE_CALL_PROPS
                + "_HelloPortComponent2" + " must be not null", ra2);
        Map returned2 = (Map) JNDIUtils.getObjectFromBytes((byte[]) ra2
                .getContent());
        assertFalse("Call properties shouldn't be empty", returned2.isEmpty());
        Properties exp2 = new Properties();
        exp2.setProperty("other.test.property", "test.value");
        exp2.setProperty("other.test.property.2", "test.value.2");
        assertEquals(
                "Call Properties for port 'HelloPortComponent' not identical",
                exp2, returned2);
    }

    public void testPortNameListEmpty() throws Exception {
        Reference ref = createServiceReference("port-name-list-empty-j2ee.xml",
                "port-name-list-empty-jonas.xml");
        assertNull(JAxisServiceFactory.REF_SERVICE_WSDL_PORT_LIST
                + " should be null", ref
                .get(JAxisServiceFactory.REF_SERVICE_WSDL_PORT_LIST));
    }

    public void testPortNameListWithMultiplePortComponent() throws Exception {
        Reference ref = createServiceReference("port-name-list-j2ee.xml",
                "port-name-list-jonas.xml");
        RefAddr ra = ref.get(JAxisServiceFactory.REF_SERVICE_WSDL_PORT_LIST);
        assertNotNull(JAxisServiceFactory.REF_SERVICE_WSDL_PORT_LIST
                + " shouldn't be null", ra);
        assertEquals("portname list incorrect",
                "HelloPortComponent,HelloPortComponent2", ra.getContent());
    }

    private Reference createServiceReference(String standard, String specific)
            throws Exception {
        // Get a ServiceRef for the test
        ServiceRefDesc sr = createServiceRefDesc(standard, specific);
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return jfactory.getServiceReference(sr, cl);
    }

    public void testGetObjectInstance() throws Exception {
        String cfg = "<deployment xmlns=\"http://xml.apache.org/axis/wsdd/\" "
                + "xmlns:java=\"http://xml.apache.org/axis/wsdd/providers/java\">"
                + "<service name=\"AxisServiceTest\"/>"
                + "<transport name=\"java\" pivot=\"java:org.apache.axis.transport.java.JavaSender\"/>"
                + "<transport name=\"http\" pivot=\"java:org.apache.axis.transport.http.HTTPSender\"/>"
                + "<transport name=\"local\" pivot=\"java:org.apache.axis.transport.local.LocalSender\"/>"
                + "</deployment>";
        Reference ref = new Reference(
                "org.objectweb.jonas.jtests.hello.HelloWsServiceLocator",
                jfactory.getClass().getName(), null);
        ref.add(new StringRefAddr(JAxisServiceFactory.REF_CLIENT_CONFIG, cfg));
        try {
            jfactory.getObjectInstance(ref, null, null, null);
        } catch (Exception e) {
            fail("JAxisServiceFactory.getObjectInstance has failed " + e);
        }
        // cannot success when using Proxies
    }

    private ServiceRefDesc createServiceRefDesc(String srFilename,
            String jsrFilename) throws Exception {
        // Get Context ClassLoader
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        ServiceRefTLE srTopLevel = new ServiceRefTLE();
        // Load ServiceRef Object
        //-----------------------------
        // Create Digester
        JDigester serviceRefDigester = new JDigester(new ServiceRefRuleSet(""),
                false, true, null, null);
        // Get Reader
        Reader r = new InputStreamReader(cl.getResourceAsStream(srFilename));
        // Parse
        serviceRefDigester.parse(r, srFilename, srTopLevel);
        // Load JonasServiceRef Object
        //-----------------------------
        // Create Digester
        JDigester jonasServiceRefDigester = new JDigester(
                new JonasServiceRefRuleSet(""), false, true, null, null);

        // Read xml file and modify path containing RESOURCES_DIR
        InputStream contentIs = cl.getResourceAsStream(jsrFilename);
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(contentIs));
        StringWriter stringWriter = new StringWriter();
        String line = null;
        while (((line = bufferedReader.readLine()) != null)) {
            if (line.indexOf("@@RESOURCES_DIR@@") != -1) {
                line = line.replaceAll("@@RESOURCES_DIR@@", "file://" + resources);
            }
            stringWriter.write(line);
        }



        // Get Reader
        r = new StringReader(stringWriter.toString());
        bufferedReader.close();
        stringWriter.close();
        // Parse
        jonasServiceRefDigester.parse(r, jsrFilename, srTopLevel);
        ServiceRefDesc sr = new ServiceRefDesc(cl, srTopLevel.getServiceRef(),
                srTopLevel.getJonasServiceRef(), resources);

        return sr;
    }

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