/**
 * Copyright (c) 2011-2012 EBM WebSourcing, 2012-2024 Linagora
 * 
 * This program/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 (at your
 * option) any later version.
 * 
 * This program/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 program/library; If not, see http://www.gnu.org/licenses/
 * for the GNU Lesser General Public License version 2.1.
 */
package org.ow2.petals.binding.soap;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.logging.Logger;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;

import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.junit.Test;
import org.mockito.Mockito;
import org.ow2.petals.binding.soap.exception.ServiceClientPoolExhaustedException;
import org.ow2.petals.binding.soap.monitoring.Monitoring;
import org.ow2.petals.component.framework.AbstractComponent;
import org.ow2.petals.component.framework.api.Message.MEPConstants;
import org.ow2.petals.component.framework.api.configuration.ConfigurationExtensions;
import org.ow2.petals.component.framework.api.configuration.SuConfigurationParameters;
import org.ow2.petals.component.framework.api.util.Placeholders;
import org.ow2.petals.component.framework.jbidescriptor.generated.Component;
import org.ow2.petals.component.framework.jbidescriptor.generated.Provides;
import org.ow2.petals.component.framework.jbidescriptor.generated.Runtimepositivestrictint;
import org.ow2.petals.probes.api.exceptions.ProbeException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.ebmwebsourcing.easycommons.xml.DocumentBuilders;

import junit.framework.TestCase;

public class SoapComponentContextTest {
    
    private final static Logger LOG = Logger.getLogger(SoapComponentContextTest.class.getName());
    
    private final static int ACCEPTOR_POOL_SIZE = 1;
    
    private final static int PROCESSOR_MAX_POOL_SIZE = 5;

    private final Monitoring monitoringMbean;

    {
        try {
            this.monitoringMbean = new Monitoring(new Timer("Monitoring sampler", true), 300000);
        } catch (final ProbeException e) {
            e.printStackTrace();
            throw new AssertionError(e);
        }
    }

    /**
     * <p>
     * Check the max size of the web-service client pool if parameter
     * 'max-http-connections-per-host' is unset:
     * </p>
     * <ul>
     * <li>it is equals to the max size of the processor pool,</li>
     * <li>
     * check that the right exception is thrown when the pool is exhausted,</li>
     * <li>web-service client is available after one was returned</li>
     * </ul>
     */
    @Test
    public void testBorrowServiceClient_002() throws Exception {
        
        final Component componentCfg = new Component();

        final Runtimepositivestrictint acceptorPoolSize = new Runtimepositivestrictint();
        acceptorPoolSize.setValue(ACCEPTOR_POOL_SIZE);
        componentCfg.setAcceptorPoolSize(acceptorPoolSize);
        
        final Runtimepositivestrictint processorMaxPoolSize = new Runtimepositivestrictint();
        processorMaxPoolSize.setValue(PROCESSOR_MAX_POOL_SIZE);
        componentCfg.setProcessorMaxPoolSize(processorMaxPoolSize);
        
        final AbstractComponent soapComponentMock = Mockito.mock(AbstractComponent.class);
        Mockito.when(soapComponentMock.getPlaceHolders()).thenReturn(new Placeholders());

        final SoapComponentContext context = new SoapComponentContext(
                ConfigurationContextFactory.createBasicConfigurationContext("jbi/axis2.xml"), soapComponentMock,
                componentCfg, new ConfigurationExtensions(componentCfg.getAny()), this.monitoringMbean, LOG);
        
        final Provides provides = new Provides();
        provides.setEndpointName("MyEndpoint");
        provides.setTimeout("1000");
        final ServiceContext<Provides> serviceCtx = context.getProvidersManager()
                .createServiceContext(provides);
        serviceCtx.setClassloader(Thread.currentThread().getContextClassLoader());
        serviceCtx.setExtensions(new SuConfigurationParameters(null, new Placeholders()));
        serviceCtx.setLogger(LOG);
        
        this.monitoringMbean.init();
        this.monitoringMbean.setHttpThreadPool(null);
        this.monitoringMbean.setWsClientPools(context.getServiceClientPools());
        this.monitoringMbean.start();
        final String address = "MyAddress";
        final List<ServiceClient> serviceClients = new ArrayList<ServiceClient>();
        try {
            for (int i = 0; i < PROCESSOR_MAX_POOL_SIZE; i++) {
                final ServiceClient psc = context.borrowServiceClient(address, new QName("MyOperation"),
                        "MySoapAction", MEPConstants.IN_OUT_PATTERN.value(), serviceCtx);
                TestCase.assertNotNull("The web-service client is null", psc);
                serviceClients.add(psc);
            }
        } catch (final ServiceClientPoolExhaustedException e) {
            TestCase.fail("The pool of web-service can't be increased to the number of message exchange processors.");
        }

        try {
            context.borrowServiceClient(address, new QName("MyOperation"), "MySoapAction",
                    MEPConstants.IN_OUT_PATTERN.value(), serviceCtx);
            TestCase.fail("The pool of web-service is bigger than the message exchange processor.");
        } catch (final ServiceClientPoolExhaustedException e) {
            // Expected exception: no more web-service client is available, and
            // the pool can not be extended.
        }

        context.returnServiceClient(serviceClients.remove(0));

        try {
            final ServiceClient psc = context.borrowServiceClient(address, new QName("MyOperation"),
                    "MySoapAction", MEPConstants.IN_OUT_PATTERN.value(), serviceCtx);
            TestCase.assertNotNull("The web-service client is null", psc);
            serviceClients.add(psc);
        } catch (final ServiceClientPoolExhaustedException e) {
            TestCase.fail("The pool of web-service is exhausted.");
        }
    }

    /**
     * <p>
     * Check the value returns by
     * {@link SoapComponentContext#getConnMaxSize()} if parameter
     * 'max-http-connections-per-host' is set to a valid value.
     * </p>
     * <p>
     * Expected value is its default value: max size of the processor pool.
     * </p>
     * @throws Exception 
     */
    @Test
    public void testGetWsClientMaxPoolSize_000() throws Exception {

        final int wsClientMaxPoolSize = 23;

        final Component componentCfg = new Component();

        final Runtimepositivestrictint acceptorPoolSize = new Runtimepositivestrictint();
        acceptorPoolSize.setValue(ACCEPTOR_POOL_SIZE);
        componentCfg.setAcceptorPoolSize(acceptorPoolSize);

        final Runtimepositivestrictint processorMaxPoolSize = new Runtimepositivestrictint();
        processorMaxPoolSize.setValue(PROCESSOR_MAX_POOL_SIZE);
        componentCfg.setProcessorMaxPoolSize(processorMaxPoolSize);

        final DocumentBuilder docBuilder = DocumentBuilders.takeDocumentBuilder();
        final Document doc = docBuilder.newDocument();
        final Element wsClientPoolSizeMaxElt = doc.createElementNS(
                "http://petals.ow2.org/components/soap/version-4", SoapConstants.WsClients.MAX_HTTP_CONNECTIONS_PER_HOST);
        wsClientPoolSizeMaxElt.setTextContent(String.valueOf(wsClientMaxPoolSize));
        componentCfg.getAny().add(wsClientPoolSizeMaxElt);

        final SoapComponentContext context = new SoapComponentContext(
                ConfigurationContextFactory.createBasicConfigurationContext("jbi/axis2.xml"),
                Mockito.mock(AbstractComponent.class), componentCfg,
                new ConfigurationExtensions(componentCfg.getAny()), this.monitoringMbean, LOG);

        TestCase.assertEquals("The configured value is not used", wsClientMaxPoolSize,
                context.getConnMaxSize());
    }

    /**
     * <p>
     * Check the value returns by
     * {@link SoapComponentContext#getConnMaxSize()} if parameter
     * 'max-http-connections-per-host' is negative.
     * </p>
     * <p>
     * Expected value is its default value: max size of the processor pool.
     * </p>
     * @throws Exception 
     */
    @Test
    public void testGetWsClientMaxPoolSize_100() throws Exception {

        final Component componentCfg = new Component();

        final Runtimepositivestrictint acceptorPoolSize = new Runtimepositivestrictint();
        acceptorPoolSize.setValue(ACCEPTOR_POOL_SIZE);
        componentCfg.setAcceptorPoolSize(acceptorPoolSize);

        final Runtimepositivestrictint processorMaxPoolSize = new Runtimepositivestrictint();
        processorMaxPoolSize.setValue(PROCESSOR_MAX_POOL_SIZE);
        componentCfg.setProcessorMaxPoolSize(processorMaxPoolSize);

        final DocumentBuilder docBuilder = DocumentBuilders.takeDocumentBuilder();
        final Document doc = docBuilder.newDocument();
        final Element wsClientPoolSizeMaxElt = doc.createElementNS(
                "http://petals.ow2.org/components/soap/version-4", SoapConstants.WsClients.MAX_HTTP_CONNECTIONS_PER_HOST);
        wsClientPoolSizeMaxElt.setTextContent("-15");
        componentCfg.getAny().add(wsClientPoolSizeMaxElt);

        final SoapComponentContext context = new SoapComponentContext(
                ConfigurationContextFactory.createBasicConfigurationContext("jbi/axis2.xml"),
                Mockito.mock(AbstractComponent.class), componentCfg,
                new ConfigurationExtensions(componentCfg.getAny()), this.monitoringMbean, LOG);

        TestCase.assertEquals("Default value is not returned", PROCESSOR_MAX_POOL_SIZE,
                context.getConnMaxSize());
    }

    /**
     * <p>
     * Check the value returns by
     * {@link SoapComponentContext#getConnMaxSize()} if parameter
     * 'max-http-connections-per-host' is set to 0.
     * </p>
     * <p>
     * Expected value is its default value: max size of the processor pool.
     * </p>
     * @throws Exception 
     */
    @Test
    public void testGetWsClientMaxPoolSize_101() throws Exception {

        final Component componentCfg = new Component();

        final Runtimepositivestrictint acceptorPoolSize = new Runtimepositivestrictint();
        acceptorPoolSize.setValue(ACCEPTOR_POOL_SIZE);
        componentCfg.setAcceptorPoolSize(acceptorPoolSize);

        final Runtimepositivestrictint processorMaxPoolSize = new Runtimepositivestrictint();
        processorMaxPoolSize.setValue(PROCESSOR_MAX_POOL_SIZE);
        componentCfg.setProcessorMaxPoolSize(processorMaxPoolSize);

        final DocumentBuilder docBuilder = DocumentBuilders.takeDocumentBuilder();
        final Document doc = docBuilder.newDocument();
        final Element wsClientPoolSizeMaxElt = doc.createElementNS(
                "http://petals.ow2.org/components/soap/version-4", SoapConstants.WsClients.MAX_HTTP_CONNECTIONS_PER_HOST);
        wsClientPoolSizeMaxElt.setTextContent("0");
        componentCfg.getAny().add(wsClientPoolSizeMaxElt);

        final SoapComponentContext context = new SoapComponentContext(
                ConfigurationContextFactory.createBasicConfigurationContext("jbi/axis2.xml"),
                Mockito.mock(AbstractComponent.class), componentCfg,
                new ConfigurationExtensions(componentCfg.getAny()), this.monitoringMbean, LOG);

        TestCase.assertEquals("Default value is not returned", PROCESSOR_MAX_POOL_SIZE,
                context.getConnMaxSize());
    }

    /**
     * <p>
     * Check the value returns by
     * {@link SoapComponentContext#getConnMaxSize()} if parameter
     * 'max-http-connections-per-host' is set to not number value.
     * </p>
     * <p>
     * Expected value is its default value: max size of the processor pool.
     * </p>
     * @throws Exception 
     */
    @Test
    public void testGetWsClientMaxPoolSize_102() throws Exception {

        final Component componentCfg = new Component();

        final Runtimepositivestrictint acceptorPoolSize = new Runtimepositivestrictint();
        acceptorPoolSize.setValue(ACCEPTOR_POOL_SIZE);
        componentCfg.setAcceptorPoolSize(acceptorPoolSize);

        final Runtimepositivestrictint processorMaxPoolSize = new Runtimepositivestrictint();
        processorMaxPoolSize.setValue(PROCESSOR_MAX_POOL_SIZE);
        componentCfg.setProcessorMaxPoolSize(processorMaxPoolSize);

        final DocumentBuilder docBuilder = DocumentBuilders.takeDocumentBuilder();
        final Document doc = docBuilder.newDocument();
        final Element wsClientPoolSizeMaxElt = doc.createElementNS(
                "http://petals.ow2.org/components/soap/version-4", SoapConstants.WsClients.MAX_HTTP_CONNECTIONS_PER_HOST);
        wsClientPoolSizeMaxElt.setTextContent("abcdef");
        componentCfg.getAny().add(wsClientPoolSizeMaxElt);

        final SoapComponentContext context = new SoapComponentContext(
                ConfigurationContextFactory.createBasicConfigurationContext("jbi/axis2.xml"),
                Mockito.mock(AbstractComponent.class), componentCfg,
                new ConfigurationExtensions(componentCfg.getAny()), this.monitoringMbean, LOG);

        TestCase.assertEquals("Default value is not returned", PROCESSOR_MAX_POOL_SIZE,
                context.getConnMaxSize());
    }

    /**
     * <p>
     * Check the value returns by
     * {@link SoapComponentContext#getConnMaxSize()} if parameter
     * 'max-http-connections-per-host' is set to an empty {@link String}.
     * </p>
     * <p>
     * Expected value is its default value: max size of the processor pool.
     * </p>
     * @throws Exception 
     */
    @Test
    public void testGetWsClientMaxPoolSize_103() throws Exception {

        final Component componentCfg = new Component();

        final Runtimepositivestrictint acceptorPoolSize = new Runtimepositivestrictint();
        acceptorPoolSize.setValue(ACCEPTOR_POOL_SIZE);
        componentCfg.setAcceptorPoolSize(acceptorPoolSize);

        final Runtimepositivestrictint processorMaxPoolSize = new Runtimepositivestrictint();
        processorMaxPoolSize.setValue(PROCESSOR_MAX_POOL_SIZE);
        componentCfg.setProcessorMaxPoolSize(processorMaxPoolSize);

        final DocumentBuilder docBuilder = DocumentBuilders.takeDocumentBuilder();
        final Document doc = docBuilder.newDocument();
        final Element wsClientPoolSizeMaxElt = doc.createElementNS(
                "http://petals.ow2.org/components/soap/version-4", SoapConstants.WsClients.MAX_HTTP_CONNECTIONS_PER_HOST);
        wsClientPoolSizeMaxElt.setTextContent("");
        componentCfg.getAny().add(wsClientPoolSizeMaxElt);

        final SoapComponentContext context = new SoapComponentContext(
                ConfigurationContextFactory.createBasicConfigurationContext("jbi/axis2.xml"),
                Mockito.mock(AbstractComponent.class), componentCfg,
                new ConfigurationExtensions(componentCfg.getAny()), this.monitoringMbean, LOG);

        TestCase.assertEquals("Default value is not returned", PROCESSOR_MAX_POOL_SIZE,
                context.getConnMaxSize());
    }

    // TODO: Add test about unset parameters (a null value for each parameter should use the default value) 

}
