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

Java tutorial

Introduction

Here is the source code for org.ow2.petals.binding.soap.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.soap;

import java.io.File;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
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.soap.listener.outgoing.ServiceClient;
import org.ow2.petals.binding.soap.listener.outgoing.ServiceClientPoolObjectFactory;
import org.ow2.petals.binding.soap.util.SUPropertiesHelper;
import org.ow2.petals.component.framework.api.Message.MEPConstants;
import org.ow2.petals.component.framework.api.configuration.ConfigurationExtensions;
import org.ow2.petals.component.framework.jbidescriptor.generated.Component;
import org.ow2.petals.component.framework.jbidescriptor.generated.Consumes;
import org.ow2.petals.component.framework.jbidescriptor.generated.Jbi;
import org.ow2.petals.component.framework.jbidescriptor.generated.Provides;
import org.ow2.petals.ws.notification.WsnManager;
import org.ow2.petals.ws.notification.WsnPersistance;
import org.ow2.petals.ws.notification.handlers.request.GetCurrentMessageHandler;
import org.ow2.petals.ws.notification.handlers.request.SubscribeHandler;
import org.ow2.petals.ws.notification.handlers.request.UnsubscribeHandler;

/**
 * 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();
        }
    }

    public class ServiceManager<E> {
        private final Map<E, ServiceContext<E>> contexts;

        public ServiceManager() {
            this.contexts = new HashMap<E, ServiceContext<E>>();
        }

        /**
         * 
         * @param consumes
         * @return
         */
        public ServiceContext<E> createServiceContext(final E e) {
            ServiceContext<E> context = new ServiceContext<E>(e);
            this.contexts.put(e, context);
            return context;
        }

        /**
         * Delete the service context
         * 
         * @param consumes
         */
        public ServiceContext<E> deleteServiceContext(final E e) {
            return this.contexts.remove(e);
        }

        /**
         * 
         * @param e
         * @param modulesList
         */
        public void addModules(final E e, final List<String> modulesList) {
            if (e == null) {
                throw new IllegalArgumentException("Block can not be null");
            }
            ServiceContext<E> serviceContext = getServiceContext(e);
            if (serviceContext == null) {
                serviceContext = createServiceContext(e);
            }
            serviceContext.setModules(modulesList);
        }

        /**
         * @param
         * @return
         */
        public ServiceContext<E> getServiceContext(final E e) {
            return this.contexts.get(e);
        }

        /**
         * Get the modules
         * 
         * @param address
         * @return the modules of the given consumes block. Should at least
         *         contains the addressing module
         */
        public List<String> getModules(final E e) {
            ServiceContext<E> ctx = getServiceContext(e);
            if (ctx != null) {
                return ctx.getModules();
            }
            return null;
        }

        /**
         * Set parameters to a serviceAddress
         * 
         * @param serviceAddress
         *            the service address
         * @param parameters
         *            the parameters to set
         */
        public void setServicePamameters(final E e, final String parameters) {
            if (e == null) {
                throw new IllegalArgumentException("Element could not be null");
            }
            ServiceContext<E> ctx = this.getServiceContext(e);
            if (ctx == null) {
                ctx = createServiceContext(e);
            }
            ctx.setServiceParams(parameters);
        }

        /**
         * Get the policy path
         * 
         * @param serviceAddress
         * @return
         */
        public File getPolicyPath(final E e) {
            ServiceContext<E> serviceContext = this.getServiceContext(e);
            if (serviceContext != null) {
                return serviceContext.getPolicyPath();
            }
            return null;
        }

        /**
         * Set the policy path
         * 
         * @param serviceAddress
         * @param absolutePath
         */
        public void setPolicyPath(final E e, final File absolutePath) {
            ServiceContext<E> ctx = this.getServiceContext(e);
            if (ctx == null) {
                ctx = createServiceContext(e);
            }
            ctx.setPolicyPath(absolutePath);
        }

        /**
         * Get the parameters for the given serviceAddress.
         * 
         * @param serviceAddress
         *            the service address
         * @return a string containing the parameters of the given
         *         serviceAddress.
         */
        public String getServiceParameters(final E e) {
            ServiceContext<E> ctx = this.getServiceContext(e);
            if (ctx != null) {
                return ctx.getServiceParams();
            }
            return null;
        }

        /**
         * Set the class loader
         * 
         * @param serviceAddress
         * @param classLoader
         */
        public void setClassLoader(final E e, final ClassLoader classLoader) {
            ServiceContext<E> ctx = this.getServiceContext(e);
            if (ctx == null) {
                ctx = createServiceContext(e);
            }
            ctx.setClassloader(classLoader);
        }
    }

    private final ServiceManager<Consumes> consumersManager;

    private final ServiceManager<Provides> providersManager;

    private ConfigurationContext axis2ConfigurationContext;

    /**
     * The map of JBI descriptors. Key is the service unit name.
     */
    private final Map<String, Jbi> jbiDescriptors;

    /**
     * The map of services.xml files. Key is the service unit name.
     */
    private final Map<String, File> servicesDescriptors;

    /**
     * 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 web service notification manager
     */
    protected WsnManager wsnManager;

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

    /**
     * The JNDI initial factory used by the JMS transport layer.
     */
    private String jmsJndiInitialFactory;

    /**
     * The JNDI provider URL used by the JMS transport layer.
     */
    private String jmsJndiProviderUrl;

    /**
     * The connection factory JNDI name used by the JMS transport layer.
     */
    private String jmsConnectionFactoryName;

    /**
     * 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;
        this.jbiDescriptors = new HashMap<String, Jbi>();
        this.servicesDescriptors = new HashMap<String, File>();

        // managers
        this.consumersManager = new ServiceManager<Consumes>();
        this.providersManager = new ServiceManager<Provides>();

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

        this.wsnManager = new WsnManager(this.logger);
        this.wsnManager.setPersistance(new WsnPersistance(new File(context.getInstallRoot(), "topics")));

        // add handlers to manager
        final SubscribeHandler subHandler = new SubscribeHandler();
        this.wsnManager.addHandler(subHandler);
        final GetCurrentMessageHandler currentHandler = new GetCurrentMessageHandler();
        this.wsnManager.addHandler(currentHandler);
        final UnsubscribeHandler unsubHandler = new UnsubscribeHandler();
        this.wsnManager.addHandler(unsubHandler);
    }

    /**
     * Add a {@link JBIDescriptor}
     * 
     * @param address
     * @param jbiDescriptor
     */
    public void addJbiDescriptor(final String serviceUnitName, final Jbi jbiDescriptor) {
        if (serviceUnitName == null) {
            throw new IllegalArgumentException("Service unit name could not be null");
        }
        this.jbiDescriptors.put(serviceUnitName, jbiDescriptor);
    }

    /**
     * Get the JBI descriptor for the given address.
     * 
     * @param address
     * @return the {@link JBIDescriptor} if found, else return null
     */
    public Jbi getJbiDescriptor(final String serviceUnitName) {
        return this.jbiDescriptors.get(serviceUnitName);
    }

    /**
     * Remove the {@link JBIDescriptor} for the given address
     * 
     * @param address
     */
    public void removeJbiDescriptor(final String serviceUnitName) {
        if (this.jbiDescriptors != null) {
            this.jbiDescriptors.remove(serviceUnitName);
        }
    }

    /**
     * Add a {@link JBIDescriptor}
     * 
     * @param address
     * @param jbiDescriptor
     */
    public void addServiceDescriptor(final String serviceUnitName, final File serviceDescriptor) {
        if (serviceUnitName == null) {
            throw new IllegalArgumentException("Service unit name could not be null");
        }
        this.servicesDescriptors.put(serviceUnitName, serviceDescriptor);
    }

    /**
     * Get the service descriptor as {@link File} of the given service unit if
     * available.
     * 
     * @param address
     * @return the file (services.xml) or null if no service descriptor is
     *         available
     */
    public File getServiceDescriptor(final String serviceUnitName) {
        return this.servicesDescriptors.get(serviceUnitName);
    }

    /**
     * Remove the {@link JBIDescriptor} for the given service unit
     * 
     * @param address
     */
    public void removeServiceDescriptor(final String serviceUnitName) {
        this.servicesDescriptors.remove(serviceUnitName);
    }

    /**
     * @return the notificationManager
     */
    public WsnManager getWsnManager() {
        return this.wsnManager;
    }

    /**
     * @param wsnManager
     *            the notificationManager to set
     */
    public void setWsnManager(final WsnManager wsnManager) {
        this.wsnManager = wsnManager;
    }

    /**
     * 
     * @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, final ConfigurationExtensions cdkExtensions, final Provides provides,
            String rampartUserName) 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, cdkExtensions, this, provides,
                                this.logger, soapAction, rampartUserName),

                        // 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)
                                ? SUPropertiesHelper.retrieveTimeout(cdkExtensions)
                                : 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 axis2ConfigurationContext;
    }

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

    /**
     * @return the consumersManager
     */
    public ServiceManager<Consumes> getConsumersManager() {
        return consumersManager;
    }

    /**
     * @return the providersManager
     */
    public ServiceManager<Provides> getProvidersManager() {
        return providersManager;
    }

    /**
     * The JNDI initial factory used by the JMS transport layer.
     * 
     * @return The JNDI initial factory used by the JMS transport layer.
     */
    public String getJmsJndiInitialFactory() {
        return jmsJndiInitialFactory;
    }

    /**
     * Set the JNDI initial factory used by the JMS transport layer.
     * 
     * @param jmsJndiInitialFactory
     *            The JNDI initial factory used by the JMS transport layer.
     */
    public void setJmsJndiInitialFactory(final String jmsJndiInitialFactory) {
        this.jmsJndiInitialFactory = jmsJndiInitialFactory;
    }

    /**
     * The JNDI provider URL used by the JMS transport layer.
     * 
     * @return The JNDI provider URL used by the JMS transport layer.
     */
    public String getJmsJndiProviderUrl() {
        return this.jmsJndiProviderUrl;
    }

    /**
     * Set the JNDI provider URL used by the JMS transport layer.
     * 
     * @param jmsJndiProviderUrl
     *            The JNDI provider URL used by the JMS transport layer.
     */
    public void setJmsJndiProviderUrl(final String jmsJndiProviderUrl) {
        this.jmsJndiProviderUrl = jmsJndiProviderUrl;
    }

    /**
     * The connection factory JNDI name used by the JMS transport layer.
     * 
     * @return The connection factory JNDI name used by the JMS transport layer.
     */
    public String getJmsConnectionFactoryName() {
        return this.jmsConnectionFactoryName;
    }

    /**
     * Set the connection factory JNDI name used by the JMS transport layer.
     * 
     * @param jmsConnectionFactoryName
     *            The connection factory JNDI name used by the JMS transport
     *            layer.
     */
    public void setJmsConnectionFactoryName(final String jmsConnectionFactoryName) {
        this.jmsConnectionFactoryName = jmsConnectionFactoryName;
    }
}