org.springframework.integration.jms.SubscribableJmsChannel.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.integration.jms.SubscribableJmsChannel.java

Source

/*
 * Copyright 2002-2012 the original author or authors.
 *
 * 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.springframework.integration.jms;

import javax.jms.MessageListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.SmartLifecycle;
import org.springframework.integration.Message;
import org.springframework.integration.MessageDeliveryException;
import org.springframework.integration.MessageDispatchingException;
import org.springframework.integration.MessagingException;
import org.springframework.integration.core.MessageHandler;
import org.springframework.integration.core.SubscribableChannel;
import org.springframework.integration.dispatcher.AbstractDispatcher;
import org.springframework.integration.dispatcher.BroadcastingDispatcher;
import org.springframework.integration.dispatcher.MessageDispatcher;
import org.springframework.integration.dispatcher.RoundRobinLoadBalancingStrategy;
import org.springframework.integration.dispatcher.UnicastingDispatcher;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.listener.AbstractMessageListenerContainer;
import org.springframework.util.Assert;

/**
 * @author Mark Fisher
 * @author Gary Russell
 * @since 2.0
 */
public class SubscribableJmsChannel extends AbstractJmsChannel
        implements SubscribableChannel, SmartLifecycle, DisposableBean {

    private final AbstractMessageListenerContainer container;

    private volatile AbstractDispatcher dispatcher;

    private volatile boolean initialized;

    private volatile int maxSubscribers = Integer.MAX_VALUE;

    public SubscribableJmsChannel(AbstractMessageListenerContainer container, JmsTemplate jmsTemplate) {
        super(jmsTemplate);
        Assert.notNull(container, "container must not be null");
        this.container = container;
    }

    /**
     * Specify the maximum number of subscribers supported by the
     * channel's dispatcher.
     * @param maxSubscribers
     */
    public void setMaxSubscribers(int maxSubscribers) {
        this.maxSubscribers = maxSubscribers;
    }

    public boolean subscribe(MessageHandler handler) {
        Assert.state(this.dispatcher != null,
                "'MessageDispatcher' must not be null. This channel might not have been initialized");
        return this.dispatcher.addHandler(handler);
    }

    public boolean unsubscribe(MessageHandler handler) {
        Assert.state(this.dispatcher != null,
                "'MessageDispatcher' must not be null. This channel might not have been initialized");
        return this.dispatcher.removeHandler(handler);
    }

    @Override
    public void onInit() throws Exception {
        if (this.initialized) {
            return;
        }
        super.onInit();
        boolean isPubSub = this.container.isPubSubDomain();
        this.configureDispatcher(isPubSub);
        MessageListener listener = new DispatchingMessageListener(this.getJmsTemplate(), this.dispatcher, this,
                isPubSub);
        this.container.setMessageListener(listener);
        if (!this.container.isActive()) {
            this.container.afterPropertiesSet();
        }
        this.initialized = true;
    }

    private void configureDispatcher(boolean isPubSub) {
        if (isPubSub) {
            this.dispatcher = new BroadcastingDispatcher(true);
        } else {
            UnicastingDispatcher unicastingDispatcher = new UnicastingDispatcher();
            unicastingDispatcher.setLoadBalancingStrategy(new RoundRobinLoadBalancingStrategy());
            this.dispatcher = unicastingDispatcher;
        }
        this.dispatcher.setMaxSubscribers(this.maxSubscribers);
    }

    private static class DispatchingMessageListener implements MessageListener {

        private final Log logger = LogFactory.getLog(this.getClass());

        private final JmsTemplate jmsTemplate;

        private final MessageDispatcher dispatcher;

        private final SubscribableJmsChannel channel;

        private final boolean isPubSub;

        private DispatchingMessageListener(JmsTemplate jmsTemplate, MessageDispatcher dispatcher,
                SubscribableJmsChannel channel, boolean isPubSub) {
            this.jmsTemplate = jmsTemplate;
            this.dispatcher = dispatcher;
            this.channel = channel;
            this.isPubSub = isPubSub;
        }

        public void onMessage(javax.jms.Message message) {
            Message<?> messageToSend = null;
            try {
                Object converted = this.jmsTemplate.getMessageConverter().fromMessage(message);
                if (converted != null) {
                    messageToSend = (converted instanceof Message<?>) ? (Message<?>) converted
                            : MessageBuilder.withPayload(converted).build();
                    this.dispatcher.dispatch(messageToSend);
                } else if (this.logger.isWarnEnabled()) {
                    logger.warn("MessageConverter returned null, no Message to dispatch");
                }
            } catch (MessageDispatchingException e) {
                String exceptionMessage = e.getMessage() + " for jms-channel '" + this.channel.getFullChannelName()
                        + "'.";
                if (this.isPubSub) {
                    // log only for backwards compatibility with pub/sub
                    if (logger.isWarnEnabled()) {
                        logger.warn(exceptionMessage, e);
                    }
                } else {
                    throw new MessageDeliveryException(messageToSend, exceptionMessage, e);
                }
            } catch (Exception e) {
                throw new MessagingException("failed to handle incoming JMS Message", e);
            }
        }
    }

    /*
     * SmartLifecycle implementation (delegates to the MessageListener container)
     */

    public boolean isAutoStartup() {
        return (this.container != null) ? this.container.isAutoStartup() : false;
    }

    public int getPhase() {
        return (this.container != null) ? this.container.getPhase() : 0;
    }

    public boolean isRunning() {
        return (this.container != null) ? this.container.isRunning() : false;
    }

    public void start() {
        if (this.container != null) {
            this.container.start();
        }
    }

    public void stop() {
        if (this.container != null) {
            this.container.stop();
        }
    }

    public void stop(Runnable callback) {
        if (this.container != null) {
            this.container.stop(callback);
        }
    }

    public void destroy() throws Exception {
        if (this.container != null) {
            this.container.destroy();
        }
    }

}