org.apache.servicemix.jms.endpoints.JmsConsumerEndpoint.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.servicemix.jms.endpoints.JmsConsumerEndpoint.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.servicemix.jms.endpoints;

import org.apache.servicemix.common.DefaultComponent;
import org.apache.servicemix.common.ServiceUnit;
import org.apache.servicemix.jms.JmsComponent;
import org.apache.servicemix.jms.JmsEndpointType;
import org.springframework.jms.connection.JmsTransactionManager;
import org.springframework.jms.connection.JmsTransactionManager102;
import org.springframework.jms.listener.*;
import org.springframework.jms.listener.serversession.ServerSessionFactory;
import org.springframework.jms.listener.serversession.ServerSessionMessageListenerContainer;
import org.springframework.jms.listener.serversession.ServerSessionMessageListenerContainer102;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager;

import javax.jbi.management.DeploymentException;
import javax.jbi.servicedesc.ServiceEndpoint;
import javax.jms.*;
import javax.transaction.TransactionManager;
import javax.xml.namespace.QName;
import java.lang.IllegalStateException;

/**
 * A Sping-based JMS consumer endpoint.
 *
 * @author gnodet
 * @org.apache.xbean.XBean element="consumer" 
 * @since 3.2
 */
public class JmsConsumerEndpoint extends AbstractConsumerEndpoint implements JmsEndpointType {

    public static final String LISTENER_TYPE_DEFAULT = "default";
    public static final String LISTENER_TYPE_SIMPLE = "simple";
    public static final String LISTENER_TYPE_SERVER = "server";

    public static final String TRANSACTED_NONE = "none";
    public static final String TRANSACTED_XA = "xa";
    public static final String TRANSACTED_JMS = "jms";

    // type of listener
    private String listenerType = LISTENER_TYPE_DEFAULT;
    private String transacted = TRANSACTED_NONE;

    // Standard jms properties
    private String clientId;
    private Destination destination;
    private String destinationName;
    private String durableSubscriptionName;
    private ExceptionListener exceptionListener;
    private String messageSelector;
    private int sessionAcknowledgeMode = Session.AUTO_ACKNOWLEDGE;
    private boolean subscriptionDurable;

    // simple and default listener properties
    private boolean pubSubNoLocal;
    private int concurrentConsumers = 1;

    // default listener properties
    private int cacheLevel = DefaultMessageListenerContainer.CACHE_NONE;
    private long receiveTimeout = DefaultMessageListenerContainer.DEFAULT_RECEIVE_TIMEOUT;
    private long recoveryInterval = DefaultMessageListenerContainer.DEFAULT_RECOVERY_INTERVAL;

    // default and server listener properties
    private int maxMessagesPerTask = Integer.MIN_VALUE;

    // server listener properties
    private ServerSessionFactory serverSessionFactory;

    private AbstractMessageListenerContainer listenerContainer;

    public JmsConsumerEndpoint() {
        super();
    }

    public JmsConsumerEndpoint(DefaultComponent component, ServiceEndpoint endpoint) {
        super(component, endpoint);
    }

    public JmsConsumerEndpoint(ServiceUnit serviceUnit, QName service, String endpoint) {
        super(serviceUnit, service, endpoint);
    }

    /**
     * @return the transacted
     */
    public String getTransacted() {
        return transacted;
    }

    /**
    * Specifies the type of transaction used to wrap the message exchanges. 
    * Valid values are <code>none</code>, <code>xa</code>, and <code>jms</code>.
    *
     * @param transacted the type of transaction wrapper to use
     */
    public void setTransacted(String transacted) {
        this.transacted = transacted;
    }

    /**
     * @return the cacheLevel
     */
    public int getCacheLevel() {
        return cacheLevel;
    }

    /**
    * Specifies the level of caching allowed by the listener. Valid values are 
    * 0 through 3. The values map to the following:
    * <ul>
    * <li>0 - <code>CACHE_NONE</code></li>
    * <li>1 - <code>CACHE_CONNECTION</code></li>
    * <li>2 - <code>CACHE_SESSION</code></li>
    * <li>3 - <code>CACHE_CONSUMER</code></li>
    * </ul>
    * The default is <code>CACHE_NONE</code>.<br/>
    * This property only effects consumers whose <code>listenerType</code> 
    * property is set to <code>default</code>.
    *
     * @param cacheLevel the cacheLevel to set
     * @see org.springframework.jms.listener.DefaultMessageListenerContainer#setCacheLevel(int)
     */
    public void setCacheLevel(int cacheLevel) {
        this.cacheLevel = cacheLevel;
    }

    /**
     * @return the clientId
     */
    public String getClientId() {
        return clientId;
    }

    /**
    * Specifies the JMS client id for a shared <code>Connection</code> created and used by 
    * this listener.
    * 
     * @param clientId the clientId to set
     * @see org.springframework.jms.listener.AbstractMessageListenerContainer#setClientId(String)
     */
    public void setClientId(String clientId) {
        this.clientId = clientId;
    }

    /**
     * @return the concurrentConsumers
     */
    public int getConcurrentConsumers() {
        return concurrentConsumers;
    }

    /**
    * Specifies the number of concurrent consumers created by the listener.
    * This property is only used for consumers whose <code>listenerType</code> 
    * property is set to either <code>simple</code> or <code>default</code>.
    * 
     * @param concurrentConsumers the number of concurrent consumers to create
     * @see org.springframework.jms.listener.DefaultMessageListenerContainer#setConcurrentConsumers(int)
     * @see org.springframework.jms.listener.SimpleMessageListenerContainer#setConcurrentConsumers(int)
     */
    public void setConcurrentConsumers(int concurrentConsumers) {
        this.concurrentConsumers = concurrentConsumers;
    }

    /**
     * @return the destination
     */
    public Destination getDestination() {
        return destination;
    }

    /**
    * Specifies the JMS <code>Destination</code> used to receive messages.
    *
     * @param destination the JMS destination
     * @see org.springframework.jms.listener.AbstractMessageListenerContainer#setDestination(Destination)
     */
    public void setDestination(Destination destination) {
        this.destination = destination;
    }

    /**
     * @return the destinationName
     */
    public String getDestinationName() {
        return destinationName;
    }

    /**
    * Specifies a string identifying the JMS destination used to recieve 
     * messages. The destination is resolved using the 
     * <code>DesitinationResolver</code>.
     *
     * @param destinationName the destination name
     * @see org.springframework.jms.listener.AbstractMessageListenerContainer#setDestinationName(String)
     */
    public void setDestinationName(String destinationName) {
        this.destinationName = destinationName;
    }

    /**
     * @return the durableSubscriptionName
     */
    public String getDurableSubscriptionName() {
        return durableSubscriptionName;
    }

    /**
    * Specifies the name used to register the durable subscription.
    *
     * @param durableSubscriptionName the registration name
     * @see org.springframework.jms.listener.AbstractMessageListenerContainer#setDurableSubscriptionName(String)
     */
    public void setDurableSubscriptionName(String durableSubscriptionName) {
        this.durableSubscriptionName = durableSubscriptionName;
    }

    /**
     * @return the exceptionListener
     */
    public ExceptionListener getExceptionListener() {
        return exceptionListener;
    }

    /**
    * Specifies an <code>ExceptionListener</code> to notify in case of a 
    * <code>JMSException</code> is thrown by the registered message listener or 
    * the invocation infrastructure.
    *
     * @param exceptionListener the exception listener
     * @see org.springframework.jms.listener.AbstractMessageListenerContainer#setExceptionListener(ExceptionListener)
     */
    public void setExceptionListener(ExceptionListener exceptionListener) {
        this.exceptionListener = exceptionListener;
    }

    /**
     * @return the listenerType
     */
    public String getListenerType() {
        return listenerType;
    }

    /**
    * Specifies the type of Spring JMS message listener to use. Valid values 
    * are: <code>default</code>, <code>simple</code>, and <code>server</code>.
    *
     * @param listenerType the listener type
     */
    public void setListenerType(String listenerType) {
        this.listenerType = listenerType;
    }

    /**
     * @return the maxMessagesPerTask
     */
    public int getMaxMessagesPerTask() {
        return maxMessagesPerTask;
    }

    /**
    * Specifies the number of attempts to receive messages per task. The 
    * default is -1 which specifies an unlimited number of attempts.<br/>
    * This property only effects consumers whose <code>listenerType</code> 
    * property is set to either <code>default</code> or <code>simple</code>.
    * 
     * @param maxMessagesPerTask the number of attempts to make
     * @see org.springframework.jms.listener.DefaultMessageListenerContainer#setMaxMessagesPerTask(int)
     * @see org.springframework.jms.listener.serversession.ServerSessionMessageListenerContainer#setMaxMessagesPerTask(int)
     */
    public void setMaxMessagesPerTask(int maxMessagesPerTask) {
        this.maxMessagesPerTask = maxMessagesPerTask;
    }

    /**
     * @return the messageSelector
     */
    public String getMessageSelector() {
        return messageSelector;
    }

    /**
    * Specifies the message selector string to use. The message selector string 
    * should conform to the descrition in the JMS spec.
    *
     * @param messageSelector the message selector string
     * @see org.springframework.jms.listener.AbstractMessageListenerContainer#setMessageSelector(String)
     */
    public void setMessageSelector(String messageSelector) {
        this.messageSelector = messageSelector;
    }

    /**
     * @return the pubSubNoLocal
     */
    public boolean isPubSubNoLocal() {
        return pubSubNoLocal;
    }

    /**
    * Specifies if messages published by the listener's <code>Connection</code> 
    * are suppressed. The default is <code>false</code>.<br/>
    * This property only effects consumers whose <code>listenerType</code> 
    * property is set to either <code>default</code> or <code>simple</code>.
    *
     * @param pubSubNoLocal messages are surpressed?
     * @see org.springframework.jms.listener.DefaultMessageListenerContainer#setPubSubNoLocal(boolean)
     * @see org.springframework.jms.listener.SimpleMessageListenerContainer#setPubSubNoLocal(boolean)
     */
    public void setPubSubNoLocal(boolean pubSubNoLocal) {
        this.pubSubNoLocal = pubSubNoLocal;
    }

    /**
     * @return the receiveTimeout
     */
    public long getReceiveTimeout() {
        return receiveTimeout;
    }

    /**
    * Specifies the timeout for receiving a message in milliseconds. Defaults 
    * to 1000.<br/>
    * This property only effects consumers whose <code>listenerType</code> 
    * property is set to <code>default</code>.
    *
     * @param receiveTimeout the number of milliseconds before timing out
     * @see org.springframework.jms.listener.DefaultMessageListenerContainer#setReceiveTimeout(long)
     */
    public void setReceiveTimeout(long receiveTimeout) {
        this.receiveTimeout = receiveTimeout;
    }

    /**
     * @return the recoveryInterval
     */
    public long getRecoveryInterval() {
        return recoveryInterval;
    }

    /**
    *Specifies the interval, in milliseconds, between attempts to recover after 
    * a failed listener set-up. Defaults to 5000.<br/>
    * This property only effects consumers whose <code>listenerType</code> 
    * property is set to <code>default</code>.
    *
     * @param recoveryInterval the number of milliseconds to wait
     * @see org.springframework.jms.listener.DefaultMessageListenerContainer#setRecoveryInterval(long)
     */
    public void setRecoveryInterval(long recoveryInterval) {
        this.recoveryInterval = recoveryInterval;
    }

    /**
     * @return the serverSessionFactory
     */
    public ServerSessionFactory getServerSessionFactory() {
        return serverSessionFactory;
    }

    /**
    * Specifies the <code>ServerSessionFactory</code> to use. The default is 
    * <code>SimpleServerSessionFactory</code>.<br/>
    * This property only effects consumers whose <code>listenerType</code> 
    * property is set to <code>server</code>.
    *
     * @param serverSessionFactory an implementation of the <code>ServerSessionFactory</code> interface
     * @see ServerSessionMessageListenerContainer#setServerSessionFactory(ServerSessionFactory)
     */
    public void setServerSessionFactory(ServerSessionFactory serverSessionFactory) {
        this.serverSessionFactory = serverSessionFactory;
    }

    /**
     * @return the sessionAcknowledgeMode
     */
    public int getSessionAcknowledgeMode() {
        return sessionAcknowledgeMode;
    }

    /**
    * Specifies the acknowledgment mode that is used when creating a 
    * <code>Session</code> to send a message. Deafults to 
    * <code>Session.AUTO_ACKNOWLEDGE</code>.
    *
     * @param sessionAcknowledgeMode the sessionAcknowledgeMode to set
     * @see org.springframework.jms.support.JmsAccessor#setSessionAcknowledgeMode(int)
     */
    public void setSessionAcknowledgeMode(int sessionAcknowledgeMode) {
        this.sessionAcknowledgeMode = sessionAcknowledgeMode;
    }

    /**
     * @return the subscriptionDurable
     */
    public boolean isSubscriptionDurable() {
        return subscriptionDurable;
    }

    /**
    * Specifies if the listener uses a durable subscription to listen for 
    * messages. Defaults to <code>false</code>.
    *
     * @param subscriptionDurable the listener uses a durable subscription?
     * @see org.springframework.jms.listener.AbstractMessageListenerContainer#setSubscriptionDurable(boolean)
     */
    public void setSubscriptionDurable(boolean subscriptionDurable) {
        this.subscriptionDurable = subscriptionDurable;
    }

    public String getLocationURI() {
        // TODO: Need to return a real URI
        return getService() + "#" + getEndpoint();
    }

    public synchronized void activate() throws Exception {
        super.activate();
        listenerContainer = createListenerContainer();
        ((JmsComponent) getServiceUnit().getComponent()).addListenerContainer(listenerContainer);
        listenerContainer.setMessageListener(new SessionAwareMessageListener() {
            public void onMessage(Message message, Session session) throws JMSException {
                JmsConsumerEndpoint.this.onMessage(message, session);
            }
        });
        listenerContainer.setAutoStartup(false);
        listenerContainer.afterPropertiesSet();
    }

    public synchronized void start() throws Exception {
        listenerContainer.start();
    }

    public synchronized void stop() throws Exception {
        listenerContainer.stop();
    }

    public synchronized void deactivate() throws Exception {
        if (listenerContainer != null) {
            listenerContainer.stop();
            listenerContainer.shutdown();
            ((JmsComponent) getServiceUnit().getComponent()).removeListenerContainer(listenerContainer);
            listenerContainer = null;
        }
        super.deactivate();
    }

    public void validate() throws DeploymentException {
        // TODO: check service, endpoint
        super.validate();
        if (getConnectionFactory() == null) {
            throw new DeploymentException("connectionFactory is required");
        }
        if (destination == null && destinationName == null) {
            throw new DeploymentException("destination or destinationName is required");
        }
        if (!LISTENER_TYPE_DEFAULT.equals(listenerType) && !LISTENER_TYPE_SIMPLE.equals(listenerType)
                && !LISTENER_TYPE_SERVER.equals(listenerType)) {
            throw new DeploymentException("listenerType must be default, simple or server");
        }
        if (TRANSACTED_XA.equals(transacted) && !LISTENER_TYPE_DEFAULT.equals(listenerType)) {
            throw new DeploymentException("XA transactions are only supported on default listener");
        }
        if (!TRANSACTED_NONE.equals(transacted) && !TRANSACTED_JMS.equals(transacted)
                && !TRANSACTED_XA.equals(transacted)) {
            throw new DeploymentException("transacted must be none, jms or xa");
        }
    }

    protected AbstractMessageListenerContainer createListenerContainer() {
        final AbstractMessageListenerContainer container;
        if (LISTENER_TYPE_DEFAULT.equals(listenerType)) {
            container = createDefaultMessageListenerContainer();
        } else if (LISTENER_TYPE_SIMPLE.equals(listenerType)) {
            container = createSimpleMessageListenerContainer();
        } else if (LISTENER_TYPE_SERVER.equals(listenerType)) {
            container = createServerSessionMessageListenerContainer();
        } else {
            throw new IllegalStateException();
        }
        container.setAutoStartup(false);
        container.setClientId(clientId);
        container.setConnectionFactory(getConnectionFactory());
        if (destination != null) {
            container.setDestination(destination);
        } else if (destinationName != null) {
            container.setDestinationName(destinationName);
        }
        if (getDestinationResolver() != null) {
            container.setDestinationResolver(getDestinationResolver());
        }
        if (subscriptionDurable) {
            if (durableSubscriptionName == null) {
                // Use unique name generated from this endpoint
                durableSubscriptionName = getService() + "#" + getEndpoint();
            }
            container.setDurableSubscriptionName(durableSubscriptionName);
        }
        container.setExceptionListener(exceptionListener);
        container.setMessageSelector(messageSelector);
        container.setPubSubDomain(isPubSubDomain());
        container.setSessionAcknowledgeMode(sessionAcknowledgeMode);
        container.setSubscriptionDurable(subscriptionDurable);
        return container;
    }

    private AbstractMessageListenerContainer createServerSessionMessageListenerContainer() {
        final ServerSessionMessageListenerContainer cont;
        if (isJms102()) {
            cont = new ServerSessionMessageListenerContainer102();
        } else {
            cont = new ServerSessionMessageListenerContainer();
        }
        cont.setMaxMessagesPerTask(maxMessagesPerTask > 0 ? maxMessagesPerTask : 1);
        cont.setServerSessionFactory(serverSessionFactory);
        if (TRANSACTED_JMS.equals(transacted)) {
            cont.setSessionTransacted(true);
        }
        return cont;
    }

    private AbstractMessageListenerContainer createSimpleMessageListenerContainer() {
        final SimpleMessageListenerContainer cont;
        if (isJms102()) {
            cont = new SimpleMessageListenerContainer102();
        } else {
            cont = new SimpleMessageListenerContainer();
        }
        cont.setConcurrentConsumers(concurrentConsumers);
        cont.setPubSubNoLocal(pubSubNoLocal);
        cont.setTaskExecutor(null); // TODO: value ?
        if (TRANSACTED_JMS.equals(transacted)) {
            cont.setSessionTransacted(true);
        }
        return cont;
    }

    private AbstractMessageListenerContainer createDefaultMessageListenerContainer() {
        final DefaultMessageListenerContainer cont;
        if (isJms102()) {
            cont = new DefaultMessageListenerContainer102();
        } else {
            cont = new DefaultMessageListenerContainer();
        }
        cont.setCacheLevel(cacheLevel);
        cont.setConcurrentConsumers(concurrentConsumers);
        cont.setMaxMessagesPerTask(maxMessagesPerTask);
        cont.setPubSubNoLocal(pubSubNoLocal);
        cont.setReceiveTimeout(receiveTimeout);
        cont.setRecoveryInterval(recoveryInterval);
        if (TRANSACTED_XA.equals(transacted)) {
            cont.setSessionTransacted(true);
            TransactionManager tm = (TransactionManager) getContext().getTransactionManager();
            if (tm == null) {
                throw new IllegalStateException("No TransactionManager available");
            } else if (tm instanceof PlatformTransactionManager) {
                cont.setTransactionManager((PlatformTransactionManager) tm);
            } else {
                cont.setTransactionManager(new JtaTransactionManager(tm));
            }
        } else if (TRANSACTED_JMS.equals(transacted)) {
            cont.setSessionTransacted(true);
            if (isJms102()) {
                cont.setTransactionManager(new JmsTransactionManager102(getConnectionFactory(), isPubSubDomain()));
            } else {
                cont.setTransactionManager(new JmsTransactionManager(getConnectionFactory()));
            }
        }
        return cont;
    }

}