# BaseConfiguration.java

    /**
     *  Copyright (c) 2009, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
     *
     *  Licensed under the Apache License, Version 2.0 (the "License");
     *  you may not use this file except in compliance with the License.
     *  You may obtain a copy of the License at
     *
     *        http://www.apache.org/licenses/LICENSE-2.0
     *
     *  Unless required by applicable law or agreed to in writing, software
     *  distributed under the License is distributed on an "AS IS" BASIS,
     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     *  See the License for the specific language governing permissions and
     *  limitations under the License.
     */

    package org.apache.synapse.transport.passthru.config;

    import org.apache.axis2.AxisFault;
    import org.apache.axis2.context.ConfigurationContext;
    import org.apache.axis2.description.ParameterInclude;
    import org.apache.axis2.transport.base.threads.WorkerPool;
    import org.apache.axis2.transport.base.threads.WorkerPoolFactory;
    import org.apache.http.impl.nio.reactor.IOReactorConfig;
    import org.apache.http.nio.util.HeapByteBufferAllocator;
    import org.apache.http.params.BasicHttpParams;
    import org.apache.http.params.HttpConnectionParams;
    import org.apache.http.params.HttpParams;
    import org.apache.http.params.HttpProtocolParams;
    import org.apache.http.protocol.HTTP;
    import org.apache.synapse.transport.passthru.PassThroughConstants;
    import org.apache.synapse.transport.passthru.jmx.PassThroughTransportMetricsCollector;
    import org.apache.synapse.transport.passthru.util.BufferFactory;

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;

    /**
     * This class has common configurations for both sender and receiver.
     */
    public abstract class BaseConfiguration {

        /**
         * Configurations given by axis2.xml
         */
        protected ParameterInclude parameters = null;

        /** The thread pool for executing the messages passing through */
        private WorkerPool workerPool = null;

        /** The secondary thread pool for executing the messages passing through */
        private WorkerPool secondaryWorkerPool = null;

        /** The Axis2 ConfigurationContext */
        protected ConfigurationContext configurationContext = null;

        /** Default http parameters */
        protected HttpParams httpParams = null;

        protected IOReactorConfig ioReactorConfig = null;

        protected BufferFactory bufferFactory = null;

        /** Weather User-Agent header coming from client should be preserved */
        protected boolean preserveUserAgentHeader = false;
        /** Weather Server header coming from server should be preserved */
        protected boolean preserveServerHeader = true;
        /** Http headers which should be preserved */
        protected List<String> preserveHttpHeaders;

        private PassThroughTransportMetricsCollector metrics = null;

        private int iOBufferSize;

        protected PassThroughConfiguration conf = PassThroughConfiguration.getInstance();

        private static final String PASSTHROUGH_THREAD_GROUP = "Pass-through Message Processing Thread Group";
        private static final String PASSTHROUGH_THREAD_ID ="PassThroughMessageProcessor";

        private static final String SECONDARY_PASSTHROUGH_THREAD_GROUP = "Secondary Pass-through Message Processing "
                + "Thread Group";
        private static final String SECONDARY_PASSTHROUGH_THREAD_ID = "PassThroughMessageSecondaryProcessor";

        private Integer socketTimeout = null;
        private Integer connectionTimeout = null;

        public BaseConfiguration(ConfigurationContext configurationContext,
                                 ParameterInclude parameters,
                                 WorkerPool workerPool,
                                 PassThroughTransportMetricsCollector metrics) {
            this.parameters = parameters;
            this.workerPool = workerPool;
            this.configurationContext = configurationContext;
            this.metrics = metrics;
        }

        public void build() throws AxisFault {
            iOBufferSize = conf.getIOBufferSize();

            if (workerPool == null) {
                workerPool = WorkerPoolFactory.getWorkerPool(
                                conf.getWorkerPoolCoreSize(),
                                conf.getWorkerPoolMaxSize(),
                                conf.getWorkerThreadKeepaliveSec(),
                                conf.getWorkerPoolQueueLen(),
                                PASSTHROUGH_THREAD_GROUP,
                                PASSTHROUGH_THREAD_ID);
            }

            if (secondaryWorkerPool == null) {
                secondaryWorkerPool = WorkerPoolFactory.getWorkerPool(
                        conf.getSecondaryWorkerPoolCoreSize(),
                        conf.getSecondaryWorkerPoolMaxSize(),
                        conf.getSecondaryWorkerThreadKeepaliveSec(),
                        conf.getSecondaryWorkerPoolQueueLen(),
                        SECONDARY_PASSTHROUGH_THREAD_GROUP,
                        SECONDARY_PASSTHROUGH_THREAD_ID);
            }

            httpParams = buildHttpParams();
            ioReactorConfig = buildIOReactorConfig();
            String sysCorrelationStatus = System.getProperty(PassThroughConstants.CORRELATION_LOGS_SYS_PROPERTY);
            if (sysCorrelationStatus != null && !PassThroughCorrelationConfigDataHolder.isEnable()) {
                PassThroughCorrelationConfigDataHolder.setSystemEnable(Boolean.parseBoolean(sysCorrelationStatus));
            }

            bufferFactory = new BufferFactory(iOBufferSize, new HeapByteBufferAllocator(), 512);
        }

        public WorkerPool getWorkerPool(int workerPoolCoreSize, int workerPoolMaxSize,
                                        int workerThreadKeepaliveSec, int workerPoolQueuLen,
                                        String threadGroupName, String threadgroupID) {
            if (threadGroupName == null) {
                threadGroupName = PASSTHROUGH_THREAD_GROUP;
            }
            if (threadgroupID == null) {
                threadgroupID = PASSTHROUGH_THREAD_ID;
            }
            if (workerPoolCoreSize == 0) {
                workerPoolCoreSize = conf.getWorkerPoolCoreSize();
            }
            if (workerPoolMaxSize == 0) {
                workerPoolMaxSize = conf.getWorkerPoolMaxSize();
            }
            if (workerThreadKeepaliveSec == 0) {
                workerThreadKeepaliveSec = conf.getWorkerThreadKeepaliveSec();
            }
            if (workerPoolQueuLen == 0) {
                workerPoolQueuLen = conf.getWorkerPoolQueueLen();
            }
            return WorkerPoolFactory.getWorkerPool(workerPoolCoreSize, workerPoolMaxSize,
                                                   workerThreadKeepaliveSec, workerPoolQueuLen,
                                                   threadGroupName, threadgroupID);
        }

        public int getIOBufferSize() {
            return iOBufferSize;
        }

        public WorkerPool getWorkerPool() {
            return workerPool;
        }
        public WorkerPool getSecondaryWorkerPool() {
            return secondaryWorkerPool;
        }

        public ConfigurationContext getConfigurationContext() {
            return configurationContext;
        }

        protected HttpParams buildHttpParams() {
            HttpParams params = new BasicHttpParams();
            params.
                    setIntParameter(HttpConnectionParams.SO_TIMEOUT, getSocketTimeout()).
                    setIntParameter(HttpConnectionParams.CONNECTION_TIMEOUT, getConnectionTimeout()).
                    setIntParameter(HttpConnectionParams.SOCKET_BUFFER_SIZE,
                            conf.getIntProperty(HttpConnectionParams.SOCKET_BUFFER_SIZE, 8 * 1024)).
                    setParameter(HttpProtocolParams.ORIGIN_SERVER,
                            conf.getStringProperty(HttpProtocolParams.ORIGIN_SERVER, "WSO2-PassThrough-HTTP")).
                    setParameter(HttpProtocolParams.USER_AGENT,
                            conf.getStringProperty(HttpProtocolParams.USER_AGENT, "Synapse-PT-HttpComponents-NIO"));
    //                setParameter(HttpProtocolParams.HTTP_ELEMENT_CHARSET,
    //                        conf.getStringProperty(HttpProtocolParams.HTTP_ELEMENT_CHARSET, HTTP.DEFAULT_PROTOCOL_CHARSET));//TODO:This does not works with HTTPCore 4.3

            return params;
        }

        protected IOReactorConfig buildIOReactorConfig() {
            IOReactorConfig config = new IOReactorConfig();
            config.setIoThreadCount(conf.getIOThreadsPerReactor());
            config.setSoTimeout(getSocketTimeout());
            config.setConnectTimeout(getConnectionTimeout());
            config.setTcpNoDelay(conf.getBooleanProperty(HttpConnectionParams.TCP_NODELAY, true));
            config.setSoLinger(conf.getIntProperty(HttpConnectionParams.SO_LINGER, -1));
            config.setSoReuseAddress(conf.getBooleanProperty(HttpConnectionParams.SO_REUSEADDR, false));
            config.setInterestOpQueued(conf.getBooleanProperty("http.nio.interest-ops-queueing", false));
            config.setSelectInterval(conf.getIntProperty("http.nio.select-interval", 1000));
            return config;
        }

        public BufferFactory getBufferFactory() {
            return bufferFactory;
        }

        public PassThroughTransportMetricsCollector getMetrics() {
            return metrics;
        }

        public Boolean isCorrelationLoggingEnabled() { return PassThroughCorrelationConfigDataHolder.isEnable(); }

        private Integer getSocketTimeout() {
            if (socketTimeout != null) {
                return socketTimeout;
            }
            socketTimeout = conf.getIntProperty(HttpConnectionParams.SO_TIMEOUT, 60000);
            return socketTimeout;
        }

        private Integer getConnectionTimeout() {
            if (connectionTimeout != null) {
                return connectionTimeout;
            }
            connectionTimeout = conf.getIntProperty(HttpConnectionParams.CONNECTION_TIMEOUT, getSocketTimeout() / 2);
            return connectionTimeout;
        }

        /**
         * Check preserving status of the given http header name
         *
         * @param headerName http header name which need to check preserving status
         * @return preserving status of the given http header
         */
        public boolean isPreserveHttpHeader(String headerName) {

            if (preserveHttpHeaders == null || preserveHttpHeaders.isEmpty() || headerName == null) {
                return false;
            }
            return preserveHttpHeaders.contains(headerName.toUpperCase());
        }

        public List<String> getPreserveHttpHeaders() {
            return preserveHttpHeaders;
        }

        /**
         * Populate preserve http headers from comma separate string
         *
         * @param preserveHeaders Comma separated preserve enable http headers
         */
        protected void populatePreserveHttpHeaders(String preserveHeaders) {

            preserveHttpHeaders = new ArrayList<String>();
            if (preserveHeaders != null && !preserveHeaders.isEmpty()) {
                String[] presHeaders = preserveHeaders.trim().toUpperCase().split(",");
                if (presHeaders != null && presHeaders.length > 0) {
                    preserveHttpHeaders.addAll(Arrays.asList(presHeaders));
                }
            }

            if (preserveServerHeader && !preserveHttpHeaders.contains(HTTP.SERVER_HEADER.toUpperCase())) {
                preserveHttpHeaders.add(HTTP.SERVER_HEADER.toUpperCase());
            }

            if (preserveUserAgentHeader && !preserveHttpHeaders.contains(HTTP.USER_AGENT.toUpperCase())) {
                preserveHttpHeaders.add(HTTP.USER_AGENT.toUpperCase());
            }
        }
    }