Package org.apache.activemq.network

Source Code of org.apache.activemq.network.DemandForwardingBridgeSupport

/**
*
* 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.activemq.network;

import java.io.IOException;

import org.apache.activemq.advisory.AdvisorySupport;
import org.apache.activemq.command.ActiveMQDestination;
import org.apache.activemq.command.ActiveMQTempDestination;
import org.apache.activemq.command.ActiveMQTopic;
import org.apache.activemq.command.BrokerId;
import org.apache.activemq.command.BrokerInfo;
import org.apache.activemq.command.Command;
import org.apache.activemq.command.ConnectionError;
import org.apache.activemq.command.ConnectionId;
import org.apache.activemq.command.ConnectionInfo;
import org.apache.activemq.command.ConsumerId;
import org.apache.activemq.command.ConsumerInfo;
import org.apache.activemq.command.DataStructure;
import org.apache.activemq.command.DestinationInfo;
import org.apache.activemq.command.ExceptionResponse;
import org.apache.activemq.command.KeepAliveInfo;
import org.apache.activemq.command.Message;
import org.apache.activemq.command.MessageAck;
import org.apache.activemq.command.MessageDispatch;
import org.apache.activemq.command.NetworkBridgeFilter;
import org.apache.activemq.command.ProducerInfo;
import org.apache.activemq.command.RemoveInfo;
import org.apache.activemq.command.Response;
import org.apache.activemq.command.SessionInfo;
import org.apache.activemq.command.ShutdownInfo;
import org.apache.activemq.command.WireFormatInfo;
import org.apache.activemq.filter.DestinationFilter;
import org.apache.activemq.transport.DefaultTransportListener;
import org.apache.activemq.transport.FutureResponse;
import org.apache.activemq.transport.ResponseCallback;
import org.apache.activemq.transport.Transport;
import org.apache.activemq.transport.TransportDisposedIOException;
import org.apache.activemq.transport.TransportListener;
import org.apache.activemq.util.IdGenerator;
import org.apache.activemq.util.LongSequenceGenerator;
import org.apache.activemq.util.ServiceStopper;
import org.apache.activemq.util.ServiceSupport;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

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

/**
* A useful base class for implementing demand forwarding bridges.
*
* @version $Revision: 464110 $
*/
public abstract class DemandForwardingBridgeSupport implements Bridge {
    protected static final Log log = LogFactory.getLog(DemandForwardingBridge.class);
    protected final Transport localBroker;
    protected final Transport remoteBroker;
    protected final IdGenerator idGenerator = new IdGenerator();
    protected final LongSequenceGenerator consumerIdGenerator = new LongSequenceGenerator();
    protected ConnectionInfo localConnectionInfo;
    protected ConnectionInfo remoteConnectionInfo;
    protected SessionInfo localSessionInfo;
    protected ProducerInfo producerInfo;
    protected String localBrokerName = "Unknown";
    protected String remoteBrokerName = "Unknown";
    protected String localClientId;
    protected String userName;
    protected String password;
    protected int prefetchSize = 1000;
    protected boolean dispatchAsync;
    protected String destinationFilter = ">";
    protected boolean bridgeTempDestinations = true;
    protected String name = "bridge";
    protected ConsumerInfo demandConsumerInfo;
    protected int demandConsumerDispatched;
    protected final AtomicBoolean localBridgeStarted = new AtomicBoolean(false);
    protected final AtomicBoolean remoteBridgeStarted = new AtomicBoolean(false);
    protected boolean disposed = false;
    protected BrokerId localBrokerId;
    protected ActiveMQDestination[] excludedDestinations;
    protected ActiveMQDestination[] dynamicallyIncludedDestinations;
    protected ActiveMQDestination[] staticallyIncludedDestinations;
    protected ActiveMQDestination[] durableDestinations;
    protected final ConcurrentHashMap subscriptionMapByLocalId = new ConcurrentHashMap();
    protected final ConcurrentHashMap subscriptionMapByRemoteId = new ConcurrentHashMap();
    protected final BrokerId localBrokerPath[] = new BrokerId[] { null };
    protected CountDownLatch startedLatch = new CountDownLatch(2);
    protected CountDownLatch remoteBrokerNameKnownLatch = new CountDownLatch(1);
    protected boolean decreaseNetworkConsumerPriority;
    protected int networkTTL = 1;
    protected final AtomicBoolean remoteInterupted = new AtomicBoolean(false);
    protected final AtomicBoolean lastConnectSucceeded = new AtomicBoolean(false);

   
    public DemandForwardingBridgeSupport(final Transport localBroker, final Transport remoteBroker) {
        this.localBroker = localBroker;
        this.remoteBroker = remoteBroker;
    }

    public void start() throws Exception {
        localBroker.setTransportListener(new DefaultTransportListener(){
            public void onCommand(Object o){
              Command command = (Command) o;
                serviceLocalCommand(command);
            }
   
            public void onException(IOException error){
                serviceLocalException(error);
            }
        });
        remoteBroker.setTransportListener(new TransportListener(){
            public void onCommand(Object o){
              Command command = (Command) o;
                serviceRemoteCommand(command);
            }
   
            public void onException(IOException error){
                serviceRemoteException(error);
            }
   
            public void transportInterupted(){
                //clear any subscriptions - to try and prevent the bridge from stalling the broker
                if( remoteInterupted.compareAndSet(false, true) ) {
                 
                    log.debug("Outbound transport to " + remoteBrokerName + " interrupted.");                                       

                  if( localBridgeStarted.get() ) {
                      clearDownSubscriptions();
                      synchronized( DemandForwardingBridgeSupport.this ) {
                        try{
                            localBroker.oneway(localConnectionInfo.createRemoveCommand());
                        }catch(TransportDisposedIOException td){
                                log.debug("local broker is now disposed",td);
                            }
                            catch(IOException e){
                            log.warn("Caught exception from local start",e);
                        }
                      }
                  }
                 
                    localBridgeStarted.set(false);
                    remoteBridgeStarted.set(false);
                    startedLatch = new CountDownLatch(2);
                }
               
            }
   
            public void transportResumed(){               
                if( remoteInterupted.compareAndSet(true, false) ) {
                 
                  // We want to slow down false connects so that we don't get in a busy loop.
                  // False connects can occurr if you using SSH tunnels.
                  if( !lastConnectSucceeded.get() ) {
                    try {
                            log.debug("Previous connection was never fully established. Sleeping for second to avoid busy loop.");                                       
              Thread.sleep(1000);
            } catch (InterruptedException e) {
              Thread.currentThread().interrupt();
            }
                  }
                    lastConnectSucceeded.set(false);

                    log.debug("Outbound transport to " + remoteBrokerName + " resumed");                                       
                }
            }
        });
        localBroker.start();
        remoteBroker.start();
       
        try{                     
            triggerRemoteStartBridge();
        }catch(IOException e){
            log.warn("Caught exception from remote start",e);
        }
    }

    protected void triggerLocalStartBridge() throws IOException {
        Thread thead=new Thread(){
            public void run(){
                try{
                    startLocalBridge();
                }catch(Exception e){
                    serviceLocalException(e);
                }
            }
        };
        thead.start();
    }

    protected void triggerRemoteStartBridge() throws IOException {
        Thread thead=new Thread(){
            public void run(){
                try{
                    startRemoteBridge();
                }catch(Exception e){
                    serviceRemoteException(e);
                }
            }
        };
        thead.start();
    }

    protected void startLocalBridge() throws Exception {
        if(localBridgeStarted.compareAndSet(false,true)){
            synchronized( this ) {
             
            remoteBrokerNameKnownLatch.await();

              localConnectionInfo=new ConnectionInfo();
              localConnectionInfo.setConnectionId(new ConnectionId(idGenerator.generateId()));
              localClientId="NC_"+remoteBrokerName+"_inbound"+name;
              localConnectionInfo.setClientId(localClientId);
              localConnectionInfo.setUserName(userName);
              localConnectionInfo.setPassword(password);
              localBroker.oneway(localConnectionInfo);
 
              localSessionInfo=new SessionInfo(localConnectionInfo,1);
              localBroker.oneway(localSessionInfo);
             
              log.info("Network connection between "+localBroker+" and "+remoteBroker+"("+remoteBrokerName
                              +") has been established.");
             
              startedLatch.countDown();
              setupStaticDestinations();
            }
        }
    }

    protected void startRemoteBridge() throws Exception {
        if(remoteBridgeStarted.compareAndSet(false,true)) {
   
          synchronized (this) {
                       
              if( remoteConnectionInfo!=null ) {
                remoteBroker.oneway(remoteConnectionInfo.createRemoveCommand());
              }
             
                remoteConnectionInfo=new ConnectionInfo();
                remoteConnectionInfo.setConnectionId(new ConnectionId(idGenerator.generateId()));
                remoteConnectionInfo.setClientId("NC_"+localBrokerName+"_outbound"+name);
                remoteConnectionInfo.setUserName(userName);
                remoteConnectionInfo.setPassword(password);
                remoteBroker.oneway(remoteConnectionInfo);

                BrokerInfo brokerInfo=new BrokerInfo();
                brokerInfo.setBrokerName(localBrokerName);
                remoteBroker.oneway(brokerInfo);

                SessionInfo remoteSessionInfo=new SessionInfo(remoteConnectionInfo,1);
                remoteBroker.oneway(remoteSessionInfo);

                producerInfo=new ProducerInfo(remoteSessionInfo,1);
                producerInfo.setResponseRequired(false);
                remoteBroker.oneway(producerInfo);

                // Listen to consumer advisory messages on the remote broker to determine demand.
                demandConsumerInfo=new ConsumerInfo(remoteSessionInfo,1);
                demandConsumerInfo.setDispatchAsync(dispatchAsync);
                String advisoryTopic = AdvisorySupport.CONSUMER_ADVISORY_TOPIC_PREFIX+destinationFilter;
                if( bridgeTempDestinations ) {
                  advisoryTopic += ","+AdvisorySupport.TEMP_DESTINATION_COMPOSITE_ADVISORY_TOPIC;
                }
                demandConsumerInfo.setDestination(new ActiveMQTopic(advisoryTopic));
                demandConsumerInfo.setPrefetchSize(prefetchSize);
                remoteBroker.oneway(demandConsumerInfo);               
                startedLatch.countDown();
               
                if (!disposed){
                    triggerLocalStartBridge();
                }
           
          }
        }
    }

    public void stop() throws Exception {
        log.debug(" stopping "+localBrokerName+ " bridge to " + remoteBrokerName + " is disposed already ? "+disposed);
        if (!disposed) {
      try {
        disposed = true;

        remoteBridgeStarted.set(false);
       
        localBroker.oneway(new ShutdownInfo());
        remoteBroker.oneway(new ShutdownInfo());
       
      } catch (IOException e) {
        log.debug("Caught exception stopping", e);
      } finally {
        ServiceStopper ss = new ServiceStopper();
        ss.stop(localBroker);
        ss.stop(remoteBroker);
        ss.throwFirstException();
      }
    }
        log.debug(localBrokerName+ " bridge to " + remoteBrokerName + " stopped");
    }
   
    protected void serviceRemoteException(Throwable error) {
      if( !disposed ) {
          log.info("Network connection between "+localBroker+" and "+remoteBroker+" shutdown due to a remote error: "+error);
          log.debug("The remote Exception was: "+error, error);
          new Thread() {
            public void run() {
                  ServiceSupport.dispose(DemandForwardingBridgeSupport.this);
            }
          }.start();
      }
    }

    protected void serviceRemoteCommand(Command command) {
        if(!disposed){
            try{
                if(command.isMessageDispatch()){
                    waitStarted();
                    MessageDispatch md=(MessageDispatch) command;
                    serviceRemoteConsumerAdvisory(md.getMessage().getDataStructure());
                    demandConsumerDispatched++;
                    if(demandConsumerDispatched>(demandConsumerInfo.getPrefetchSize()*.75)){
                        remoteBroker.oneway(new MessageAck(md,MessageAck.STANDARD_ACK_TYPE,demandConsumerDispatched));
                        demandConsumerDispatched=0;
                    }
                }else if(command.isBrokerInfo()){
                 
                  lastConnectSucceeded.set(true);
                  serviceRemoteBrokerInfo(command);
                   
                }else if(command.getClass() == ConnectionError.class ) {
                  ConnectionError ce = (ConnectionError) command;
                  serviceRemoteException(ce.getException());
                }else{
                    switch(command.getDataStructureType()){
                    case KeepAliveInfo.DATA_STRUCTURE_TYPE:
                    case WireFormatInfo.DATA_STRUCTURE_TYPE:
                    case ShutdownInfo.DATA_STRUCTURE_TYPE:
                        break;
                    default:
                        log.warn("Unexpected remote command: "+command);
                    }
                }
            }catch(Exception e){
                serviceRemoteException(e);
            }
        }
    }

    private void serviceRemoteConsumerAdvisory(DataStructure data) throws IOException {
        if(data.getClass()==ConsumerInfo.class){
            // Create a new local subscription
            ConsumerInfo info=(ConsumerInfo) data;
            BrokerId[] path=info.getBrokerPath();
            if((path!=null&&path.length>= networkTTL)){
                if(log.isDebugEnabled())
                    log.debug(localBrokerName + " Ignoring Subscription " + info + " restricted to " + networkTTL + " network hops only");
                return;
            }
            if(contains(info.getBrokerPath(),localBrokerPath[0])){
                // Ignore this consumer as it's a consumer we locally sent to the broker.
                if(log.isDebugEnabled())
                    log.debug(localBrokerName  + " Ignoring sub " + info + " already routed through this broker once");
                return;
            }
            if (!isPermissableDestination(info.getDestination())){
                //ignore if not in the permited or in the excluded list
                if(log.isDebugEnabled())
                    log.debug(localBrokerName  + " Ignoring sub " + info + " destination " + info.getDestination() + " is not permiited");
                return;
            }
            // Update the packet to show where it came from.
            info=info.copy();
            addRemoteBrokerToBrokerPath(info);
            DemandSubscription sub=createDemandSubscription(info);
            if (sub != null){
                addSubscription(sub);
                if(log.isDebugEnabled())
                    log.debug(localBrokerName + " Forwarding sub on "+localBroker+" from "+remoteBrokerName+" :  "+info);
            }else {
                if(log.isDebugEnabled())
                    log.debug(localBrokerName  + " Ignoring sub " + info + " already subscribed to matching destination");
            }
        }
        else if (data.getClass()==DestinationInfo.class){
//          It's a destination info - we want to pass up
            //infomation about temporary destinations
            DestinationInfo destInfo = (DestinationInfo) data;
            BrokerId[] path=destInfo.getBrokerPath();
            if((path!=null&&path.length>= networkTTL)){
                if(log.isDebugEnabled())
                    log.debug("Ignoring Subscription " + destInfo + " restricted to " + networkTTL + " network hops only");
                return;
            }
            if(contains(destInfo.getBrokerPath(),localBrokerPath[0])){
                // Ignore this consumer as it's a consumer we locally sent to the broker.
                if(log.isDebugEnabled())
                    log.debug("Ignoring sub " + destInfo + " already routed through this broker once");
                return;
            }
           
            destInfo.setConnectionId(localConnectionInfo.getConnectionId());
            if (destInfo.getDestination() instanceof ActiveMQTempDestination){
                //re-set connection id so comes from here
                ActiveMQTempDestination tempDest = (ActiveMQTempDestination) destInfo.getDestination();
                tempDest.setConnectionId(localSessionInfo.getSessionId().getConnectionId());
            }
                       
            destInfo.setBrokerPath(appendToBrokerPath(destInfo.getBrokerPath(),getRemoteBrokerPath()));
           
            log.debug("Replying destination control command: "+destInfo);           
            localBroker.oneway(destInfo);
           
        }
        else if(data.getClass()==RemoveInfo.class){
            ConsumerId id=(ConsumerId) ((RemoveInfo) data).getObjectId();
            removeDemandSubscription(id);
        }
    }

    protected void serviceLocalException(Throwable error) {
      if( !disposed ) {
          log.info("Network connection between "+localBroker+" and "+remoteBroker+" shutdown due to a local error: "+error);
          log.debug("The local Exception was:"+error,error);
          new Thread() {
            public void run() {
                  ServiceSupport.dispose(DemandForwardingBridgeSupport.this);
            }
          }.start();
      }
    }

    protected void addSubscription(DemandSubscription sub) throws IOException {
        if (sub != null){
            localBroker.oneway(sub.getLocalInfo());
        }
    }

    protected void removeSubscription(DemandSubscription sub) throws IOException {
        if(sub!=null){
            subscriptionMapByLocalId.remove(sub.getLocalInfo().getConsumerId());
            localBroker.oneway(sub.getLocalInfo().createRemoveCommand());
        }
    }

    protected DemandSubscription getDemandSubscription(MessageDispatch md) {
        return (DemandSubscription) subscriptionMapByLocalId.get(md.getConsumerId());
    }

    protected Message configureMessage(MessageDispatch md) {
        Message message=md.getMessage().copy();
        // Update the packet to show where it came from.
        message.setBrokerPath(appendToBrokerPath(message.getBrokerPath(),localBrokerPath));
        message.setProducerId(producerInfo.getProducerId());
        message.setDestination(md.getDestination());
        if(message.getOriginalTransactionId()==null)
            message.setOriginalTransactionId(message.getTransactionId());
        message.setTransactionId(null);
        message.evictMarshlledForm();
        return message;
    }

    protected void serviceLocalCommand(Command command) {
        if(!disposed){
            final boolean trace=log.isTraceEnabled();
            try{
                if(command.isMessageDispatch()){
                    waitStarted();
                    final MessageDispatch md=(MessageDispatch) command;
                    DemandSubscription sub=(DemandSubscription) subscriptionMapByLocalId.get(md.getConsumerId());
                    if(sub!=null){
                        Message message= configureMessage(md);
                        if(trace)
                            log.trace("bridging "+localBrokerName+" -> "+remoteBrokerName+": "+message);
                       
                       
                       
                        if( !message.isResponseRequired() ) {
                           
                            // If the message was originally sent using async send, we will preserve that QOS
                            // by bridging it using an async send (small chance of message loss).
                            remoteBroker.oneway(message);
                            localBroker.oneway(new MessageAck(md,MessageAck.STANDARD_ACK_TYPE,1));
                           
                        } else {
                           
                            // The message was not sent using async send, so we should only ack the local
                            // broker when we get confirmation that the remote broker has received the message.
                            ResponseCallback callback = new ResponseCallback() {
                                public void onCompletion(FutureResponse future) {
                                    try {
                                        Response response = future.getResult();
                                        if(response.isException()){
                                            ExceptionResponse er=(ExceptionResponse) response;
                                            serviceLocalException(er.getException());
                                        } else {
                                            localBroker.oneway(new MessageAck(md,MessageAck.STANDARD_ACK_TYPE,1));
                                        }
                                    } catch (IOException e) {
                                        serviceLocalException(e);
                                    }
                                }
                            };

                            remoteBroker.asyncRequest(message, callback);
                        }
                       
                    }else{
                        if (trace)log.trace("No subscription registered with this network bridge for consumerId " + md.getConsumerId() + " for message: " + md.getMessage());
                    }
                }else if(command.isBrokerInfo()){
                    serviceLocalBrokerInfo(command);
                }else if(command.isShutdownInfo()){
                    log.info(localBrokerName+" Shutting down");
                    // Don't shut down the whole connector if the remote side was interrupted.
                    // the local transport is just shutting down temporarily until the remote side
                    // is restored.
                    if( !remoteInterupted.get() ) {
                        stop();
                    }
                }else if(command.getClass() == ConnectionError.class ) {
                  ConnectionError ce = (ConnectionError) command;
                  serviceLocalException(ce.getException());                   
                }else{
                    switch(command.getDataStructureType()){
                    case WireFormatInfo.DATA_STRUCTURE_TYPE:
                        break;
                    default:
                        log.warn("Unexpected local command: "+command);
                    }
                }
            }catch(Exception e){
                serviceLocalException(e);
            }
        }
    }

    /**
     * @return prefetch size
     */
    public int getPrefetchSize() {
        return prefetchSize;
    }

    /**
     * @param prefetchSize
     */
    public void setPrefetchSize(int prefetchSize) {
        this.prefetchSize=prefetchSize;
    }

    /**
     * @return true if dispatch async
     */
    public boolean isDispatchAsync() {
        return dispatchAsync;
    }

    /**
     * @param dispatchAsync
     */
    public void setDispatchAsync(boolean dispatchAsync) {
        this.dispatchAsync=dispatchAsync;
    }

    /**
     * @return Returns the dynamicallyIncludedDestinations.
     */
    public ActiveMQDestination[] getDynamicallyIncludedDestinations() {
        return dynamicallyIncludedDestinations;
    }

    /**
     * @param dynamicallyIncludedDestinations The dynamicallyIncludedDestinations to set.
     */
    public void setDynamicallyIncludedDestinations(ActiveMQDestination[] dynamicallyIncludedDestinations) {
        this.dynamicallyIncludedDestinations=dynamicallyIncludedDestinations;
    }

    /**
     * @return Returns the excludedDestinations.
     */
    public ActiveMQDestination[] getExcludedDestinations() {
        return excludedDestinations;
    }

    /**
     * @param excludedDestinations The excludedDestinations to set.
     */
    public void setExcludedDestinations(ActiveMQDestination[] excludedDestinations) {
        this.excludedDestinations=excludedDestinations;
    }

    /**
     * @return Returns the staticallyIncludedDestinations.
     */
    public ActiveMQDestination[] getStaticallyIncludedDestinations() {
        return staticallyIncludedDestinations;
    }

    /**
     * @param staticallyIncludedDestinations The staticallyIncludedDestinations to set.
     */
    public void setStaticallyIncludedDestinations(ActiveMQDestination[] staticallyIncludedDestinations) {
        this.staticallyIncludedDestinations=staticallyIncludedDestinations;
    }

    /**
     * @return Returns the durableDestinations.
     */
    public ActiveMQDestination[] getDurableDestinations() {
        return durableDestinations;
    }

    /**
     * @param durableDestinations The durableDestinations to set.
     */
    public void setDurableDestinations(ActiveMQDestination[] durableDestinations) {
        this.durableDestinations=durableDestinations;
    }

    /**
     * @return Returns the localBrokerName.
     */
    public String getLocalBrokerName() {
        return localBrokerName;
    }

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

    /**
     * @return Returns the localBroker.
     */
    public Transport getLocalBroker() {
        return localBroker;
    }

    /**
     * @return Returns the remoteBroker.
     */
    public Transport getRemoteBroker() {
        return remoteBroker;
    }

    /**
     * @return Returns the name.
     */
    public String getName() {
        return name;
    }

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

    /**
     * @return Returns the decreaseNetworkConsumerPriority.
     */
    public boolean isDecreaseNetworkConsumerPriority() {
        return decreaseNetworkConsumerPriority;
    }

    /**
     * @param decreaseNetworkConsumerPriority The decreaseNetworkConsumerPriority to set.
     */
    public void setDecreaseNetworkConsumerPriority(boolean decreaseNetworkConsumerPriority) {
        this.decreaseNetworkConsumerPriority=decreaseNetworkConsumerPriority;
    }

    /**
     * @return Returns the networkTTL.
     */
    public int getNetworkTTL() {
        return networkTTL;
    }

    /**
     * @param networkTTL The networkTTL to set.
     */
    public void setNetworkTTL(int networkTTL) {
        this.networkTTL=networkTTL;
    }
 
    public static boolean contains(BrokerId[] brokerPath, BrokerId brokerId) {
        if(brokerPath!=null){
            for(int i=0;i<brokerPath.length;i++){
                if(brokerId.equals(brokerPath[i]))
                    return true;
            }
        }
        return false;
    }

    protected BrokerId[] appendToBrokerPath(BrokerId[] brokerPath, BrokerId[] pathsToAppend) {
        if (brokerPath == null || brokerPath.length == 0)
            return pathsToAppend;
        BrokerId rc[] = new BrokerId[brokerPath.length + pathsToAppend.length];
        System.arraycopy(brokerPath, 0, rc, 0, brokerPath.length);
        System.arraycopy(pathsToAppend, 0, rc, brokerPath.length, pathsToAppend.length);
        return rc;
    }

    protected BrokerId[] appendToBrokerPath(BrokerId[] brokerPath, BrokerId idToAppend) {
        if (brokerPath == null || brokerPath.length == 0)
            return new BrokerId[] { idToAppend };
        BrokerId rc[] = new BrokerId[brokerPath.length + 1];
        System.arraycopy(brokerPath, 0, rc, 0, brokerPath.length);
        rc[brokerPath.length] = idToAppend;
        return rc;
    }

    protected boolean isPermissableDestination(ActiveMQDestination destination) {
     
      // Are we not bridging temp destinations?
      if( destination.isTemporary() && !bridgeTempDestinations )
        return false;
     
        DestinationFilter filter=DestinationFilter.parseFilter(destination);
        ActiveMQDestination[] dests = excludedDestinations;
        if(dests!=null&&dests.length>0){
            for(int i=0;i<dests.length;i++){
                ActiveMQDestination match=dests[i];
                if(match!=null&&filter.matches(match)){
                    return false;
                }
            }
        }
        dests = dynamicallyIncludedDestinations;
        if(dests!=null&&dests.length>0){
            for(int i=0;i<dests.length;i++){
                ActiveMQDestination match=dests[i];
                if(match!=null&&filter.matches(match)){
                    return true;
                }
            }
            return false;
        }
   
        return true;
    }

    /**
     * Subscriptions for these desitnations are always created
     *
     */
    protected void setupStaticDestinations() {
        ActiveMQDestination[] dests = staticallyIncludedDestinations;
        if (dests != null){
            for(int i=0;i<dests.length;i++){
                ActiveMQDestination dest=dests[i];
                DemandSubscription sub = createDemandSubscription(dest);
                try{
                    addSubscription(sub);
                }catch(IOException e){
                   log.error("Failed to add static destination " + dest,e);
                }
                if(log.isTraceEnabled())
                    log.trace("Forwarding messages for static destination: " + dest);
            }
        }
    }

    protected DemandSubscription createDemandSubscription(ConsumerInfo info) throws IOException {
        return doCreateDemandSubscription(info);
    }

    protected DemandSubscription doCreateDemandSubscription(ConsumerInfo info) throws IOException {
        DemandSubscription result=new DemandSubscription(info);
        result.getLocalInfo().setConsumerId(new ConsumerId(localSessionInfo.getSessionId(),consumerIdGenerator
                        .getNextSequenceId()));
       
        if( decreaseNetworkConsumerPriority ) {
            byte priority=ConsumerInfo.NETWORK_CONSUMER_PRIORITY;
            if(priority>Byte.MIN_VALUE&&info.getBrokerPath()!=null&&info.getBrokerPath().length>1){
                // The longer the path to the consumer, the less it's consumer priority.
                priority-=info.getBrokerPath().length+1;
            }
            result.getLocalInfo().setPriority(priority);
        }
        configureDemandSubscription(info, result);
        return result;
    }

    protected DemandSubscription createDemandSubscription(ActiveMQDestination destination) {
        ConsumerInfo info = new ConsumerInfo();
        info.setDestination(destination);
        //the remote info held by the DemandSubscription holds the original consumerId,
        //the local info get's overwritten
        info.setConsumerId(new ConsumerId(localSessionInfo.getSessionId(),consumerIdGenerator
                        .getNextSequenceId()));
        DemandSubscription result=new DemandSubscription(info);
        result.getLocalInfo().setPriority(ConsumerInfo.NETWORK_CONSUMER_PRIORITY);
       
        return result;
    }

    protected void configureDemandSubscription(ConsumerInfo info, DemandSubscription sub) throws IOException {
        sub.getLocalInfo().setDispatchAsync(dispatchAsync);
        sub.getLocalInfo().setPrefetchSize(prefetchSize);
        subscriptionMapByLocalId.put(sub.getLocalInfo().getConsumerId(),sub);
        subscriptionMapByRemoteId.put(sub.getRemoteInfo().getConsumerId(),sub);
   
        // This works for now since we use a VM connection to the local broker.
        // may need to change if we ever subscribe to a remote broker.
        sub.getLocalInfo().setAdditionalPredicate(createNetworkBridgeFilter(info));
    }

    protected void removeDemandSubscription(ConsumerId id) throws IOException {
        DemandSubscription sub=(DemandSubscription) subscriptionMapByRemoteId.remove(id);
        if (sub != null){
            removeSubscription(sub);
            if(log.isTraceEnabled())
                log.trace("removing sub on "+localBroker+" from "+remoteBrokerName+" :  "+sub.getRemoteInfo());
        }
    }

    protected void waitStarted() throws InterruptedException {
        startedLatch.await();
    }

    protected void clearDownSubscriptions() {
        subscriptionMapByLocalId.clear();
        subscriptionMapByRemoteId.clear();
    }

    protected abstract NetworkBridgeFilter createNetworkBridgeFilter(ConsumerInfo info) throws IOException;

    protected abstract void serviceLocalBrokerInfo(Command command) throws InterruptedException;

    protected abstract void addRemoteBrokerToBrokerPath(ConsumerInfo info) throws IOException;

    protected abstract void serviceRemoteBrokerInfo(Command command) throws IOException;
   
    protected abstract BrokerId[] getRemoteBrokerPath();

  public String getPassword() {
    return password;
  }

  public void setPassword(String password) {
    this.password = password;
  }

  public String getUserName() {
    return userName;
  }

  public void setUserName(String userName) {
    this.userName = userName;
  }

  public boolean isBridgeTempDestinations() {
    return bridgeTempDestinations;
  }

  public void setBridgeTempDestinations(boolean bridgeTempDestinations) {
    this.bridgeTempDestinations = bridgeTempDestinations;
  }

}
TOP

Related Classes of org.apache.activemq.network.DemandForwardingBridgeSupport

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.