git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@920306 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Robert Davies 2010-03-08 12:48:45 +00:00
parent cc18e703b2
commit f392884e31
41 changed files with 1014 additions and 294 deletions

View File

@ -215,6 +215,7 @@ public class ActiveMQConnection implements Connection, TopicConnection, QueueCon
this.info = new ConnectionInfo(new ConnectionId(CONNECTION_ID_GENERATOR.generateId())); this.info = new ConnectionInfo(new ConnectionId(CONNECTION_ID_GENERATOR.generateId()));
this.info.setManageable(true); this.info.setManageable(true);
this.info.setFaultTolerant(transport.isFaultTolerant());
this.connectionSessionId = new SessionId(info.getConnectionId(), -1); this.connectionSessionId = new SessionId(info.getConnectionId(), -1);
this.transport.setTransportListener(this); this.transport.setTransportListener(this);

View File

@ -440,10 +440,9 @@ public class AdvisoryBroker extends BrokerFilter {
String id = getBrokerId() != null ? getBrokerId().getValue() : "NOT_SET"; String id = getBrokerId() != null ? getBrokerId().getValue() : "NOT_SET";
advisoryMessage.setStringProperty(AdvisorySupport.MSG_PROPERTY_ORIGIN_BROKER_ID, id); advisoryMessage.setStringProperty(AdvisorySupport.MSG_PROPERTY_ORIGIN_BROKER_ID, id);
String[] uris = getBrokerService().getTransportConnectorURIs();
String url = getBrokerService().getVmConnectorURI().toString(); String url = getBrokerService().getVmConnectorURI().toString();
if (uris != null && uris.length > 0) { if (getBrokerService().getDefaultSocketURI() != null) {
url = uris[0]; url = getBrokerService().getDefaultSocketURI().toString();
} }
advisoryMessage.setStringProperty(AdvisorySupport.MSG_PROPERTY_ORIGIN_BROKER_URL, url); advisoryMessage.setStringProperty(AdvisorySupport.MSG_PROPERTY_ORIGIN_BROKER_URL, url);

View File

@ -31,7 +31,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
import javax.management.MalformedObjectNameException; import javax.management.MalformedObjectNameException;
@ -154,6 +153,7 @@ public class BrokerService implements Service {
private boolean deleteAllMessagesOnStartup; private boolean deleteAllMessagesOnStartup;
private boolean advisorySupport = true; private boolean advisorySupport = true;
private URI vmConnectorURI; private URI vmConnectorURI;
private URI defaultSocketURI;
private PolicyMap destinationPolicy; private PolicyMap destinationPolicy;
private final AtomicBoolean started = new AtomicBoolean(false); private final AtomicBoolean started = new AtomicBoolean(false);
private final AtomicBoolean stopped = new AtomicBoolean(false); private final AtomicBoolean stopped = new AtomicBoolean(false);
@ -1272,6 +1272,28 @@ public class BrokerService implements Service {
this.vmConnectorURI = vmConnectorURI; this.vmConnectorURI = vmConnectorURI;
} }
public URI getDefaultSocketURI() {
if (started.get()) {
if (this.defaultSocketURI==null) {
for (TransportConnector tc:this.transportConnectors) {
URI result = null;
try {
result = tc.getConnectUri();
} catch (Exception e) {
LOG.warn("Failed to get the ConnectURI for "+tc,e);
}
if (result != null) {
this.defaultSocketURI=result;
break;
}
}
}
return this.defaultSocketURI;
}
return null;
}
/** /**
* @return Returns the shutdownOnMasterFailure. * @return Returns the shutdownOnMasterFailure.
*/ */
@ -2007,6 +2029,9 @@ public class BrokerService implements Service {
connector.setLocalUri(uri); connector.setLocalUri(uri);
connector.setBrokerName(getBrokerName()); connector.setBrokerName(getBrokerName());
connector.setDurableDestinations(durableDestinations); connector.setDurableDestinations(durableDestinations);
if (getDefaultSocketURI() != null) {
connector.setBrokerURL(getDefaultSocketURI().toString());
}
connector.start(); connector.start();
} }
for (Iterator<ProxyConnector> iter = getProxyConnectors().iterator(); iter.hasNext();) { for (Iterator<ProxyConnector> iter = getProxyConnectors().iterator(); iter.hasNext();) {

View File

@ -17,10 +17,10 @@
package org.apache.activemq.broker; package org.apache.activemq.broker;
import java.io.IOException; import java.io.IOException;
import org.apache.activemq.Service; import org.apache.activemq.Service;
import org.apache.activemq.broker.region.ConnectionStatistics; import org.apache.activemq.broker.region.ConnectionStatistics;
import org.apache.activemq.command.Command; import org.apache.activemq.command.Command;
import org.apache.activemq.command.ConnectionControl;
import org.apache.activemq.command.Response; import org.apache.activemq.command.Response;
/** /**
@ -51,6 +51,7 @@ public interface Connection extends Service {
* Services a client command and submits it to the broker. * Services a client command and submits it to the broker.
* *
* @param command * @param command
* @return Response
*/ */
Response service(Command command); Response service(Command command);
@ -111,4 +112,11 @@ public interface Connection extends Service {
*/ */
boolean isNetworkConnection(); boolean isNetworkConnection();
/**
* @return true if a fault tolerant connection
*/
boolean isFaultTolerantConnection();
void updateClient(ConnectionControl control);
} }

View File

@ -28,8 +28,7 @@ import org.apache.activemq.command.BrokerInfo;
public interface Connector extends Service { public interface Connector extends Service {
/** /**
* * @return brokerInfo
* @return
*/ */
BrokerInfo getBrokerInfo(); BrokerInfo getBrokerInfo();
@ -37,4 +36,21 @@ public interface Connector extends Service {
* @return the statistics for this connector * @return the statistics for this connector
*/ */
ConnectorStatistics getStatistics(); ConnectorStatistics getStatistics();
/**
* @return true if update client connections when brokers leave/join a cluster
*/
public boolean isUpdateClusterClients();
/**
* @return true if clients should be re-balanced across the cluster
*/
public boolean isRebalanceClusterClients();
/**
* Update all the connections with information
* about the connected brokers in the cluster
*/
public void updateClientClusterInfo();
} }

View File

@ -121,7 +121,7 @@ public class TransportConnection implements Connection, Task, CommandVisitor {
// Used to do async dispatch.. this should perhaps be pushed down into the // Used to do async dispatch.. this should perhaps be pushed down into the
// transport layer.. // transport layer..
private boolean inServiceException; private boolean inServiceException;
private ConnectionStatistics statistics = new ConnectionStatistics(); private final ConnectionStatistics statistics = new ConnectionStatistics();
private boolean manageable; private boolean manageable;
private boolean slow; private boolean slow;
private boolean markedCandidate; private boolean markedCandidate;
@ -133,15 +133,15 @@ public class TransportConnection implements Connection, Task, CommandVisitor {
private boolean pendingStop; private boolean pendingStop;
private long timeStamp; private long timeStamp;
private final AtomicBoolean stopping = new AtomicBoolean(false); private final AtomicBoolean stopping = new AtomicBoolean(false);
private CountDownLatch stopped = new CountDownLatch(1); private final CountDownLatch stopped = new CountDownLatch(1);
private final AtomicBoolean asyncException = new AtomicBoolean(false); private final AtomicBoolean asyncException = new AtomicBoolean(false);
private final Map<ProducerId, ProducerBrokerExchange> producerExchanges = new HashMap<ProducerId, ProducerBrokerExchange>(); private final Map<ProducerId, ProducerBrokerExchange> producerExchanges = new HashMap<ProducerId, ProducerBrokerExchange>();
private final Map<ConsumerId, ConsumerBrokerExchange> consumerExchanges = new HashMap<ConsumerId, ConsumerBrokerExchange>(); private final Map<ConsumerId, ConsumerBrokerExchange> consumerExchanges = new HashMap<ConsumerId, ConsumerBrokerExchange>();
private CountDownLatch dispatchStoppedLatch = new CountDownLatch(1); private final CountDownLatch dispatchStoppedLatch = new CountDownLatch(1);
private ConnectionContext context; private ConnectionContext context;
private boolean networkConnection; private boolean networkConnection;
private boolean faultTolerantConnection; private boolean faultTolerantConnection;
private AtomicInteger protocolVersion = new AtomicInteger(CommandTypes.PROTOCOL_VERSION); private final AtomicInteger protocolVersion = new AtomicInteger(CommandTypes.PROTOCOL_VERSION);
private DemandForwardingBridge duplexBridge; private DemandForwardingBridge duplexBridge;
private final TaskRunnerFactory taskRunnerFactory; private final TaskRunnerFactory taskRunnerFactory;
private TransportConnectionStateRegister connectionStateRegister = new SingleTransportConnectionStateRegister(); private TransportConnectionStateRegister connectionStateRegister = new SingleTransportConnectionStateRegister();
@ -168,6 +168,7 @@ public class TransportConnection implements Connection, Task, CommandVisitor {
this.taskRunnerFactory = taskRunnerFactory; this.taskRunnerFactory = taskRunnerFactory;
this.transport = transport; this.transport = transport;
this.transport.setTransportListener(new DefaultTransportListener() { this.transport.setTransportListener(new DefaultTransportListener() {
@Override
public void onCommand(Object o) { public void onCommand(Object o) {
serviceLock.readLock().lock(); serviceLock.readLock().lock();
try { try {
@ -184,6 +185,7 @@ public class TransportConnection implements Connection, Task, CommandVisitor {
} }
} }
@Override
public void onException(IOException exception) { public void onException(IOException exception) {
serviceLock.readLock().lock(); serviceLock.readLock().lock();
try { try {
@ -241,6 +243,7 @@ public class TransportConnection implements Connection, Task, CommandVisitor {
public void serviceExceptionAsync(final IOException e) { public void serviceExceptionAsync(final IOException e) {
if (asyncException.compareAndSet(false, true)) { if (asyncException.compareAndSet(false, true)) {
new Thread("Async Exception Handler") { new Thread("Async Exception Handler") {
@Override
public void run() { public void run() {
serviceException(e); serviceException(e);
} }
@ -654,6 +657,7 @@ public class TransportConnection implements Connection, Task, CommandVisitor {
} }
registerConnectionState(info.getConnectionId(), state); registerConnectionState(info.getConnectionId(), state);
LOG.debug("Setting up new connection id: " + info.getConnectionId() + ", address: " + getRemoteAddress()); LOG.debug("Setting up new connection id: " + info.getConnectionId() + ", address: " + getRemoteAddress());
this.faultTolerantConnection=info.isFaultTolerant();
// Setup the context. // Setup the context.
String clientId = info.getClientId(); String clientId = info.getClientId();
context = new ConnectionContext(); context = new ConnectionContext();
@ -672,6 +676,7 @@ public class TransportConnection implements Connection, Task, CommandVisitor {
this.manageable = info.isManageable(); this.manageable = info.isManageable();
state.setContext(context); state.setContext(context);
state.setConnection(this); state.setConnection(this);
try { try {
broker.addConnection(context, info); broker.addConnection(context, info);
} catch (Exception e) { } catch (Exception e) {
@ -679,9 +684,9 @@ public class TransportConnection implements Connection, Task, CommandVisitor {
LOG.warn("Failed to add Connection", e); LOG.warn("Failed to add Connection", e);
throw e; throw e;
} }
if (info.isManageable() && broker.isFaultTolerantConfiguration()) { if (info.isManageable()) {
// send ConnectionCommand // send ConnectionCommand
ConnectionControl command = new ConnectionControl(); ConnectionControl command = this.connector.getConnectionControl();
command.setFaultTolerant(broker.isFaultTolerantConfiguration()); command.setFaultTolerant(broker.isFaultTolerantConfiguration());
dispatchAsync(command); dispatchAsync(command);
} }
@ -867,7 +872,10 @@ public class TransportConnection implements Connection, Task, CommandVisitor {
} }
transport.start(); transport.start();
active = true; active = true;
dispatchAsync(connector.getBrokerInfo()); BrokerInfo info = connector.getBrokerInfo().copy();
info.setPeerBrokerInfos(this.broker.getPeerBrokerInfos());
dispatchAsync(info);
connector.onStarted(this); connector.onStarted(this);
} }
} catch (Exception e) { } catch (Exception e) {
@ -1121,6 +1129,10 @@ public class TransportConnection implements Connection, Task, CommandVisitor {
return networkConnection; return networkConnection;
} }
public boolean isFaultTolerantConnection() {
return this.faultTolerantConnection;
}
protected synchronized void setStarting(boolean starting) { protected synchronized void setStarting(boolean starting) {
this.starting = starting; this.starting = starting;
} }
@ -1223,6 +1235,13 @@ public class TransportConnection implements Connection, Task, CommandVisitor {
return null; return null;
} }
public void updateClient(ConnectionControl control) {
if (isActive() && isBlocked() == false && isFaultTolerantConnection() && this.wireFormatInfo != null
&& this.wireFormatInfo.getVersion() >= 6) {
dispatchAsync(control);
}
}
private ProducerBrokerExchange getProducerBrokerExchange(ProducerId id) { private ProducerBrokerExchange getProducerBrokerExchange(ProducerId id) {
ProducerBrokerExchange result = producerExchanges.get(id); ProducerBrokerExchange result = producerExchanges.get(id);
if (result == null) { if (result == null) {

View File

@ -16,10 +16,17 @@
*/ */
package org.apache.activemq.broker; package org.apache.activemq.broker;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.management.ObjectName;
import org.apache.activemq.broker.jmx.ManagedTransportConnector; import org.apache.activemq.broker.jmx.ManagedTransportConnector;
import org.apache.activemq.broker.jmx.ManagementContext; import org.apache.activemq.broker.jmx.ManagementContext;
import org.apache.activemq.broker.region.ConnectorStatistics; import org.apache.activemq.broker.region.ConnectorStatistics;
import org.apache.activemq.command.BrokerInfo; import org.apache.activemq.command.BrokerInfo;
import org.apache.activemq.command.ConnectionControl;
import org.apache.activemq.security.MessageAuthorizationPolicy; import org.apache.activemq.security.MessageAuthorizationPolicy;
import org.apache.activemq.thread.DefaultThreadPools; import org.apache.activemq.thread.DefaultThreadPools;
import org.apache.activemq.thread.TaskRunnerFactory; import org.apache.activemq.thread.TaskRunnerFactory;
@ -34,6 +41,7 @@ import org.apache.activemq.util.ServiceSupport;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import static org.apache.activemq.thread.DefaultThreadPools.*; import static org.apache.activemq.thread.DefaultThreadPools.*;
import java.io.IOException; import java.io.IOException;
@ -53,7 +61,6 @@ public class TransportConnector implements Connector, BrokerServiceAware {
protected CopyOnWriteArrayList<TransportConnection> connections = new CopyOnWriteArrayList<TransportConnection>(); protected CopyOnWriteArrayList<TransportConnection> connections = new CopyOnWriteArrayList<TransportConnection>();
protected TransportStatusDetector statusDector; protected TransportStatusDetector statusDector;
private BrokerService brokerService; private BrokerService brokerService;
private TransportServer server; private TransportServer server;
private URI uri; private URI uri;
@ -61,13 +68,15 @@ public class TransportConnector implements Connector, BrokerServiceAware {
private TaskRunnerFactory taskRunnerFactory; private TaskRunnerFactory taskRunnerFactory;
private MessageAuthorizationPolicy messageAuthorizationPolicy; private MessageAuthorizationPolicy messageAuthorizationPolicy;
private DiscoveryAgent discoveryAgent; private DiscoveryAgent discoveryAgent;
private ConnectorStatistics statistics = new ConnectorStatistics(); private final ConnectorStatistics statistics = new ConnectorStatistics();
private URI discoveryUri; private URI discoveryUri;
private URI connectUri; private URI connectUri;
private String name; private String name;
private boolean disableAsyncDispatch; private boolean disableAsyncDispatch;
private boolean enableStatusMonitor = false; private boolean enableStatusMonitor = false;
private Broker broker; private Broker broker;
private boolean updateClusterClients=false;
private boolean rebalanceClusterClients;
public TransportConnector() { public TransportConnector() {
} }
@ -109,6 +118,8 @@ public class TransportConnector implements Connector, BrokerServiceAware {
rc.setTaskRunnerFactory(getTaskRunnerFactory()); rc.setTaskRunnerFactory(getTaskRunnerFactory());
rc.setUri(getUri()); rc.setUri(getUri());
rc.setBrokerService(brokerService); rc.setBrokerService(brokerService);
rc.setUpdateClusterClients(isUpdateClusterClients());
rc.setRebalanceClusterClients(isRebalanceClusterClients());
return rc; return rc;
} }
@ -193,16 +204,13 @@ public class TransportConnector implements Connector, BrokerServiceAware {
} }
public void start() throws Exception { public void start() throws Exception {
TransportServer server = getServer(); TransportServer server = getServer();
broker = brokerService.getBroker(); broker = brokerService.getBroker();
brokerInfo.setBrokerName(broker.getBrokerName()); brokerInfo.setBrokerName(broker.getBrokerName());
brokerInfo.setBrokerId(broker.getBrokerId()); brokerInfo.setBrokerId(broker.getBrokerId());
brokerInfo.setPeerBrokerInfos(broker.getPeerBrokerInfos()); brokerInfo.setPeerBrokerInfos(broker.getPeerBrokerInfos());
brokerInfo.setFaultTolerantConfiguration(broker.isFaultTolerantConfiguration()); brokerInfo.setFaultTolerantConfiguration(broker.isFaultTolerantConfiguration());
brokerInfo.setBrokerURL(server.getConnectURI().toString()); brokerInfo.setBrokerURL(server.getConnectURI().toString());
server.setAcceptListener(new TransportAcceptListener() { server.setAcceptListener(new TransportAcceptListener() {
public void onAccept(final Transport transport) { public void onAccept(final Transport transport) {
try { try {
@ -233,7 +241,6 @@ public class TransportConnector implements Connector, BrokerServiceAware {
LOG.debug("Reason: " + error, error); LOG.debug("Reason: " + error, error);
} }
}); });
server.setBrokerInfo(brokerInfo); server.setBrokerInfo(brokerInfo);
server.start(); server.start();
@ -366,6 +373,7 @@ public class TransportConnector implements Connector, BrokerServiceAware {
this.name = name; this.name = name;
} }
@Override
public String toString() { public String toString() {
String rc = getName(); String rc = getName();
if (rc == null) { if (rc == null) {
@ -374,6 +382,43 @@ public class TransportConnector implements Connector, BrokerServiceAware {
return rc; return rc;
} }
protected ConnectionControl getConnectionControl() {
boolean rebalance = isRebalanceClusterClients();
String connectedBrokers = "";
String self = "";
if (brokerService.getDefaultSocketURI() != null) {
self += brokerService.getDefaultSocketURI().toString();
self += ",";
}
if (rebalance == false) {
connectedBrokers += self;
}
if (this.broker.getPeerBrokerInfos() != null) {
for (BrokerInfo info : this.broker.getPeerBrokerInfos()) {
connectedBrokers += info.getBrokerURL();
connectedBrokers += ",";
}
}
if (rebalance) {
connectedBrokers += self;
}
ConnectionControl control = new ConnectionControl();
control.setConnectedBrokers(connectedBrokers);
control.setRebalanceConnection(rebalance);
return control;
}
public void updateClientClusterInfo() {
if (isRebalanceClusterClients() || isUpdateClusterClients()) {
ConnectionControl control = getConnectionControl();
for (Connection c: this.connections) {
c.updateClient(control);
}
}
}
public boolean isDisableAsyncDispatch() { public boolean isDisableAsyncDispatch() {
return disableAsyncDispatch; return disableAsyncDispatch;
} }
@ -410,4 +455,32 @@ public class TransportConnector implements Connector, BrokerServiceAware {
public BrokerService getBrokerService() { public BrokerService getBrokerService() {
return brokerService; return brokerService;
} }
/**
* @return the updateClusterClients
*/
public boolean isUpdateClusterClients() {
return this.updateClusterClients;
}
/**
* @param updateClusterClients the updateClusterClients to set
*/
public void setUpdateClusterClients(boolean updateClusterClients) {
this.updateClusterClients = updateClusterClients;
}
/**
* @return the rebalanceClusterClients
*/
public boolean isRebalanceClusterClients() {
return this.rebalanceClusterClients;
}
/**
* @param rebalanceClusterClients the rebalanceClusterClients to set
*/
public void setRebalanceClusterClients(boolean rebalanceClusterClients) {
this.rebalanceClusterClients = rebalanceClusterClients;
}
} }

View File

@ -21,6 +21,7 @@ import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -34,6 +35,7 @@ import org.apache.activemq.broker.ConnectionContext;
import org.apache.activemq.broker.ConsumerBrokerExchange; import org.apache.activemq.broker.ConsumerBrokerExchange;
import org.apache.activemq.broker.EmptyBroker; import org.apache.activemq.broker.EmptyBroker;
import org.apache.activemq.broker.ProducerBrokerExchange; import org.apache.activemq.broker.ProducerBrokerExchange;
import org.apache.activemq.broker.TransportConnector;
import org.apache.activemq.broker.region.policy.DeadLetterStrategy; import org.apache.activemq.broker.region.policy.DeadLetterStrategy;
import org.apache.activemq.broker.region.policy.PolicyMap; import org.apache.activemq.broker.region.policy.PolicyMap;
import org.apache.activemq.command.ActiveMQDestination; import org.apache.activemq.command.ActiveMQDestination;
@ -585,12 +587,14 @@ public class RegionBroker extends EmptyBroker {
@Override @Override
public synchronized void addBroker(Connection connection, BrokerInfo info) { public synchronized void addBroker(Connection connection, BrokerInfo info) {
brokerInfos.add(info); brokerInfos.add(info);
updateClients();
} }
@Override @Override
public synchronized void removeBroker(Connection connection, BrokerInfo info) { public synchronized void removeBroker(Connection connection, BrokerInfo info) {
if (info != null) { if (info != null) {
brokerInfos.remove(info); brokerInfos.remove(info);
updateClients();
} }
} }
@ -830,4 +834,11 @@ public class RegionBroker extends EmptyBroker {
LOG.warn("unmatched destination: " + destination + ", in consumerControl: " + control); LOG.warn("unmatched destination: " + destination + ", in consumerControl: " + control);
} }
} }
protected void updateClients() {
List<TransportConnector> connectors = this.brokerService.getTransportConnectors();
for (TransportConnector connector : connectors) {
connector.updateClientClusterInfo();
}
}
} }

View File

@ -17,7 +17,6 @@
package org.apache.activemq.command; package org.apache.activemq.command;
import java.util.Map; import java.util.Map;
import org.apache.activemq.util.IntrospectionSupport; import org.apache.activemq.util.IntrospectionSupport;
@ -61,6 +60,7 @@ public abstract class BaseCommand implements Command {
this.responseRequired = responseRequired; this.responseRequired = responseRequired;
} }
@Override
public String toString() { public String toString() {
return toString(null); return toString(null);
} }
@ -105,6 +105,10 @@ public abstract class BaseCommand implements Command {
return false; return false;
} }
public boolean isConnectionControl() {
return false;
}
/** /**
* The endpoint within the transport where this message came from. * The endpoint within the transport where this message came from.
*/ */

View File

@ -16,13 +16,12 @@
*/ */
package org.apache.activemq.command; package org.apache.activemq.command;
import org.apache.activemq.plugin.StatisticsBrokerPlugin; import java.io.IOException;
import java.util.Properties;
import org.apache.activemq.state.CommandVisitor; import org.apache.activemq.state.CommandVisitor;
import org.apache.activemq.util.MarshallingSupport; import org.apache.activemq.util.MarshallingSupport;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import java.io.IOException;
import java.util.Properties;
/** /**
* When a client connects to a broker, the broker send the client a BrokerInfo * When a client connects to a broker, the broker send the client a BrokerInfo
@ -50,6 +49,29 @@ public class BrokerInfo extends BaseCommand {
String brokerUploadUrl; String brokerUploadUrl;
String networkProperties; String networkProperties;
public BrokerInfo copy() {
BrokerInfo copy = new BrokerInfo();
copy(copy);
return copy;
}
private void copy(BrokerInfo copy) {
super.copy(copy);
copy.brokerId = this.brokerId;
copy.brokerURL = this.brokerURL;
copy.slaveBroker = this.slaveBroker;
copy.masterBroker = this.masterBroker;
copy.faultTolerantConfiguration = this.faultTolerantConfiguration;
copy.networkConnection = this.networkConnection;
copy.duplexConnection = this.duplexConnection;
copy.peerBrokerInfos = this.peerBrokerInfos;
copy.brokerName = this.brokerName;
copy.connectionId = this.connectionId;
copy.brokerUploadUrl = this.brokerUploadUrl;
copy.networkProperties = this.networkProperties;
}
@Override
public boolean isBrokerInfo() { public boolean isBrokerInfo() {
return true; return true;
} }

View File

@ -53,6 +53,8 @@ public interface Command extends DataStructure {
boolean isShutdownInfo(); boolean isShutdownInfo();
boolean isConnectionControl();
Response visit(CommandVisitor visitor) throws Exception; Response visit(CommandVisitor visitor) throws Exception;
/** /**

View File

@ -31,6 +31,9 @@ public class ConnectionControl extends BaseCommand {
protected boolean close; protected boolean close;
protected boolean exit; protected boolean exit;
protected boolean faultTolerant; protected boolean faultTolerant;
protected String connectedBrokers="";
protected String reconnectTo = "";
protected boolean rebalanceConnection;
public byte getDataStructureType() { public byte getDataStructureType() {
return DATA_STRUCTURE_TYPE; return DATA_STRUCTURE_TYPE;
@ -39,6 +42,10 @@ public class ConnectionControl extends BaseCommand {
public Response visit(CommandVisitor visitor) throws Exception { public Response visit(CommandVisitor visitor) throws Exception {
return visitor.processConnectionControl(this); return visitor.processConnectionControl(this);
} }
@Override
public boolean isConnectionControl() {
return true;
}
/** /**
* @openwire:property version=1 * @openwire:property version=1
@ -114,4 +121,49 @@ public class ConnectionControl extends BaseCommand {
public void setSuspend(boolean suspend) { public void setSuspend(boolean suspend) {
this.suspend = suspend; this.suspend = suspend;
} }
/**
* @openwire:property version=6 cache=false
* @return connected brokers.
*/
public String getConnectedBrokers() {
return this.connectedBrokers;
}
/**
* @param connectedBrokers the connectedBrokers to set
*/
public void setConnectedBrokers(String connectedBrokers) {
this.connectedBrokers = connectedBrokers;
}
/**
* @openwire:property version=6 cache=false
* @return the reconnectTo
*/
public String getReconnectTo() {
return this.reconnectTo;
}
/**
* @param reconnectTo the reconnectTo to set
*/
public void setReconnectTo(String reconnectTo) {
this.reconnectTo = reconnectTo;
}
/**
* @return the rebalanceConnection
* @openwire:property version=6 cache=false
*/
public boolean isRebalanceConnection() {
return this.rebalanceConnection;
}
/**
* @param rebalanceConnection the rebalanceConnection to set
*/
public void setRebalanceConnection(boolean rebalanceConnection) {
this.rebalanceConnection = rebalanceConnection;
}
} }

View File

@ -35,6 +35,7 @@ public class ConnectionInfo extends BaseCommand {
protected boolean brokerMasterConnector; protected boolean brokerMasterConnector;
protected boolean manageable; protected boolean manageable;
protected boolean clientMaster = true; protected boolean clientMaster = true;
protected boolean faultTolerant = false;
protected transient Object transportContext; protected transient Object transportContext;
public ConnectionInfo() { public ConnectionInfo() {
@ -65,6 +66,7 @@ public class ConnectionInfo extends BaseCommand {
copy.manageable = manageable; copy.manageable = manageable;
copy.clientMaster = clientMaster; copy.clientMaster = clientMaster;
copy.transportContext = transportContext; copy.transportContext = transportContext;
copy.faultTolerant= faultTolerant;
} }
/** /**
@ -199,4 +201,19 @@ public class ConnectionInfo extends BaseCommand {
this.clientMaster = clientMaster; this.clientMaster = clientMaster;
} }
/**
* @openwire:property version=6 cache=false
* @return the faultTolerant
*/
public boolean isFaultTolerant() {
return this.faultTolerant;
}
/**
* @param faultTolerant the faultTolerant to set
*/
public void setFaultTolerant(boolean faultTolerant) {
this.faultTolerant = faultTolerant;
}
} }

View File

@ -118,6 +118,10 @@ public class PartialCommand implements Command {
return false; return false;
} }
public boolean isConnectionControl() {
return false;
}
public void setResponseRequired(boolean responseRequired) { public void setResponseRequired(boolean responseRequired) {
} }
@ -137,5 +141,4 @@ public class PartialCommand implements Command {
return "PartialCommand[id: " + commandId + " data: " + size + " byte(s)]"; return "PartialCommand[id: " + commandId + " data: " + size + " byte(s)]";
} }
} }

View File

@ -47,14 +47,12 @@ public class RemoveSubscriptionInfo extends BaseCommand {
/** /**
* @openwire:property version=1 * @openwire:property version=1
* @deprecated
*/ */
public String getSubcriptionName() { public String getSubcriptionName() {
return subscriptionName; return subscriptionName;
} }
/** /**
* @deprecated
*/ */
public void setSubcriptionName(String subscriptionName) { public void setSubcriptionName(String subscriptionName) {
this.subscriptionName = subscriptionName; this.subscriptionName = subscriptionName;

View File

@ -76,7 +76,6 @@ public class SubscriptionInfo implements DataStructure {
/** /**
* @openwire:property version=1 * @openwire:property version=1
* @deprecated
*/ */
public String getSubcriptionName() { public String getSubcriptionName() {
return subscriptionName; return subscriptionName;
@ -84,7 +83,6 @@ public class SubscriptionInfo implements DataStructure {
/** /**
* @param subscriptionName * * @param subscriptionName *
* @deprecated
*/ */
public void setSubcriptionName(String subscriptionName) { public void setSubcriptionName(String subscriptionName) {
this.subscriptionName = subscriptionName; this.subscriptionName = subscriptionName;
@ -102,16 +100,19 @@ public class SubscriptionInfo implements DataStructure {
return false; return false;
} }
@Override
public String toString() { public String toString() {
return IntrospectionSupport.toString(this); return IntrospectionSupport.toString(this);
} }
@Override
public int hashCode() { public int hashCode() {
int h1 = clientId != null ? clientId.hashCode() : -1; int h1 = clientId != null ? clientId.hashCode() : -1;
int h2 = subscriptionName != null ? subscriptionName.hashCode() : -1; int h2 = subscriptionName != null ? subscriptionName.hashCode() : -1;
return h1 ^ h2; return h1 ^ h2;
} }
@Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
boolean result = false; boolean result = false;
if (obj instanceof SubscriptionInfo) { if (obj instanceof SubscriptionInfo) {

View File

@ -23,7 +23,6 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.apache.activemq.state.CommandVisitor; import org.apache.activemq.state.CommandVisitor;
import org.apache.activemq.util.ByteArrayInputStream; import org.apache.activemq.util.ByteArrayInputStream;
import org.apache.activemq.util.ByteArrayOutputStream; import org.apache.activemq.util.ByteArrayOutputStream;
@ -290,6 +289,7 @@ public class WireFormatInfo implements Command, MarshallAware {
return visitor.processWireFormat(this); return visitor.processWireFormat(this);
} }
@Override
public String toString() { public String toString() {
Map<String, Object> p = null; Map<String, Object> p = null;
try { try {
@ -357,6 +357,10 @@ public class WireFormatInfo implements Command, MarshallAware {
return false; return false;
} }
public boolean isConnectionControl() {
return false;
}
public void setCachedMarshalledForm(WireFormat wireFormat, ByteSequence data) { public void setCachedMarshalledForm(WireFormat wireFormat, ByteSequence data) {
} }

View File

@ -30,7 +30,6 @@ import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import org.apache.activemq.Service; import org.apache.activemq.Service;
import org.apache.activemq.advisory.AdvisorySupport; import org.apache.activemq.advisory.AdvisorySupport;
import org.apache.activemq.broker.BrokerService; import org.apache.activemq.broker.BrokerService;
@ -131,7 +130,7 @@ public abstract class DemandForwardingBridgeSupport implements NetworkBridge, Br
private BrokerInfo localBrokerInfo; private BrokerInfo localBrokerInfo;
private BrokerInfo remoteBrokerInfo; private BrokerInfo remoteBrokerInfo;
private AtomicBoolean started = new AtomicBoolean(); private final AtomicBoolean started = new AtomicBoolean();
private TransportConnection duplexInitiatingConnection; private TransportConnection duplexInitiatingConnection;
private BrokerService brokerService = null; private BrokerService brokerService = null;
@ -153,11 +152,13 @@ public abstract class DemandForwardingBridgeSupport implements NetworkBridge, Br
if (started.compareAndSet(false, true)) { if (started.compareAndSet(false, true)) {
localBroker.setTransportListener(new DefaultTransportListener() { localBroker.setTransportListener(new DefaultTransportListener() {
@Override
public void onCommand(Object o) { public void onCommand(Object o) {
Command command = (Command) o; Command command = (Command) o;
serviceLocalCommand(command); serviceLocalCommand(command);
} }
@Override
public void onException(IOException error) { public void onException(IOException error) {
serviceLocalException(error); serviceLocalException(error);
} }
@ -318,6 +319,7 @@ public abstract class DemandForwardingBridgeSupport implements NetworkBridge, Br
if (!isCreatedByDuplex()) { if (!isCreatedByDuplex()) {
BrokerInfo brokerInfo = new BrokerInfo(); BrokerInfo brokerInfo = new BrokerInfo();
brokerInfo.setBrokerName(configuration.getBrokerName()); brokerInfo.setBrokerName(configuration.getBrokerName());
brokerInfo.setBrokerURL(configuration.getBrokerURL());
brokerInfo.setNetworkConnection(true); brokerInfo.setNetworkConnection(true);
brokerInfo.setDuplexConnection(configuration.isDuplex()); brokerInfo.setDuplexConnection(configuration.isDuplex());
// set our properties // set our properties

View File

@ -17,7 +17,6 @@
package org.apache.activemq.network; package org.apache.activemq.network;
import java.util.List; import java.util.List;
import org.apache.activemq.command.ActiveMQDestination; import org.apache.activemq.command.ActiveMQDestination;
/** /**
@ -36,6 +35,7 @@ public class NetworkBridgeConfiguration {
private int prefetchSize = 1000; private int prefetchSize = 1000;
private int networkTTL = 1; private int networkTTL = 1;
private String brokerName = "localhost"; private String brokerName = "localhost";
private String brokerURL = "";
private String userName; private String userName;
private String password; private String password;
private String destinationFilter = ">"; private String destinationFilter = ">";
@ -274,4 +274,18 @@ public class NetworkBridgeConfiguration {
public void setSuppressDuplicateQueueSubscriptions(boolean val) { public void setSuppressDuplicateQueueSubscriptions(boolean val) {
suppressDuplicateQueueSubscriptions = val; suppressDuplicateQueueSubscriptions = val;
} }
/**
* @return the brokerURL
*/
public String getBrokerURL() {
return this.brokerURL;
}
/**
* @param brokerURL the brokerURL to set
*/
public void setBrokerURL(String brokerURL) {
this.brokerURL = brokerURL;
}
} }

View File

@ -71,6 +71,9 @@ public class ConnectionControlMarshaller extends BaseCommandMarshaller {
info.setFaultTolerant(bs.readBoolean()); info.setFaultTolerant(bs.readBoolean());
info.setResume(bs.readBoolean()); info.setResume(bs.readBoolean());
info.setSuspend(bs.readBoolean()); info.setSuspend(bs.readBoolean());
info.setConnectedBrokers(tightUnmarshalString(dataIn, bs));
info.setReconnectTo(tightUnmarshalString(dataIn, bs));
info.setRebalanceConnection(bs.readBoolean());
} }
@ -88,6 +91,9 @@ public class ConnectionControlMarshaller extends BaseCommandMarshaller {
bs.writeBoolean(info.isFaultTolerant()); bs.writeBoolean(info.isFaultTolerant());
bs.writeBoolean(info.isResume()); bs.writeBoolean(info.isResume());
bs.writeBoolean(info.isSuspend()); bs.writeBoolean(info.isSuspend());
rc += tightMarshalString1(info.getConnectedBrokers(), bs);
rc += tightMarshalString1(info.getReconnectTo(), bs);
bs.writeBoolean(info.isRebalanceConnection());
return rc + 0; return rc + 0;
} }
@ -108,6 +114,9 @@ public class ConnectionControlMarshaller extends BaseCommandMarshaller {
bs.readBoolean(); bs.readBoolean();
bs.readBoolean(); bs.readBoolean();
bs.readBoolean(); bs.readBoolean();
tightMarshalString2(info.getConnectedBrokers(), dataOut, bs);
tightMarshalString2(info.getReconnectTo(), dataOut, bs);
bs.readBoolean();
} }
@ -127,6 +136,9 @@ public class ConnectionControlMarshaller extends BaseCommandMarshaller {
info.setFaultTolerant(dataIn.readBoolean()); info.setFaultTolerant(dataIn.readBoolean());
info.setResume(dataIn.readBoolean()); info.setResume(dataIn.readBoolean());
info.setSuspend(dataIn.readBoolean()); info.setSuspend(dataIn.readBoolean());
info.setConnectedBrokers(looseUnmarshalString(dataIn));
info.setReconnectTo(looseUnmarshalString(dataIn));
info.setRebalanceConnection(dataIn.readBoolean());
} }
@ -144,6 +156,9 @@ public class ConnectionControlMarshaller extends BaseCommandMarshaller {
dataOut.writeBoolean(info.isFaultTolerant()); dataOut.writeBoolean(info.isFaultTolerant());
dataOut.writeBoolean(info.isResume()); dataOut.writeBoolean(info.isResume());
dataOut.writeBoolean(info.isSuspend()); dataOut.writeBoolean(info.isSuspend());
looseMarshalString(info.getConnectedBrokers(), dataOut);
looseMarshalString(info.getReconnectTo(), dataOut);
dataOut.writeBoolean(info.isRebalanceConnection());
} }
} }

View File

@ -85,6 +85,7 @@ public class ConnectionInfoMarshaller extends BaseCommandMarshaller {
info.setBrokerMasterConnector(bs.readBoolean()); info.setBrokerMasterConnector(bs.readBoolean());
info.setManageable(bs.readBoolean()); info.setManageable(bs.readBoolean());
info.setClientMaster(bs.readBoolean()); info.setClientMaster(bs.readBoolean());
info.setFaultTolerant(bs.readBoolean());
} }
@ -105,6 +106,7 @@ public class ConnectionInfoMarshaller extends BaseCommandMarshaller {
bs.writeBoolean(info.isBrokerMasterConnector()); bs.writeBoolean(info.isBrokerMasterConnector());
bs.writeBoolean(info.isManageable()); bs.writeBoolean(info.isManageable());
bs.writeBoolean(info.isClientMaster()); bs.writeBoolean(info.isClientMaster());
bs.writeBoolean(info.isFaultTolerant());
return rc + 0; return rc + 0;
} }
@ -128,6 +130,7 @@ public class ConnectionInfoMarshaller extends BaseCommandMarshaller {
bs.readBoolean(); bs.readBoolean();
bs.readBoolean(); bs.readBoolean();
bs.readBoolean(); bs.readBoolean();
bs.readBoolean();
} }
@ -161,6 +164,7 @@ public class ConnectionInfoMarshaller extends BaseCommandMarshaller {
info.setBrokerMasterConnector(dataIn.readBoolean()); info.setBrokerMasterConnector(dataIn.readBoolean());
info.setManageable(dataIn.readBoolean()); info.setManageable(dataIn.readBoolean());
info.setClientMaster(dataIn.readBoolean()); info.setClientMaster(dataIn.readBoolean());
info.setFaultTolerant(dataIn.readBoolean());
} }
@ -181,6 +185,7 @@ public class ConnectionInfoMarshaller extends BaseCommandMarshaller {
dataOut.writeBoolean(info.isBrokerMasterConnector()); dataOut.writeBoolean(info.isBrokerMasterConnector());
dataOut.writeBoolean(info.isManageable()); dataOut.writeBoolean(info.isManageable());
dataOut.writeBoolean(info.isClientMaster()); dataOut.writeBoolean(info.isClientMaster());
dataOut.writeBoolean(info.isFaultTolerant());
} }
} }

View File

@ -21,7 +21,6 @@ import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.Iterator; import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.activemq.Service; import org.apache.activemq.Service;
import org.apache.activemq.transport.CompositeTransport; import org.apache.activemq.transport.CompositeTransport;
import org.apache.activemq.transport.Transport; import org.apache.activemq.transport.Transport;
@ -46,7 +45,7 @@ public class ProxyConnector implements Service {
private URI remote; private URI remote;
private URI localUri; private URI localUri;
private String name; private String name;
private CopyOnWriteArrayList<ProxyConnection> connections = new CopyOnWriteArrayList<ProxyConnection>(); private final CopyOnWriteArrayList<ProxyConnection> connections = new CopyOnWriteArrayList<ProxyConnection>();
public void start() throws Exception { public void start() throws Exception {
@ -131,13 +130,14 @@ public class ProxyConnector implements Service {
private Transport createRemoteTransport() throws Exception { private Transport createRemoteTransport() throws Exception {
Transport transport = TransportFactory.compositeConnect(remote); Transport transport = TransportFactory.compositeConnect(remote);
CompositeTransport ct = (CompositeTransport)transport.narrow(CompositeTransport.class); CompositeTransport ct = transport.narrow(CompositeTransport.class);
if (ct != null && localUri != null) { if (ct != null && localUri != null) {
ct.add(new URI[] {localUri}); ct.add(false,new URI[] {localUri});
} }
// Add a transport filter so that can track the transport life cycle // Add a transport filter so that can track the transport life cycle
transport = new TransportFilter(transport) { transport = new TransportFilter(transport) {
@Override
public void stop() throws Exception { public void stop() throws Exception {
LOG.info("Stopping proxy."); LOG.info("Stopping proxy.");
super.stop(); super.stop();

View File

@ -19,6 +19,6 @@ package org.apache.activemq.transport;
import java.net.URI; import java.net.URI;
public interface CompositeTransport extends Transport { public interface CompositeTransport extends Transport {
void add(URI[] uris); void add(boolean rebalance,URI[] uris);
void remove(URI[] uris); void remove(boolean rebalance,URI[] uris);
} }

View File

@ -18,7 +18,6 @@ package org.apache.activemq.transport;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import org.apache.activemq.Service; import org.apache.activemq.Service;
/** /**
@ -147,6 +146,15 @@ public interface Transport extends Service {
*/ */
boolean isConnected(); boolean isConnected();
/**
* @return true if reconnect is supported
*/
boolean isReconnectSupported();
/**
* @return true if updating uris is supported
*/
boolean isUpdateURIsSupported();
/** /**
* reconnect to another location * reconnect to another location
* @param uri * @param uri
@ -154,6 +162,14 @@ public interface Transport extends Service {
*/ */
void reconnect(URI uri) throws IOException; void reconnect(URI uri) throws IOException;
/**
* Provide a list of available alternative locations
* @param rebalance
* @param uris
* @throws IOException
*/
void updateURIs(boolean rebalance,URI[] uris) throws IOException;
/** /**
* Returns a counter which gets incremented as data is read from the transport. * Returns a counter which gets incremented as data is read from the transport.
* It should only be used to determine if there is progress being made in reading the next command from the transport. * It should only be used to determine if there is progress being made in reading the next command from the transport.

View File

@ -45,7 +45,8 @@ public class TransportFilter implements TransportListener, Transport {
/** /**
* @see org.apache.activemq.Service#start() * @see org.apache.activemq.Service#start()
* @throws IOException if the next channel has not been set. * @throws IOException
* if the next channel has not been set.
*/ */
public void start() throws Exception { public void start() throws Exception {
if (next == null) { if (next == null) {
@ -75,6 +76,7 @@ public class TransportFilter implements TransportListener, Transport {
return next; return next;
} }
@Override
public String toString() { public String toString() {
return next.toString(); return next.toString();
} }
@ -141,4 +143,16 @@ public class TransportFilter implements TransportListener, Transport {
public int getReceiveCounter() { public int getReceiveCounter() {
return next.getReceiveCounter(); return next.getReceiveCounter();
} }
public boolean isReconnectSupported() {
return next.isReconnectSupported();
}
public boolean isUpdateURIsSupported() {
return next.isUpdateURIsSupported();
}
public void updateURIs(boolean rebalance,URI[] uris) throws IOException {
next.updateURIs(rebalance,uris);
}
} }

View File

@ -18,7 +18,6 @@ package org.apache.activemq.transport;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import org.apache.activemq.util.ServiceSupport; import org.apache.activemq.util.ServiceSupport;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -96,7 +95,8 @@ public abstract class TransportSupport extends ServiceSupport implements Transpo
try { try {
transportListener.onException(e); transportListener.onException(e);
} catch (RuntimeException e2) { } catch (RuntimeException e2) {
// Handle any unexpected runtime exceptions by debug logging them. // Handle any unexpected runtime exceptions by debug logging
// them.
LOG.debug("Unexpected runtime exception: " + e2, e2); LOG.debug("Unexpected runtime exception: " + e2, e2);
} }
} }
@ -112,11 +112,21 @@ public abstract class TransportSupport extends ServiceSupport implements Transpo
return false; return false;
} }
public void reconnect(URI uri) throws IOException { public void reconnect(URI uri) throws IOException {
throw new IOException("Not supported"); throw new IOException("Not supported");
} }
public boolean isReconnectSupported() {
return false;
}
public boolean isUpdateURIsSupported() {
return false;
}
public void updateURIs(boolean reblance,URI[] uris) throws IOException {
throw new IOException("Not supported");
}
public boolean isDisposed() { public boolean isDisposed() {
return isStopped(); return isStopped();
} }

View File

@ -20,7 +20,6 @@ import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.apache.activemq.command.DiscoveryEvent; import org.apache.activemq.command.DiscoveryEvent;
import org.apache.activemq.transport.CompositeTransport; import org.apache.activemq.transport.CompositeTransport;
import org.apache.activemq.transport.TransportFilter; import org.apache.activemq.transport.TransportFilter;
@ -50,6 +49,7 @@ public class DiscoveryTransport extends TransportFilter implements DiscoveryList
this.next = next; this.next = next;
} }
@Override
public void start() throws Exception { public void start() throws Exception {
if (discoveryAgent == null) { if (discoveryAgent == null) {
throw new IllegalStateException("discoveryAgent not configured"); throw new IllegalStateException("discoveryAgent not configured");
@ -61,6 +61,7 @@ public class DiscoveryTransport extends TransportFilter implements DiscoveryList
next.start(); next.start();
} }
@Override
public void stop() throws Exception { public void stop() throws Exception {
ServiceStopper ss = new ServiceStopper(); ServiceStopper ss = new ServiceStopper();
ss.stop(discoveryAgent); ss.stop(discoveryAgent);
@ -75,7 +76,7 @@ public class DiscoveryTransport extends TransportFilter implements DiscoveryList
URI uri = new URI(url); URI uri = new URI(url);
serviceURIs.put(event.getServiceName(), uri); serviceURIs.put(event.getServiceName(), uri);
LOG.info("Adding new broker connection URL: " + uri); LOG.info("Adding new broker connection URL: " + uri);
next.add(new URI[] {URISupport.applyParameters(uri, parameters)}); next.add(false,new URI[] {URISupport.applyParameters(uri, parameters)});
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
LOG.warn("Could not connect to remote URI: " + url + " due to bad URI syntax: " + e, e); LOG.warn("Could not connect to remote URI: " + url + " due to bad URI syntax: " + e, e);
} }
@ -85,7 +86,7 @@ public class DiscoveryTransport extends TransportFilter implements DiscoveryList
public void onServiceRemove(DiscoveryEvent event) { public void onServiceRemove(DiscoveryEvent event) {
URI uri = serviceURIs.get(event.getServiceName()); URI uri = serviceURIs.get(event.getServiceName());
if (uri != null) { if (uri != null) {
next.remove(new URI[] {uri}); next.remove(false,new URI[] {uri});
} }
} }

View File

@ -20,12 +20,11 @@ package org.apache.activemq.transport.failover;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import org.apache.activemq.transport.DefaultTransportListener; import org.apache.activemq.transport.DefaultTransportListener;
import org.apache.activemq.transport.Transport; import org.apache.activemq.transport.Transport;
class BackupTransport extends DefaultTransportListener{ class BackupTransport extends DefaultTransportListener{
private FailoverTransport failoverTransport; private final FailoverTransport failoverTransport;
private Transport transport; private Transport transport;
private URI uri; private URI uri;
private boolean disposed; private boolean disposed;
@ -33,10 +32,11 @@ class BackupTransport extends DefaultTransportListener{
BackupTransport(FailoverTransport ft){ BackupTransport(FailoverTransport ft){
this.failoverTransport=ft; this.failoverTransport=ft;
} }
@Override
public void onException(IOException error) { public void onException(IOException error) {
this.disposed=true; this.disposed=true;
if (failoverTransport!=null) { if (failoverTransport!=null) {
this.failoverTransport.reconnect(); this.failoverTransport.reconnect(false);
} }
} }
@ -62,10 +62,12 @@ class BackupTransport extends DefaultTransportListener{
this.disposed = disposed; this.disposed = disposed;
} }
@Override
public int hashCode() { public int hashCode() {
return uri != null ? uri.hashCode():-1; return uri != null ? uri.hashCode():-1;
} }
@Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj instanceof BackupTransport) { if (obj instanceof BackupTransport) {
BackupTransport other = (BackupTransport) obj; BackupTransport other = (BackupTransport) obj;

View File

@ -19,15 +19,18 @@ package org.apache.activemq.transport.failover;
import java.io.IOException; import java.io.IOException;
import java.io.InterruptedIOException; import java.io.InterruptedIOException;
import java.net.InetAddress;
import java.net.URI; import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.apache.activemq.command.BrokerInfo;
import org.apache.activemq.command.Command; import org.apache.activemq.command.Command;
import org.apache.activemq.command.ConnectionControl; import org.apache.activemq.command.ConnectionControl;
import org.apache.activemq.command.ConnectionId; import org.apache.activemq.command.ConnectionId;
@ -50,6 +53,7 @@ import org.apache.activemq.util.ServiceSupport;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
/** /**
* A Transport that is made reliable by being able to fail over to another * A Transport that is made reliable by being able to fail over to another
* transport when a transport failure is detected. * transport when a transport failure is detected.
@ -64,6 +68,7 @@ public class FailoverTransport implements CompositeTransport {
private boolean disposed; private boolean disposed;
private boolean connected; private boolean connected;
private final CopyOnWriteArrayList<URI> uris = new CopyOnWriteArrayList<URI>(); private final CopyOnWriteArrayList<URI> uris = new CopyOnWriteArrayList<URI>();
private final CopyOnWriteArrayList<URI> updated = new CopyOnWriteArrayList<URI>();
private final Object reconnectMutex = new Object(); private final Object reconnectMutex = new Object();
private final Object backupMutex = new Object(); private final Object backupMutex = new Object();
@ -77,14 +82,13 @@ public class FailoverTransport implements CompositeTransport {
private final AtomicReference<Transport> connectedTransport = new AtomicReference<Transport>(); private final AtomicReference<Transport> connectedTransport = new AtomicReference<Transport>();
private final TaskRunner reconnectTask; private final TaskRunner reconnectTask;
private boolean started; private boolean started;
private boolean initialized;
private long initialReconnectDelay = 10; private long initialReconnectDelay = 10;
private long maxReconnectDelay = 1000 * 30; private long maxReconnectDelay = 1000 * 30;
private double backOffMultiplier = 2d; private double backOffMultiplier = 2d;
private long timeout = -1; private long timeout = -1;
private boolean useExponentialBackOff = true; private boolean useExponentialBackOff = true;
private boolean randomize = true; private boolean randomize = true;
private boolean initialized;
private int maxReconnectAttempts; private int maxReconnectAttempts;
private int startupMaxReconnectAttempts; private int startupMaxReconnectAttempts;
private int connectFailures; private int connectFailures;
@ -93,12 +97,13 @@ public class FailoverTransport implements CompositeTransport {
private boolean firstConnection = true; private boolean firstConnection = true;
// optionally always have a backup created // optionally always have a backup created
private boolean backup = false; private boolean backup = false;
private List<BackupTransport> backups=new CopyOnWriteArrayList<BackupTransport>(); private final List<BackupTransport> backups = new CopyOnWriteArrayList<BackupTransport>();
private int backupPoolSize = 1; private int backupPoolSize = 1;
private boolean trackMessages = false; private boolean trackMessages = false;
private boolean trackTransactionProducers = true; private boolean trackTransactionProducers = true;
private int maxCacheSize = 128 * 1024; private int maxCacheSize = 128 * 1024;
private TransportListener disposedListener = new DefaultTransportListener() {}; private final TransportListener disposedListener = new DefaultTransportListener() {
};
private boolean connectionInterruptProcessingComplete; private boolean connectionInterruptProcessingComplete;
private final TransportListener myTransportListener = createTransportListener(); private final TransportListener myTransportListener = createTransportListener();
@ -152,18 +157,11 @@ public class FailoverTransport implements CompositeTransport {
} }
} }
if (!initialized) { if (!initialized) {
if (command.isBrokerInfo()) {
BrokerInfo info = (BrokerInfo)command;
BrokerInfo[] peers = info.getPeerBrokerInfos();
if (peers != null) {
for (int i = 0; i < peers.length; i++) {
String brokerString = peers[i].getBrokerURL();
add(brokerString);
}
}
initialized = true; initialized = true;
} }
if(command.isConnectionControl()) {
handleConnectionControl((ConnectionControl) command);
} }
if (transportListener != null) { if (transportListener != null) {
transportListener.onCommand(command); transportListener.onCommand(command);
@ -193,7 +191,6 @@ public class FailoverTransport implements CompositeTransport {
}; };
} }
public final void handleTransportFailure(IOException e) throws InterruptedException { public final void handleTransportFailure(IOException e) throws InterruptedException {
if (LOG.isTraceEnabled()) { if (LOG.isTraceEnabled()) {
LOG.trace(this + " handleTransportFailure: " + e); LOG.trace(this + " handleTransportFailure: " + e);
@ -213,7 +210,8 @@ public class FailoverTransport implements CompositeTransport {
boolean reconnectOk = false; boolean reconnectOk = false;
synchronized (reconnectMutex) { synchronized (reconnectMutex) {
if (started) { if (started) {
LOG.warn("Transport (" + transport.getRemoteAddress() + ") failed to " + connectedTransportURI+ " , attempting to automatically reconnect due to: " + e); LOG.warn("Transport (" + transport.getRemoteAddress() + ") failed to " + connectedTransportURI
+ " , attempting to automatically reconnect due to: " + e);
LOG.debug("Transport failed with the following exception:", e); LOG.debug("Transport failed with the following exception:", e);
reconnectOk = true; reconnectOk = true;
} }
@ -224,7 +222,8 @@ public class FailoverTransport implements CompositeTransport {
stateTracker.transportInterrupted(); stateTracker.transportInterrupted();
// notify before any reconnect attempt so ack state can be whacked // notify before any reconnect attempt so ack state can be
// whacked
if (transportListener != null) { if (transportListener != null) {
transportListener.transportInterupted(); transportListener.transportInterupted();
} }
@ -234,7 +233,49 @@ public class FailoverTransport implements CompositeTransport {
} }
} }
} }
}
public final void handleConnectionControl(ConnectionControl control) {
String reconnectStr = control.getReconnectTo();
if (reconnectStr != null) {
reconnectStr = reconnectStr.trim();
if (reconnectStr.length() > 0) {
try {
URI uri = new URI(reconnectStr);
if (isReconnectSupported()) {
reconnect(uri);
LOG.info("Reconnected to: " + uri);
}
} catch (Exception e) {
LOG.error("Failed to handle ConnectionControl reconnect to " + reconnectStr, e);
}
}
}
String connectedStr = control.getConnectedBrokers();
if (connectedStr != null) {
connectedStr = connectedStr.trim();
if (connectedStr.length() > 0 && isUpdateURIsSupported()) {
List<URI> list = new ArrayList<URI>();
StringTokenizer tokenizer = new StringTokenizer(connectedStr, ",");
while (tokenizer.hasMoreTokens()) {
String str = tokenizer.nextToken();
try {
URI uri = new URI(str);
list.add(uri);
} catch (Exception e) {
LOG.error("Failed to parse broker address: " + str, e);
}
}
if (list.isEmpty() == false) {
try {
updateURIs(control.isRebalanceConnection(), list.toArray(new URI[list.size()]));
} catch (IOException e) {
LOG.error("Failed to update transport URI's from: " + connectedStr, e);
}
}
}
}
} }
public void start() throws Exception { public void start() throws Exception {
@ -250,7 +291,7 @@ public class FailoverTransport implements CompositeTransport {
if (connectedTransport.get() != null) { if (connectedTransport.get() != null) {
stateTracker.restore(connectedTransport.get()); stateTracker.restore(connectedTransport.get());
} else { } else {
reconnect(); reconnect(false);
} }
} }
} }
@ -356,7 +397,8 @@ public class FailoverTransport implements CompositeTransport {
} }
/** /**
* @param randomize The randomize to set. * @param randomize
* The randomize to set.
*/ */
public void setRandomize(boolean randomize) { public void setRandomize(boolean randomize) {
this.randomize = randomize; this.randomize = randomize;
@ -403,14 +445,13 @@ public class FailoverTransport implements CompositeTransport {
} }
/** /**
* @return Returns true if the command is one sent when a connection * @return Returns true if the command is one sent when a connection is
* is being closed. * being closed.
*/ */
private boolean isShutdownCommand(Command command) { private boolean isShutdownCommand(Command command) {
return (command != null && (command.isShutdownInfo() || command instanceof RemoveInfo)); return (command != null && (command.isShutdownInfo() || command instanceof RemoveInfo));
} }
public void oneway(Object o) throws IOException { public void oneway(Object o) throws IOException {
Command command = (Command) o; Command command = (Command) o;
@ -421,11 +462,13 @@ public class FailoverTransport implements CompositeTransport {
if (isShutdownCommand(command) && connectedTransport.get() == null) { if (isShutdownCommand(command) && connectedTransport.get() == null) {
if (command.isShutdownInfo()) { if (command.isShutdownInfo()) {
// Skipping send of ShutdownInfo command when not connected. // Skipping send of ShutdownInfo command when not
// connected.
return; return;
} }
if (command instanceof RemoveInfo || command.isMessageAck()) { if (command instanceof RemoveInfo || command.isMessageAck()) {
// Simulate response to RemoveInfo command or ack (as it will be stale) // Simulate response to RemoveInfo command or ack (as it
// will be stale)
stateTracker.track(command); stateTracker.track(command);
Response response = new Response(); Response response = new Response();
response.setCorrelationId(command.getCommandId()); response.setCorrelationId(command.getCommandId());
@ -441,8 +484,7 @@ public class FailoverTransport implements CompositeTransport {
Transport transport = connectedTransport.get(); Transport transport = connectedTransport.get();
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
boolean timedout = false; boolean timedout = false;
while (transport == null && !disposed while (transport == null && !disposed && connectionFailure == null
&& connectionFailure == null
&& !Thread.currentThread().isInterrupted()) { && !Thread.currentThread().isInterrupted()) {
LOG.trace("Waiting for transport to reconnect..: " + command); LOG.trace("Waiting for transport to reconnect..: " + command);
long end = System.currentTimeMillis(); long end = System.currentTimeMillis();
@ -550,38 +592,53 @@ public class FailoverTransport implements CompositeTransport {
throw new AssertionError("Unsupported Method"); throw new AssertionError("Unsupported Method");
} }
public void add(URI u[]) { public void add(boolean rebalance, URI u[]) {
boolean newURI = false;
for (int i = 0; i < u.length; i++) { for (int i = 0; i < u.length; i++) {
if (!uris.contains(u[i])) { if (contains(u[i])==false) {
uris.add(u[i]); uris.add(i, u[i]);
newURI = true;
} }
} }
reconnect(); if (newURI) {
reconnect(rebalance);
}
} }
public void remove(URI u[]) { public void remove(boolean rebalance, URI u[]) {
for (int i = 0; i < u.length; i++) { for (int i = 0; i < u.length; i++) {
uris.remove(u[i]); uris.remove(u[i]);
} }
reconnect(); reconnect(rebalance);
} }
public void add(String u) { public void add(boolean rebalance, String u) {
try { try {
URI uri = new URI(u); URI newURI = new URI(u);
if (!uris.contains(uri)) { if (contains(newURI)==false) {
uris.add(uri); uris.add(newURI);
reconnect(rebalance);
} }
reconnect();
} catch (Exception e) { } catch (Exception e) {
LOG.error("Failed to parse URI: " + u); LOG.error("Failed to parse URI: " + u);
} }
} }
public void reconnect() { public void reconnect(boolean rebalance) {
synchronized (reconnectMutex) { synchronized (reconnectMutex) {
if (started) { if (started) {
if (rebalance) {
Transport transport = this.connectedTransport.getAndSet(null);
if (transport != null) {
try {
transport.stop();
} catch (Exception e) {
LOG.debug("Caught an exception stopping existing transport", e);
}
}
}
LOG.debug("Waking up reconnect task"); LOG.debug("Waking up reconnect task");
try { try {
reconnectTask.wakeup(); reconnectTask.wakeup();
@ -668,6 +725,7 @@ public class FailoverTransport implements CompositeTransport {
this.useExponentialBackOff = useExponentialBackOff; this.useExponentialBackOff = useExponentialBackOff;
} }
@Override
public String toString() { public String toString() {
return connectedTransportURI == null ? "unconnected" : connectedTransportURI.toString(); return connectedTransportURI == null ? "unconnected" : connectedTransportURI.toString();
} }
@ -746,7 +804,8 @@ public class FailoverTransport implements CompositeTransport {
connectedTransport.set(t); connectedTransport.set(t);
reconnectMutex.notifyAll(); reconnectMutex.notifyAll();
connectFailures = 0; connectFailures = 0;
// Make sure on initial startup, that the transportListener // Make sure on initial startup, that the
// transportListener
// has been initialized for this instance. // has been initialized for this instance.
synchronized (listenerMutex) { synchronized (listenerMutex) {
if (transportListener == null) { if (transportListener == null) {
@ -754,7 +813,8 @@ public class FailoverTransport implements CompositeTransport {
// if it isn't set after 2secs - it // if it isn't set after 2secs - it
// probably never will be // probably never will be
listenerMutex.wait(2000); listenerMutex.wait(2000);
}catch(InterruptedException ex) {} } catch (InterruptedException ex) {
}
} }
} }
if (transportListener != null) { if (transportListener != null) {
@ -797,16 +857,17 @@ public class FailoverTransport implements CompositeTransport {
LOG.error("Failed to connect to transport after: " + connectFailures + " attempt(s)"); LOG.error("Failed to connect to transport after: " + connectFailures + " attempt(s)");
connectionFailure = failure; connectionFailure = failure;
// Make sure on initial startup, that the transportListener has been initialized // Make sure on initial startup, that the transportListener has
// been initialized
// for this instance. // for this instance.
synchronized (listenerMutex) { synchronized (listenerMutex) {
if (transportListener == null) { if (transportListener == null) {
try { try {
listenerMutex.wait(2000); listenerMutex.wait(2000);
}catch(InterruptedException ex) {} } catch (InterruptedException ex) {
}
} }
} }
if (transportListener != null) { if (transportListener != null) {
if (connectionFailure instanceof IOException) { if (connectionFailure instanceof IOException) {
@ -841,7 +902,6 @@ public class FailoverTransport implements CompositeTransport {
return !disposed; return !disposed;
} }
final boolean buildBackups() { final boolean buildBackups() {
synchronized (backupMutex) { synchronized (backupMutex) {
if (!disposed && backup && backups.size() < backupPoolSize) { if (!disposed && backup && backups.size() < backupPoolSize) {
@ -882,13 +942,47 @@ public class FailoverTransport implements CompositeTransport {
return disposed; return disposed;
} }
public boolean isConnected() { public boolean isConnected() {
return connected; return connected;
} }
public void reconnect(URI uri) throws IOException { public void reconnect(URI uri) throws IOException {
add(new URI[] {uri}); add(true, new URI[] { uri });
}
public boolean isReconnectSupported() {
return true;
}
public boolean isUpdateURIsSupported() {
return true;
}
public void updateURIs(boolean rebalance, URI[] updatedURIs) throws IOException {
List<URI> copy = new ArrayList<URI>(this.updated);
List<URI> add = new ArrayList<URI>();
if (updatedURIs != null && updatedURIs.length > 0) {
Set<URI> set = new HashSet<URI>();
for (int i = 0; i < updatedURIs.length; i++) {
URI uri = updatedURIs[i];
if (uri != null) {
set.add(uri);
}
}
for (URI uri : set) {
if (copy.remove(uri) == false) {
add.add(uri);
}
}
synchronized (reconnectMutex) {
this.updated.clear();
this.updated.addAll(add);
for (URI uri : copy) {
this.uris.remove(uri);
}
add(rebalance, add.toArray(new URI[add.size()]));
}
}
} }
public int getReceiveCounter() { public int getReceiveCounter() {
@ -904,4 +998,25 @@ public class FailoverTransport implements CompositeTransport {
stateTracker.connectionInterruptProcessingComplete(this, connectionId); stateTracker.connectionInterruptProcessingComplete(this, connectionId);
} }
} }
private boolean contains(URI newURI) {
boolean result = false;
try {
for (URI uri:uris) {
if (newURI.getPort()==uri.getPort()) {
InetAddress newAddr = InetAddress.getByName(newURI.getHost());
InetAddress addr = InetAddress.getByName(uri.getHost());
if (addr.equals(newAddr)) {
result = true;
break;
}
}
}
}catch(IOException e) {
result = true;
LOG.error("Failed to verify URI " + newURI + " already known: " + e);
}
return result;
}
} }

View File

@ -20,7 +20,6 @@ import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.Map; import java.util.Map;
import org.apache.activemq.transport.MutexTransport; import org.apache.activemq.transport.MutexTransport;
import org.apache.activemq.transport.ResponseCorrelator; import org.apache.activemq.transport.ResponseCorrelator;
import org.apache.activemq.transport.Transport; import org.apache.activemq.transport.Transport;
@ -32,6 +31,7 @@ import org.apache.activemq.util.URISupport.CompositeData;
public class FailoverTransportFactory extends TransportFactory { public class FailoverTransportFactory extends TransportFactory {
@Override
public Transport doConnect(URI location) throws IOException { public Transport doConnect(URI location) throws IOException {
try { try {
Transport transport = createTransport(URISupport.parseComposite(location)); Transport transport = createTransport(URISupport.parseComposite(location));
@ -43,6 +43,7 @@ public class FailoverTransportFactory extends TransportFactory {
} }
} }
@Override
public Transport doCompositeConnect(URI location) throws IOException { public Transport doCompositeConnect(URI location) throws IOException {
try { try {
return createTransport(URISupport.parseComposite(location)); return createTransport(URISupport.parseComposite(location));
@ -62,7 +63,7 @@ public class FailoverTransportFactory extends TransportFactory {
if (!options.isEmpty()) { if (!options.isEmpty()) {
throw new IllegalArgumentException("Invalid connect parameters: " + options); throw new IllegalArgumentException("Invalid connect parameters: " + options);
} }
transport.add(compositData.getComponents()); transport.add(false,compositData.getComponents());
return transport; return transport;
} }
@ -72,6 +73,7 @@ public class FailoverTransportFactory extends TransportFactory {
return transport; return transport;
} }
@Override
public TransportServer doBind(URI location) throws IOException { public TransportServer doBind(URI location) throws IOException {
throw new IOException("Invalid server URI: " + location); throw new IOException("Invalid server URI: " + location);
} }

View File

@ -23,7 +23,6 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import org.apache.activemq.command.Command; import org.apache.activemq.command.Command;
import org.apache.activemq.command.ConsumerInfo; import org.apache.activemq.command.ConsumerInfo;
import org.apache.activemq.command.Message; import org.apache.activemq.command.Message;
@ -65,7 +64,7 @@ public class FanoutTransport implements CompositeTransport {
private final TaskRunner reconnectTask; private final TaskRunner reconnectTask;
private boolean started; private boolean started;
private ArrayList<FanoutTransportHandler> transports = new ArrayList<FanoutTransportHandler>(); private final ArrayList<FanoutTransportHandler> transports = new ArrayList<FanoutTransportHandler>();
private int connectedCount; private int connectedCount;
private int minAckCount = 2; private int minAckCount = 2;
@ -73,7 +72,7 @@ public class FanoutTransport implements CompositeTransport {
private long initialReconnectDelay = 10; private long initialReconnectDelay = 10;
private long maxReconnectDelay = 1000 * 30; private long maxReconnectDelay = 1000 * 30;
private long backOffMultiplier = 2; private long backOffMultiplier = 2;
private boolean useExponentialBackOff = true; private final boolean useExponentialBackOff = true;
private int maxReconnectAttempts; private int maxReconnectAttempts;
private Exception connectionFailure; private Exception connectionFailure;
private FanoutTransportHandler primary; private FanoutTransportHandler primary;
@ -89,6 +88,7 @@ public class FanoutTransport implements CompositeTransport {
this.ackCount = new AtomicInteger(count); this.ackCount = new AtomicInteger(count);
} }
@Override
public String toString() { public String toString() {
return command.getCommandId() + "=" + ackCount.get(); return command.getCommandId() + "=" + ackCount.get();
} }
@ -107,6 +107,7 @@ public class FanoutTransport implements CompositeTransport {
this.uri = uri; this.uri = uri;
} }
@Override
public void onCommand(Object o) { public void onCommand(Object o) {
Command command = (Command)o; Command command = (Command)o;
if (command.isResponse()) { if (command.isResponse()) {
@ -125,6 +126,7 @@ public class FanoutTransport implements CompositeTransport {
} }
} }
@Override
public void onException(IOException error) { public void onException(IOException error) {
try { try {
synchronized (reconnectMutex) { synchronized (reconnectMutex) {
@ -499,7 +501,7 @@ public class FanoutTransport implements CompositeTransport {
} }
} }
public void add(URI uris[]) { public void add(boolean reblance,URI uris[]) {
synchronized (reconnectMutex) { synchronized (reconnectMutex) {
for (int i = 0; i < uris.length; i++) { for (int i = 0; i < uris.length; i++) {
@ -523,7 +525,7 @@ public class FanoutTransport implements CompositeTransport {
} }
public void remove(URI uris[]) { public void remove(boolean rebalance,URI uris[]) {
synchronized (reconnectMutex) { synchronized (reconnectMutex) {
for (int i = 0; i < uris.length; i++) { for (int i = 0; i < uris.length; i++) {
@ -546,10 +548,21 @@ public class FanoutTransport implements CompositeTransport {
} }
public void reconnect(URI uri) throws IOException { public void reconnect(URI uri) throws IOException {
add(new URI[]{uri}); add(true,new URI[]{uri});
} }
public boolean isReconnectSupported() {
return true;
}
public boolean isUpdateURIsSupported() {
return true;
}
public void updateURIs(boolean reblance,URI[] uris) throws IOException {
add(reblance,uris);
}
public String getRemoteAddress() { public String getRemoteAddress() {
if (primary != null) { if (primary != null) {

View File

@ -18,7 +18,6 @@ package org.apache.activemq.transport.mock;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import org.apache.activemq.transport.DefaultTransportListener; import org.apache.activemq.transport.DefaultTransportListener;
import org.apache.activemq.transport.FutureResponse; import org.apache.activemq.transport.FutureResponse;
import org.apache.activemq.transport.ResponseCallback; import org.apache.activemq.transport.ResponseCallback;
@ -70,6 +69,7 @@ public class MockTransport extends DefaultTransportListener implements Transport
getNext().stop(); getNext().stop();
} }
@Override
public void onCommand(Object command) { public void onCommand(Object command) {
getTransportListener().onCommand(command); getTransportListener().onCommand(command);
} }
@ -88,6 +88,7 @@ public class MockTransport extends DefaultTransportListener implements Transport
return transportListener; return transportListener;
} }
@Override
public String toString() { public String toString() {
return getNext().toString(); return getNext().toString();
} }
@ -108,6 +109,7 @@ public class MockTransport extends DefaultTransportListener implements Transport
return getNext().request(command, timeout); return getNext().request(command, timeout);
} }
@Override
public void onException(IOException error) { public void onException(IOException error) {
getTransportListener().onException(error); getTransportListener().onException(error);
} }
@ -155,4 +157,16 @@ public class MockTransport extends DefaultTransportListener implements Transport
public int getReceiveCounter() { public int getReceiveCounter() {
return getNext().getReceiveCounter(); return getNext().getReceiveCounter();
} }
public boolean isReconnectSupported() {
return getNext().isReconnectSupported();
}
public boolean isUpdateURIsSupported() {
return getNext().isUpdateURIsSupported();
}
public void updateURIs(boolean reblance,URI[] uris) throws IOException {
getNext().updateURIs(reblance,uris);
}
} }

View File

@ -134,6 +134,10 @@ public class StompFrame implements Command {
return false; return false;
} }
public boolean isConnectionControl() {
return false;
}
public boolean isWireFormatInfo() { public boolean isWireFormatInfo() {
return false; return false;
} }

View File

@ -35,9 +35,7 @@ import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import javax.net.SocketFactory; import javax.net.SocketFactory;
import org.apache.activemq.Service; import org.apache.activemq.Service;
import org.apache.activemq.transport.Transport; import org.apache.activemq.transport.Transport;
import org.apache.activemq.transport.TransportLoggerFactory; import org.apache.activemq.transport.TransportLoggerFactory;
@ -171,6 +169,7 @@ public class TcpTransport extends TransportThreadSupport implements Transport, S
/** /**
* @return pretty print of 'this' * @return pretty print of 'this'
*/ */
@Override
public String toString() { public String toString() {
return "tcp://" + socket.getInetAddress() + ":" + socket.getPort(); return "tcp://" + socket.getInetAddress() + ":" + socket.getPort();
} }
@ -398,6 +397,7 @@ public class TcpTransport extends TransportThreadSupport implements Transport, S
} }
} }
@Override
protected void doStart() throws Exception { protected void doStart() throws Exception {
connect(); connect();
stoppedLatch.set(new CountDownLatch(1)); stoppedLatch.set(new CountDownLatch(1));
@ -454,6 +454,7 @@ public class TcpTransport extends TransportThreadSupport implements Transport, S
initializeStreams(); initializeStreams();
} }
@Override
protected void doStop(ServiceStopper stopper) throws Exception { protected void doStop(ServiceStopper stopper) throws Exception {
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("Stopping transport " + this); LOG.debug("Stopping transport " + this);

View File

@ -21,7 +21,6 @@ import java.net.URI;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import org.apache.activemq.thread.Task; import org.apache.activemq.thread.Task;
import org.apache.activemq.thread.TaskRunner; import org.apache.activemq.thread.TaskRunner;
import org.apache.activemq.thread.TaskRunnerFactory; import org.apache.activemq.thread.TaskRunnerFactory;
@ -275,6 +274,7 @@ public class VMTransport implements Transport, Task {
this.network = network; this.network = network;
} }
@Override
public String toString() { public String toString() {
return location + "#" + id; return location + "#" + id;
} }
@ -345,6 +345,17 @@ public class VMTransport implements Transport, Task {
throw new IOException("Not supported"); throw new IOException("Not supported");
} }
public boolean isReconnectSupported() {
return false;
}
public boolean isUpdateURIsSupported() {
return false;
}
public void updateURIs(boolean reblance,URI[] uris) throws IOException {
throw new IOException("Not supported");
}
public int getReceiveCounter() { public int getReceiveCounter() {
return receiveCounter; return receiveCounter;
} }

View File

@ -56,5 +56,8 @@ public class ConnectionControlTest extends BaseCommandTestSupport {
info.setFaultTolerant(true); info.setFaultTolerant(true);
info.setResume(false); info.setResume(false);
info.setSuspend(true); info.setSuspend(true);
info.setConnectedBrokers("ConnectedBrokers:1");
info.setReconnectTo("ReconnectTo:2");
info.setRebalanceConnection(false);
} }
} }

View File

@ -65,5 +65,6 @@ public class ConnectionInfoTest extends BaseCommandTestSupport {
info.setBrokerMasterConnector(true); info.setBrokerMasterConnector(true);
info.setManageable(false); info.setManageable(false);
info.setClientMaster(true); info.setClientMaster(true);
info.setFaultTolerant(false);
} }
} }

View File

@ -17,6 +17,7 @@
package org.apache.activemq.perf; package org.apache.activemq.perf;
import java.io.File; import java.io.File;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.broker.BrokerService; import org.apache.activemq.broker.BrokerService;
import org.apache.activemq.store.kahadb.KahaDBStore; import org.apache.activemq.store.kahadb.KahaDBStore;
@ -31,6 +32,13 @@ public class KahaDBDurableTopicTest extends SimpleDurableTopicTest {
super.setUp(); super.setUp();
} }
@Override
protected ActiveMQConnectionFactory createConnectionFactory(String uri) throws Exception {
ActiveMQConnectionFactory result = new ActiveMQConnectionFactory(uri);
//result.setDispatchAsync(false);
return result;
}
@Override @Override
protected void configureBroker(BrokerService answer, String uri) throws Exception { protected void configureBroker(BrokerService answer, String uri) throws Exception {
@ -52,7 +60,7 @@ public class KahaDBDurableTopicTest extends SimpleDurableTopicTest {
// small batch means more frequent and smaller writes // small batch means more frequent and smaller writes
kaha.setIndexWriteBatchSize(100); kaha.setIndexWriteBatchSize(100);
kaha.setIndexCacheSize(10000); kaha.setIndexCacheSize(1000);
// do the index write in a separate thread // do the index write in a separate thread
//kaha.setEnableIndexWriteAsync(true); //kaha.setEnableIndexWriteAsync(true);

View File

@ -27,7 +27,7 @@ public class KahaDBQueueTest extends SimpleQueueTest {
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
this.initialConsumerDelay = 10 * 1000; // this.initialConsumerDelay = 10 * 1000;
super.setUp(); super.setUp();
} }
@Override @Override
@ -43,7 +43,7 @@ public class KahaDBQueueTest extends SimpleQueueTest {
// The setEnableJournalDiskSyncs(false) setting is a little dangerous right now, as I have not verified // The setEnableJournalDiskSyncs(false) setting is a little dangerous right now, as I have not verified
// what happens if the index is updated but a journal update is lost. // what happens if the index is updated but a journal update is lost.
// Index is going to be in consistent, but can it be repaired? // Index is going to be in consistent, but can it be repaired?
//kaha.setEnableJournalDiskSyncs(false); kaha.setEnableJournalDiskSyncs(false);
// Using a bigger journal file size makes he take fewer spikes as it is not switching files as often. // Using a bigger journal file size makes he take fewer spikes as it is not switching files as often.
//kaha.setJournalMaxFileLength(1024*1024*100); //kaha.setJournalMaxFileLength(1024*1024*100);
@ -51,6 +51,7 @@ public class KahaDBQueueTest extends SimpleQueueTest {
kaha.setIndexWriteBatchSize(100); kaha.setIndexWriteBatchSize(100);
// do the index write in a separate thread // do the index write in a separate thread
kaha.setEnableIndexWriteAsync(true); kaha.setEnableIndexWriteAsync(true);
kaha.setIndexCacheSize(10000);
answer.setPersistenceAdapter(kaha); answer.setPersistenceAdapter(kaha);
answer.addConnector(uri); answer.addConnector(uri);

View File

@ -0,0 +1,64 @@
/**
* 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.perf;
import java.io.File;
import org.apache.activemq.broker.BrokerService;
import org.apache.activemq.store.kahadaptor.KahaPersistenceAdapter;
import org.apache.activemq.store.kahadb.KahaDBStore;
public class RunBroker {
public static void main(String arg[]) {
try {
KahaPersistenceAdapter adaptor = new KahaPersistenceAdapter();
File dataFileDir = new File("target/test-amq-data/perfTest/kahadb");
File archiveDir = new File(dataFileDir,"archive");
KahaDBStore kahaDB = new KahaDBStore();
kahaDB.setDirectory(dataFileDir);
kahaDB.setDirectoryArchive(archiveDir);
kahaDB.setArchiveDataLogs(true);
// The setEnableJournalDiskSyncs(false) setting is a little dangerous right now, as I have not verified
// what happens if the index is updated but a journal update is lost.
// Index is going to be in consistent, but can it be repaired?
//kaha.setEnableJournalDiskSyncs(false);
// Using a bigger journal file size makes he take fewer spikes as it is not switching files as often.
//kaha.setJournalMaxFileLength(1024*1024*100);
// small batch means more frequent and smaller writes
kahaDB.setIndexWriteBatchSize(1000);
kahaDB.setIndexCacheSize(10000);
// do the index write in a separate thread
kahaDB.setEnableIndexWriteAsync(true);
BrokerService broker = new BrokerService();
broker.setUseJmx(false);
//broker.setPersistenceAdapter(adaptor);
//broker.setPersistenceAdapter(kahaDB);
broker.setPersistent(false);
broker.setDeleteAllMessagesOnStartup(true);
broker.addConnector("tcp://0.0.0.0:61616");
broker.start();
System.err.println("Running");
Thread.sleep(Long.MAX_VALUE);
}catch(Throwable e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,149 @@
/**
* 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.transport.failover;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.jms.Connection;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.Session;
import junit.framework.TestCase;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.broker.BrokerService;
import org.apache.activemq.broker.TransportConnector;
import org.apache.activemq.network.NetworkConnector;
public class FailoverClusterTest extends TestCase {
private static final int NUMBER = 10;
private static final String BROKER_A_BIND_ADDRESS = "tcp://0.0.0.0:61616";
private static final String BROKER_B_BIND_ADDRESS = "tcp://0.0.0.0:61617";
private static final String CLIENT_URL = "failover://("+BROKER_A_BIND_ADDRESS+")";
private static final String BROKER_A_NAME = "BROKERA";
private static final String BROKER_B_NAME = "BROKERB";
private BrokerService brokerA;
private BrokerService brokerB;
private final List<ActiveMQConnection>connections = new ArrayList<ActiveMQConnection>();
public void testClusterConnectedAfterClients() throws Exception{
createClients();
if (brokerB == null) {
brokerB = createBrokerB(BROKER_B_BIND_ADDRESS);
}
Thread.sleep(3000);
Set<String> set = new HashSet<String>();
for (ActiveMQConnection c:connections) {
set.add(c.getTransportChannel().getRemoteAddress());
}
assertTrue(set.size() > 1);
}
public void testClusterConnectedBeforeClients() throws Exception{
if (brokerB == null) {
brokerB = createBrokerB(BROKER_B_BIND_ADDRESS);
}
Thread.sleep(5000);
createClients();
Thread.sleep(2000);
brokerA.stop();
Thread.sleep(2000);
URI brokerBURI = new URI(BROKER_B_BIND_ADDRESS);
for (ActiveMQConnection c:connections) {
String addr = c.getTransportChannel().getRemoteAddress();
assertTrue(addr.indexOf(""+brokerBURI.getPort()) > 0);
}
}
@Override
protected void setUp() throws Exception {
if (brokerA == null) {
brokerA = createBrokerA(BROKER_A_BIND_ADDRESS);
}
}
@Override
protected void tearDown() throws Exception {
for (Connection c:connections) {
c.close();
}
if (brokerB != null) {
brokerB.stop();
brokerB = null;
}
if (brokerA != null) {
brokerA.stop();
brokerA = null;
}
}
protected BrokerService createBrokerA(String uri) throws Exception {
BrokerService answer = new BrokerService();
configureConsumerBroker(answer,uri);
answer.start();
return answer;
}
protected void configureConsumerBroker(BrokerService answer,String uri) throws Exception {
answer.setBrokerName(BROKER_A_NAME);
answer.setPersistent(false);
TransportConnector connector = answer.addConnector(uri);
connector.setRebalanceClusterClients(true);
connector.setUpdateClusterClients(true);
answer.setUseShutdownHook(false);
}
protected BrokerService createBrokerB(String uri) throws Exception {
BrokerService answer = new BrokerService();
configureNetwork(answer,uri);
answer.start();
return answer;
}
protected void configureNetwork(BrokerService answer,String uri) throws Exception {
answer.setBrokerName(BROKER_B_NAME);
answer.setPersistent(false);
NetworkConnector network = answer.addNetworkConnector("static://"+BROKER_A_BIND_ADDRESS);
network.setDuplex(true);
TransportConnector connector =answer.addConnector(uri);
connector.setRebalanceClusterClients(true);
connector.setUpdateClusterClients(true);
answer.setUseShutdownHook(false);
}
protected void createClients() throws Exception {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(CLIENT_URL);
for (int i =0;i < NUMBER; i++) {
ActiveMQConnection c = (ActiveMQConnection) factory.createConnection();
c.start();
Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = s.createQueue(getClass().getName());
MessageConsumer consumer = s.createConsumer(queue);
connections.add(c);
}
}
}