org.apache.activemq.network.DiscoveryNetworkConnector Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of activemq-osgi Show documentation
Show all versions of activemq-osgi Show documentation
Puts together an ActiveMQ OSGi bundle
/**
* 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 java.net.URI;
import java.net.URISyntaxException;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.management.ObjectName;
import org.apache.activemq.broker.BrokerService;
import org.apache.activemq.broker.SslContext;
import org.apache.activemq.command.DiscoveryEvent;
import org.apache.activemq.transport.Transport;
import org.apache.activemq.transport.TransportFactory;
import org.apache.activemq.transport.discovery.DiscoveryAgent;
import org.apache.activemq.transport.discovery.DiscoveryAgentFactory;
import org.apache.activemq.transport.discovery.DiscoveryListener;
import org.apache.activemq.util.IntrospectionSupport;
import org.apache.activemq.util.ServiceStopper;
import org.apache.activemq.util.ServiceSupport;
import org.apache.activemq.util.URISupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A network connector which uses a discovery agent to detect the remote brokers
* available and setup a connection to each available remote broker
*
* @org.apache.xbean.XBean element="networkConnector"
*
*/
public class DiscoveryNetworkConnector extends NetworkConnector implements DiscoveryListener {
private static final Logger LOG = LoggerFactory.getLogger(DiscoveryNetworkConnector.class);
private DiscoveryAgent discoveryAgent;
private Map parameters;
private final ConcurrentMap activeEvents = new ConcurrentHashMap();
private URI discoveryUri;
public DiscoveryNetworkConnector() {
}
public DiscoveryNetworkConnector(URI discoveryURI) throws IOException {
setUri(discoveryURI);
}
public void setUri(URI discoveryURI) throws IOException {
this.discoveryUri = discoveryURI;
setDiscoveryAgent(DiscoveryAgentFactory.createDiscoveryAgent(discoveryURI));
try {
parameters = URISupport.parseParameters(discoveryURI);
// allow discovery agent to grab it's parameters
IntrospectionSupport.setProperties(getDiscoveryAgent(), parameters);
} catch (URISyntaxException e) {
LOG.warn("failed to parse query parameters from discoveryURI: {}", discoveryURI, e);
}
}
public URI getUri() {
return discoveryUri;
}
@Override
public void onServiceAdd(DiscoveryEvent event) {
// Ignore events once we start stopping.
if (serviceSupport.isStopped() || serviceSupport.isStopping()) {
return;
}
String url = event.getServiceName();
if (url != null) {
URI uri;
try {
uri = new URI(url);
} catch (URISyntaxException e) {
LOG.warn("Could not connect to remote URI: {} due to bad URI syntax: ", url, e);
return;
}
if (localURI.equals(uri)) {
LOG.debug("not connecting loopback: {}", uri);
return;
}
if (connectionFilter != null && !connectionFilter.connectTo(uri)) {
LOG.debug("connectionFilter disallows connection to: {}", uri);
return;
}
// Should we try to connect to that URI?
if (activeEvents.putIfAbsent(uri, event) != null) {
LOG.debug("Discovery agent generated a duplicate onServiceAdd event for: {}", uri);
return;
}
URI connectUri = uri;
try {
connectUri = URISupport.applyParameters(connectUri, parameters, DISCOVERED_OPTION_PREFIX);
} catch (URISyntaxException e) {
LOG.warn("could not apply query parameters: {} to: {}", new Object[]{ parameters, connectUri }, e);
}
LOG.info("Establishing network connection from {} to {}", localURI, connectUri);
Transport remoteTransport;
Transport localTransport;
try {
// Allows the transport to access the broker's ssl configuration.
SslContext.setCurrentSslContext(getBrokerService().getSslContext());
try {
remoteTransport = TransportFactory.connect(connectUri);
} catch (Exception e) {
LOG.warn("Could not connect to remote URI: {}: {}", connectUri, e.getMessage());
LOG.debug("Connection failure exception: ", e);
activeEvents.remove(uri);
return;
}
try {
localTransport = createLocalTransport();
} catch (Exception e) {
ServiceSupport.dispose(remoteTransport);
LOG.warn("Could not connect to local URI: {}: {}", localURI, e.getMessage());
LOG.debug("Connection failure exception: ", e);
activeEvents.remove(uri);
return;
}
} finally {
SslContext.setCurrentSslContext(null);
}
NetworkBridge bridge = createBridge(localTransport, remoteTransport, event);
try {
synchronized (bridges) {
bridges.put(uri, bridge);
}
bridge.start();
} catch (Exception e) {
ServiceSupport.dispose(localTransport);
ServiceSupport.dispose(remoteTransport);
LOG.warn("Could not start network bridge between: {} and: {} due to: {}", new Object[]{ localURI, uri, e.getMessage() });
LOG.debug("Start failure exception: ", e);
try {
// Will remove bridge and active event.
discoveryAgent.serviceFailed(event);
} catch (IOException e1) {
LOG.debug("Discovery agent failure while handling failure event: {}", e1.getMessage(), e1);
}
}
}
}
@Override
public void onServiceRemove(DiscoveryEvent event) {
String url = event.getServiceName();
if (url != null) {
URI uri;
try {
uri = new URI(url);
} catch (URISyntaxException e) {
LOG.warn("Could not connect to remote URI: {} due to bad URI syntax: ", url, e);
return;
}
// Only remove bridge if this is the active discovery event for the URL.
if (activeEvents.remove(uri, event)) {
synchronized (bridges) {
bridges.remove(uri);
}
}
}
}
public DiscoveryAgent getDiscoveryAgent() {
return discoveryAgent;
}
public void setDiscoveryAgent(DiscoveryAgent discoveryAgent) {
this.discoveryAgent = discoveryAgent;
if (discoveryAgent != null) {
this.discoveryAgent.setDiscoveryListener(this);
}
}
@Override
protected void handleStart() throws Exception {
if (discoveryAgent == null) {
throw new IllegalStateException("You must configure the 'discoveryAgent' property");
}
this.discoveryAgent.start();
super.handleStart();
}
@Override
protected void handleStop(ServiceStopper stopper) throws Exception {
for (Iterator i = bridges.values().iterator(); i.hasNext();) {
NetworkBridge bridge = i.next();
try {
bridge.stop();
} catch (Exception e) {
stopper.onException(this, e);
}
}
bridges.clear();
activeEvents.clear();
try {
this.discoveryAgent.stop();
} catch (Exception e) {
stopper.onException(this, e);
}
super.handleStop(stopper);
}
protected NetworkBridge createBridge(Transport localTransport, Transport remoteTransport, final DiscoveryEvent event) {
class DiscoverNetworkBridgeListener extends MBeanNetworkListener {
public DiscoverNetworkBridgeListener(BrokerService brokerService, ObjectName connectorName) {
super(brokerService, DiscoveryNetworkConnector.this, connectorName);
}
@Override
public void bridgeFailed() {
if (!serviceSupport.isStopped()) {
try {
discoveryAgent.serviceFailed(event);
} catch (IOException e) {
}
}
}
}
NetworkBridgeListener listener = new DiscoverNetworkBridgeListener(getBrokerService(), getObjectName());
DemandForwardingBridge result = NetworkBridgeFactory.createBridge(this, localTransport, remoteTransport, listener);
result.setBrokerService(getBrokerService());
return configureBridge(result);
}
@Override
public String toString() {
return "DiscoveryNetworkConnector:" + getName() + ":" + getBrokerService();
}
}