Package org.activemq.transport

Source Code of org.activemq.transport.NetworkChannel

/**
*
* Copyright 2004 Protique 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.activemq.transport;
import java.util.Iterator;
import java.util.Map;
import javax.jms.JMSException;
import javax.jms.Session;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.activemq.ActiveMQConnection;
import org.activemq.ActiveMQConnectionFactory;
import org.activemq.ActiveMQPrefetchPolicy;
import org.activemq.advisories.ConnectionAdvisor;
import org.activemq.advisories.ConnectionAdvisoryEvent;
import org.activemq.advisories.ConnectionAdvisoryEventListener;
import org.activemq.broker.BrokerClient;
import org.activemq.broker.BrokerContainer;
import org.activemq.broker.ConsumerInfoListener;
import org.activemq.message.ActiveMQDestination;
import org.activemq.message.BrokerInfo;
import org.activemq.message.ConsumerInfo;
import org.activemq.message.Receipt;
import org.activemq.service.MessageContainerManager;
import org.activemq.service.Service;
import org.activemq.transport.composite.CompositeTransportChannel;
import EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;
import EDU.oswego.cs.dl.util.concurrent.PooledExecutor;
import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;

/**
* Represents a broker's connection with a single remote broker which bridges the two brokers to form a network. <p/>
* The NetworkChannel contains a JMS connection with the remote broker. <p/>New subscriptions on the local broker are
* multiplexed into the JMS connection so that messages published on the remote broker can be replayed onto the local
* broker.
*
* @version $Revision: 1.1.1.1 $
*/
public class NetworkChannel
        implements
            Service,
            ConsumerInfoListener,
            ConnectionAdvisoryEventListener,
            TransportStatusEventListener {
    private static final Log log = LogFactory.getLog(NetworkChannel.class);
    protected String uri;
    protected BrokerContainer brokerContainer;
    protected ActiveMQConnection localConnection;
    protected ActiveMQConnection remoteConnection;
    protected ConcurrentHashMap topicConsumerMap;
    protected ConcurrentHashMap queueConsumerMap;
    protected String remoteUserName;
    protected String remotePassword;
    protected String remoteBrokerName;
    protected String remoteClusterName;
    protected int maximumRetries = 0;
    protected long reconnectSleepTime = 2000L;
    protected PooledExecutor threadPool;
    private boolean remote = false;
    private SynchronizedBoolean started = new SynchronizedBoolean(false);
    private SynchronizedBoolean connected = new SynchronizedBoolean(false);
    private SynchronizedBoolean stopped = new SynchronizedBoolean(false);
    private ConnectionAdvisor connectionAdvisor;
    private ActiveMQPrefetchPolicy localPrefetchPolicy;
    private ActiveMQPrefetchPolicy remotePrefetchPolicy;

    /**
     * Default constructor
     */
    public NetworkChannel() {
        this.topicConsumerMap = new ConcurrentHashMap();
        this.queueConsumerMap = new ConcurrentHashMap();
    }

    /**
     * Default Constructor
     *
     * @param tp
     */
    public NetworkChannel(PooledExecutor tp) {
        this();
        this.threadPool = tp;
    }

    /**
     * Constructor
     *
     * @param connector
     * @param brokerContainer
     * @param uri
     */
    public NetworkChannel(NetworkConnector connector, BrokerContainer brokerContainer, String uri) {
        this(connector.threadPool);
        this.brokerContainer = brokerContainer;
        this.uri = uri;
    }

    /**
     * Create a NetworkConnector from a TransportChannel
     *
     * @param connector
     * @param brokerContainer
     * @param channel
     * @param remoteBrokerName
     * @param remoteclusterName
     * @throws JMSException
     */
    public NetworkChannel(NetworkConnector connector, BrokerContainer brokerContainer, TransportChannel channel,
            String remoteBrokerName, String remoteclusterName) throws JMSException {
        this(connector.threadPool);
        this.brokerContainer = brokerContainer;
        this.uri = "";
        this.remoteBrokerName = remoteBrokerName;
        this.remoteClusterName = remoteclusterName;
        ActiveMQConnectionFactory fac = new ActiveMQConnectionFactory();
        fac.setJ2EEcompliant(false);
        fac.setTurboBoost(true);
        remoteConnection = new ActiveMQConnection(fac, remoteUserName, remotePassword, channel);
        remoteConnection.setClientID("Boondocks:" + remoteClusterName + ":" + remoteBrokerName);
        remoteConnection.setQuickClose(true);
        remoteConnection.start();
        BrokerInfo info = new BrokerInfo();
        info.setBrokerName(brokerContainer.getBroker().getBrokerName());
        info.setClusterName(brokerContainer.getBroker().getBrokerClusterName());
        channel.asyncSend(info);
        remote = true;
    }

    /**
     * @see org.activemq.transport.TransportStatusEventListener#statusChanged(org.activemq.transport.TransportStatusEvent)
     */
    public void statusChanged(TransportStatusEvent event) {
       if (event != null
           && (event.getChannelStatus() == TransportStatusEvent.CONNECTED
               || event.getChannelStatus() == TransportStatusEvent.RECONNECTED)) {
           connected.set(true);
       }else {
           connected.set(false);
       }
    }

    private void doSetConnected() {
        synchronized (connected) {
            connected.set(true);
            connected.notifyAll();
        }
    }

    /**
     * @return text info on this
     */
    public String toString() {
        return "NetworkChannel{ " + ", uri = '" + uri + "' " + ", remoteBrokerName = '" + remoteBrokerName + "' "
                + " }";
    }

    /**
     * Start the channel
     */
    public void start() {
        if (started.commit(false, true)) {
            try {
                stopped.set(false);
                threadPool.execute(new Runnable() {
                    public void run() {
                        String originalName = Thread.currentThread().getName();
                        try {
                            Thread.currentThread().setName("NetworkChannel Initiator to " + uri);
                            initialize();
                            startSubscriptions();
                            log.info("Started NetworkChannel to " + uri);
                        }
                        catch (JMSException jmsEx) {
                            log.error("Failed to start NetworkChannel: " + uri, jmsEx);
                        }
                        finally {
                            Thread.currentThread().setName(originalName);
                        }
                    }
                });
            }
            catch (InterruptedException e) {
                log.warn("Failed to start - interuppted", e);
            }
        }
    }

    /**
     * stop the channel
     *
     * @throws JMSException on error
     */
    public void stop() throws JMSException {
        if (started.commit(true, false)) {
            stopped.set(true);
            topicConsumerMap.clear();
            if (remoteConnection != null) {
                remoteConnection.close();
                remoteConnection = null;
            }
            if (localConnection != null) {
                localConnection.close();
                localConnection = null;
            }
            for (Iterator i = topicConsumerMap.values().iterator();i.hasNext();) {
                NetworkMessageBridge consumer = (NetworkMessageBridge) i.next();
                consumer.stop();
            }
        }
    }

    /**
     * Listen for new Consumer events at this broker
     *
     * @param client
     * @param info
     */
    public void onConsumerInfo(final BrokerClient client, final ConsumerInfo info) {
        String brokerName = client.getBrokerConnector().getBrokerInfo().getBrokerName();
        if (!client.isClusteredConnection()) {
            if (connected.get()) {
                if (!info.hasVisited(remoteBrokerName)) {
                    if (info.isStarted()) {
                        addConsumerInfo(info);
                    }
                    else {
                        removeConsumerInfo(info);
                    }
                }
            }
            else {
                try {
                    threadPool.execute(new Runnable() {
                        public void run() {
                            if (!client.isClusteredConnection()) {
                                if (!info.hasVisited(remoteBrokerName)) {
                                    synchronized (connected) {
                                        while (!connected.get() && !stopped.get()) {
                                            try {
                                                connected.wait(500);
                                            }
                                            catch (InterruptedException e) {
                                                log.debug("interuppted", e);
                                            }
                                        }
                                        if (info.isStarted()) {
                                            addConsumerInfo(info);
                                        }
                                        else {
                                            removeConsumerInfo(info);
                                        }
                                    }
                                }
                            }
                        }
                    });
                }
                catch (InterruptedException e) {
                    log.warn("Failed to process ConsumerInfo: " + info, e);
                }
            }
        }
    }

    /**
     * @return the uri of the broker(s) this channel is connected to
     */
    public String getUri() {
        return uri;
    }

    /**
     * set the uri of the broker(s) this channel is connected to
     *
     * @param uri
     */
    public void setUri(String uri) {
        this.uri = uri;
    }

    /**
     * @return Returns the remotePassword.
     */
    public String getRemotePassword() {
        return remotePassword;
    }

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

    /**
     * @return Returns the remoteUserName.
     */
    public String getRemoteUserName() {
        return remoteUserName;
    }

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

    /**
     * @return Returns the brokerContainer.
     */
    public BrokerContainer getBrokerContainer() {
        return brokerContainer;
    }

    /**
     * @param brokerContainer The brokerContainer to set.
     */
    public void setBrokerContainer(BrokerContainer brokerContainer) {
        this.brokerContainer = brokerContainer;
    }

    public int getMaximumRetries() {
        return maximumRetries;
    }

    public void setMaximumRetries(int maximumRetries) {
        this.maximumRetries = maximumRetries;
    }

    public long getReconnectSleepTime() {
        return reconnectSleepTime;
    }

    public void setReconnectSleepTime(long reconnectSleepTime) {
        this.reconnectSleepTime = reconnectSleepTime;
    }

    public String getRemoteBrokerName() {
        return remoteBrokerName;
    }

    public void setRemoteBrokerName(String remoteBrokerName) {
        this.remoteBrokerName = remoteBrokerName;
    }

    /**
     * @return Returns the threadPool.
     */
    protected PooledExecutor getThreadPool() {
        return threadPool;
    }

    /**
     * @param threadPool The threadPool to set.
     */
    protected void setThreadPool(PooledExecutor threadPool) {
        this.threadPool = threadPool;
    }

    private synchronized ActiveMQConnection getLocalConnection() throws JMSException {
        if (localConnection == null) {
            initializeLocal();
        }
        return localConnection;
    }

    private synchronized ActiveMQConnection getRemoteConnection() throws JMSException {
        if (remoteConnection == null) {
            initializeRemote();
        }
        return remoteConnection;
    }

    /**
     * @return Returns the localPrefetchPolicy.
     */
    public ActiveMQPrefetchPolicy getLocalPrefetchPolicy() {
        return localPrefetchPolicy;
    }

    /**
     * @param localPrefetchPolicy The localPrefetchPolicy to set.
     */
    public void setLocalPrefetchPolicy(ActiveMQPrefetchPolicy localPrefetchPolicy) {
        this.localPrefetchPolicy = localPrefetchPolicy;
    }

    /**
     * @return Returns the remotePrefetchPolicy.
     */
    public ActiveMQPrefetchPolicy getRemotePrefetchPolicy() {
        return remotePrefetchPolicy;
    }

    /**
     * @param remotePrefetchPolicy The remotePrefetchPolicy to set.
     */
    public void setRemotePrefetchPolicy(ActiveMQPrefetchPolicy remotePrefetchPolicy) {
        this.remotePrefetchPolicy = remotePrefetchPolicy;
    }

    // Implementation methods
    //-------------------------------------------------------------------------
    /**
     * Implementation of ConnectionAdvisoryEventListener
     *
     * @param event
     */
    public void onEvent(ConnectionAdvisoryEvent event) {
        String localBrokerName = brokerContainer.getBroker().getBrokerName();
        if (!event.getInfo().isClosed()) {
            brokerContainer.registerRemoteClientID(event.getInfo().getClientId());
        }
        else {
            brokerContainer.deregisterRemoteClientID(event.getInfo().getClientId());
        }
    }

    private void addConsumerInfo(ConsumerInfo info) {
        addConsumerInfo(info.getDestination(), info.getDestination().isTopic(), info.isDurableTopic());
    }

    private void addConsumerInfo(ActiveMQDestination destination, boolean topic, boolean durableTopic) {
        Map map = topic ? topicConsumerMap : queueConsumerMap;
        NetworkMessageBridge bridge = (NetworkMessageBridge) map.get(destination.getPhysicalName());
        if (bridge == null) {
            bridge = createBridge(map, destination, durableTopic);
        }
        else if (durableTopic && !bridge.isDurableTopic()) {
            //upgrade our subscription
            bridge.decrementReferenceCount();
            upgradeBridge(bridge);
        }
        bridge.incrementReferenceCount();
    }

    private void upgradeBridge(NetworkMessageBridge bridge) {
        try {
            remoteConnection.stop();
            bridge.upgrade();
        }
        catch (JMSException e) {
            log.warn("Could not upgrade the NetworkMessageBridge to a durable subscription for destination: "
                    + bridge.getDestination(), e);
        }
        try {
            remoteConnection.start();
        }
        catch (JMSException e) {
            log.error("Failed to restart the NetworkMessageBridge", e);
        }
    }

    private NetworkMessageBridge createBridge(Map map, ActiveMQDestination destination, boolean durableTopic) {
        NetworkMessageBridge bridge = new NetworkMessageBridge();
        try {
            bridge.setDestination(destination);
            bridge.setDurableTopic(durableTopic);
            bridge.setLocalBrokerName(brokerContainer.getBroker().getBrokerName());
            bridge.setLocalSession(getLocalConnection().createSession(false, Session.CLIENT_ACKNOWLEDGE));
            bridge.setRemoteSession(getRemoteConnection().createSession(false, Session.CLIENT_ACKNOWLEDGE));
            map.put(destination.getPhysicalName(), bridge);
            bridge.start();
            log.info("started NetworkMessageBridge for destination: " + destination + " -- NetworkChannel: "
                    + this.toString());
        }
        catch (JMSException jmsEx) {
            log.error("Failed to start NetworkMessageBridge for destination: " + destination, jmsEx);
        }
        return bridge;
    }

    private void removeConsumerInfo(final ConsumerInfo info) {
        final String physicalName = info.getDestination().getPhysicalName();
        final NetworkMessageBridge bridge = (NetworkMessageBridge) topicConsumerMap.get(physicalName);
        if (bridge != null) {
            if (bridge.decrementReferenceCount() <= 0) {
                try {
                    threadPool.execute(new Runnable() {
                        public void run() {
                            bridge.stop();
                            topicConsumerMap.remove(physicalName);
                            log.info("stopped MetworkMessageBridge for destination: " + info.getDestination());
                        }
                    });
                }
                catch (InterruptedException e) {
                    log.warn("got interrupted stoping NetworkBridge", e);
                }
            }
        }
    }

    private void startSubscriptions() {
        if (!remote) {
            MessageContainerManager mcm = brokerContainer.getBroker().getPersistentTopicContainerManager();
            if (mcm != null) {
                Map map = mcm.getLocalDestinations();
                startSubscriptions(map, true, true);
            }
            mcm = brokerContainer.getBroker().getTransientTopicContainerManager();
            if (mcm != null) {
                Map map = mcm.getLocalDestinations();
                startSubscriptions(map, true, false);
            }
            mcm = brokerContainer.getBroker().getTransientQueueContainerManager();
            if (mcm != null) {
                Map map = mcm.getLocalDestinations();
                startSubscriptions(map, false, false);
            }
            mcm = brokerContainer.getBroker().getPersistentQueueContainerManager();
            if (mcm != null) {
                Map map = mcm.getLocalDestinations();
                startSubscriptions(map, false, false);
            }
        }
    }

    private void startSubscriptions(Map destinations, boolean topic, boolean durableTopic) {
        if (destinations != null) {
            for (Iterator i = destinations.values().iterator();i.hasNext();) {
                ActiveMQDestination dest = (ActiveMQDestination) i.next();
                addConsumerInfo(dest, topic, durableTopic);
            }
        }
    }

    protected void initialize() throws JMSException {
        // force lazy construction
        initializeLocal();
        initializeRemote();
        brokerContainer.getBroker().addConsumerInfoListener(NetworkChannel.this);
    }

    private synchronized void initializeRemote() throws JMSException {
        if (remoteConnection == null) {
            ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(remoteUserName, remotePassword, uri);
            //factory.setTurboBoost(true);
            factory.setJ2EEcompliant(false);
            factory.setQuickClose(true);
            factory.setInternalConnection(true);
            remoteConnection = (ActiveMQConnection) factory.createConnection();
            TransportChannel transportChannel = remoteConnection.getTransportChannel();
            if (transportChannel instanceof CompositeTransportChannel) {
                CompositeTransportChannel composite = (CompositeTransportChannel) transportChannel;
                composite.setMaximumRetries(maximumRetries);
                composite.setFailureSleepTime(reconnectSleepTime);
                composite.setIncrementTimeout(false);
            }
            transportChannel.addTransportStatusEventListener(this);
            remoteConnection.setClientID(brokerContainer.getBroker().getBrokerName() + "_NetworkChannel");
            remoteConnection.start();
            BrokerInfo info = new BrokerInfo();
            info.setBrokerName(brokerContainer.getBroker().getBrokerName());
            info.setClusterName(brokerContainer.getBroker().getBrokerClusterName());
            Receipt receipt = remoteConnection.syncSendRequest(info);
            if (receipt != null) {
                remoteBrokerName = receipt.getBrokerName();
                remoteClusterName = receipt.getClusterName();
            }
            connectionAdvisor = new ConnectionAdvisor(remoteConnection);
            connectionAdvisor.addListener(this);
            connectionAdvisor.start();
            if (remotePrefetchPolicy != null) {
                remoteConnection.setPrefetchPolicy(remotePrefetchPolicy);
            }
        }
        doSetConnected();
    }

    private void initializeLocal() throws JMSException {
        String brokerName = brokerContainer.getBroker().getBrokerName();
        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://" + brokerName);
        factory.setTurboBoost(true);
        factory.setJ2EEcompliant(false);
        factory.setBrokerName(brokerName);
        factory.setQuickClose(true);
        factory.setInternalConnection(true);
        localConnection = (ActiveMQConnection) factory.createConnection();
        localConnection.start();
        BrokerInfo info = new BrokerInfo();
        info.setBrokerName(remoteBrokerName);
        info.setClusterName(remoteClusterName);
        localConnection.asyncSendPacket(info);
        if (localPrefetchPolicy != null) {
            localConnection.setPrefetchPolicy(localPrefetchPolicy);
        }
    }
   
    /*private synchronized void releaseRemote() throws JMSException {
      if (remoteConnection != null) {
        TransportChannel transportChannel = remoteConnection.getTransportChannel();
        transportChannel.stop();
            if (connectionAdvisor != null) {
            connectionAdvisor.stop();
            }
        try {
          remoteConnection.stop();
        } catch (JMSException e) {
          // ignore this exception, since the remote broker is most likely down
        }
        remoteConnection = null;
      }
    }*/
  
}
TOP

Related Classes of org.activemq.transport.NetworkChannel

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.