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.net.URI; 021import java.net.URISyntaxException; 022import java.util.Iterator; 023import java.util.Map; 024import java.util.concurrent.ConcurrentHashMap; 025import java.util.concurrent.ConcurrentMap; 026 027import javax.management.ObjectName; 028 029import org.apache.activemq.broker.BrokerService; 030import org.apache.activemq.broker.SslContext; 031import org.apache.activemq.command.DiscoveryEvent; 032import org.apache.activemq.transport.Transport; 033import org.apache.activemq.transport.TransportFactory; 034import org.apache.activemq.transport.discovery.DiscoveryAgent; 035import org.apache.activemq.transport.discovery.DiscoveryAgentFactory; 036import org.apache.activemq.transport.discovery.DiscoveryListener; 037import org.apache.activemq.util.IntrospectionSupport; 038import org.apache.activemq.util.ServiceStopper; 039import org.apache.activemq.util.ServiceSupport; 040import org.apache.activemq.util.URISupport; 041import org.slf4j.Logger; 042import org.slf4j.LoggerFactory; 043 044/** 045 * A network connector which uses a discovery agent to detect the remote brokers 046 * available and setup a connection to each available remote broker 047 * 048 * @org.apache.xbean.XBean element="networkConnector" 049 * 050 */ 051public class DiscoveryNetworkConnector extends NetworkConnector implements DiscoveryListener { 052 private static final Logger LOG = LoggerFactory.getLogger(DiscoveryNetworkConnector.class); 053 054 private DiscoveryAgent discoveryAgent; 055 private Map<String, String> parameters; 056 private final ConcurrentMap<URI, DiscoveryEvent> activeEvents = new ConcurrentHashMap<URI, DiscoveryEvent>(); 057 private URI discoveryUri; 058 public DiscoveryNetworkConnector() { 059 } 060 061 public DiscoveryNetworkConnector(URI discoveryURI) throws IOException { 062 setUri(discoveryURI); 063 } 064 065 public void setUri(URI discoveryURI) throws IOException { 066 this.discoveryUri = discoveryURI; 067 setDiscoveryAgent(DiscoveryAgentFactory.createDiscoveryAgent(discoveryURI)); 068 try { 069 parameters = URISupport.parseParameters(discoveryURI); 070 // allow discovery agent to grab it's parameters 071 IntrospectionSupport.setProperties(getDiscoveryAgent(), parameters); 072 } catch (URISyntaxException e) { 073 LOG.warn("failed to parse query parameters from discoveryURI: {}", discoveryURI, e); 074 } 075 } 076 077 public URI getUri() { 078 return discoveryUri; 079 } 080 081 @Override 082 public void onServiceAdd(DiscoveryEvent event) { 083 // Ignore events once we start stopping. 084 if (serviceSupport.isStopped() || serviceSupport.isStopping()) { 085 return; 086 } 087 String url = event.getServiceName(); 088 if (url != null) { 089 URI uri; 090 try { 091 uri = new URI(url); 092 } catch (URISyntaxException e) { 093 LOG.warn("Could not connect to remote URI: {} due to bad URI syntax: ", url, e); 094 return; 095 } 096 097 if (localURI.equals(uri)) { 098 LOG.debug("not connecting loopback: {}", uri); 099 return; 100 } 101 102 if (connectionFilter != null && !connectionFilter.connectTo(uri)) { 103 LOG.debug("connectionFilter disallows connection to: {}", uri); 104 return; 105 } 106 107 // Should we try to connect to that URI? 108 if (activeEvents.putIfAbsent(uri, event) != null) { 109 LOG.debug("Discovery agent generated a duplicate onServiceAdd event for: {}", uri); 110 return; 111 } 112 113 URI connectUri = uri; 114 try { 115 connectUri = URISupport.applyParameters(connectUri, parameters, DISCOVERED_OPTION_PREFIX); 116 } catch (URISyntaxException e) { 117 LOG.warn("could not apply query parameters: {} to: {}",parameters, connectUri, e); 118 } 119 120 LOG.info("Establishing network connection from {} to {}", localURI, connectUri); 121 122 Transport remoteTransport; 123 Transport localTransport; 124 try { 125 // Allows the transport to access the broker's ssl configuration. 126 if (getSslContext() != null) { 127 SslContext.setCurrentSslContext(getSslContext()); 128 } else { 129 SslContext.setCurrentSslContext(getBrokerService().getSslContext()); 130 } 131 try { 132 remoteTransport = TransportFactory.connect(connectUri); 133 } catch (Exception e) { 134 LOG.warn("Could not connect to remote URI: {}: {}", connectUri, e.getMessage()); 135 LOG.debug("Connection failure exception: ", e); 136 try { 137 discoveryAgent.serviceFailed(event); 138 } catch (IOException e1) { 139 LOG.debug("Failure while handling create remote transport failure event: {}", e1.getMessage(), e1); 140 } 141 return; 142 } 143 try { 144 localTransport = createLocalTransport(); 145 } catch (Exception e) { 146 ServiceSupport.dispose(remoteTransport); 147 LOG.warn("Could not connect to local URI: {}: {}", localURI, e.getMessage()); 148 LOG.debug("Connection failure exception: ", e); 149 150 try { 151 discoveryAgent.serviceFailed(event); 152 } catch (IOException e1) { 153 LOG.debug("Failure while handling create local transport failure event: {}", e1.getMessage(), e1); 154 } 155 return; 156 } 157 } finally { 158 SslContext.setCurrentSslContext(null); 159 } 160 NetworkBridge bridge = createBridge(localTransport, remoteTransport, event); 161 try { 162 synchronized (bridges) { 163 bridges.put(uri, bridge); 164 } 165 bridge.start(); 166 } catch (Exception e) { 167 ServiceSupport.dispose(localTransport); 168 ServiceSupport.dispose(remoteTransport); 169 LOG.warn("Could not start network bridge between: {} and: {} due to: {}", localURI, uri, e.getMessage()); 170 LOG.debug("Start failure exception: ", e); 171 try { 172 // Will remove bridge and active event. 173 discoveryAgent.serviceFailed(event); 174 } catch (IOException e1) { 175 LOG.debug("Discovery agent failure while handling failure event: {}", e1.getMessage(), e1); 176 } 177 } 178 } 179 } 180 181 @Override 182 public void onServiceRemove(DiscoveryEvent event) { 183 String url = event.getServiceName(); 184 if (url != null) { 185 URI uri; 186 try { 187 uri = new URI(url); 188 } catch (URISyntaxException e) { 189 LOG.warn("Could not connect to remote URI: {} due to bad URI syntax: ", url, e); 190 return; 191 } 192 193 // Only remove bridge if this is the active discovery event for the URL. 194 if (activeEvents.remove(uri, event)) { 195 synchronized (bridges) { 196 bridges.remove(uri); 197 } 198 } 199 } 200 } 201 202 public DiscoveryAgent getDiscoveryAgent() { 203 return discoveryAgent; 204 } 205 206 public void setDiscoveryAgent(DiscoveryAgent discoveryAgent) { 207 this.discoveryAgent = discoveryAgent; 208 if (discoveryAgent != null) { 209 this.discoveryAgent.setDiscoveryListener(this); 210 } 211 } 212 213 @Override 214 protected void handleStart() throws Exception { 215 if (discoveryAgent == null) { 216 throw new IllegalStateException("You must configure the 'discoveryAgent' property"); 217 } 218 this.discoveryAgent.start(); 219 super.handleStart(); 220 } 221 222 @Override 223 protected void handleStop(ServiceStopper stopper) throws Exception { 224 for (Iterator<NetworkBridge> i = bridges.values().iterator(); i.hasNext();) { 225 NetworkBridge bridge = i.next(); 226 try { 227 bridge.stop(); 228 } catch (Exception e) { 229 stopper.onException(this, e); 230 } 231 } 232 bridges.clear(); 233 activeEvents.clear(); 234 try { 235 this.discoveryAgent.stop(); 236 } catch (Exception e) { 237 stopper.onException(this, e); 238 } 239 240 super.handleStop(stopper); 241 } 242 243 protected NetworkBridge createBridge(Transport localTransport, Transport remoteTransport, final DiscoveryEvent event) { 244 class DiscoverNetworkBridgeListener extends MBeanNetworkListener { 245 246 public DiscoverNetworkBridgeListener(BrokerService brokerService, ObjectName connectorName) { 247 super(brokerService, DiscoveryNetworkConnector.this, connectorName); 248 } 249 250 @Override 251 public void bridgeFailed() { 252 if (!serviceSupport.isStopped()) { 253 try { 254 discoveryAgent.serviceFailed(event); 255 } catch (IOException e) { 256 } 257 } 258 259 } 260 } 261 NetworkBridgeListener listener = new DiscoverNetworkBridgeListener(getBrokerService(), getObjectName()); 262 263 DemandForwardingBridge result = getBridgeFactory().createNetworkBridge(this, localTransport, remoteTransport, listener); 264 result.setBrokerService(getBrokerService()); 265 return configureBridge(result); 266 } 267 268 @Override 269 public String toString() { 270 return "DiscoveryNetworkConnector:" + getName() + ":" + getBrokerService(); 271 } 272}