/**
*
* Copyright 2004 Protique Ltd
*
* Licensed 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.activemq;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.naming.Context;
import org.activemq.broker.Broker;
import org.activemq.broker.BrokerConnector;
import org.activemq.broker.BrokerContainer;
import org.activemq.broker.BrokerContainerFactory;
import org.activemq.broker.BrokerContext;
import org.activemq.broker.impl.BrokerClientImpl;
import org.activemq.broker.impl.BrokerConnectorImpl;
import org.activemq.broker.impl.BrokerContainerFactoryImpl;
import org.activemq.io.WireFormat;
import org.activemq.io.WireFormatLoader;
import org.activemq.io.impl.DefaultWireFormat;
import org.activemq.io.util.ByteArrayCompression;
import org.activemq.io.util.ByteArrayFragmentation;
import org.activemq.jndi.JNDIBaseStorable;
import org.activemq.management.JMSStatsImpl;
import org.activemq.management.StatsCapable;
import org.activemq.management.StatsImpl;
import org.activemq.message.ActiveMQQueue;
import org.activemq.message.ActiveMQTopic;
import org.activemq.message.ConnectionInfo;
import org.activemq.message.ConsumerInfo;
import org.activemq.service.Service;
import org.activemq.transport.TransportChannel;
import org.activemq.transport.TransportChannelFactory;
import org.activemq.transport.TransportChannelListener;
import org.activemq.transport.TransportChannelProvider;
import org.activemq.transport.vm.VmTransportChannel;
import org.activemq.util.BeanUtils;
import org.activemq.util.IdGenerator;
import org.activemq.util.URIHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A ConnectionFactory is an an Administed object, and is used for creating
* Connections.
* <p/>
* This class also implements QueueConnectionFactory and TopicConnectionFactory and is an Administered object.
* You can use this connection to create both QueueConnections and TopicConnections.
*
* @version $Revision: 1.2 $
* @see javax.jms.ConnectionFactory
*/
public class ActiveMQConnectionFactory extends JNDIBaseStorable implements ConnectionFactory, QueueConnectionFactory, TopicConnectionFactory, Service, StatsCapable {
private static final Log log = LogFactory.getLog(ActiveMQConnectionFactory.class);
private BrokerContext brokerContext = BrokerContext.getInstance();
private BrokerContainerFactory brokerContainerFactory;
protected BrokerContainer brokerContainer;
protected String userName;
protected String password;
protected String brokerURL;
protected String clientID;
protected String brokerName;
private boolean useEmbeddedBroker;
/**
* Should we use an async send for persistent non transacted messages ?
*/
protected boolean useAsyncSend = true;
protected boolean disableTimeStampsByDefault = false;
protected boolean J2EEcompliant = true;
/* The list of emebeded brokers that this object started */
private List startedEmbeddedBrokers = new ArrayList();
private JMSStatsImpl stats = new JMSStatsImpl();
private WireFormat wireFormat = new DefaultWireFormat();
private IdGenerator idGenerator = new IdGenerator();
private int connectionCount;
private String brokerXmlConfig;
//compression and fragmentation variables
protected boolean doMessageCompression = true;
protected int messageCompressionLimit = ByteArrayCompression.DEFAULT_COMPRESSION_LIMIT;//data size above which compression will be used
protected int messageCompressionLevel = ByteArrayCompression.DEFAULT_COMPRESSION_LEVEL;
protected int messageCompressionStrategy = ByteArrayCompression.DEFAULT_COMPRESSION_STRATEGY;//default compression strategy
protected boolean doMessageFragmentation = true;
protected int messageFragmentationLimit = ByteArrayFragmentation.DEFAULT_FRAGMENTATION_LIMIT;
protected boolean cachingEnabled = true;
protected boolean prepareMessageBodyOnSend = true; //causes pre-serialization of messages
protected boolean quickClose = false;
protected boolean internalConnection = false;//connections are used internally - for networks etc.
protected boolean optimizedMessageDispatch = false;//set to true for better consumption for transient topics
protected boolean copyMessageOnSend = true;//set false for better throughput
/**
* Default Constructor for ActiveMQConnectionFactory
*/
public ActiveMQConnectionFactory() {
this( ActiveMQConnection.DEFAULT_USER, ActiveMQConnection.DEFAULT_PASSWORD, ActiveMQConnection.DEFAULT_URL);
}
public ActiveMQConnectionFactory(String brokerURL) {
this(ActiveMQConnection.DEFAULT_USER, ActiveMQConnection.DEFAULT_PASSWORD, brokerURL);
}
public ActiveMQConnectionFactory(String userName, String password, String brokerURL) {
this.userName = userName;
this.password = password;
this.brokerURL = brokerURL;
if( brokerURL.indexOf("?")>= 0 ) {
String options = brokerURL.substring(brokerURL.indexOf("?")+1);
Map properties = URIHelper.parseQuery(options);
if (!properties.isEmpty()) {
BeanUtils.populate(this, properties);
}
}
}
/**
* Constructs a {@link ConnectionFactory} with an already configured and <b>started</b> {@link BrokerContainer}
* ready for use in embedded mode.
*
* @param container
*/
public ActiveMQConnectionFactory(BrokerContainer container) {
this(container, "vm://" + container.getBroker().getName());
}
/**
* Constructs a {@link ConnectionFactory} with an already configured and <b>started</b> {@link BrokerContainer}
* ready for use in embedded mode and the brokerURL connection.
*
* @param container
*/
public ActiveMQConnectionFactory(BrokerContainer container, String brokerURL) {
this.brokerContainer = container;
this.useEmbeddedBroker = false;
this.brokerURL = brokerURL;
if( brokerURL.indexOf("?")>= 0 ) {
String options = brokerURL.substring(brokerURL.indexOf("?")+1);
Map properties = URIHelper.parseQuery(options);
if (!properties.isEmpty()) {
BeanUtils.populate(this, properties);
}
}
}
public StatsImpl getStats() {
return stats;
}
public JMSStatsImpl getFactoryStats() {
return stats;
}
/**
* @return Returns the brokerURL.
*/
public String getBrokerURL() {
return brokerURL;
}
/**
* @param brokerURL The brokerURL to set.
*/
public void setBrokerURL(String brokerURL) {
this.brokerURL = brokerURL;
}
/**
* @return Returns the clientID.
*/
public String getClientID() {
return clientID;
}
/**
* @param clientID The clientID to set.
*/
public void setClientID(String clientID) {
this.clientID = clientID;
}
/**
* @return Returns the password.
*/
public String getPassword() {
return password;
}
/**
* @param password The password to set.
*/
public void setPassword(String password) {
this.password = password;
}
/**
* @return Returns the userName.
*/
public String getUserName() {
return userName;
}
/**
* @param userName The userName to set.
*/
public void setUserName(String userName) {
this.userName = userName;
}
/**
* Is an embedded broker used by this connection factory
*
* @return true if an embedded broker will be used by this connection factory
*/
public boolean isUseEmbeddedBroker() {
return useEmbeddedBroker;
}
/**
* Allows embedded brokers to be associated with a connection factory
*
* @param useEmbeddedBroker
*/
public void setUseEmbeddedBroker(boolean useEmbeddedBroker) {
this.useEmbeddedBroker = useEmbeddedBroker;
}
/**
* The name of the broker to use if creating an embedded broker
*
* @return
*/
public String getBrokerName() {
if (brokerName == null) {
// lets auto-create a broker name
brokerName = idGenerator.generateId();
}
return brokerName;
}
/**
* The name of the broker to use if creating an embedded broker
*
* @return
*/
public String getBrokerName(String url) {
if (brokerName == null) {
brokerName = url;
}
return brokerName;
}
public void setBrokerName(String brokerName) {
this.brokerName = brokerName;
}
/**
* @return Returns the useAsyncSend.
*/
public boolean isUseAsyncSend() {
return useAsyncSend;
}
/**
* @param useAsyncSend The useAsyncSend to set.
*/
public void setUseAsyncSend(boolean useAsyncSend) {
this.useAsyncSend = useAsyncSend;
}
public WireFormat getWireFormat() {
return wireFormat.copy();//need a separate instance - especially if wire format caching enabled
}
/**
* Set this flag for fast throughput!
* <P>
* Enables asynchronous sending of messages and disables timestamps by default
* </P>
* @param value - the flag to set
*/
public void setTurboBoost(boolean value){
disableTimeStampsByDefault = value;
useAsyncSend = value;
cachingEnabled = value;
optimizedMessageDispatch = value;
prepareMessageBodyOnSend = !value;
copyMessageOnSend = !value;
}
/**
* @return true if turboBoost enabled
*/
public boolean isTurboBoost(){
return disableTimeStampsByDefault && useAsyncSend && cachingEnabled;
}
/**
* @return Returns the optimizedMessageDispatch.
*/
public boolean isOptimizedMessageDispatch() {
return optimizedMessageDispatch;
}
/**
* @param optimizedMessageDispatch The optimizedMessageDispatch to set.
*/
public void setOptimizedMessageDispatch(boolean optimizedMessageDispatch) {
this.optimizedMessageDispatch = optimizedMessageDispatch;
}
/**
* @return Returns the disableTimeStampsByDefault.
*/
public boolean isDisableTimeStampsByDefault() {
return disableTimeStampsByDefault;
}
/**
* @param disableTimeStampsByDefault The disableTimeStampsByDefault to set.
*/
public void setDisableTimeStampsByDefault(boolean disableTimeStampsByDefault) {
this.disableTimeStampsByDefault = disableTimeStampsByDefault;
}
/**
* @return Returns the j2EEcompliant.
*/
public boolean isJ2EEcompliant() {
return J2EEcompliant;
}
/**
* @param ecompliant The j2EEcompliant to set.
*/
public void setJ2EEcompliant(boolean ecompliant) {
J2EEcompliant = ecompliant;
}
/**
* @return Returns the internalConnection.
*/
public boolean isInternalConnection() {
return internalConnection;
}
/**
* @param internalConnection The internalConnection to set.
*/
public void setInternalConnection(boolean internalConnection) {
this.internalConnection = internalConnection;
}
/**
* @return Returns the quickClose.
*/
public boolean isQuickClose() {
return quickClose;
}
/**
* @param quickClose The quickClose to set.
*/
public void setQuickClose(boolean quickClose) {
this.quickClose = quickClose;
}
/**
* @return Returns the doMessageCompression.
*/
public boolean isDoMessageCompression() {
return doMessageCompression;
}
/**
* @param doMessageCompression The doMessageCompression to set.
*/
public void setDoMessageCompression(boolean doMessageCompression) {
this.doMessageCompression = doMessageCompression;
}
/**
* @return Returns the doMessageFragmentation.
*/
public boolean isDoMessageFragmentation() {
return doMessageFragmentation;
}
/**
* @param doMessageFragmentation The doMessageFragmentation to set.
*/
public void setDoMessageFragmentation(boolean doMessageFragmentation) {
this.doMessageFragmentation = doMessageFragmentation;
}
/**
* @return Returns the messageCompressionLimit.
*/
public int getMessageCompressionLimit() {
return messageCompressionLimit;
}
/**
* @param messageCompressionLimit The messageCompressionLimit to set.
*/
public void setMessageCompressionLimit(int messageCompressionLimit) {
this.messageCompressionLimit = messageCompressionLimit;
}
/**
* @return Returns the messageCompressionStrategy.
*/
public int getMessageCompressionStrategy() {
return messageCompressionStrategy;
}
/**
* @param messageCompressionStrategy The messageCompressionStrategy to set.
*/
public void setMessageCompressionStrategy(int messageCompressionStrategy) {
this.messageCompressionStrategy = messageCompressionStrategy;
}
/**
* @return Returns the messageFragmentationLimit.
*/
public int getMessageFragmentationLimit() {
return messageFragmentationLimit;
}
/**
* @param messageFragmentationLimit The messageFragmentationLimit to set.
*/
public void setMessageFragmentationLimit(int messageFragmentationLimit) {
this.messageFragmentationLimit = messageFragmentationLimit;
}
/**
* @return Returns the cachingEnabled.
*/
public boolean isCachingEnabled() {
return cachingEnabled;
}
/**
* @param cachingEnabled The cachingEnabled to set.
*/
public void setCachingEnabled(boolean cachingEnabled) {
this.cachingEnabled = cachingEnabled;
}
/**
* Causes pre-serialization of messages before send
* By default this is on
* @return Returns the prePrepareMessageOnSend.
*/
public boolean isPrepareMessageBodyOnSend() {
return prepareMessageBodyOnSend;
}
/**
* Causes pre-serialization of messages before send
* By default this is on
* @param prePrepareMessageOnSend The prePrepareMessageOnSend to set.
*/
public void setPrepareMessageBodyOnSend(boolean prePrepareMessageOnSend) {
this.prepareMessageBodyOnSend = prePrepareMessageOnSend;
}
/**
* @return Returns the copyMessageOnSend.
*/
public boolean isCopyMessageOnSend() {
return copyMessageOnSend;
}
/**
* @param copyMessageOnSend The copyMessageOnSend to set.
*/
public void setCopyMessageOnSend(boolean copyMessageOnSend) {
this.copyMessageOnSend = copyMessageOnSend;
}
/**
* Allows a custom wire format to be used; otherwise the default Java wire format is used
* which is designed for minimum size and maximum speed on the Java platform
*
* @param wireFormat
*/
public void setWireFormat(WireFormat wireFormat) {
this.wireFormat = wireFormat;
}
/**
* set the WireFormat by name - e.g. 'default','amqpfast' etc.
*
* @param format
* @throws JMSException
*/
public void setWireFormat(String format) throws JMSException{
this.wireFormat = WireFormatLoader.getWireFormat(format);
}
public String getBrokerXmlConfig() {
return brokerXmlConfig;
}
public BrokerContainer getBrokerContainer() {
return brokerContainer;
}
/**
* Sets the <a href="http://activemq.org/Xml+Configuration">XML configuration file</a>
* used to configure the ActiveMQ broker via Spring if using embedded mode.
*
* @param brokerXmlConfig is the filename which is assumed to be on the classpath unless a URL
* is specified. So a value of <code>foo/bar.xml</code> would be assumed to be on the classpath
* whereas <code>file:dir/file.xml</code> would use the file system.
* Any valid URL string is supported.
* @see #setUseEmbeddedBroker(boolean)
*/
public void setBrokerXmlConfig(String brokerXmlConfig) {
this.brokerXmlConfig = brokerXmlConfig;
}
public BrokerContainerFactory getBrokerContainerFactory() throws JMSException {
if (brokerContainerFactory == null) {
brokerContainerFactory = createBrokerContainerFactory();
}
return brokerContainerFactory;
}
public void setBrokerContainerFactory(BrokerContainerFactory brokerContainerFactory) {
this.brokerContainerFactory = brokerContainerFactory;
}
/**
* Returns the context used to store broker containers and connectors which defaults
* to using the singleton
*/
public BrokerContext getBrokerContext() {
return brokerContext;
}
public void setBrokerContext(BrokerContext brokerContext) {
this.brokerContext = brokerContext;
}
/**
* Create a JMS Connection
*
* @return the JMS Connection
* @throws JMSException if an error occurs creating the Connection
*/
public Connection createConnection() throws JMSException {
return this.createConnection(this.userName, this.password);
}
/**
* @param userName
* @param password
* @return the Connection
* @throws JMSException if an error occurs creating the Connection
*/
public Connection createConnection(String userName, String password) throws JMSException {
ActiveMQConnection connection = new ActiveMQConnection(this, userName, password, createTransportChannel(this.brokerURL));
connection.setCachingEnabled(isCachingEnabled());
connection.setUseAsyncSend(isUseAsyncSend());
connection.setDisableTimeStampsByDefault(isDisableTimeStampsByDefault());
connection.setJ2EEcompliant(isJ2EEcompliant());
connection.setDoMessageCompression(isDoMessageCompression());
connection.setMessageCompressionLevel(messageCompressionLevel);
connection.setMessageCompressionLimit(getMessageCompressionLimit());
connection.setMessageCompressionStrategy(getMessageCompressionStrategy());
connection.setDoMessageFragmentation(isDoMessageFragmentation());
connection.setMessageFragmentationLimit(getMessageFragmentationLimit());
connection.setPrepareMessageBodyOnSend(isPrepareMessageBodyOnSend());
connection.setInternalConnection(isInternalConnection());
connection.setQuickClose(isQuickClose());
connection.setOptimizedMessageDispatch(isOptimizedMessageDispatch());
connection.setCopyMessageOnSend(isCopyMessageOnSend());
if (this.clientID != null && this.clientID.length() > 0) {
connection.setClientID(this.clientID);
}
return connection;
}
/**
* Create a JMS QueueConnection
*
* @return the JMS QueueConnection
* @throws JMSException if an error occurs creating the Connection
*/
public QueueConnection createQueueConnection() throws JMSException {
return this.createQueueConnection(this.userName, this.password);
}
/**
* @param userName
* @param password
* @return the QueueConnection
* @throws JMSException if an error occurs creating the Connection
*/
public QueueConnection createQueueConnection(String userName, String password) throws JMSException {
return (QueueConnection) createConnection(userName, password);
}
/**
* Create a JMS TopicConnection
*
* @return the JMS TopicConnection
* @throws JMSException if an error occurs creating the Connection
*/
public TopicConnection createTopicConnection() throws JMSException {
return this.createTopicConnection(this.userName, this.password);
}
/**
* @param userName
* @param password
* @return the TopicConnection
* @throws JMSException if an error occurs creating the Connection
*/
public TopicConnection createTopicConnection(String userName, String password) throws JMSException {
return (TopicConnection) createConnection(userName, password);
}
public void start() throws JMSException {
}
/**
* A hook to allow any embedded JMS Broker's to be closed down
*
* @throws JMSException
*/
public synchronized void stop() throws JMSException {
// Stop all embded brokers that we started.
for (Iterator iter = startedEmbeddedBrokers.iterator(); iter.hasNext();) {
String uri = (String) iter.next();
brokerContext.deregisterConnector(uri);
}
if (brokerContainer != null) {
brokerContainer.stop();
brokerContainer = null;
}
}
public Broker getEmbeddedBroker() throws JMSException {
if (isUseEmbeddedBroker()) {
return getContainer(getBrokerName(), getBrokerName()).getBroker();
}
return null;
}
public static synchronized void registerBroker(String theURLString, BrokerConnector brokerConnector) {
BrokerContext.getInstance().registerConnector(theURLString, brokerConnector);
}
public static synchronized void unregisterBroker(String theURLString) {
BrokerContext.getInstance().deregisterConnector(theURLString);
}
// Implementation methods
//-------------------------------------------------------------------------
/**
* Set the properties that will represent the instance in JNDI
*
* @param props
*/
protected void buildFromProperties(Properties props) {
this.userName = props.getProperty("userName", this.userName);
this.password = props.getProperty("password", this.password);
String temp = props.getProperty(Context.PROVIDER_URL);
if (temp == null || temp.length() == 0) {
temp = props.getProperty("brokerURL");
}
if (temp != null && temp.length() > 0) {
this.brokerURL = temp;
}
this.brokerName = props.getProperty("brokerName", this.brokerName);
this.clientID = props.getProperty("clientID");
this.useAsyncSend = getBoolean(props, "useAsyncSend", true);
this.useEmbeddedBroker = getBoolean(props, "useEmbeddedBroker");
this.brokerXmlConfig = props.getProperty("brokerXmlConfig", this.brokerXmlConfig);
this.J2EEcompliant = getBoolean(props,"J2EEcompliant",true);
if (props.containsKey("turboBoost")){
this.setTurboBoost(getBoolean(props, "turboBoost"));
}
}
/**
* Initialize the instance from properties stored in JNDI
*
* @param props
*/
protected void populateProperties(Properties props) {
props.put("userName", this.userName);
props.put("password", this.password);
props.put("brokerURL", this.brokerURL);
props.put(Context.PROVIDER_URL, this.brokerURL);
props.put("brokerName", this.brokerName);
if (this.clientID != null) {
props.put("clientID", this.clientID);
}
props.put("useAsyncSend", (useAsyncSend) ? "true" : "false");
props.put("useEmbeddedBroker", (useEmbeddedBroker) ? "true" : "false");
props.put("J2EEcompliant", (this.J2EEcompliant) ? "true" : "false");
props.put("turboBoost", (isTurboBoost()) ? "true" : "false");
if (this.brokerXmlConfig != null) {
props.put("brokerXmlConfig", this.brokerXmlConfig);
}
}
/**
* Helper method to return the property value as a boolean flag
*
* @param props
* @param key
* @return
*/
protected boolean getBoolean(Properties props, String key) {
return getBoolean(props, key, false);
}
/**
* Helper method to return the property value as a boolean flag
*
* @param props
* @param key
* @param defaultValue
* @return
*/
protected boolean getBoolean(Properties props, String key, boolean defaultValue) {
String value = props.getProperty(key);
return value != null ? value.equalsIgnoreCase("true") : defaultValue;
}
protected BrokerContainerFactory createBrokerContainerFactory() throws JMSException {
if (brokerXmlConfig != null) {
return XmlConfigHelper.createBrokerContainerFactory(brokerXmlConfig);
}
return new BrokerContainerFactoryImpl();
}
/**
* Factory method to create a TransportChannel from a URL
* @param theURLString
* @return the TransportChannel to use with the embedded broker
* @throws JMSException
*/
protected TransportChannel createTransportChannel(String theURLString) throws JMSException {
URI uri = createURI(theURLString);
TransportChannelFactory factory = TransportChannelProvider.getFactory(uri);
BrokerConnector brokerConnector = null;
boolean created = false;
TransportChannel transportChannel = null;
boolean embedServer = isUseEmbeddedBroker() || factory.requiresEmbeddedBroker();
if (embedServer) {
synchronized (this) {
if (factory.requiresEmbeddedBroker()) {
transportChannel = factory.create(getWireFormat(), uri);
brokerConnector = transportChannel.getEmbeddedBrokerConnector();
}
if (brokerConnector == null) {
brokerConnector = brokerContext.getConnectorByURL(theURLString);
if (brokerConnector == null) {
brokerConnector = createBrokerConnector(theURLString);
brokerContext.registerConnector(theURLString, brokerConnector);
startedEmbeddedBrokers.add(theURLString);
created = true;
}
}
else {
created = true;
}
}
}
if (transportChannel == null){
transportChannel = factory.create(getWireFormat(), uri);
}
if (embedServer) {
return ensureServerIsAvailable(uri, transportChannel, brokerConnector, created);
}
return transportChannel;
}
protected synchronized BrokerContainer getContainer(String url, String name) throws JMSException {
if (brokerContainer == null) {
brokerContainer = brokerContext.getBrokerContainerByName(url, name, getBrokerContainerFactory());
}
return brokerContainer;
}
protected BrokerConnector createBrokerConnector(String url) throws JMSException {
BrokerConnector brokerConnector;
brokerConnector = new BrokerConnectorImpl(getContainer(url, getBrokerName()), url, getWireFormat());
brokerConnector.start();
// lets wait a little for the server to startup
log.info("Embedded JMS Broker has started");
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
System.out.println("Caught: " + e);
e.printStackTrace();
}
return brokerConnector;
}
protected TransportChannel ensureServerIsAvailable(URI remoteLocation, TransportChannel channel, BrokerConnector brokerConnector, boolean created) throws JMSException {
ensureVmServerIsAvailable(channel, brokerConnector);
if (channel.isMulticast()) {
return ensureMulticastChannelIsAvailable(remoteLocation, channel, brokerConnector, created);
}
return channel;
}
private void ensureVmServerIsAvailable(TransportChannel channel, BrokerConnector brokerConnector) throws JMSException {
if (channel instanceof VmTransportChannel && brokerConnector instanceof TransportChannelListener) {
VmTransportChannel answer = (VmTransportChannel) channel;
answer.connect(brokerConnector);
}
}
protected TransportChannel ensureMulticastChannelIsAvailable(URI remoteLocation, TransportChannel channel, BrokerConnector brokerConnector, boolean created) throws JMSException {
if (created) {
BrokerConnectorImpl brokerImpl = (BrokerConnectorImpl) brokerConnector;
BrokerClientImpl client = new BrokerClientImpl();
client.initialize(brokerImpl, channel);
channel.start();
String brokerClientID = createMulticastClientID();
channel.setClientID(brokerClientID);
// lets spoof a consumer for topics which will replicate messages
// over the multicast transport
ConnectionInfo info = new ConnectionInfo();
info.setHostName(IdGenerator.getHostName());
info.setClientId(brokerClientID);
info.setStarted(true);
client.consumeConnectionInfo(info);
ConsumerInfo consumerInfo = new ConsumerInfo();
consumerInfo.setDestination(new ActiveMQTopic(">"));
consumerInfo.setNoLocal(true);
consumerInfo.setClientId(brokerClientID);
consumerInfo.setConsumerId(idGenerator.generateId());
consumerInfo.setStarted(true);
client.consumeConsumerInfo(consumerInfo);
consumerInfo = new ConsumerInfo();
consumerInfo.setDestination(new ActiveMQQueue(">"));
consumerInfo.setNoLocal(true);
consumerInfo.setClientId(brokerClientID);
consumerInfo.setConsumerId(idGenerator.generateId());
consumerInfo.setStarted(true);
client.consumeConsumerInfo(consumerInfo);
}
// now lets create a VM channel that the JMS client will use
// to connect to the embedded brokerConnector
URI localURI = createURI("vm", remoteLocation);
TransportChannel localChannel = TransportChannelProvider.create(getWireFormat(), localURI);
ensureVmServerIsAvailable(localChannel, brokerConnector);
return localChannel;
}
/**
* Creates the clientID for the multicast client (used to dispatch local
* messages over a multicast bus)
*/
protected String createMulticastClientID() {
return idGenerator.generateId();
}
protected URI createURI(String protocol, URI uri) throws JMSException {
try {
return new URI(protocol, uri.getRawSchemeSpecificPart(), uri.getFragment());
}
catch (URISyntaxException e) {
JMSException jmsEx = new JMSException("the URL string is badly formated:", e.getMessage());
jmsEx.setLinkedException(e);
throw jmsEx;
}
}
protected URI createURI(String uri) throws JMSException {
try {
if (uri == null) {
throw new JMSException("The connection URI must be specified!");
}
return new URI(uri);
}
catch (URISyntaxException e) {
e.printStackTrace();
JMSException jmsEx = new JMSException("the URL string is badly formated:", e.getMessage());
jmsEx.setLinkedException(e);
throw jmsEx;
}
}
/**
* Called when a connection is closed so that we can shut down any embedded brokers cleanly
*
* @param connection
*/
synchronized void onConnectionClose(ActiveMQConnection connection) throws JMSException {
if (--connectionCount <= 0) {
// close any broker if we've got one
stop();
}
}
synchronized void onConnectionCreate(ActiveMQConnection connection) {
++connectionCount;
}
}