Package org.servicemix.jbi.nmr.flow.jms

Source Code of org.servicemix.jbi.nmr.flow.jms.JMSFlow

/**
* <a href="http://servicemix.org">ServiceMix: The open source ESB</a>
*
* Copyright 2005 RAJD Consultancy Ltd
*
* 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.servicemix.jbi.nmr.flow.jms;

import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
import edu.emory.mathcs.backport.java.util.concurrent.CopyOnWriteArraySet;
import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;

import org.activemq.ActiveMQConnection;
import org.activemq.ActiveMQConnectionFactory;
import org.activemq.advisories.ConsumerAdvisor;
import org.activemq.advisories.ConsumerAdvisoryEvent;
import org.activemq.advisories.ConsumerAdvisoryEventListener;
import org.activemq.message.ConsumerInfo;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.servicemix.jbi.framework.ComponentConnector;
import org.servicemix.jbi.framework.ComponentNameSpace;
import org.servicemix.jbi.framework.ComponentPacket;
import org.servicemix.jbi.framework.ComponentPacketEvent;
import org.servicemix.jbi.framework.ComponentPacketEventListener;
import org.servicemix.jbi.framework.LocalComponentConnector;
import org.servicemix.jbi.messaging.MessageExchangeImpl;
import org.servicemix.jbi.nmr.Broker;
import org.servicemix.jbi.nmr.flow.AbstractFlow;

import javax.jbi.JBIException;
import javax.jbi.messaging.MessagingException;
import javax.jbi.messaging.MessageExchange.Role;
import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.Topic;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
* Use for message routing among a network of containers. All routing/registration happens automatically.
*
* @version $Revision: 749 $
*/
public class JMSFlow extends AbstractFlow implements ConsumerAdvisoryEventListener, MessageListener, ComponentPacketEventListener {
   
    private static final Log log = LogFactory.getLog(JMSFlow.class);
    private static final String INBOUND_PREFIX = "org.servicemix.inbound.";
    private String jmsURL = "peer://org.servicemix?persistent=false";
    private String userName;
    private String password;
    private ActiveMQConnectionFactory connectionFactory;
    private ActiveMQConnection connection;
    private String broadcastDestinationName = "org.servicemix.JMSFlow";
    private MessageProducer queueProducer;
    private MessageProducer topicProducer;
    private Topic broadcastTopic;
    private Session broadcastSession;
    private Session inboundSession;
    private ConsumerAdvisor advisor;
    private Map networkNodeKeyMap = new ConcurrentHashMap();
    private Map networkComponentKeyMap = new ConcurrentHashMap();
    private Map consumerMap = new ConcurrentHashMap();
    private AtomicBoolean started = new AtomicBoolean(false);

    /**
     * The type of Flow
     *
     * @return the type
     */
    public String getDescription() {
        return "jms";
    }

    /**
     * @return Returns the jmsURL.
     */
    public String getJmsURL() {
        return jmsURL;
    }

    /**
     * @param jmsURL The jmsURL to set.
     */
    public void setJmsURL(String jmsURL) {
        this.jmsURL = jmsURL;
    }

    /**
     * @return Returns the password.
     */
    public String getPassword() {
        return password;
    }

    /**
     * @param password The password to set.
     */
    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * @return Returns the userName.
     */
    public String getUserName() {
        return userName;
    }

    /**
     * @param userName The userName to set.
     */
    public void setUserName(String userName) {
        this.userName = userName;
    }

    /**
     * @return Returns the connectionFactory.
     */
    public ActiveMQConnectionFactory getConnectionFactory() {
        return connectionFactory;
    }

    /**
     * @param connectionFactory The connectionFactory to set.
     */
    public void setConnectionFactory(ActiveMQConnectionFactory connectionFactory) {
        this.connectionFactory = connectionFactory;
    }


    /**
     * @return Returns the broadcastDestinationName.
     */
    public String getBroadcastDestinationName() {
        return broadcastDestinationName;
    }

    /**
     * @param broadcastDestinationName The broadcastDestinationName to set.
     */
    public void setBroadcastDestinationName(String broadcastDestinationName) {
        this.broadcastDestinationName = broadcastDestinationName;
    }

    /**
     * Initialize the Region
     *
     * @param broker
     * @throws JBIException
     */
    public void init(Broker broker, String subType) throws JBIException {
        super.init(broker, subType);
        broker.getRegistry().addComponentPacketListener(this);
        try {
            if (connectionFactory == null) {
                if (jmsURL != null) {
                    connectionFactory = new ActiveMQConnectionFactory(jmsURL);
                }
                else {
                    connectionFactory = new ActiveMQConnectionFactory();
                }
            }
            if (userName != null) {
                connection = (ActiveMQConnection) connectionFactory.createConnection(userName, password);
            } else {
                connection = (ActiveMQConnection) connectionFactory.createConnection();
            }
            connection.setClientID(broker.getContainerName());
            connection.start();
             inboundSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            Queue queue = inboundSession.createQueue(INBOUND_PREFIX + broker.getContainerName());
            MessageConsumer inboundQueue = inboundSession.createConsumer(queue);
            inboundQueue.setMessageListener(this);
            queueProducer = inboundSession.createProducer(null);
            broadcastSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            broadcastTopic = broadcastSession.createTopic(broadcastDestinationName);
            MessageConsumer broadcastConsumer = broadcastSession.createConsumer(broadcastTopic, null, true);
            broadcastConsumer.setMessageListener(this);
            topicProducer = broadcastSession.createProducer(broadcastTopic);
            topicProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
            advisor = new ConsumerAdvisor(connection, broadcastTopic);
            advisor.addListener(this);
        }
        catch (JMSException e) {
            log.error("Failed to initialize JMSFlow", e);
            throw new JBIException(e);
        }
    }

    /**
     * start the flow
     *
     * @throws JBIException
     */
    public void start() throws JBIException {
        if (started.compareAndSet(false, true)) {
            super.start();
            try {
                advisor.start();
            }
            catch (JMSException e) {
                JBIException jbiEx = new JBIException("JMSException caught in start: " + e.getMessage());
                throw jbiEx;
            }
        }
    }

    /**
     * stop the flow
     *
     * @throws JBIException
     */
    public void stop() throws JBIException {
        if (started.compareAndSet(true, false)) {
            super.stop();
            try {
                advisor.stop();
            }
            catch (JMSException e) {
                JBIException jbiEx = new JBIException("JMSException caught in stop: " + e.getMessage());
                throw jbiEx;
            }
        }
    }

    public void shutDown() throws JBIException {
        super.shutDown();
        stop();
        if (this.connection != null) {
            try {
                this.connection.close();
            }
            catch (JMSException e) {
                log.warn("Error closing JMS Connection", e);
            }
        }
    }

    /**
     * useful for testing
     *
     * @return number of containers in the network
     */
    public int numberInNetwork() {
        return advisor.activeConsumers(broadcastTopic).size();
    }

    /**
     * Process state changes in Components
     *
     * @param event
     */
    public void onEvent(ComponentPacketEvent event) {
        try {
            String componentName = event.getPacket().getComponentNameSpace().getName();
            if (event.getStatus() == ComponentPacketEvent.ACTIVATED){
                Queue queue = inboundSession.createQueue(INBOUND_PREFIX +componentName);
                MessageConsumer consumer = inboundSession.createConsumer(queue);
                consumer.setMessageListener(this);
                consumerMap.put(componentName,consumer);
            } else if (event.getStatus() == ComponentPacketEvent.DEACTIVATED){
                MessageConsumer consumer = (MessageConsumer) consumerMap.remove(componentName);
                if (consumer != null){
                    consumer.close();
                }
            }
            // broadcast change to the network
            ObjectMessage msg = broadcastSession.createObjectMessage(event);
            topicProducer.send(msg);
            log.info("broadcast to internal JMS network: " + event);
        }
        catch (JMSException e) {
            log.error("failed to broadcast to the internal JMS network: " + event, e);
        }
    }

    /**
     * ConsumerAdvisoerEventListener implementation
     *
     * @param event
     */
    public void onEvent(ConsumerAdvisoryEvent event) {
        if (started.get()) {
            ConsumerInfo info = event.getInfo();
            if (info.isStarted()) {
                for (Iterator i = broker.getRegistry().getLocalComponentConnectors().iterator();i.hasNext();) {
                    LocalComponentConnector lcc = (LocalComponentConnector) i.next();
                    ComponentPacket packet = lcc.getPacket();
                    ComponentPacketEvent cpe = new ComponentPacketEvent(packet, ComponentPacketEvent.ACTIVATED);
                    onEvent(cpe);
                }
            }
            else {
                removeAllPackets(info.getClientId());
            }
        }
    }

    /**
     * Distribute an ExchangePacket
     *
     * @param packet
     * @throws MessagingException
     */
    protected void doSend(MessageExchangeImpl me) throws MessagingException {
        doRouting(me);
    }
   
    /**
     * Distribute an ExchangePacket
     *
     * @param packet
     * @throws MessagingException
     */
    public void doRouting(MessageExchangeImpl me) throws MessagingException{
        ComponentNameSpace id=me.getRole()==Role.PROVIDER?me.getDestinationId():me.getSourceId();
        ComponentConnector cc=broker.getRegistry().getComponentConnector(id);
        if(cc!=null){
            // let ActiveMQ do the routing ...
            try{
                String componentName=cc.getComponentNameSpace().getName();
                String destination = "";
                if (me.getRole() == Role.PROVIDER){
                    destination = INBOUND_PREFIX + componentName;
                }else {
                    destination = INBOUND_PREFIX + id.getContainerName();
                }
                Queue queue=inboundSession.createQueue(destination);
                ObjectMessage msg=inboundSession.createObjectMessage(me);
                queueProducer.send(queue,msg);
            }catch(JMSException e){
                log.error("Failed to send exchange: "+me+" internal JMS Network",e);
                throw new MessagingException(e);
            }
        }else{
            throw new MessagingException("No component with id ("+id+") - Couldn't route MessageExchange "+me);
        }
    }

    /**
     * MessageListener implementation
     *
     * @param message
     */
    public void onMessage(Message message) {
        try {
            if (message != null && message instanceof ObjectMessage) {
                ObjectMessage objMsg = (ObjectMessage) message;
                Object obj = objMsg.getObject();
                if (obj != null) {
                    if (obj instanceof ComponentPacketEvent) {
                        ComponentPacketEvent event = (ComponentPacketEvent) obj;
                        String containerName = event.getPacket().getComponentNameSpace().getContainerName();
                        processInBoundPacket(containerName, event);
                    }
                    else if (obj instanceof MessageExchangeImpl) {
                        MessageExchangeImpl me = (MessageExchangeImpl) obj;
                        super.doRouting(me);
                    }
                }
            }
        }
        catch (JMSException jmsEx) {
            log.error("Caught an exception unpacking JMS Message: ", jmsEx);
        }
        catch (MessagingException e) {
            log.error("Caught an exception routing ExchangePacket: ", e);
        }
    }

    /**
     * Process Inbound packets
     *
     * @param containerName
     * @param event
     */
    protected void processInBoundPacket(String containerName, ComponentPacketEvent event) {
        ComponentPacket packet = event.getPacket();
        if (!packet.getComponentNameSpace().getContainerName().equals(broker.getContainerName())) {
            if (event.getStatus() == ComponentPacketEvent.ACTIVATED) {
                addRemotePacket(containerName, packet);
            }
            else if (event.getStatus() == ComponentPacketEvent.DEACTIVATED) {
                removeRemotePacket(containerName, packet);
            }
            else if (event.getStatus() == ComponentPacketEvent.STATE_CHANGE) {
                updateRemotePacket(containerName, packet);
            }
            else {
                log.warn("Unable to determine ComponentPacketEvent type: " + event.getStatus() + " for packet: "
                        + packet);
            }
        }
    }

    private void addRemotePacket(String containerName, ComponentPacket packet) {
        networkComponentKeyMap.put(packet.getComponentNameSpace(), containerName);
        Set set = (Set) networkNodeKeyMap.get(containerName);
        if (set == null) {
            set = new CopyOnWriteArraySet();
            networkNodeKeyMap.put(containerName, set);
        }
        ComponentConnector cc = new ComponentConnector(packet);
        log.info("Adding Remote Component: " + cc);
        broker.getRegistry().addRemoteComponentConnector(cc);
        set.add(packet);
    }

    private void updateRemotePacket(String containerName, ComponentPacket packet) {
        Set set = (Set) networkNodeKeyMap.get(containerName);
        if (set != null) {
            set.remove(packet);
            set.add(packet);
        }
        ComponentConnector cc = new ComponentConnector(packet);
        log.info("Updating remote Component: " + cc);
        broker.getRegistry().updateRemoteComponentConnector(cc);
    }

    private void removeRemotePacket(String containerName, ComponentPacket packet) {
        networkComponentKeyMap.remove(packet.getComponentNameSpace());
        Set set = (Set) networkNodeKeyMap.get(containerName);
        if (set != null) {
            set.remove(packet);
            ComponentConnector cc = new ComponentConnector(packet);
            log.info("Removing remote Component: " + cc);
            broker.getRegistry().removeRemoteComponentConnector(cc);
            if (set.isEmpty()) {
                networkNodeKeyMap.remove(containerName);
            }
        }
    }

    private void removeAllPackets(String containerName) {
        Set set = (Set) networkNodeKeyMap.remove(containerName);
        if (set != null) {
          for (Iterator i = set.iterator();i.hasNext();) {
              ComponentPacket packet = (ComponentPacket) i.next();
              ComponentConnector cc = new ComponentConnector(packet);
              log.info("Network node: " + containerName + " Stopped. Removing remote Component: " + cc);
              broker.getRegistry().removeRemoteComponentConnector(cc);
              networkComponentKeyMap.remove(packet.getComponentNameSpace());
          }
        }
    }
}
TOP

Related Classes of org.servicemix.jbi.nmr.flow.jms.JMSFlow

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.