001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.network; 018 019import java.io.IOException; 020import java.util.ArrayList; 021import java.util.List; 022 023import org.apache.activemq.command.BrokerId; 024import org.apache.activemq.command.ConsumerId; 025import org.apache.activemq.command.ConsumerInfo; 026import org.apache.activemq.command.SubscriptionInfo; 027import org.apache.activemq.filter.DestinationFilter; 028import org.apache.activemq.transport.Transport; 029import org.slf4j.Logger; 030import org.slf4j.LoggerFactory; 031 032/** 033 * Consolidates subscriptions 034 */ 035public class ConduitBridge extends DemandForwardingBridge { 036 private static final Logger LOG = LoggerFactory.getLogger(ConduitBridge.class); 037 038 /** 039 * Constructor 040 * 041 * @param localBroker 042 * @param remoteBroker 043 */ 044 public ConduitBridge(NetworkBridgeConfiguration configuration, Transport localBroker, Transport remoteBroker) { 045 super(configuration, localBroker, remoteBroker); 046 } 047 048 @Override 049 protected DemandSubscription createDemandSubscription(ConsumerInfo info) throws IOException { 050 if (addToAlreadyInterestedConsumers(info, false)) { 051 return null; // don't want this subscription added 052 } 053 //add our original id to ourselves 054 info.addNetworkConsumerId(info.getConsumerId()); 055 info.setSelector(null); 056 return doCreateDemandSubscription(info); 057 } 058 059 protected boolean addToAlreadyInterestedConsumers(ConsumerInfo info, boolean isForcedDurable) { 060 //If a network subscription and a queue check if isConduitNetworkQueueSubscriptions is true 061 //If true then we want to try and conduit 062 //For topics we always want to conduit regardless of network subscription or not 063 if (info.isNetworkSubscription() && info.getDestination().isQueue() && 064 !configuration.isConduitNetworkQueueSubscriptions()) { 065 return false; 066 } 067 boolean matched = false; 068 069 // search through existing subscriptions and see if we have a match 070 for (DemandSubscription ds : subscriptionMapByLocalId.values()) { 071 DestinationFilter filter = DestinationFilter.parseFilter(ds.getLocalInfo().getDestination()); 072 if (canConduit(ds) && filter.matches(info.getDestination())) { 073 LOG.debug("{} {} with ids {} matched (add interest) {}", 074 configuration.getBrokerName(), info, info.getNetworkConsumerIds(), ds); 075 // add the interest in the subscription 076 if (!info.isDurable()) { 077 ds.add(info.getConsumerId()); 078 if (isForcedDurable) { 079 forcedDurableRemoteId.add(info.getConsumerId()); 080 ds.addForcedDurableConsumer(info.getConsumerId()); 081 } 082 } else { 083 //Handle the demand generated by proxy network subscriptions 084 //The broker path is case is normal 085 if (isProxyNSConsumerBrokerPath(info) && 086 info.getSubscriptionName() != null && info.getSubscriptionName().startsWith(DURABLE_SUB_PREFIX)) { 087 final BrokerId[] path = info.getBrokerPath(); 088 addProxyNetworkSubscriptionBrokerPath(ds, path, info.getSubscriptionName()); 089 //This is the durable sync case on broker restart 090 } else if (isProxyNSConsumerClientId(info.getClientId()) && 091 isProxyBridgeSubscription(info.getClientId(), info.getSubscriptionName())) { 092 addProxyNetworkSubscriptionClientId(ds, info.getClientId(), info.getSubscriptionName()); 093 } else { 094 ds.getDurableRemoteSubs().add(new SubscriptionInfo(info.getClientId(), info.getSubscriptionName())); 095 } 096 } 097 matched = true; 098 // continue - we want interest to any existing DemandSubscriptions 099 } 100 } 101 return matched; 102 } 103 104 // we want to conduit statically included consumers which are local networkSubs 105 // but we don't want to conduit remote network queue subs i.e. (proxy proxy) consumers 106 // unless isConduitNetworkQueueSubscriptions is true 107 // We always want to conduit topic subscriptions 108 private boolean canConduit(DemandSubscription ds) { 109 return ds.isStaticallyIncluded() || ds.getRemoteInfo().getDestination().isTopic() || 110 !ds.getRemoteInfo().isNetworkSubscription() || 111 (ds.getRemoteInfo().getDestination().isQueue() && configuration.isConduitNetworkQueueSubscriptions()); 112 } 113 114 @Override 115 protected void removeDemandSubscription(ConsumerId id) throws IOException { 116 List<DemandSubscription> tmpList = new ArrayList<DemandSubscription>(); 117 118 for (DemandSubscription ds : subscriptionMapByLocalId.values()) { 119 if (ds.remove(id)) { 120 LOG.debug("{} on {} from {} removed interest for: {} from {}", 121 configuration.getBrokerName(), localBroker, remoteBrokerName, id, ds); 122 } 123 if (ds.isEmpty()) { 124 tmpList.add(ds); 125 } 126 } 127 128 for (DemandSubscription ds : tmpList) { 129 removeSubscription(ds); 130 LOG.debug("{} on {} from {} removed {}", 131 configuration.getBrokerName(), localBroker, remoteBrokerName, ds); 132 } 133 } 134}