org.ow2.petals.binding.soapproxy.SoapComponentContext.java Source code

Java tutorial

Introduction

Here is the source code for org.ow2.petals.binding.soapproxy.SoapComponentContext.java

Source

/**
 * PETALS - PETALS Services Platform. Copyright (c) 2007 EBM Websourcing,
 * http://www.ebmwebsourcing.com/
 * 
 * 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 (at your option)
 * 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.ow2.petals.binding.soapproxy;

import java.net.URI;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;

import javax.jbi.component.ComponentContext;
import javax.jbi.messaging.MessagingException;
import javax.xml.namespace.QName;

import org.apache.axis2.context.ConfigurationContext;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.ow2.petals.binding.soapproxy.listener.outgoing.ServiceClient;
import org.ow2.petals.binding.soapproxy.listener.outgoing.ServiceClientPoolObjectFactory;
import org.ow2.petals.component.framework.api.Message.MEPConstants;
import org.ow2.petals.component.framework.jbidescriptor.generated.Component;

/**
 * The SOAP component context. The context is filled by the SU listener (adding
 * modules, service descriptions...) and used by the listeners/workers.
 * 
 * @author Christophe HAMERLING (chamerling) - eBMWebSourcing
 * 
 */
public class SoapComponentContext {

    private class ServiceClientKey {
        protected final String address;

        protected final String operation;

        protected final URI mep;

        /**
         * Creates a new instance of ServiceClientKey
         * 
         * @param address
         * @param operation
         * @param mep
         */
        public ServiceClientKey(final String address, final String operation, final URI mep) {
            this.address = address;
            this.operation = operation;
            this.mep = mep;
        }

        /*
         * (non-Javadoc)
         * 
         * @see java.lang.Object#equals(java.lang.Object)
         */
        @Override
        public boolean equals(final Object obj) {
            final boolean bRes;

            if (obj instanceof ServiceClientKey) {
                bRes = this.address.equals(((ServiceClientKey) obj).address)
                        && this.operation.equals(((ServiceClientKey) obj).operation)
                        && this.mep.equals(((ServiceClientKey) obj).mep);
            } else {
                bRes = false;
            }

            return bRes;
        }

        /*
         * (non-Javadoc)
         * 
         * @see java.lang.Object#hashCode()
         */
        @Override
        public int hashCode() {
            return this.address.hashCode() + this.operation.hashCode() + this.mep.hashCode();
        }
    }

    private ConfigurationContext axis2ConfigurationContext;

    /**
     * The pools of service clients used to call external web services. Key is a
     * ServiceClientKey object, value is a pool of service clientstring
     * containing parameters.
     */
    private final Map<ServiceClientKey, ObjectPool> serviceClientPools;

    /**
     * The component configuration information
     */
    private Component componentConfiguration;

    /**
     * The logger
     */
    private final Logger logger;

    /**
     * Creates a new instance of SoapComponentContext
     * 
     * @param context
     * @param componentConfiguration
     * @param logger
     */
    public SoapComponentContext(final ComponentContext context, final Component componentConfiguration,
            final Logger logger) {
        this.logger = logger;
        this.componentConfiguration = componentConfiguration;

        // Service client pools creation
        this.serviceClientPools = new ConcurrentHashMap<ServiceClientKey, ObjectPool>();
    }

    /**
     * 
     * @return
     */
    public Component getComponentConfiguration() {
        return this.componentConfiguration;
    }

    /**
     * 
     * @param componentConfiguration
     */
    public void setComponentConfiguration(final Component componentConfiguration) {
        this.componentConfiguration = componentConfiguration;
    }

    /**
     * <p>
     * Get a service client associated to an axis service set with the good
     * operation. It is taken from a pool object.
     * </p>
     * <p>
     * <b>This service client must be returned to the pool after usage using
     * API:
     * <code>{@link #returnServiceClient(String, QName, URI, ServiceClient)}</code>
     * .</b>
     * </p>
     * 
     * @param address
     *            the address of the service, mainly used as key to retrieve the
     *            associated SU.
     * @param operation
     *            the target operation QName. Non null
     * @param mep
     *            the message exchange pattern used. Non null
     * @param cdkExtensions
     *            SU extensions used by the service client pool when the
     *            creation of a service client is needed
     * @param provides
     *            the provides block of the endpoint which is creating the
     *            external WS call
     * @param ramprtUserName
     * @return a ServiceClient. Not null. Must be returned to the pool after
     *         usage using API:
     *         <code>{@link #returnServiceClient(String, QName, URI, ServiceClient)}</code>
     * @throws HandlingException
     */
    public ServiceClient borrowServiceClient(final String address, final QName operation, final String soapAction,
            final URI mep) throws MessagingException {

        try {

            String resolvedOp;
            if (operation != null) {
                resolvedOp = operation.toString();
            } else if (soapAction != null) {
                resolvedOp = soapAction;
            } else {
                throw new MessagingException(
                        "Unable to resolve the operation. Set it in the Jbi exchange or SoapAction.");
            }

            final ServiceClientKey key = new ServiceClientKey(address, resolvedOp, mep);
            ObjectPool pool = this.serviceClientPools.get(key);
            if (pool == null) {
                // TODO: The pool max size should be limited by the JBI worker
                // number
                pool = new GenericObjectPool(
                        // object factory
                        new ServiceClientPoolObjectFactory(address, operation, mep, this, this.logger, soapAction),

                        // max number of borrowed object sized to the number of
                        // JBI message processors
                        this.componentConfiguration.getProcessorPoolSize().getValue(),

                        // getting an object blocks until a new or idle object
                        // is available
                        GenericObjectPool.WHEN_EXHAUSTED_BLOCK,

                        // if getting an object is blocked for at most this
                        // delay, a NoSuchElementException will be thrown. In
                        // case of a synchronous call the delay is sized to the
                        // value of the SU's parameter "synchronous-timeout",
                        // otherwise it sized to 5 minutes.
                        MEPConstants.IN_OUT_PATTERN.equals(mep) || MEPConstants.IN_OPTIONAL_OUT_PATTERN.equals(mep)
                                ? 300000l
                                : 300000l,

                        // max number of idle object in the pool. Sized to the
                        // number of JBI acceptors.
                        this.componentConfiguration.getAcceptorPoolSize().getValue(),

                        // min number of idle object in the pool. Sized to 0
                        // (ie when no activity no object in pool)
                        GenericObjectPool.DEFAULT_MIN_IDLE,

                        // no validation test of the borrowed object
                        false,

                        // no validation test of the returned object
                        false,

                        // how long the eviction thread should sleep before
                        // "runs" of examining idle objects. Sized to 5min.
                        300000l,

                        // the number of objects examined in each run of the
                        // idle object evictor. Size to the default value (ie.
                        // 3)
                        GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,

                        // the minimum amount of time that an object may sit
                        // idle in the pool before it is eligible for eviction
                        // due to idle time. Sized to 30min
                        GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,

                        // no validation test of the idle object
                        false,

                        // the minimum amount of time an object may sit idle in
                        // the pool before it is eligible for eviction by the
                        // idle object evictor (if any), with the extra
                        // condition that at least "minIdle" amount of object
                        // remain in the pool.
                        GenericObjectPool.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS,

                        // the pool returns idle objects in last-in-first-out
                        // order
                        true);

                this.serviceClientPools.put(key, pool);
            }

            return (ServiceClient) pool.borrowObject();

        } catch (final Exception e) {
            throw new MessagingException("Can't create get an Axis service client from the pool", e);
        }
    }

    /**
     * Release the service client to the pool
     * 
     * @param address
     * @param operation
     * @param mep
     * @param serviceClient
     * @throws MessagingException
     */
    public void returnServiceClient(final String address, final QName operation, final URI mep,
            final ServiceClient serviceClient, final String soapAction) throws MessagingException {

        try {

            String resolvedOp = null;
            if (operation != null) {
                resolvedOp = operation.toString();
            } else if (soapAction != null) {
                resolvedOp = soapAction;
            } else {
                throw new MessagingException(
                        "Unable to resolve the operation. Set it in the Jbi exchange or SoapAction.");
            }

            ObjectPool pool = this.serviceClientPools.get(new ServiceClientKey(address, resolvedOp, mep));
            if (pool != null) {
                pool.returnObject(serviceClient);
            }

        } catch (final Exception e) {
            throw new MessagingException("Can't return the Axis service client to the pool", e);
        }
    }

    /**
     * @return the axis2ConfigurationContext
     */
    public ConfigurationContext getAxis2ConfigurationContext() {
        return this.axis2ConfigurationContext;
    }

    /**
     * @param axis2ConfigurationContext
     *            the axis2ConfigurationContext to set
     */
    public void setAxis2ConfigurationContext(ConfigurationContext axis2ConfigurationContext) {
        this.axis2ConfigurationContext = axis2ConfigurationContext;
    }
}