/**
* 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 io.hawtjms.test.support;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.broker.BrokerPlugin;
import org.apache.activemq.broker.BrokerService;
import org.apache.activemq.broker.TransportConnector;
import org.apache.activemq.broker.jmx.BrokerViewMBean;
import org.apache.activemq.broker.jmx.ConnectorViewMBean;
import org.apache.activemq.broker.jmx.QueueViewMBean;
import org.apache.activemq.broker.jmx.TopicViewMBean;
import org.apache.activemq.filter.DestinationMapEntry;
import org.apache.activemq.security.AuthenticationUser;
import org.apache.activemq.security.AuthorizationEntry;
import org.apache.activemq.security.AuthorizationPlugin;
import org.apache.activemq.security.DefaultAuthorizationMap;
import org.apache.activemq.security.SimpleAuthenticationPlugin;
import org.apache.activemq.security.TempDestinationAuthorizationEntry;
import org.apache.activemq.store.kahadb.KahaDBStore;
import org.apache.activemq.util.JMXSupport;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TestName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Base class for all protocol test support classes.
*/
public class HawtJmsTestSupport {
public static final String KAHADB_DIRECTORY = "target/activemq-data";
@Rule public TestName name = new TestName();
protected static final Logger LOG = LoggerFactory.getLogger(HawtJmsTestSupport.class);
protected BrokerService brokerService;
protected final List<BrokerService> brokers = new ArrayList<BrokerService>();
protected final Vector<Throwable> exceptions = new Vector<Throwable>();
protected int numberOfMessages;
protected Connection connection;
@Before
public void setUp() throws Exception {
exceptions.clear();
startPrimaryBroker();
this.numberOfMessages = 2000;
}
@After
public void tearDown() throws Exception {
if (connection != null) {
connection.close();
}
stopPrimaryBroker();
for (BrokerService broker : brokers) {
try {
stopBroker(broker);
} catch (Exception ex) {}
}
}
public String getDestinationName() {
return name.getMethodName();
}
public URI getBrokerOpenWireConnectionURI() {
try {
return new URI("tcp://127.0.0.1:" +
brokerService.getTransportConnectorByName("openwire").getPublishableConnectURI().getPort());
} catch (Exception e) {
throw new RuntimeException();
}
}
protected boolean isPersistent() {
return false;
}
protected boolean isAdvisorySupport() {
return false;
}
protected BrokerService createBroker(String name, boolean deleteAllMessages) throws Exception {
return createBroker(name, deleteAllMessages, Collections.<String, Integer> emptyMap());
}
protected void configureBrokerPolicies(BrokerService broker) {
}
protected BrokerService createBroker(String name, boolean deleteAllMessages, Map<String, Integer> portMap) throws Exception {
KahaDBStore kaha = new KahaDBStore();
kaha.setDirectory(new File(KAHADB_DIRECTORY + "/" + name));
BrokerService brokerService = new BrokerService();
brokerService.setBrokerName(name);
brokerService.setPersistent(isPersistent());
brokerService.setAdvisorySupport(isAdvisorySupport());
brokerService.setDeleteAllMessagesOnStartup(deleteAllMessages);
brokerService.setUseJmx(true);
brokerService.setDataDirectory("target/" + name);
brokerService.setPersistenceAdapter(kaha);
brokerService.setStoreOpenWireVersion(10);
configureBrokerPolicies(brokerService);
ArrayList<BrokerPlugin> plugins = new ArrayList<BrokerPlugin>();
BrokerPlugin authenticationPlugin = configureAuthentication();
if (authenticationPlugin != null) {
plugins.add(configureAuthorization());
}
BrokerPlugin authorizationPlugin = configureAuthorization();
if (authorizationPlugin != null) {
plugins.add(configureAuthentication());
}
if (!plugins.isEmpty()) {
BrokerPlugin[] array = new BrokerPlugin[plugins.size()];
brokerService.setPlugins(plugins.toArray(array));
}
addOpenWireConnector(brokerService, portMap);
addAdditionalConnectors(brokerService, portMap);
return brokerService;
}
protected int addOpenWireConnector(BrokerService brokerService, Map<String, Integer> portMap) throws Exception {
int port = 0;
if (portMap.containsKey("openwire")) {
port = portMap.get("openwire");
}
TransportConnector connector = brokerService.addConnector("tcp://0.0.0.0:" + port);
connector.setName("openwire");
int openwirePort = connector.getPublishableConnectURI().getPort();
LOG.debug("Using openwire port: {}", openwirePort);
return openwirePort;
}
protected void addAdditionalConnectors(BrokerService brokerService, Map<String, Integer> portMap) throws Exception {
// Subclasses can add their own connectors, we don't add any here.
}
public void startPrimaryBroker() throws Exception {
if (brokerService != null && brokerService.isStarted()) {
throw new IllegalStateException("Broker is already created.");
}
brokerService = createBroker("localhost", true);
brokerService.start();
brokerService.waitUntilStarted();
}
public void restartPrimaryBroker() throws Exception {
stopBroker(brokerService);
brokerService = restartBroker(brokerService);
}
public void stopPrimaryBroker() throws Exception {
stopBroker(brokerService);
}
public void startNewBroker() throws Exception {
String brokerName = "localhost" + (brokers.size() + 1);
BrokerService brokerService = createBroker(brokerName, true);
brokerService.setUseJmx(false);
brokerService.start();
brokerService.waitUntilStarted();
brokers.add(brokerService);
}
public BrokerService restartBroker(BrokerService brokerService) throws Exception {
String name = brokerService.getBrokerName();
Map<String, Integer> portMap = new HashMap<String, Integer>();
for (TransportConnector connector : brokerService.getTransportConnectors()) {
portMap.put(connector.getName(), connector.getPublishableConnectURI().getPort());
}
stopBroker(brokerService);
BrokerService broker = createBroker(name, false, portMap);
broker.start();
broker.waitUntilStarted();
return broker;
}
public void stopBroker(BrokerService broker) throws Exception {
if (broker != null) {
broker.stop();
broker.waitUntilStopped();
}
}
public List<URI> getBrokerURIs() throws Exception {
ArrayList<URI> result = new ArrayList<URI>();
result.add(brokerService.getTransportConnectorByName("amqp").getPublishableConnectURI());
for (BrokerService broker : brokers) {
result.add(broker.getTransportConnectorByName("amqp").getPublishableConnectURI());
}
return result;
}
public Connection createActiveMQConnection() throws Exception {
return createActiveMQConnection(getBrokerOpenWireConnectionURI());
}
public Connection createActiveMQConnection(URI brokerURI) throws Exception {
ConnectionFactory factory = new ActiveMQConnectionFactory(brokerURI);
return factory.createConnection();
}
public void sendMessages(Connection connection, Destination destination, int count) throws Exception {
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer p = session.createProducer(destination);
for (int i = 0; i < count; i++) {
TextMessage message = session.createTextMessage();
message.setText("TextMessage: " + i);
p.send(message);
}
session.close();
}
protected BrokerViewMBean getProxyToBroker() throws MalformedObjectNameException, JMSException {
return getProxyToBroker(brokerService);
}
protected BrokerViewMBean getProxyToBroker(BrokerService broker) throws MalformedObjectNameException, JMSException {
ObjectName brokerViewMBean = broker.getBrokerObjectName();
BrokerViewMBean proxy = (BrokerViewMBean) brokerService.getManagementContext()
.newProxyInstance(brokerViewMBean, BrokerViewMBean.class, true);
return proxy;
}
protected ConnectorViewMBean getProxyToConnectionView(String connectionType) throws Exception {
return getProxyToConnectionView(connectionType);
}
protected ConnectorViewMBean getProxyToConnectionView(BrokerService broker, String connectionType) throws Exception {
ObjectName connectorQuery = new ObjectName(
broker.getBrokerObjectName() + ",connector=clientConnectors,connectorName="+connectionType+"_//*");
Set<ObjectName> results = brokerService.getManagementContext().queryNames(connectorQuery, null);
if (results == null || results.isEmpty() || results.size() > 1) {
throw new Exception("Unable to find the exact Connector instance.");
}
ConnectorViewMBean proxy = (ConnectorViewMBean) brokerService.getManagementContext()
.newProxyInstance(results.iterator().next(), ConnectorViewMBean.class, true);
return proxy;
}
protected QueueViewMBean getProxyToQueue(String name) throws MalformedObjectNameException, JMSException {
return getProxyToQueue(brokerService, name);
}
protected QueueViewMBean getProxyToQueue(BrokerService broker, String name) throws MalformedObjectNameException, JMSException {
ObjectName queueViewMBeanName = new ObjectName(
broker.getBrokerObjectName() + ",destinationType=Queue,destinationName=" + name);
QueueViewMBean proxy = (QueueViewMBean) brokerService.getManagementContext()
.newProxyInstance(queueViewMBeanName, QueueViewMBean.class, true);
return proxy;
}
protected QueueViewMBean getProxyToTemporaryQueue(String name) throws MalformedObjectNameException, JMSException {
return getProxyToTemporaryQueue(brokerService, name);
}
protected QueueViewMBean getProxyToTemporaryQueue(BrokerService broker, String name) throws MalformedObjectNameException, JMSException {
name = JMXSupport.encodeObjectNamePart(name);
ObjectName queueViewMBeanName = new ObjectName(
broker.getBrokerObjectName() + ",destinationType=TempQueue,destinationName=" + name);
QueueViewMBean proxy = (QueueViewMBean) brokerService.getManagementContext()
.newProxyInstance(queueViewMBeanName, QueueViewMBean.class, true);
return proxy;
}
protected TopicViewMBean getProxyToTopic(String name) throws MalformedObjectNameException, JMSException {
return getProxyToTopic(brokerService, name);
}
protected TopicViewMBean getProxyToTopic(BrokerService broker, String name) throws MalformedObjectNameException, JMSException {
ObjectName topicViewMBeanName = new ObjectName(
broker.getBrokerObjectName() + ",destinationType=Topic,destinationName=" + name);
TopicViewMBean proxy = (TopicViewMBean) brokerService.getManagementContext()
.newProxyInstance(topicViewMBeanName, TopicViewMBean.class, true);
return proxy;
}
protected TopicViewMBean getProxyToTemporaryTopic(String name) throws MalformedObjectNameException, JMSException {
return getProxyToTemporaryTopic(brokerService, name);
}
protected TopicViewMBean getProxyToTemporaryTopic(BrokerService broker, String name) throws MalformedObjectNameException, JMSException {
name = JMXSupport.encodeObjectNamePart(name);
ObjectName topicViewMBeanName = new ObjectName(
broker.getBrokerObjectName() + ",destinationType=TempTopic,destinationName=" + name);
TopicViewMBean proxy = (TopicViewMBean) brokerService.getManagementContext()
.newProxyInstance(topicViewMBeanName, TopicViewMBean.class, true);
return proxy;
}
protected void sendToAmqQueue(int count) throws Exception {
Connection activemqConnection = createActiveMQConnection();
Session amqSession = activemqConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue amqTestQueue = amqSession.createQueue(name.getMethodName());
sendMessages(activemqConnection, amqTestQueue, count);
}
protected void sendToAmqTopic(int count) throws Exception {
Connection activemqConnection = createActiveMQConnection();
Session amqSession = activemqConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic amqTestTopic = amqSession.createTopic(name.getMethodName());
sendMessages(activemqConnection, amqTestTopic, count);
}
protected BrokerPlugin configureAuthentication() throws Exception {
List<AuthenticationUser> users = new ArrayList<AuthenticationUser>();
users.add(new AuthenticationUser("system", "manager", "users,admins"));
users.add(new AuthenticationUser("user", "password", "users"));
users.add(new AuthenticationUser("guest", "password", "guests"));
SimpleAuthenticationPlugin authenticationPlugin = new SimpleAuthenticationPlugin(users);
authenticationPlugin.setAnonymousAccessAllowed(true);
return authenticationPlugin;
}
protected BrokerPlugin configureAuthorization() throws Exception {
@SuppressWarnings("rawtypes")
List<DestinationMapEntry> authorizationEntries = new ArrayList<DestinationMapEntry>();
AuthorizationEntry entry = new AuthorizationEntry();
entry.setQueue(">");
entry.setRead("admins,anonymous");
entry.setWrite("admins,anonymous");
entry.setAdmin("admins,anonymous");
authorizationEntries.add(entry);
entry = new AuthorizationEntry();
entry.setQueue("USERS.>");
entry.setRead("users,anonymous");
entry.setWrite("users,anonymous");
entry.setAdmin("users,anonymous");
authorizationEntries.add(entry);
entry = new AuthorizationEntry();
entry.setQueue("GUEST.>");
entry.setRead("guests,anonymous");
entry.setWrite("guests,users,anonymous");
entry.setAdmin("guests,users,anonymous");
authorizationEntries.add(entry);
entry = new AuthorizationEntry();
entry.setTopic(">");
entry.setRead("admins,anonymous");
entry.setWrite("admins,anonymous");
entry.setAdmin("admins,anonymous");
authorizationEntries.add(entry);
entry = new AuthorizationEntry();
entry.setTopic("USERS.>");
entry.setRead("users,anonymous");
entry.setWrite("users,anonymous");
entry.setAdmin("users,anonymous");
authorizationEntries.add(entry);
entry = new AuthorizationEntry();
entry.setTopic("GUEST.>");
entry.setRead("guests,anonymous");
entry.setWrite("guests,users,anonymous");
entry.setAdmin("guests,users,anonymous");
authorizationEntries.add(entry);
entry = new AuthorizationEntry();
entry.setTopic("ActiveMQ.Advisory.>");
entry.setRead("guests,users,anonymous");
entry.setWrite("guests,users,anonymous");
entry.setAdmin("guests,users,anonymous");
authorizationEntries.add(entry);
TempDestinationAuthorizationEntry tempEntry = new TempDestinationAuthorizationEntry();
tempEntry.setRead("admins,anonymous");
tempEntry.setWrite("admins,anonymous");
tempEntry.setAdmin("admins,anonymous");
DefaultAuthorizationMap authorizationMap = new DefaultAuthorizationMap(authorizationEntries);
authorizationMap.setTempDestinationAuthorizationEntry(tempEntry);
AuthorizationPlugin authorizationPlugin = new AuthorizationPlugin(authorizationMap);
return authorizationPlugin;
}
protected boolean isForceAsyncSends() {
return false;
}
protected boolean isAlwaysSyncSend() {
return false;
}
protected boolean isMessagePrioritySupported() {
return true;
}
protected boolean isSendAcksAsync() {
return false;
}
}