ARTEMIS-788 Stomp refactor + track autocreation for addresses

This commit is contained in:
jbertram 2016-10-18 19:45:02 +01:00 committed by Martyn Taylor
parent 0189f156ec
commit a88853fe53
79 changed files with 3669 additions and 6103 deletions

View File

@ -550,11 +550,11 @@ public class ArtemisTest {
ClientSessionFactory factory = locator.createSessionFactory();
ClientSession coreSession = factory.createSession("admin", "admin", false, true, true, false, 0)) {
for (String str : queues.split(",")) {
ClientSession.QueueQuery queryResult = coreSession.queueQuery(SimpleString.toSimpleString("jms.queue." + str));
ClientSession.QueueQuery queryResult = coreSession.queueQuery(SimpleString.toSimpleString(str));
assertTrue("Couldn't find queue " + str, queryResult.isExists());
}
for (String str : topics.split(",")) {
ClientSession.QueueQuery queryResult = coreSession.queueQuery(SimpleString.toSimpleString("jms.topic." + str));
ClientSession.QueueQuery queryResult = coreSession.queueQuery(SimpleString.toSimpleString(str));
assertTrue("Couldn't find topic " + str, queryResult.isExists());
}
}

View File

@ -198,7 +198,7 @@ public interface ClientSession extends XAResource, AutoCloseable {
*/
int getVersion();
void createAddress(final SimpleString address, final boolean multicast) throws ActiveMQException;
void createAddress(final SimpleString address, final boolean multicast, final boolean autoCreated) throws ActiveMQException;
// Queue Operations ----------------------------------------------

View File

@ -279,12 +279,12 @@ public final class ClientSessionImpl implements ClientSessionInternal, FailureLi
}
@Override
public void createAddress(final SimpleString address, final boolean multicast) throws ActiveMQException {
public void createAddress(final SimpleString address, final boolean multicast, boolean autoCreated) throws ActiveMQException {
checkClosed();
startCall();
try {
sessionContext.createAddress(address, multicast);
sessionContext.createAddress(address, multicast, autoCreated);
} finally {
endCall();
}

View File

@ -584,8 +584,8 @@ public class ActiveMQSessionContext extends SessionContext {
}
@Override
public void createAddress(SimpleString address, final boolean multicast) throws ActiveMQException {
CreateAddressMessage request = new CreateAddressMessage(address, multicast, true);
public void createAddress(SimpleString address, final boolean multicast, final boolean autoCreated) throws ActiveMQException {
CreateAddressMessage request = new CreateAddressMessage(address, multicast, autoCreated, true);
sessionChannel.sendBlocking(request, PacketImpl.NULL_RESPONSE);
}

View File

@ -26,15 +26,19 @@ public class CreateAddressMessage extends PacketImpl {
private boolean multicast;
private boolean autoCreated;
private boolean requiresResponse;
public CreateAddressMessage(final SimpleString address,
final boolean multicast,
final boolean autoCreated,
final boolean requiresResponse) {
this();
this.address = address;
this.multicast = multicast;
this.autoCreated = autoCreated;
this.requiresResponse = requiresResponse;
}
@ -49,6 +53,7 @@ public class CreateAddressMessage extends PacketImpl {
StringBuffer buff = new StringBuffer(getParentString());
buff.append(", address=" + address);
buff.append(", multicast=" + multicast);
buff.append(", autoCreated=" + autoCreated);
buff.append("]");
return buff.toString();
}
@ -65,6 +70,10 @@ public class CreateAddressMessage extends PacketImpl {
return requiresResponse;
}
public boolean isAutoCreated() {
return autoCreated;
}
public void setAddress(SimpleString address) {
this.address = address;
}
@ -74,6 +83,7 @@ public class CreateAddressMessage extends PacketImpl {
buffer.writeSimpleString(address);
buffer.writeBoolean(multicast);
buffer.writeBoolean(requiresResponse);
buffer.writeBoolean(autoCreated);
}
@Override
@ -81,6 +91,7 @@ public class CreateAddressMessage extends PacketImpl {
address = buffer.readSimpleString();
multicast = buffer.readBoolean();
requiresResponse = buffer.readBoolean();
autoCreated = buffer.readBoolean();
}
@Override
@ -89,6 +100,7 @@ public class CreateAddressMessage extends PacketImpl {
int result = super.hashCode();
result = prime * result + ((address == null) ? 0 : address.hashCode());
result = prime * result + (multicast ? 1231 : 1237);
result = prime * result + (autoCreated ? 1231 : 1237);
result = prime * result + (requiresResponse ? 1231 : 1237);
return result;
}
@ -109,6 +121,8 @@ public class CreateAddressMessage extends PacketImpl {
return false;
if (multicast != other.multicast)
return false;
if (autoCreated != other.autoCreated)
return false;
if (requiresResponse != other.requiresResponse)
return false;
return true;

View File

@ -203,6 +203,14 @@ public class TransportConstants {
public static final String STOMP_MIN_LARGE_MESSAGE_SIZE = "stomp-min-large-message-size";
public static final String STOMP_ANYCAST_PREFIX = "stompAnycastPrefix";
public static final String DEFAULT_STOMP_ANYCAST_PREFIX = "";
public static final String STOMP_MULTICAST_PREFIX = "stompMulticastPrefix";
public static final String DEFAULT_STOMP_MULTICAST_PREFIX = "";
public static final String NETTY_CONNECT_TIMEOUT = "connect-timeout-millis";
public static final int DEFAULT_NETTY_CONNECT_TIMEOUT = -1;
@ -242,6 +250,8 @@ public class TransportConstants {
allowableAcceptorKeys.add(TransportConstants.CLUSTER_CONNECTION);
allowableAcceptorKeys.add(TransportConstants.STOMP_CONSUMERS_CREDIT);
allowableAcceptorKeys.add(TransportConstants.STOMP_MIN_LARGE_MESSAGE_SIZE);
allowableAcceptorKeys.add(TransportConstants.STOMP_ANYCAST_PREFIX);
allowableAcceptorKeys.add(TransportConstants.STOMP_MULTICAST_PREFIX);
allowableAcceptorKeys.add(TransportConstants.CONNECTION_TTL);
allowableAcceptorKeys.add(TransportConstants.CONNECTION_TTL_MAX);
allowableAcceptorKeys.add(TransportConstants.CONNECTION_TTL_MIN);

View File

@ -166,7 +166,7 @@ public abstract class SessionContext {
public abstract void deleteQueue(SimpleString queueName) throws ActiveMQException;
public abstract void createAddress(SimpleString address, boolean multicast) throws ActiveMQException;
public abstract void createAddress(SimpleString address, boolean multicast, boolean autoCreated) throws ActiveMQException;
public abstract void createQueue(SimpleString address,
SimpleString queueName,

View File

@ -403,20 +403,20 @@ public class ActiveMQMessageProducer implements MessageProducer, QueueSender, To
try {
ClientSession.AddressQuery query = clientSession.addressQuery(address);
if (!query.isExists() && query.isAutoCreateJmsQueues()) {
if (destination.isQueue() && !destination.isTemporary()) {
clientSession.createAddress(address, false);
clientSession.createQueue(address, address, null, true);
} else if (destination.isQueue() && destination.isTemporary()) {
clientSession.createAddress(address, false);
clientSession.createTemporaryQueue(address, address);
} else if (!destination.isQueue() && !destination.isTemporary()) {
clientSession.createAddress(address, true);
} else if (!destination.isQueue() && destination.isTemporary()) {
clientSession.createAddress(address, true);
if (!query.isExists()) {
if (destination.isQueue() && query.isAutoCreateJmsQueues()) {
clientSession.createAddress(address, false, true);
if (destination.isTemporary()) {
// TODO is it right to use the address for the queue name here?
clientSession.createTemporaryQueue(address, address);
} else {
clientSession.createQueue(address, address, null, true);
}
} else if (!destination.isQueue() && query.isAutoCreateJmsTopics()) {
clientSession.createAddress(address, true, true);
} else if ((destination.isQueue() && !query.isAutoCreateJmsQueues()) || (!destination.isQueue() && !query.isAutoCreateJmsTopics())) {
throw new InvalidDestinationException("Destination " + address + " does not exist");
}
} else if (!query.isExists() && !query.isAutoCreateJmsQueues()) {
throw new InvalidDestinationException("Destination " + address + " does not exist");
} else {
connection.addKnownDestination(address);
}

View File

@ -299,29 +299,16 @@ public class ActiveMQSession implements QueueSession, TopicSession {
if (jbd != null) {
ClientSession.AddressQuery response = session.addressQuery(jbd.getSimpleAddress());
if (jbd.isQueue()) {
if (!response.isExists()) {
if (response.isAutoCreateJmsQueues()) {
session.createAddress(jbd.getSimpleAddress(), false);
} else {
throw new InvalidDestinationException("Destination " + jbd.getName() + " does not exist");
}
}
if (response.getQueueNames().isEmpty()) {
if (response.isAutoCreateJmsQueues()) {
session.createQueue(jbd.getSimpleAddress(), jbd.getSimpleAddress(), null, true);
} else {
throw new InvalidDestinationException("Destination " + jbd.getName() + " does not exist");
}
}
} else {
if (!response.isExists()) {
if (response.isAutoCreateJmsTopics()) {
session.createAddress(jbd.getSimpleAddress(), true);
} else {
throw new InvalidDestinationException("Destination " + jbd.getName() + " does not exist");
}
if (!response.isExists()) {
if (jbd.isQueue() && response.isAutoCreateJmsQueues()) {
// TODO create queue here in such a way that it is deleted when consumerCount == 0
// perhaps just relying on the broker to do it is simplest (i.e. deleteOnNoConsumers)
session.createAddress(jbd.getSimpleAddress(), false, true);
session.createQueue(jbd.getSimpleAddress(), jbd.getSimpleAddress(), null, true);
} else if (!jbd.isQueue() && response.isAutoCreateJmsTopics()) {
session.createAddress(jbd.getSimpleAddress(), true, true);
} else {
throw new InvalidDestinationException("Destination " + jbd.getName() + " does not exist");
}
}
}
@ -660,6 +647,8 @@ public class ActiveMQSession implements QueueSession, TopicSession {
*/
if (!response.isExists() || !response.getQueueNames().contains(dest.getSimpleAddress())) {
if (response.isAutoCreateJmsQueues()) {
// TODO create queue here in such a way that it is deleted when consumerCount == 0
// perhaps just relying on the broker to do it is simplest (i.e. deleteOnNoConsumers)
session.createQueue(dest.getSimpleAddress(), dest.getSimpleAddress(), true);
} else {
throw new InvalidDestinationException("Destination " + dest.getName() + " does not exist");
@ -673,8 +662,8 @@ public class ActiveMQSession implements QueueSession, TopicSession {
AddressQuery response = session.addressQuery(dest.getSimpleAddress());
if (!response.isExists()) {
if (response.isAutoCreateJmsQueues()) {
session.createAddress(dest.getSimpleAddress(), true);
if (response.isAutoCreateJmsTopics()) {
session.createAddress(dest.getSimpleAddress(), true, true);
} else {
throw new InvalidDestinationException("Topic " + dest.getName() + " does not exist");
}
@ -1106,7 +1095,7 @@ public class ActiveMQSession implements QueueSession, TopicSession {
AddressQuery query = session.addressQuery(topic.getSimpleAddress());
if (!query.isExists() && !query.isAutoCreateJmsQueues()) {
if (!query.isExists() && !query.isAutoCreateJmsTopics()) {
return null;
} else {
return topic;

View File

@ -93,7 +93,7 @@ public class MQTTSubscriptionManager {
Queue q = session.getServer().locateQueue(queue);
if (q == null) {
q = session.getServerSession().createQueue(new SimpleString(address), queue, managementFilter, false, MQTTUtil.DURABLE_MESSAGES && qos >= 0, -1, false);
q = session.getServerSession().createQueue(new SimpleString(address), queue, managementFilter, false, MQTTUtil.DURABLE_MESSAGES && qos >= 0, -1, false, true);
} else {
if (q.isDeleteOnNoConsumers()) {
throw ActiveMQMessageBundle.BUNDLE.invalidQueueConfiguration(q.getAddress(), q.getName(), "deleteOnNoConsumers", false, true);

View File

@ -41,12 +41,12 @@ public class ActiveMQStompException extends Exception {
}
public ActiveMQStompException(String msg) {
super(msg);
super(msg.replace(":", ""));
handler = null;
}
public ActiveMQStompException(String msg, Throwable t) {
super(msg, t);
super(msg.replace(":", ""), t);
this.body = t.getMessage();
handler = null;
}

View File

@ -86,10 +86,10 @@ public interface ActiveMQStompProtocolMessageBundle {
ActiveMQStompException noDestination();
@Message(id = 339016, value = "Error creating subscription {0}", format = Message.Format.MESSAGE_FORMAT)
ActiveMQStompException errorCreatSubscription(String subscriptionID, @Cause Exception e);
ActiveMQStompException errorCreatingSubscription(String subscriptionID, @Cause Exception e);
@Message(id = 339017, value = "Error unsubscribing {0}", format = Message.Format.MESSAGE_FORMAT)
ActiveMQStompException errorUnsubscrib(String subscriptionID, @Cause Exception e);
ActiveMQStompException errorUnsubscribing(String subscriptionID, @Cause Exception e);
@Message(id = 339018, value = "Error acknowledging message {0}", format = Message.Format.MESSAGE_FORMAT)
ActiveMQStompException errorAck(String messageID, @Cause Exception e);
@ -153,4 +153,7 @@ public interface ActiveMQStompProtocolMessageBundle {
@Message(id = 339040, value = "Undefined escape sequence: {0}", format = Message.Format.MESSAGE_FORMAT)
ActiveMQStompException undefinedEscapeSequence(String sequence);
@Message(id = 339041, value = "Not allowed to specify {0} semantics on {1} address.", format = Message.Format.MESSAGE_FORMAT)
ActiveMQStompException illegalSemantics(String requested, String exists);
}

View File

@ -18,8 +18,6 @@ package org.apache.activemq.artemis.core.protocol.stomp;
/**
* The standard verbs and headers used for the <a href="http://stomp.codehaus.org/">STOMP</a> protocol.
*
* @version $Revision: 57 $
*/
public interface Stomp {
@ -27,7 +25,7 @@ public interface Stomp {
String NEWLINE = "\n";
public interface Commands {
interface Commands {
String CONNECT = "CONNECT";
@ -53,7 +51,7 @@ public interface Stomp {
String STOMP = "STOMP";
}
public interface Responses {
interface Responses {
String CONNECTED = "CONNECTED";
@ -64,7 +62,7 @@ public interface Stomp {
String RECEIPT = "RECEIPT";
}
public interface Headers {
interface Headers {
String SEPARATOR = ":";
@ -78,15 +76,17 @@ public interface Stomp {
String CONTENT_TYPE = "content-type";
public interface Response {
interface Response {
String RECEIPT_ID = "receipt-id";
}
public interface Send {
interface Send {
String DESTINATION = "destination";
String DESTINATION_TYPE = "destination-type";
String CORRELATION_ID = "correlation-id";
String REPLY_TO = "reply-to";
@ -97,10 +97,10 @@ public interface Stomp {
String TYPE = "type";
Object PERSISTENT = "persistent";
String PERSISTENT = "persistent";
}
public interface Message {
interface Message {
String MESSAGE_ID = "message-id";
@ -129,7 +129,7 @@ public interface Stomp {
String VALIDATED_USER = "JMSXUserID";
}
public interface Subscribe {
interface Subscribe {
String DESTINATION = "destination";
@ -144,6 +144,8 @@ public interface Stomp {
String DURABLE_SUBSCRIPTION_NAME = "durable-subscription-name";
String SUBSCRIPTION_TYPE = "subscription-type";
String NO_LOCAL = "no-local";
public interface AckModeValues {
@ -156,7 +158,7 @@ public interface Stomp {
}
}
public interface Unsubscribe {
interface Unsubscribe {
String DESTINATION = "destination";
@ -168,7 +170,7 @@ public interface Stomp {
String DURABLE_SUBSCRIPTION_NAME = "durable-subscription-name";
}
public interface Connect {
interface Connect {
String LOGIN = "login";
@ -182,10 +184,10 @@ public interface Stomp {
String ACCEPT_VERSION = "accept-version";
String HOST = "host";
Object HEART_BEAT = "heart-beat";
String HEART_BEAT = "heart-beat";
}
public interface Error {
interface Error {
String MESSAGE = "message";
@ -193,7 +195,7 @@ public interface Stomp {
String VERSION = "version";
}
public interface Connected {
interface Connected {
String SESSION = "session";
@ -207,7 +209,7 @@ public interface Stomp {
String HEART_BEAT = "heart-beat";
}
public interface Ack {
interface Ack {
String MESSAGE_ID = "message-id";

View File

@ -86,6 +86,12 @@ public final class StompConnection implements RemotingConnection {
private final boolean enableMessageID;
private final int minLargeMessageSize;
private final String anycastPrefix;
private final String multicastPrefix;
private StompVersions version;
private VersionedStompFrameHandler frameHandler;
@ -97,8 +103,6 @@ public final class StompConnection implements RemotingConnection {
private final Object sendLock = new Object();
private final int minLargeMessageSize;
private final ScheduledExecutorService scheduledExecutorService;
private final ExecutorFactory factory;
@ -162,6 +166,8 @@ public final class StompConnection implements RemotingConnection {
this.enableMessageID = ConfigurationHelper.getBooleanProperty(TransportConstants.STOMP_ENABLE_MESSAGE_ID, false, acceptorUsed.getConfiguration());
this.minLargeMessageSize = ConfigurationHelper.getIntProperty(TransportConstants.STOMP_MIN_LARGE_MESSAGE_SIZE, ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE, acceptorUsed.getConfiguration());
this.anycastPrefix = ConfigurationHelper.getStringProperty(TransportConstants.STOMP_ANYCAST_PREFIX, TransportConstants.DEFAULT_STOMP_ANYCAST_PREFIX, acceptorUsed.getConfiguration());
this.multicastPrefix = ConfigurationHelper.getStringProperty(TransportConstants.STOMP_MULTICAST_PREFIX, TransportConstants.DEFAULT_STOMP_MULTICAST_PREFIX, acceptorUsed.getConfiguration());
}
@Override
@ -246,23 +252,39 @@ public final class StompConnection implements RemotingConnection {
}
public void checkDestination(String destination) throws ActiveMQStompException {
autoCreateDestinationIfPossible(destination);
if (!manager.destinationExists(destination)) {
throw BUNDLE.destinationNotExist(destination).setHandler(frameHandler);
}
}
public void autoCreateDestinationIfPossible(String queue) throws ActiveMQStompException {
// TODO: STOMP clients will have to prefix their destination with queue:// or topic:// so we can determine what to do here
public boolean autoCreateDestinationIfPossible(String queue, AddressInfo.RoutingType routingType) throws ActiveMQStompException {
boolean result = false;
try {
manager.getServer().createOrUpdateAddressInfo(new AddressInfo(SimpleString.toSimpleString(queue)).setRoutingType(AddressInfo.RoutingType.ANYCAST));
manager.getServer().createQueue(SimpleString.toSimpleString(queue), SimpleString.toSimpleString(queue), null, true, false);
if (manager.getServer().getAddressInfo(SimpleString.toSimpleString(queue)) == null) {
// TODO check here to see if auto-creation is enabled
if (routingType.equals(AddressInfo.RoutingType.MULTICAST)) {
manager.getServer().createOrUpdateAddressInfo(new AddressInfo(SimpleString.toSimpleString(queue)).setAutoCreated(true));
} else {
manager.getServer().createOrUpdateAddressInfo(new AddressInfo(SimpleString.toSimpleString(queue)).setRoutingType(AddressInfo.RoutingType.ANYCAST).setAutoCreated(true));
manager.getServer().createQueue(SimpleString.toSimpleString(queue), SimpleString.toSimpleString(queue), null, null, true, false, true);
}
result = true;
}
} catch (ActiveMQQueueExistsException e) {
// ignore
} catch (Exception e) {
throw new ActiveMQStompException(e.getMessage(), e).setHandler(frameHandler);
}
return result;
}
public void checkRoutingSemantics(String destination, AddressInfo.RoutingType routingType) throws ActiveMQStompException {
AddressInfo.RoutingType actualRoutingTypeOfAddress = manager.getServer().getAddressInfo(SimpleString.toSimpleString(destination)).getRoutingType();
if (routingType != null && !routingType.equals(actualRoutingTypeOfAddress)) {
throw BUNDLE.illegalSemantics(routingType.toString(), actualRoutingTypeOfAddress.toString());
}
}
@Override
@ -560,7 +582,7 @@ public final class StompConnection implements RemotingConnection {
if (stompSession.isNoLocal()) {
message.putStringProperty(CONNECTION_ID_PROP, getID().toString());
}
if (enableMessageID()) {
if (isEnableMessageID()) {
message.putStringProperty("amqMessageId", "STOMP" + message.getMessageID());
}
try {
@ -617,8 +639,11 @@ public final class StompConnection implements RemotingConnection {
String ack,
String id,
String durableSubscriptionName,
boolean noLocal) throws ActiveMQStompException {
autoCreateDestinationIfPossible(destination);
boolean noLocal,
AddressInfo.RoutingType subscriptionType) throws ActiveMQStompException {
autoCreateDestinationIfPossible(destination, subscriptionType);
checkDestination(destination);
checkRoutingSemantics(destination, subscriptionType);
if (noLocal) {
String noLocalFilter = CONNECTION_ID_PROP + " <> '" + getID().toString() + "'";
if (selector == null) {
@ -643,11 +668,11 @@ public final class StompConnection implements RemotingConnection {
}
try {
manager.createSubscription(this, subscriptionID, durableSubscriptionName, destination, selector, ack, noLocal);
manager.subscribe(this, subscriptionID, durableSubscriptionName, destination, selector, ack, noLocal);
} catch (ActiveMQStompException e) {
throw e;
} catch (Exception e) {
throw BUNDLE.errorCreatSubscription(subscriptionID, e).setHandler(frameHandler);
throw BUNDLE.errorCreatingSubscription(subscriptionID, e).setHandler(frameHandler);
}
}
@ -657,7 +682,7 @@ public final class StompConnection implements RemotingConnection {
} catch (ActiveMQStompException e) {
throw e;
} catch (Exception e) {
throw BUNDLE.errorUnsubscrib(subscriptionID, e).setHandler(frameHandler);
throw BUNDLE.errorUnsubscribing(subscriptionID, e).setHandler(frameHandler);
}
}
@ -710,7 +735,7 @@ public final class StompConnection implements RemotingConnection {
return this.frameHandler;
}
public boolean enableMessageID() {
public boolean isEnableMessageID() {
return enableMessageID;
}
@ -718,6 +743,14 @@ public final class StompConnection implements RemotingConnection {
return minLargeMessageSize;
}
public String getAnycastPrefix() {
return anycastPrefix;
}
public String getMulticastPrefix() {
return multicastPrefix;
}
public StompProtocolManager getManager() {
return manager;
}

View File

@ -368,13 +368,13 @@ public class StompProtocolManager extends AbstractProtocolManager<StompFrame, St
}
// Inner classes -------------------------------------------------
public void createSubscription(StompConnection connection,
String subscriptionID,
String durableSubscriptionName,
String destination,
String selector,
String ack,
boolean noLocal) throws Exception {
public void subscribe(StompConnection connection,
String subscriptionID,
String durableSubscriptionName,
String destination,
String selector,
String ack,
boolean noLocal) throws Exception {
StompSession stompSession = getSession(connection);
stompSession.setNoLocal(noLocal);
if (stompSession.containsSubscription(subscriptionID)) {
@ -411,7 +411,7 @@ public class StompProtocolManager extends AbstractProtocolManager<StompFrame, St
}
public boolean destinationExists(String destination) {
return server.getPostOffice().getAddresses().contains(SimpleString.toSimpleString(destination));
return server.getPostOffice().getAddressInfo(SimpleString.toSimpleString(destination)) != null;
}
public ActiveMQServer getServer() {

View File

@ -28,6 +28,7 @@ import org.apache.activemq.artemis.core.protocol.stomp.v10.StompFrameHandlerV10;
import org.apache.activemq.artemis.core.protocol.stomp.v11.StompFrameHandlerV11;
import org.apache.activemq.artemis.core.protocol.stomp.v12.StompFrameHandlerV12;
import org.apache.activemq.artemis.core.server.ServerMessage;
import org.apache.activemq.artemis.core.server.impl.AddressInfo;
import org.apache.activemq.artemis.core.server.impl.ServerMessageImpl;
import org.apache.activemq.artemis.utils.DataConstants;
import org.apache.activemq.artemis.utils.ExecutorFactory;
@ -167,8 +168,11 @@ public abstract class VersionedStompFrameHandler {
StompFrame response = null;
try {
connection.validate();
String destination = frame.getHeader(Stomp.Headers.Send.DESTINATION);
checkDestination(destination);
String destination = getDestination(frame);
AddressInfo.RoutingType routingType = getRoutingType(frame.getHeader(Headers.Send.DESTINATION_TYPE), frame.getHeader(Headers.Send.DESTINATION));
connection.autoCreateDestinationIfPossible(destination, routingType);
connection.checkDestination(destination);
connection.checkRoutingSemantics(destination, routingType);
String txID = frame.getHeader(Stomp.Headers.TRANSACTION);
long timestamp = System.currentTimeMillis();
@ -197,10 +201,6 @@ public abstract class VersionedStompFrameHandler {
return response;
}
private void checkDestination(String destination) throws ActiveMQStompException {
connection.checkDestination(destination);
}
public StompFrame onBegin(StompFrame frame) {
StompFrame response = null;
String txID = frame.getHeader(Stomp.Headers.TRANSACTION);
@ -238,7 +238,7 @@ public abstract class VersionedStompFrameHandler {
public StompFrame onSubscribe(StompFrame request) {
StompFrame response = null;
String destination = request.getHeader(Stomp.Headers.Subscribe.DESTINATION);
String destination = getDestination(request);
String selector = request.getHeader(Stomp.Headers.Subscribe.SELECTOR);
String ack = request.getHeader(Stomp.Headers.Subscribe.ACK_MODE);
@ -247,6 +247,7 @@ public abstract class VersionedStompFrameHandler {
if (durableSubscriptionName == null) {
durableSubscriptionName = request.getHeader(Stomp.Headers.Subscribe.DURABLE_SUBSCRIPTION_NAME);
}
AddressInfo.RoutingType routingType = getRoutingType(request.getHeader(Headers.Subscribe.SUBSCRIPTION_TYPE), request.getHeader(Headers.Subscribe.DESTINATION));
boolean noLocal = false;
if (request.hasHeader(Stomp.Headers.Subscribe.NO_LOCAL)) {
@ -254,7 +255,7 @@ public abstract class VersionedStompFrameHandler {
}
try {
connection.subscribe(destination, selector, ack, id, durableSubscriptionName, noLocal);
connection.subscribe(destination, selector, ack, id, durableSubscriptionName, noLocal, routingType);
} catch (ActiveMQStompException e) {
response = e.getFrame();
}
@ -262,6 +263,17 @@ public abstract class VersionedStompFrameHandler {
return response;
}
public String getDestination(StompFrame request) {
String destination = request.getHeader(Headers.Subscribe.DESTINATION);
if (connection.getMulticastPrefix().length() > 0 && destination.startsWith(connection.getMulticastPrefix())) {
destination = destination.substring(connection.getMulticastPrefix().length());
} else if (connection.getAnycastPrefix().length() > 0 && destination.startsWith(connection.getAnycastPrefix())) {
destination = destination.substring(connection.getAnycastPrefix().length());
}
return destination;
}
public StompFrame postprocess(StompFrame request) {
StompFrame response = null;
if (request.hasHeader(Stomp.Headers.RECEIPT_REQUESTED)) {
@ -332,4 +344,19 @@ public abstract class VersionedStompFrameHandler {
connection.destroy();
}
private AddressInfo.RoutingType getRoutingType(String typeHeader, String destination) {
// null is valid to return here so we know when the user didn't provide any routing info
AddressInfo.RoutingType routingType = null;
if (typeHeader != null) {
routingType = AddressInfo.RoutingType.valueOf(typeHeader);
} else if (destination != null && !connection.getAnycastPrefix().equals(connection.getMulticastPrefix())) {
if (connection.getMulticastPrefix().length() > 0 && destination.startsWith(connection.getMulticastPrefix())) {
routingType = AddressInfo.RoutingType.MULTICAST;
} else if (connection.getAnycastPrefix().length() > 0 && destination.startsWith(connection.getAnycastPrefix())) {
routingType = AddressInfo.RoutingType.ANYCAST;
}
}
return routingType;
}
}

View File

@ -276,7 +276,7 @@ public class AddressControlImpl extends AbstractControl implements AddressContro
message.getBodyBuffer().writeBytes(Base64.decode(body));
}
message.setAddress(addressInfo.getName());
postOffice.route(message, null, true);
postOffice.route(message, true);
return "" + message.getMessageID();
}

View File

@ -728,7 +728,7 @@ public class QueueControlImpl extends AbstractControl implements QueueControl {
ByteBuffer buffer = ByteBuffer.allocate(8);
buffer.putLong(queue.getID());
message.putBytesProperty(MessageImpl.HDR_ROUTE_TO_IDS, buffer.array());
postOffice.route(message, null, true);
postOffice.route(message, true);
return "" + message.getMessageID();
}

View File

@ -1268,7 +1268,11 @@ public abstract class AbstractJournalStorageManager implements StorageManager {
@Override
public void addAddressBinding(final long tx, final AddressInfo addressInfo) throws Exception {
PersistentAddressBindingEncoding bindingEncoding = new PersistentAddressBindingEncoding(addressInfo.getName(), addressInfo.getRoutingType(), addressInfo.getDefaultMaxQueueConsumers());
PersistentAddressBindingEncoding bindingEncoding = new PersistentAddressBindingEncoding(addressInfo.getName(),
addressInfo.getRoutingType(),
addressInfo.getDefaultMaxQueueConsumers(),
addressInfo.isDefaultDeleteOnNoConsumers(),
addressInfo.isAutoCreated());
readLock();
try {
@ -1398,7 +1402,6 @@ public abstract class AbstractJournalStorageManager implements StorageManager {
idGenerator.loadState(record.id, buffer);
} else if (rec == JournalRecordIds.ADDRESS_BINDING_RECORD) {
PersistentAddressBindingEncoding bindingEncoding = newAddressBindingEncoding(id, buffer);
ActiveMQServerLogger.LOGGER.info("=== Loading: " + bindingEncoding);
addressBindingInfos.add(bindingEncoding);
} else if (rec == JournalRecordIds.GROUP_RECORD) {
GroupingEncoding encoding = newGroupEncoding(id, buffer);

View File

@ -31,6 +31,10 @@ public class PersistentAddressBindingEncoding implements EncodingSupport, Addres
public int defaultMaxConsumers;
public boolean defaultDeleteOnNoConsumers;
public boolean autoCreated;
public AddressInfo.RoutingType routingType;
public PersistentAddressBindingEncoding() {
@ -45,15 +49,23 @@ public class PersistentAddressBindingEncoding implements EncodingSupport, Addres
routingType +
", defaultMaxConsumers=" +
defaultMaxConsumers +
", defaultDeleteOnNoConsumers=" +
defaultDeleteOnNoConsumers +
", autoCreated=" +
autoCreated +
"]";
}
public PersistentAddressBindingEncoding(final SimpleString name,
final AddressInfo.RoutingType routingType,
final int defaultMaxConsumers) {
final int defaultMaxConsumers,
final boolean defaultDeleteOnNoConsumers,
final boolean autoCreated) {
this.name = name;
this.routingType = routingType;
this.defaultMaxConsumers = defaultMaxConsumers;
this.defaultDeleteOnNoConsumers = defaultDeleteOnNoConsumers;
this.autoCreated = autoCreated;
}
@Override
@ -85,6 +97,8 @@ public class PersistentAddressBindingEncoding implements EncodingSupport, Addres
name = buffer.readSimpleString();
routingType = AddressInfo.RoutingType.getType(buffer.readByte());
defaultMaxConsumers = buffer.readInt();
defaultDeleteOnNoConsumers = buffer.readBoolean();
autoCreated = buffer.readBoolean();
}
@Override
@ -92,10 +106,12 @@ public class PersistentAddressBindingEncoding implements EncodingSupport, Addres
buffer.writeSimpleString(name);
buffer.writeByte(routingType.getType());
buffer.writeInt(defaultMaxConsumers);
buffer.writeBoolean(defaultDeleteOnNoConsumers);
buffer.writeBoolean(autoCreated);
}
@Override
public int getEncodeSize() {
return SimpleString.sizeofString(name) + DataConstants.SIZE_BYTE + DataConstants.SIZE_INT;
return SimpleString.sizeofString(name) + DataConstants.SIZE_BYTE + DataConstants.SIZE_INT + DataConstants.SIZE_BOOLEAN + DataConstants.SIZE_BOOLEAN;
}
}

View File

@ -24,7 +24,6 @@ import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.core.server.ActiveMQComponent;
import org.apache.activemq.artemis.core.server.MessageReference;
import org.apache.activemq.artemis.core.server.Queue;
import org.apache.activemq.artemis.core.server.QueueCreator;
import org.apache.activemq.artemis.core.server.RoutingContext;
import org.apache.activemq.artemis.core.server.ServerMessage;
import org.apache.activemq.artemis.core.server.impl.AddressInfo;
@ -77,26 +76,22 @@ public interface PostOffice extends ActiveMQComponent {
Map<SimpleString, Binding> getAllBindings();
RoutingStatus route(ServerMessage message, QueueCreator queueCreator, boolean direct) throws Exception;
RoutingStatus route(ServerMessage message, boolean direct) throws Exception;
RoutingStatus route(ServerMessage message,
QueueCreator queueCreator,
Transaction tx,
boolean direct) throws Exception;
RoutingStatus route(ServerMessage message,
QueueCreator queueCreator,
Transaction tx,
boolean direct,
boolean rejectDuplicates) throws Exception;
RoutingStatus route(ServerMessage message,
QueueCreator queueCreator,
RoutingContext context,
boolean direct) throws Exception;
RoutingStatus route(ServerMessage message,
QueueCreator queueCreator,
RoutingContext context,
boolean direct,
boolean rejectDuplicates) throws Exception;

View File

@ -63,7 +63,6 @@ import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
import org.apache.activemq.artemis.core.server.LargeServerMessage;
import org.apache.activemq.artemis.core.server.MessageReference;
import org.apache.activemq.artemis.core.server.Queue;
import org.apache.activemq.artemis.core.server.QueueCreator;
import org.apache.activemq.artemis.core.server.QueueFactory;
import org.apache.activemq.artemis.core.server.RouteContextList;
import org.apache.activemq.artemis.core.server.RoutingContext;
@ -441,6 +440,11 @@ public class PostOfficeImpl implements PostOffice, NotificationListener, Binding
@Override
public AddressInfo removeAddressInfo(SimpleString address) {
try {
getServer().getManagementService().unregisterAddress(address);
} catch (Exception e) {
e.printStackTrace();
}
return addressManager.removeAddressInfo(address);
}
@ -595,39 +599,34 @@ public class PostOfficeImpl implements PostOffice, NotificationListener, Binding
@Override
public RoutingStatus route(final ServerMessage message,
QueueCreator queueCreator,
final boolean direct) throws Exception {
return route(message, queueCreator, (Transaction) null, direct);
return route(message, (Transaction) null, direct);
}
@Override
public RoutingStatus route(final ServerMessage message,
QueueCreator queueCreator,
final Transaction tx,
final boolean direct) throws Exception {
return route(message, queueCreator, new RoutingContextImpl(tx), direct);
return route(message, new RoutingContextImpl(tx), direct);
}
@Override
public RoutingStatus route(final ServerMessage message,
final QueueCreator queueCreator,
final Transaction tx,
final boolean direct,
final boolean rejectDuplicates) throws Exception {
return route(message, queueCreator, new RoutingContextImpl(tx), direct, rejectDuplicates);
return route(message, new RoutingContextImpl(tx), direct, rejectDuplicates);
}
@Override
public RoutingStatus route(final ServerMessage message,
final QueueCreator queueCreator,
final RoutingContext context,
final boolean direct) throws Exception {
return route(message, queueCreator, context, direct, true);
return route(message, context, direct, true);
}
@Override
public RoutingStatus route(final ServerMessage message,
final QueueCreator queueCreator,
final RoutingContext context,
final boolean direct,
boolean rejectDuplicates) throws Exception {
@ -657,14 +656,15 @@ public class PostOfficeImpl implements PostOffice, NotificationListener, Binding
Bindings bindings = addressManager.getBindingsForRoutingAddress(address);
// TODO auto-create queues here?
// first check for the auto-queue creation thing
if (bindings == null && queueCreator != null) {
if (bindings == null) {
// There is no queue with this address, we will check if it needs to be created
if (queueCreator.create(address)) {
// if (queueCreator.create(address)) {
// TODO: this is not working!!!!
// reassign bindings if it was created
bindings = addressManager.getBindingsForRoutingAddress(address);
}
// bindings = addressManager.getBindingsForRoutingAddress(address);
// }
}
if (bindings != null) {
@ -704,7 +704,7 @@ public class PostOfficeImpl implements PostOffice, NotificationListener, Binding
message.setAddress(dlaAddress);
route(message, null, context.getTransaction(), false);
route(message, context.getTransaction(), false);
result = RoutingStatus.NO_BINDINGS_DLA;
}
} else {

View File

@ -240,30 +240,6 @@ public interface ActiveMQServer extends ActiveMQComponent {
long getUptimeMillis();
/**
* This is the queue creator responsible for automatic JMS Queue creations.
*
* @param queueCreator
*/
void setJMSQueueCreator(QueueCreator queueCreator);
/**
* @see org.apache.activemq.artemis.core.server.ActiveMQServer#setJMSQueueCreator(QueueCreator)
*/
QueueCreator getJMSDestinationCreator();
/**
* This is the queue deleter responsible for automatic JMS Queue deletions.
*
* @param queueDeleter
*/
void setJMSQueueDeleter(QueueDeleter queueDeleter);
/**
* @see org.apache.activemq.artemis.core.server.ActiveMQServer#setJMSQueueDeleter(QueueDeleter)
*/
QueueDeleter getJMSQueueDeleter();
/**
* Returns whether the initial replication synchronization process with the backup server is complete; applicable for
* either the live or backup server.
@ -369,7 +345,7 @@ public interface ActiveMQServer extends ActiveMQComponent {
QueueQueryResult queueQuery(SimpleString name) throws Exception;
Queue deployQueue(SimpleString address,
SimpleString resourceName,
SimpleString queueName,
SimpleString filterString,
boolean durable,
boolean temporary,

View File

@ -1,32 +0,0 @@
/*
* 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.artemis.core.server;
import org.apache.activemq.artemis.api.core.SimpleString;
public interface QueueCreator {
/**
* You should return true if you even tried to create the queue and the queue was already there.
* As the callers of this method will use that as an indicator that they should re-route the messages.
* *
*
* @return True if a queue was created.
*/
boolean create(SimpleString address) throws Exception;
}

View File

@ -1,28 +0,0 @@
/*
* 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.artemis.core.server;
import org.apache.activemq.artemis.api.core.SimpleString;
public interface QueueDeleter {
/**
* @return True if a queue was deleted.
*/
boolean delete(SimpleString queueName) throws Exception;
}

View File

@ -29,7 +29,7 @@ import org.apache.activemq.artemis.core.postoffice.PostOffice;
*/
public interface QueueFactory {
Queue createQueueWith(final QueueConfig config);
Queue createQueueWith(final QueueConfig config) throws Exception;
/**
* @deprecated Replaced by {@link #createQueueWith}

View File

@ -87,8 +87,6 @@ public interface ServerSession extends SecurityAuth {
void markTXFailed(Throwable e);
QueueCreator getQueueCreator();
List<Xid> xaGetInDoubtXids();
int xaGetTimeout();
@ -194,7 +192,8 @@ public interface ServerSession extends SecurityAuth {
boolean temporary,
boolean durable,
Integer maxConsumers,
Boolean deleteOnNoConsumers) throws Exception;
Boolean deleteOnNoConsumers,
final Boolean autoCreated) throws Exception;
void createSharedQueue(SimpleString address,
SimpleString name,

View File

@ -119,8 +119,6 @@ import org.apache.activemq.artemis.core.server.PostQueueCreationCallback;
import org.apache.activemq.artemis.core.server.PostQueueDeletionCallback;
import org.apache.activemq.artemis.core.server.Queue;
import org.apache.activemq.artemis.core.server.QueueConfig;
import org.apache.activemq.artemis.core.server.QueueCreator;
import org.apache.activemq.artemis.core.server.QueueDeleter;
import org.apache.activemq.artemis.core.server.QueueFactory;
import org.apache.activemq.artemis.core.server.QueueQueryResult;
import org.apache.activemq.artemis.core.server.SecuritySettingPlugin;
@ -273,16 +271,6 @@ public class ActiveMQServerImpl implements ActiveMQServer {
private FileStoreMonitor fileStoreMonitor;
/**
* This will be set by the JMS Queue Manager.
*/
private QueueCreator jmsQueueCreator;
/**
* This will be set by the JMS Queue Manager.
*/
private QueueDeleter jmsQueueDeleter;
private final Map<String, ServerSession> sessions = new ConcurrentHashMap<>();
private final Semaphore activationLock = new Semaphore(1);
@ -721,11 +709,7 @@ public class ActiveMQServerImpl implements ActiveMQServer {
}
}
if (autoCreateJmsTopics) {
putAddressInfoIfAbsent(new AddressInfo(address));
}
return new BindingQueryResult(getAddressInfo(address) != null, names, autoCreateJmsQueues, autoCreateJmsTopics);
return new BindingQueryResult(!names.isEmpty(), names, autoCreateJmsQueues, autoCreateJmsTopics);
}
@Override
@ -793,26 +777,6 @@ public class ActiveMQServerImpl implements ActiveMQServer {
stop(failoverOnServerShutdown, false, false);
}
@Override
public QueueCreator getJMSDestinationCreator() {
return jmsQueueCreator;
}
@Override
public void setJMSQueueCreator(QueueCreator jmsQueueCreator) {
this.jmsQueueCreator = jmsQueueCreator;
}
@Override
public QueueDeleter getJMSQueueDeleter() {
return jmsQueueDeleter;
}
@Override
public void setJMSQueueDeleter(QueueDeleter jmsQueueDeleter) {
this.jmsQueueDeleter = jmsQueueDeleter;
}
@Override
public boolean isReplicaSync() {
if (activation instanceof SharedNothingLiveActivation) {
@ -1358,7 +1322,7 @@ public class ActiveMQServerImpl implements ActiveMQServer {
SessionCallback callback,
OperationContext context,
boolean autoCreateJMSQueues) throws Exception {
return new ServerSessionImpl(name, username, password, validatedUser, minLargeMessageSize, autoCommitSends, autoCommitAcks, preAcknowledge, configuration.isPersistDeliveryCountBeforeDelivery(), xa, connection, storageManager, postOffice, resourceManager, securityStore, managementService, this, configuration.getManagementAddress(), defaultAddress == null ? null : new SimpleString(defaultAddress), callback, context, autoCreateJMSQueues ? jmsQueueCreator : null, pagingManager);
return new ServerSessionImpl(name, username, password, validatedUser, minLargeMessageSize, autoCommitSends, autoCommitAcks, preAcknowledge, configuration.isPersistDeliveryCountBeforeDelivery(), xa, connection, storageManager, postOffice, resourceManager, securityStore, managementService, this, configuration.getManagementAddress(), defaultAddress == null ? null : new SimpleString(defaultAddress), callback, context, pagingManager);
}
@Override
@ -1616,17 +1580,17 @@ public class ActiveMQServerImpl implements ActiveMQServer {
@Override
public Queue deployQueue(final SimpleString address,
final SimpleString resourceName,
final SimpleString queueName,
final SimpleString filterString,
final boolean durable,
final boolean temporary,
final boolean autoCreated) throws Exception {
return deployQueue(address, resourceName, filterString, durable, temporary, autoCreated, null, null);
return deployQueue(address, queueName, filterString, durable, temporary, autoCreated, null, null);
}
@Override
public Queue deployQueue(final SimpleString address,
final SimpleString resourceName,
final SimpleString queueName,
final SimpleString filterString,
final boolean durable,
final boolean temporary,
@ -1635,9 +1599,9 @@ public class ActiveMQServerImpl implements ActiveMQServer {
final Boolean deleteOnNoConsumers) throws Exception {
// TODO: fix logging here as this could be for a topic or queue
ActiveMQServerLogger.LOGGER.deployQueue(resourceName);
ActiveMQServerLogger.LOGGER.deployQueue(queueName);
return createQueue(address, resourceName, filterString, null, durable, temporary, true, false, autoCreated, maxConsumers, deleteOnNoConsumers);
return createQueue(address, queueName, filterString, null, durable, temporary, true, false, autoCreated, maxConsumers, deleteOnNoConsumers);
}
@Override
@ -2137,6 +2101,16 @@ public class ActiveMQServerImpl implements ActiveMQServer {
// Deploy any predefined queues
deployQueuesFromConfiguration();
registerPostQueueDeletionCallback(new PostQueueDeletionCallback() {
// TODO delete auto-created addresses when queueCount == 0
@Override
public void callback(SimpleString address, SimpleString queueName) throws Exception {
if (getAddressInfo(address).isAutoCreated() && postOffice.getBindingsForAddress(address).getBindings().size() == 0) {
removeAddressInfo(address);
}
}
});
// We need to call this here, this gives any dependent server a chance to deploy its own addresses
// this needs to be done before clustering is fully activated
callActivateCallbacks();
@ -2408,7 +2382,6 @@ public class ActiveMQServerImpl implements ActiveMQServer {
final boolean autoCreated,
final Integer maxConsumers,
final Boolean deleteOnNoConsumers) throws Exception {
final QueueBinding binding = (QueueBinding) postOffice.getBinding(queueName);
if (binding != null) {
if (ignoreIfExists) {
@ -2465,7 +2438,7 @@ public class ActiveMQServerImpl implements ActiveMQServer {
if (transientQueue) {
queue.setConsumersRefCount(new TransientQueueManagerImpl(this, queue.getName()));
} else if (queue.isAutoCreated()) {
queue.setConsumersRefCount(new AutoCreatedQueueManagerImpl(this.getJMSQueueDeleter(), queue.getName()));
queue.setConsumersRefCount(new AutoCreatedQueueManagerImpl(this, queue.getName()));
}
final QueueBinding localQueueBinding = new LocalQueueBinding(getAddressInfo(queue.getAddress()), queue, nodeManager.getNodeId());

View File

@ -29,6 +29,8 @@ public class AddressInfo {
private int defaultMaxQueueConsumers = ActiveMQDefaultConfiguration.getDefaultMaxQueueConsumers();
private boolean autoCreated = false;
public AddressInfo(SimpleString name) {
this.name = name;
}
@ -67,6 +69,15 @@ public class AddressInfo {
return this;
}
public boolean isAutoCreated() {
return autoCreated;
}
public AddressInfo setAutoCreated(boolean autoCreated) {
this.autoCreated = autoCreated;
return this;
}
public SimpleString getName() {
return name;
}
@ -78,6 +89,7 @@ public class AddressInfo {
buff.append(", routingType=" + routingType);
buff.append(", defaultMaxQueueConsumers=" + defaultMaxQueueConsumers);
buff.append(", defaultDeleteOnNoConsumers=" + defaultDeleteOnNoConsumers);
buff.append(", autoCreated=" + autoCreated);
buff.append("]");
return buff.toString();
}

View File

@ -17,34 +17,48 @@
package org.apache.activemq.artemis.core.server.impl;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
import org.apache.activemq.artemis.core.server.AutoCreatedQueueManager;
import org.apache.activemq.artemis.core.server.QueueDeleter;
import org.apache.activemq.artemis.core.server.Queue;
import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
import org.apache.activemq.artemis.utils.ReferenceCounterUtil;
public class AutoCreatedQueueManagerImpl implements AutoCreatedQueueManager {
private final SimpleString queueName;
private final QueueDeleter deleter;
private final ActiveMQServer server;
private final Runnable runnable = new Runnable() {
@Override
public void run() {
try {
if (deleter != null) {
deleter.delete(queueName);
Queue queue = server.locateQueue(queueName);
SimpleString address = queue.getAddress();
AddressSettings settings = server.getAddressSettingsRepository().getMatch(address.toString());
long consumerCount = queue.getConsumerCount();
long messageCount = queue.getMessageCount();
// TODO make sure this is the right check
if ((queue.isAutoCreated() || queue.isDeleteOnNoConsumers()) && queue.getMessageCount() == 0) {
if (ActiveMQServerLogger.LOGGER.isDebugEnabled()) {
ActiveMQServerLogger.LOGGER.debug("deleting auto-created queue \"" + queueName + ".\" consumerCount = " + consumerCount + "; messageCount = " + messageCount + "; getAutoDeleteJmsQueues = " + settings.getAutoDeleteJmsQueues());
}
// TODO handle this exception better
try {
server.destroyQueue(queueName, null, true, false);
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
ActiveMQServerLogger.LOGGER.errorRemovingAutoCreatedQueue(e, queueName);
}
}
};
private final ReferenceCounterUtil referenceCounterUtil = new ReferenceCounterUtil(runnable);
public AutoCreatedQueueManagerImpl(QueueDeleter deleter, SimpleString queueName) {
this.deleter = deleter;
public AutoCreatedQueueManagerImpl(ActiveMQServer server, SimpleString queueName) {
this.server = server;
this.queueName = queueName;
}

View File

@ -104,7 +104,7 @@ public class DivertImpl implements Divert {
copy = message;
}
postOffice.route(copy, null, context.getTransaction(), false);
postOffice.route(copy, context.getTransaction(), false);
}
@Override

View File

@ -151,9 +151,7 @@ public class PostOfficeJournalLoader implements JournalLoader {
.deleteOnNoConsumers(queueBindingInfo.isDeleteOnNoConsumers())
.maxConsumers(queueBindingInfo.getMaxConsumers());
final Queue queue = queueFactory.createQueueWith(queueConfigBuilder.build());
if (queue.isAutoCreated()) {
queue.setConsumersRefCount(new AutoCreatedQueueManagerImpl(((PostOfficeImpl) postOffice).getServer().getJMSQueueDeleter(), queueBindingInfo.getQueueName()));
}
queue.setConsumersRefCount(new AutoCreatedQueueManagerImpl(((PostOfficeImpl)postOffice).getServer(), queueBindingInfo.getQueueName()));
if (queueBindingInfo.getQueueStatusEncodings() != null) {
for (QueueStatusEncoding encoding : queueBindingInfo.getQueueStatusEncodings()) {

View File

@ -2326,7 +2326,7 @@ public class QueueImpl implements Queue {
copyMessage.putBytesProperty(MessageImpl.HDR_ROUTE_TO_IDS, buffer.array());
}
postOffice.route(copyMessage, null, tx, false, rejectDuplicate);
postOffice.route(copyMessage, tx, false, rejectDuplicate);
acknowledge(tx, ref);
}
@ -2530,7 +2530,7 @@ public class QueueImpl implements Queue {
copyMessage.setAddress(address);
postOffice.route(copyMessage, null, tx, false, rejectDuplicate);
postOffice.route(copyMessage, tx, false, rejectDuplicate);
acknowledge(tx, ref, reason);

View File

@ -68,7 +68,6 @@ import org.apache.activemq.artemis.core.server.BindingQueryResult;
import org.apache.activemq.artemis.core.server.LargeServerMessage;
import org.apache.activemq.artemis.core.server.MessageReference;
import org.apache.activemq.artemis.core.server.Queue;
import org.apache.activemq.artemis.core.server.QueueCreator;
import org.apache.activemq.artemis.core.server.QueueQueryResult;
import org.apache.activemq.artemis.core.server.RoutingContext;
import org.apache.activemq.artemis.core.server.ServerConsumer;
@ -167,8 +166,6 @@ public class ServerSessionImpl implements ServerSession, FailureListener {
private final OperationContext context;
private QueueCreator queueCreator;
// Session's usage should be by definition single threaded, hence it's not needed to use a concurrentHashMap here
protected final Map<SimpleString, Pair<UUID, AtomicLong>> targetAddressInfos = new HashMap<>();
@ -203,7 +200,6 @@ public class ServerSessionImpl implements ServerSession, FailureListener {
final SimpleString defaultAddress,
final SessionCallback callback,
final OperationContext context,
final QueueCreator queueCreator,
final PagingManager pagingManager) throws Exception {
this.username = username;
@ -251,8 +247,6 @@ public class ServerSessionImpl implements ServerSession, FailureListener {
remotingConnection.addFailureListener(this);
this.context = context;
this.queueCreator = queueCreator;
if (!xa) {
tx = newTransaction();
}
@ -390,11 +384,6 @@ public class ServerSessionImpl implements ServerSession, FailureListener {
}
}
@Override
public QueueCreator getQueueCreator() {
return queueCreator;
}
protected void securityCheck(SimpleString address, CheckType checkType, SecurityAuth auth) throws Exception {
if (securityEnabled) {
securityStore.check(address, checkType, auth);
@ -500,7 +489,7 @@ public class ServerSessionImpl implements ServerSession, FailureListener {
final SimpleString filterString,
final boolean temporary,
final boolean durable) throws Exception {
return createQueue(address, name, filterString, temporary, durable, null, null);
return createQueue(address, name, filterString, temporary, durable, null, null, false);
}
@Override
@ -510,7 +499,8 @@ public class ServerSessionImpl implements ServerSession, FailureListener {
final boolean temporary,
final boolean durable,
final Integer maxConsumers,
final Boolean deleteOnNoConsumers) throws Exception {
final Boolean deleteOnNoConsumers,
final Boolean autoCreated) throws Exception {
if (durable) {
// make sure the user has privileges to create this queue
securityCheck(address, CheckType.CREATE_DURABLE_QUEUE, this);
@ -520,7 +510,7 @@ public class ServerSessionImpl implements ServerSession, FailureListener {
server.checkQueueCreationLimit(getUsername());
Queue queue = server.createQueue(address, name, filterString, SimpleString.toSimpleString(getUsername()), durable, temporary, maxConsumers, deleteOnNoConsumers);
Queue queue = server.createQueue(address, name, filterString, SimpleString.toSimpleString(getUsername()), durable, temporary, autoCreated, maxConsumers, deleteOnNoConsumers);
if (temporary) {
// Temporary queue in core simply means the queue will be deleted if
@ -1485,7 +1475,6 @@ public class ServerSessionImpl implements ServerSession, FailureListener {
}
private void installJMSHooks() {
this.queueCreator = server.getJMSDestinationCreator();
}
private Map<SimpleString, Pair<UUID, AtomicLong>> cloneTargetAddresses() {
@ -1605,11 +1594,7 @@ public class ServerSessionImpl implements ServerSession, FailureListener {
}
try {
if (noAutoCreateQueue) {
result = postOffice.route(msg, null, routingContext, direct);
} else {
result = postOffice.route(msg, queueCreator, routingContext, direct);
}
result = postOffice.route(msg, routingContext, direct);
Pair<UUID, AtomicLong> value = targetAddressInfos.get(msg.getAddress());

View File

@ -464,7 +464,6 @@ public class ManagementServiceImpl implements ManagementService {
public synchronized void registerInRegistry(final String resourceName, final Object managedResource) {
unregisterFromRegistry(resourceName);
ActiveMQServerLogger.LOGGER.info("Registering: " + resourceName);
registry.put(resourceName, managedResource);
}
@ -653,7 +652,7 @@ public class ManagementServiceImpl implements ManagementService {
notificationMessage.putStringProperty(new SimpleString("foobar"), new SimpleString(notification.getUID()));
}
postOffice.route(notificationMessage, null, false);
postOffice.route(notificationMessage, false);
}
}
}

View File

@ -46,12 +46,14 @@ import org.apache.activemq.artemis.core.security.Role;
import org.apache.activemq.artemis.core.server.JournalType;
import org.apache.activemq.artemis.core.server.SecuritySettingPlugin;
import org.apache.activemq.artemis.core.server.cluster.impl.MessageLoadBalancingType;
import org.apache.activemq.artemis.core.server.impl.AddressInfo;
import org.apache.activemq.artemis.core.server.impl.LegacyLDAPSecuritySettingPlugin;
import org.apache.activemq.artemis.core.settings.impl.SlowConsumerPolicy;
import org.junit.Assert;
import org.junit.Test;
import static org.apache.activemq.artemis.core.server.impl.AddressInfo.RoutingType.ANYCAST;
import static org.apache.activemq.artemis.core.server.impl.AddressInfo.RoutingType.MULTICAST;
public class FileConfigurationTest extends ConfigurationImplTest {
private final String fullConfigurationName = "ConfigurationTest-full-config.xml";
@ -376,7 +378,7 @@ public class FileConfigurationTest extends ConfigurationImplTest {
// Addr 1
CoreAddressConfiguration addressConfiguration = conf.getAddressConfigurations().get(0);
assertEquals("addr1", addressConfiguration.getName());
assertEquals(AddressInfo.RoutingType.ANYCAST, addressConfiguration.getRoutingType());
assertEquals(ANYCAST, addressConfiguration.getRoutingType());
assertEquals(2, addressConfiguration.getQueueConfigurations().size());
// Addr 1 Queue 1
@ -402,7 +404,7 @@ public class FileConfigurationTest extends ConfigurationImplTest {
// Addr 2
addressConfiguration = conf.getAddressConfigurations().get(1);
assertEquals("addr2", addressConfiguration.getName());
assertEquals(AddressInfo.RoutingType.MULTICAST, addressConfiguration.getRoutingType());
assertEquals(MULTICAST, addressConfiguration.getRoutingType());
assertEquals(2, addressConfiguration.getQueueConfigurations().size());
// Addr 2 Queue 1

View File

@ -154,7 +154,7 @@ class IncomingVertxEventHandler implements ConnectorService {
manualEncodeVertxMessageBody(msg.getBodyBuffer(), message.body(), type);
try {
postOffice.route(msg, null, false);
postOffice.route(msg, false);
} catch (Exception e) {
ActiveMQVertxLogger.LOGGER.error("failed to route msg " + msg, e);
}

View File

@ -506,8 +506,9 @@ public abstract class BridgeTestBase extends ActiveMQTestBase {
managementService = server1.getManagementService();
}
AddressControl topicControl = (AddressControl) managementService.getResource(ResourceNames.ADDRESS + topic.getTopicName());
Assert.assertEquals(0, topicControl.getQueueNames().length);
if (topicControl != null) {
Assert.assertEquals(0, topicControl.getQueueNames().length);
}
}
protected void removeAllMessages(final String queueName, final int index) throws Exception {

View File

@ -63,6 +63,7 @@ import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.api.core.management.ResourceNames;
import org.apache.activemq.artemis.core.postoffice.Bindings;
import org.apache.activemq.artemis.core.remoting.CloseListener;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnector;
@ -775,6 +776,7 @@ public class ProtonTest extends ProtonTestBase {
Exception expectedException = null;
try {
session.createSender("AnAddressThatDoesNotExist");
fail("Creating a sender here on an address that doesn't exist should fail");
} catch (Exception e) {
expectedException = e;
}
@ -896,7 +898,7 @@ public class ProtonTest extends ProtonTestBase {
//create request message for getQueueNames query
AmqpMessage request = new AmqpMessage();
request.setApplicationProperty("_AMQ_ResourceName", "core.server");
request.setApplicationProperty("_AMQ_ResourceName", ResourceNames.BROKER);
request.setApplicationProperty("_AMQ_OperationName", "getQueueNames");
request.setReplyToAddress(destinationAddress);
request.setText("[]");

View File

@ -28,6 +28,7 @@ import java.util.Set;
import java.util.UUID;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.api.core.management.ResourceNames;
import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient;
import org.apache.activemq.artemis.core.security.Role;
import org.apache.activemq.artemis.core.server.Queue;
@ -144,7 +145,7 @@ public class AutoCreateJmsDestinationTest extends JMSTestBase {
connection.close();
assertNotNull(server.getManagementService().getResource("core.address.test"));
assertNotNull(server.getManagementService().getResource(ResourceNames.ADDRESS + "test"));
}
@Test
@ -181,11 +182,11 @@ public class AutoCreateJmsDestinationTest extends JMSTestBase {
connection.start();
assertNotNull(consumer.receive(500));
assertNotNull(server.getManagementService().getResource("core.address." + topicName));
assertNotNull(server.getManagementService().getResource(ResourceNames.ADDRESS + topicName));
connection.close();
assertNull(server.getManagementService().getResource("core.address." + topicName));
assertNull(server.getManagementService().getResource(ResourceNames.ADDRESS + topicName));
}
@Test
@ -204,7 +205,7 @@ public class AutoCreateJmsDestinationTest extends JMSTestBase {
connection.close();
assertNotNull(server.getManagementService().getResource("core.address.test"));
assertNotNull(server.getManagementService().getResource(ResourceNames.ADDRESS + "test"));
assertNotNull(server.locateQueue(SimpleString.toSimpleString("myClientID.myDurableSub")));
}

View File

@ -513,7 +513,7 @@ public class HangConsumerTest extends ActiveMQTestBase {
}
/* (non-Javadoc)
* @see SessionCallback#sendMessage(org.apache.activemq.artemis.core.server.ServerMessage, long, int)
* @see SessionCallback#sendJmsMessage(org.apache.activemq.artemis.core.server.ServerMessage, long, int)
*/
@Override
public int sendMessage(MessageReference ref, ServerMessage message, ServerConsumer consumer, int deliveryCount) {
@ -592,7 +592,7 @@ public class HangConsumerTest extends ActiveMQTestBase {
SessionCallback callback,
OperationContext context,
boolean autoCreateQueue) throws Exception {
return new ServerSessionImpl(name, username, password, validatedUser, minLargeMessageSize, autoCommitSends, autoCommitAcks, preAcknowledge, getConfiguration().isPersistDeliveryCountBeforeDelivery(), xa, connection, getStorageManager(), getPostOffice(), getResourceManager(), getSecurityStore(), getManagementService(), this, getConfiguration().getManagementAddress(), defaultAddress == null ? null : new SimpleString(defaultAddress), new MyCallback(callback), context, null, getPagingManager());
return new ServerSessionImpl(name, username, password, validatedUser, minLargeMessageSize, autoCommitSends, autoCommitAcks, preAcknowledge, getConfiguration().isPersistDeliveryCountBeforeDelivery(), xa, connection, getStorageManager(), getPostOffice(), getResourceManager(), getSecurityStore(), getManagementService(), this, getConfiguration().getManagementAddress(), defaultAddress == null ? null : new SimpleString(defaultAddress), new MyCallback(callback), context, getPagingManager());
}
}

View File

@ -34,6 +34,7 @@ import org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryInternal
import org.apache.activemq.artemis.core.client.impl.ClientSessionInternal;
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.Queue;
import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
import org.apache.activemq.artemis.tests.util.CountDownSessionFailureListener;
@ -228,6 +229,7 @@ public class SessionTest extends ActiveMQTestBase {
@Test
public void testQueueQueryNoQ() throws Exception {
server.getAddressSettingsRepository().addMatch("#", new AddressSettings().setAutoCreateJmsQueues(false));
cf = createSessionFactory(locator);
ClientSession clientSession = cf.createSession(false, true, true);
QueueQuery resp = clientSession.queueQuery(new SimpleString(queueName));

View File

@ -58,13 +58,15 @@ public class AutoCreateQueueClusterTest extends JMSClusteredTestBase {
Session session2 = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer prod1 = session1.createProducer(ActiveMQJMSClient.createQueue("myQueue"));
// TODO the "jms." prefix is required here because the cluster connection only works for queues which start with "jms"
MessageProducer prod1 = session1.createProducer(ActiveMQJMSClient.createQueue("jms.myQueue"));
prod1.setDeliveryMode(DeliveryMode.PERSISTENT);
prod1.send(session1.createTextMessage("m1"));
MessageConsumer cons2 = session2.createConsumer(ActiveMQJMSClient.createQueue("myQueue"));
// TODO the "jms." prefix is required here because the cluster connection only works for queues which start with "jms"
MessageConsumer cons2 = session2.createConsumer(ActiveMQJMSClient.createQueue("jms.myQueue"));
TextMessage received = (TextMessage) cons2.receive(5000);

View File

@ -25,9 +25,7 @@ import javax.jms.JMSException;
import javax.jms.JMSProducer;
import javax.jms.JMSRuntimeException;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import java.util.Random;
import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient;
@ -36,26 +34,14 @@ import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory;
import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
import org.apache.activemq.artemis.tests.util.JMSTestBase;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class NonExistentQueueTest extends JMSTestBase {
private JMSContext context;
private final Random random = new Random();
private Queue queue;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
context = createContext();
queue = createQueue(JmsContextTest.class.getSimpleName() + "Queue1");
}
@Test
public void sendToNonExistentDestination() throws Exception {
server.getAddressSettingsRepository().addMatch("#", new AddressSettings().setAutoCreateJmsQueues(false));
server.getAddressSettingsRepository().addMatch("#", new AddressSettings().setAutoCreateJmsTopics(false));
Destination destination = ActiveMQJMSClient.createTopic("DoesNotExist");
TransportConfiguration transportConfiguration = new TransportConfiguration(InVMConnectorFactory.class.getName());
ConnectionFactory localConnectionFactory = ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, transportConfiguration);

View File

@ -19,7 +19,6 @@ package org.apache.activemq.artemis.tests.integration.persistence;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;
@ -28,7 +27,6 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import org.apache.activemq.artemis.api.core.Message;
@ -42,7 +40,6 @@ import org.apache.activemq.artemis.api.core.client.ClientSession;
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
import org.apache.activemq.artemis.api.core.client.ServerLocator;
import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient;
import org.apache.activemq.artemis.api.jms.JMSFactoryType;
import org.apache.activemq.artemis.cli.commands.tools.XmlDataExporter;
import org.apache.activemq.artemis.cli.commands.tools.XmlDataImporter;
import org.apache.activemq.artemis.core.persistence.impl.journal.BatchingIDGenerator;
@ -51,7 +48,6 @@ import org.apache.activemq.artemis.core.persistence.impl.journal.LargeServerMess
import org.apache.activemq.artemis.core.registry.JndiBindingRegistry;
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.apache.activemq.artemis.jms.server.JMSServerManager;
import org.apache.activemq.artemis.jms.server.impl.JMSServerManagerImpl;
import org.apache.activemq.artemis.tests.unit.util.InVMContext;
@ -435,163 +431,6 @@ public class XmlImportExportTest extends ActiveMQTestBase {
assertEquals(true, queueQuery.isDurable());
}
@Test
public void testJmsConnectionFactoryBinding() throws Exception {
final String clientId = "myClientId";
final long clientFailureCheckPeriod = 1;
final long connectionTTl = 2;
final long callTimeout = 3;
final long callFailoverTimeout = 4;
final boolean cacheLargeMessagesClient = true;
final int minLargeMessageSize = 5;
final boolean compressLargeMessages = true;
final int consumerWindowSize = 6;
final int consumerMaxRate = 7;
final int confirmationWindowSize = 8;
final int producerWindowSize = 9;
final int producerMaxrate = 10;
final boolean blockOnAcknowledge = true;
final boolean blockOnDurableSend = false;
final boolean blockOnNonDurableSend = true;
final boolean autoGroup = true;
final boolean preacknowledge = true;
final String loadBalancingPolicyClassName = "myPolicy";
final int transactionBatchSize = 11;
final int dupsOKBatchSize = 12;
final boolean useGlobalPools = true;
final int scheduledThreadPoolMaxSize = 13;
final int threadPoolMaxSize = 14;
final long retryInterval = 15;
final double retryIntervalMultiplier = 10.0;
final long maxRetryInterval = 16;
final int reconnectAttempts = 17;
final boolean failoverOnInitialConnection = true;
final String groupId = "myGroupId";
final String name = "myFirstConnectionFactoryName";
final String jndi_binding1 = name + "Binding1";
final String jndi_binding2 = name + "Binding2";
final JMSFactoryType type = JMSFactoryType.CF;
final boolean ha = true;
final List<String> connectors = Arrays.asList("in-vm1", "in-vm2");
ClientSession session = basicSetUp();
jmsServer.createConnectionFactory(name, ha, type, connectors, clientId, clientFailureCheckPeriod, connectionTTl, callTimeout, callFailoverTimeout, cacheLargeMessagesClient, minLargeMessageSize, compressLargeMessages, consumerWindowSize, consumerMaxRate, confirmationWindowSize, producerWindowSize, producerMaxrate, blockOnAcknowledge, blockOnDurableSend, blockOnNonDurableSend, autoGroup, preacknowledge, loadBalancingPolicyClassName, transactionBatchSize, dupsOKBatchSize, useGlobalPools, scheduledThreadPoolMaxSize, threadPoolMaxSize, retryInterval, retryIntervalMultiplier, maxRetryInterval, reconnectAttempts, failoverOnInitialConnection, groupId, jndi_binding1, jndi_binding2);
jmsServer.createConnectionFactory("mySecondConnectionFactoryName", false, JMSFactoryType.CF, Arrays.asList("in-vm1", "in-vm2"), "mySecondConnectionFactoryName1", "mySecondConnectionFactoryName2");
session.close();
locator.close();
server.stop();
ByteArrayOutputStream xmlOutputStream = new ByteArrayOutputStream();
XmlDataExporter xmlDataExporter = new XmlDataExporter();
xmlDataExporter.process(xmlOutputStream, server.getConfiguration().getBindingsLocation().getAbsolutePath(), server.getConfiguration().getJournalLocation().getAbsolutePath(), server.getConfiguration().getPagingLocation().getAbsolutePath(), server.getConfiguration().getLargeMessagesLocation().getAbsolutePath());
System.out.print(new String(xmlOutputStream.toByteArray()));
clearDataRecreateServerDirs();
server.start();
checkForLongs();
locator = createInVMNonHALocator();
factory = createSessionFactory(locator);
session = factory.createSession(false, true, true);
ByteArrayInputStream xmlInputStream = new ByteArrayInputStream(xmlOutputStream.toByteArray());
XmlDataImporter xmlDataImporter = new XmlDataImporter();
xmlDataImporter.process(xmlInputStream, session);
ConnectionFactory cf1 = (ConnectionFactory) namingContext.lookup(jndi_binding1);
assertNotNull(cf1);
ActiveMQConnectionFactory hcf1 = (ActiveMQConnectionFactory) cf1;
assertEquals(ha, hcf1.isHA());
assertEquals(type.intValue(), hcf1.getFactoryType());
assertEquals(clientId, hcf1.getClientID());
assertEquals(clientFailureCheckPeriod, hcf1.getClientFailureCheckPeriod());
assertEquals(connectionTTl, hcf1.getConnectionTTL());
assertEquals(callTimeout, hcf1.getCallTimeout());
// Assert.assertEquals(callFailoverTimeout, hcf1.getCallFailoverTimeout()); // this value isn't currently persisted by org.apache.activemq.artemis.jms.server.config.impl.ConnectionFactoryConfigurationImpl.encode()
// Assert.assertEquals(cacheLargeMessagesClient, hcf1.isCacheLargeMessagesClient()); // this value isn't currently supported by org.apache.activemq.artemis.api.jms.management.JMSServerControl.createConnectionFactory(java.lang.String, boolean, boolean, int, java.lang.String, java.lang.String, java.lang.String, long, long, long, long, int, boolean, int, int, int, int, int, boolean, boolean, boolean, boolean, boolean, java.lang.String, int, int, boolean, int, int, long, double, long, int, boolean, java.lang.String)
assertEquals(minLargeMessageSize, hcf1.getMinLargeMessageSize());
// Assert.assertEquals(compressLargeMessages, hcf1.isCompressLargeMessage()); // this value isn't currently handled properly by org.apache.activemq.artemis.jms.server.impl.JMSServerManagerImpl.createConnectionFactory(java.lang.String, boolean, org.apache.activemq.artemis.api.jms.JMSFactoryType, java.util.List<java.lang.String>, java.lang.String, long, long, long, long, boolean, int, boolean, int, int, int, int, int, boolean, boolean, boolean, boolean, boolean, java.lang.String, int, int, boolean, int, int, long, double, long, int, boolean, java.lang.String, java.lang.String...)()
assertEquals(consumerWindowSize, hcf1.getConsumerWindowSize());
assertEquals(consumerMaxRate, hcf1.getConsumerMaxRate());
assertEquals(confirmationWindowSize, hcf1.getConfirmationWindowSize());
assertEquals(producerWindowSize, hcf1.getProducerWindowSize());
assertEquals(producerMaxrate, hcf1.getProducerMaxRate());
assertEquals(blockOnAcknowledge, hcf1.isBlockOnAcknowledge());
assertEquals(blockOnDurableSend, hcf1.isBlockOnDurableSend());
assertEquals(blockOnNonDurableSend, hcf1.isBlockOnNonDurableSend());
assertEquals(autoGroup, hcf1.isAutoGroup());
assertEquals(preacknowledge, hcf1.isPreAcknowledge());
assertEquals(loadBalancingPolicyClassName, hcf1.getConnectionLoadBalancingPolicyClassName());
assertEquals(transactionBatchSize, hcf1.getTransactionBatchSize());
assertEquals(dupsOKBatchSize, hcf1.getDupsOKBatchSize());
assertEquals(useGlobalPools, hcf1.isUseGlobalPools());
assertEquals(scheduledThreadPoolMaxSize, hcf1.getScheduledThreadPoolMaxSize());
assertEquals(threadPoolMaxSize, hcf1.getThreadPoolMaxSize());
assertEquals(retryInterval, hcf1.getRetryInterval());
assertEquals(retryIntervalMultiplier, hcf1.getRetryIntervalMultiplier(), 0);
assertEquals(maxRetryInterval, hcf1.getMaxRetryInterval());
assertEquals(reconnectAttempts, hcf1.getReconnectAttempts());
assertEquals(failoverOnInitialConnection, hcf1.isFailoverOnInitialConnection());
assertEquals(groupId, hcf1.getGroupID());
assertNotNull(namingContext.lookup(jndi_binding2));
assertNotNull(namingContext.lookup("mySecondConnectionFactoryName1"));
assertNotNull(namingContext.lookup("mySecondConnectionFactoryName2"));
}
@Test
public void testJmsDestination() throws Exception {
ClientSession session = basicSetUp();
jmsServer.createQueue(true, "myQueue", null, true, "myQueueJndiBinding1", "myQueueJndiBinding2");
jmsServer.createTopic(true, "myTopic", "myTopicJndiBinding1", "myTopicJndiBinding2");
session.close();
locator.close();
server.stop();
ByteArrayOutputStream xmlOutputStream = new ByteArrayOutputStream();
XmlDataExporter xmlDataExporter = new XmlDataExporter();
xmlDataExporter.process(xmlOutputStream, server.getConfiguration().getBindingsDirectory(), server.getConfiguration().getJournalDirectory(), server.getConfiguration().getPagingDirectory(), server.getConfiguration().getLargeMessagesDirectory());
System.out.print(new String(xmlOutputStream.toByteArray()));
clearDataRecreateServerDirs();
server.start();
checkForLongs();
locator = createInVMNonHALocator();
factory = createSessionFactory(locator);
session = factory.createSession(false, true, true);
ByteArrayInputStream xmlInputStream = new ByteArrayInputStream(xmlOutputStream.toByteArray());
XmlDataImporter xmlDataImporter = new XmlDataImporter();
xmlDataImporter.process(xmlInputStream, session);
assertNotNull(namingContext.lookup("myQueueJndiBinding1"));
assertNotNull(namingContext.lookup("myQueueJndiBinding2"));
assertNotNull(namingContext.lookup("myTopicJndiBinding1"));
assertNotNull(namingContext.lookup("myTopicJndiBinding2"));
jmsServer.createConnectionFactory("test-cf", false, JMSFactoryType.CF, Arrays.asList("in-vm1"), "test-cf");
ConnectionFactory cf = (ConnectionFactory) namingContext.lookup("test-cf");
Connection connection = cf.createConnection();
Session jmsSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = jmsSession.createProducer((Destination) namingContext.lookup("myQueueJndiBinding1"));
producer.send(jmsSession.createTextMessage());
MessageConsumer consumer = jmsSession.createConsumer((Destination) namingContext.lookup("myQueueJndiBinding2"));
connection.start();
assertNotNull(consumer.receive(3000));
consumer = jmsSession.createConsumer((Destination) namingContext.lookup("myTopicJndiBinding1"));
producer = jmsSession.createProducer((Destination) namingContext.lookup("myTopicJndiBinding2"));
producer.send(jmsSession.createTextMessage());
assertNotNull(consumer.receive(3000));
connection.close();
}
@Test
public void testLargeMessage() throws Exception {
server = createServer(true);

View File

@ -1,136 +0,0 @@
/*
* 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.artemis.tests.integration.stomp;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.activemq.artemis.core.protocol.stomp.Stomp;
import org.junit.Assert;
import org.junit.Test;
public class ConcurrentStompTest extends StompTestBase {
private Socket stompSocket_2;
private ByteArrayOutputStream inputBuffer_2;
/**
* Send messages on 1 socket and receives them concurrently on another socket.
*/
@Test
public void testSendManyMessages() throws Exception {
try {
String connect = "CONNECT\n" + "login: brianm\n" + "passcode: wombats\n\n" + Stomp.NULL;
sendFrame(connect);
String connected = receiveFrame(10000);
Assert.assertTrue(connected.startsWith("CONNECTED"));
stompSocket_2 = createSocket();
inputBuffer_2 = new ByteArrayOutputStream();
sendFrame(stompSocket_2, connect);
connected = receiveFrame(stompSocket_2, inputBuffer_2, 10000);
Assert.assertTrue(connected.startsWith("CONNECTED"));
final int count = 1000;
final CountDownLatch latch = new CountDownLatch(count);
String subscribe = "SUBSCRIBE\n" +
"destination:" + getQueuePrefix() + getQueueName() + "\n" +
"ack:auto\n\n" +
Stomp.NULL;
sendFrame(stompSocket_2, subscribe);
Thread.sleep(2000);
new Thread() {
@Override
public void run() {
int i = 0;
while (true) {
try {
String frame = receiveFrame(stompSocket_2, inputBuffer_2, 10000);
Assert.assertTrue(frame.startsWith("MESSAGE"));
Assert.assertTrue(frame.indexOf("destination:") > 0);
System.out.println("<<< " + i++);
latch.countDown();
} catch (Exception e) {
break;
}
}
}
}.start();
String send = "SEND\n" + "destination:" + getQueuePrefix() + getQueueName() + "\n";
for (int i = 1; i <= count; i++) {
// Thread.sleep(1);
System.out.println(">>> " + i);
sendFrame(send + "count:" + i + "\n\n" + Stomp.NULL);
}
assertTrue(latch.await(60, TimeUnit.SECONDS));
} finally {
stompSocket_2.close();
inputBuffer_2.close();
}
}
// Implementation methods
// -------------------------------------------------------------------------
public void sendFrame(Socket socket, String data) throws Exception {
byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
OutputStream outputStream = socket.getOutputStream();
for (byte b : bytes) {
outputStream.write(b);
}
outputStream.flush();
}
public String receiveFrame(Socket socket, ByteArrayOutputStream input, long timeOut) throws Exception {
socket.setSoTimeout((int) timeOut);
InputStream is = socket.getInputStream();
int c = 0;
for (;;) {
c = is.read();
if (c < 0) {
throw new IOException("socket closed.");
} else if (c == 0) {
c = is.read();
if (c != '\n') {
byte[] ba = input.toByteArray();
System.out.println(new String(ba, StandardCharsets.UTF_8));
}
Assert.assertEquals("Expecting stomp frame to terminate with \0\n", c, '\n');
byte[] ba = input.toByteArray();
input.reset();
return new String(ba, StandardCharsets.UTF_8);
} else {
input.write(c);
}
}
}
}

View File

@ -1,848 +0,0 @@
/*
* 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.artemis.tests.integration.stomp;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.QueueBrowser;
import javax.jms.TextMessage;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.activemq.artemis.api.core.Interceptor;
import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
import org.apache.activemq.artemis.core.config.Configuration;
import org.apache.activemq.artemis.core.protocol.core.Packet;
import org.apache.activemq.artemis.core.protocol.stomp.Stomp;
import org.apache.activemq.artemis.core.protocol.stomp.StompFrame;
import org.apache.activemq.artemis.core.protocol.stomp.StompFrameInterceptor;
import org.apache.activemq.artemis.core.protocol.stomp.StompProtocolManagerFactory;
import org.apache.activemq.artemis.core.registry.JndiBindingRegistry;
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptorFactory;
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.ActiveMQServers;
import org.apache.activemq.artemis.jms.server.JMSServerManager;
import org.apache.activemq.artemis.jms.server.config.JMSConfiguration;
import org.apache.activemq.artemis.jms.server.config.impl.JMSConfigurationImpl;
import org.apache.activemq.artemis.jms.server.config.impl.JMSQueueConfigurationImpl;
import org.apache.activemq.artemis.jms.server.config.impl.TopicConfigurationImpl;
import org.apache.activemq.artemis.jms.server.impl.JMSServerManagerImpl;
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
import org.apache.activemq.artemis.tests.integration.largemessage.LargeMessageTestBase;
import org.apache.activemq.artemis.tests.integration.stomp.util.ClientStompFrame;
import org.apache.activemq.artemis.tests.integration.stomp.util.StompClientConnection;
import org.apache.activemq.artemis.tests.integration.stomp.util.StompClientConnectionFactory;
import org.apache.activemq.artemis.tests.unit.util.InVMNamingContext;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class ExtraStompTest extends StompTestBase {
@Override
@Before
public void setUp() throws Exception {
autoCreateServer = false;
super.setUp();
}
@Test
public void testConnectionTTL() throws Exception {
try {
server = createServerWithTTL("2000");
server.start();
setUpAfterServer();
String connect_frame = "CONNECT\n" + "login: brianm\n" + "passcode: wombats\n" + "request-id: 1\n" + "\n" + Stomp.NULL;
sendFrame(connect_frame);
String f = receiveFrame(10000);
Assert.assertTrue(f.startsWith("CONNECTED"));
Assert.assertTrue(f.indexOf("response-id:1") >= 0);
String frame = "SEND\n" + "destination:" + getQueuePrefix() + getQueueName() + "\n\n" + "Hello World 1" + Stomp.NULL;
sendFrame(frame);
assertChannelClosed();
MessageConsumer consumer = session.createConsumer(queue);
TextMessage message = (TextMessage) consumer.receiveNoWait();
Assert.assertNotNull(message);
message = (TextMessage) consumer.receiveNoWait();
Assert.assertNull(message);
} finally {
cleanUp();
server.stop();
}
}
@Test
public void testEnableMessageID() throws Exception {
enableMessageIDTest(true);
}
@Test
public void testDisableMessageID() throws Exception {
enableMessageIDTest(false);
}
@Test
public void testDefaultEnableMessageID() throws Exception {
enableMessageIDTest(null);
}
//stomp sender -> large -> stomp receiver
@Test
public void testSendReceiveLargePersistentMessages() throws Exception {
try {
server = createPersistentServerWithStompMinLargeSize(2048);
server.start();
setUpAfterServer();
String frame = "CONNECT\n" + "login: brianm\n" + "passcode: wombats\n\n" + Stomp.NULL;
sendFrame(frame);
frame = receiveFrame(10000);
Assert.assertTrue(frame.startsWith("CONNECTED"));
int count = 10;
int szBody = 1024 * 1024;
char[] contents = new char[szBody];
for (int i = 0; i < szBody; i++) {
contents[i] = 'A';
}
String body = new String(contents);
frame = "SEND\n" + "destination:" + getQueuePrefix() + getQueueName() + "\n" + "persistent:true\n" + "\n\n" + body + Stomp.NULL;
for (int i = 0; i < count; i++) {
sendFrame(frame);
}
frame = "SUBSCRIBE\n" + "destination:" + getQueuePrefix() + getQueueName() + "\n" + "ack:auto\n\nfff" + Stomp.NULL;
sendFrame(frame);
for (int i = 0; i < count; i++) {
frame = receiveFrame(60000);
Assert.assertNotNull(frame);
System.out.println("part of frame: " + frame.substring(0, 200));
Assert.assertTrue(frame.startsWith("MESSAGE"));
Assert.assertTrue(frame.indexOf("destination:") > 0);
int index = frame.indexOf("AAAA");
assertEquals(szBody, (frame.length() - index));
}
// remove suscription
frame = "UNSUBSCRIBE\n" + "destination:" +
getQueuePrefix() +
getQueueName() +
"\n" +
"receipt:567\n" +
"\n\n" +
Stomp.NULL;
sendFrame(frame);
waitForReceipt();
frame = "DISCONNECT\n" + "\n\n" + Stomp.NULL;
sendFrame(frame);
} catch (Exception ex) {
ex.printStackTrace();
throw ex;
} finally {
cleanUp();
server.stop();
}
}
//core sender -> large -> stomp receiver
@Test
public void testReceiveLargePersistentMessagesFromCore() throws Exception {
try {
server = createPersistentServerWithStompMinLargeSize(2048);
server.start();
setUpAfterServer();
int msgSize = 3 * ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE;
char[] contents = new char[msgSize];
for (int i = 0; i < msgSize; i++) {
contents[i] = 'B';
}
String msg = new String(contents);
int count = 10;
for (int i = 0; i < count; i++) {
this.sendMessage(msg);
}
String frame = "CONNECT\n" + "login: brianm\n" + "passcode: wombats\n\n" + Stomp.NULL;
sendFrame(frame);
frame = receiveFrame(10000);
Assert.assertTrue(frame.startsWith("CONNECTED"));
frame = "SUBSCRIBE\n" + "destination:" + getQueuePrefix() + getQueueName() + "\n" + "ack:auto\n\nfff" + Stomp.NULL;
sendFrame(frame);
for (int i = 0; i < count; i++) {
frame = receiveFrame(60000);
Assert.assertNotNull(frame);
System.out.println("part of frame: " + frame.substring(0, 250));
Assert.assertTrue(frame.startsWith("MESSAGE"));
Assert.assertTrue(frame.indexOf("destination:") > 0);
int index = frame.indexOf("BBBB");
assertEquals(msgSize, (frame.length() - index));
}
// remove suscription
frame = "UNSUBSCRIBE\n" + "destination:" +
getQueuePrefix() +
getQueueName() +
"\n" +
"receipt:567\n" +
"\n\n" +
Stomp.NULL;
sendFrame(frame);
waitForReceipt();
frame = "DISCONNECT\n" + "\n\n" + Stomp.NULL;
sendFrame(frame);
} catch (Exception ex) {
ex.printStackTrace();
throw ex;
} finally {
cleanUp();
server.stop();
}
}
//stomp v12 sender -> large -> stomp v12 receiver
@Test
public void testSendReceiveLargePersistentMessagesV12() throws Exception {
try {
server = createPersistentServerWithStompMinLargeSize(2048);
server.start();
setUpAfterServer();
StompClientConnection connV12 = StompClientConnectionFactory.createClientConnection("1.2", "localhost", port);
connV12.connect(defUser, defPass);
int count = 10;
int szBody = 1024 * 1024;
char[] contents = new char[szBody];
for (int i = 0; i < szBody; i++) {
contents[i] = 'A';
}
String body = new String(contents);
ClientStompFrame frame = connV12.createFrame("SEND");
frame.addHeader("destination", getQueuePrefix() + getQueueName());
frame.addHeader("persistent", "true");
frame.setBody(body);
for (int i = 0; i < count; i++) {
connV12.sendFrame(frame);
}
ClientStompFrame subFrame = connV12.createFrame("SUBSCRIBE");
subFrame.addHeader("id", "a-sub");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
connV12.sendFrame(subFrame);
for (int i = 0; i < count; i++) {
ClientStompFrame receiveFrame = connV12.receiveFrame(30000);
Assert.assertNotNull(receiveFrame);
System.out.println("part of frame: " + receiveFrame.getBody().substring(0, 20));
Assert.assertTrue(receiveFrame.getCommand().equals("MESSAGE"));
Assert.assertEquals(receiveFrame.getHeader("destination"), getQueuePrefix() + getQueueName());
assertEquals(szBody, receiveFrame.getBody().length());
}
// remove susbcription
ClientStompFrame unsubFrame = connV12.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("id", "a-sub");
connV12.sendFrame(unsubFrame);
connV12.disconnect();
} catch (Exception ex) {
ex.printStackTrace();
throw ex;
} finally {
cleanUp();
server.stop();
}
}
//core sender -> large -> stomp v12 receiver
@Test
public void testReceiveLargePersistentMessagesFromCoreV12() throws Exception {
try {
server = createPersistentServerWithStompMinLargeSize(2048);
server.start();
setUpAfterServer();
int msgSize = 3 * ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE;
char[] contents = new char[msgSize];
for (int i = 0; i < msgSize; i++) {
contents[i] = 'B';
}
String msg = new String(contents);
int count = 10;
for (int i = 0; i < count; i++) {
this.sendMessage(msg);
}
StompClientConnection connV12 = StompClientConnectionFactory.createClientConnection("1.2", "localhost", port);
connV12.connect(defUser, defPass);
ClientStompFrame subFrame = connV12.createFrame("SUBSCRIBE");
subFrame.addHeader("id", "a-sub");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
connV12.sendFrame(subFrame);
for (int i = 0; i < count; i++) {
ClientStompFrame receiveFrame = connV12.receiveFrame(30000);
Assert.assertNotNull(receiveFrame);
System.out.println("part of frame: " + receiveFrame.getBody().substring(0, 20));
Assert.assertTrue(receiveFrame.getCommand().equals("MESSAGE"));
Assert.assertEquals(receiveFrame.getHeader("destination"), getQueuePrefix() + getQueueName());
assertEquals(msgSize, receiveFrame.getBody().length());
}
// remove susbcription
ClientStompFrame unsubFrame = connV12.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("id", "a-sub");
connV12.sendFrame(unsubFrame);
connV12.disconnect();
} catch (Exception ex) {
ex.printStackTrace();
throw ex;
} finally {
cleanUp();
server.stop();
}
}
//core sender -> large (compressed regular) -> stomp v10 receiver
@Test
public void testReceiveLargeCompressedToRegularPersistentMessagesFromCore() throws Exception {
try {
server = createPersistentServerWithStompMinLargeSize(2048);
server.start();
setUpAfterServer(true);
LargeMessageTestBase.TestLargeMessageInputStream input = new LargeMessageTestBase.TestLargeMessageInputStream(ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE, true);
LargeMessageTestBase.adjustLargeCompression(true, input, ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE);
char[] contents = input.toArray();
String msg = new String(contents);
String leadingPart = msg.substring(0, 100);
int count = 10;
for (int i = 0; i < count; i++) {
this.sendMessage(msg);
}
String frame = "CONNECT\n" + "login: brianm\n" + "passcode: wombats\n\n" + Stomp.NULL;
sendFrame(frame);
frame = receiveFrame(10000);
Assert.assertTrue(frame.startsWith("CONNECTED"));
frame = "SUBSCRIBE\n" + "destination:" + getQueuePrefix() + getQueueName() + "\n" + "ack:auto\n\nfff" + Stomp.NULL;
sendFrame(frame);
for (int i = 0; i < count; i++) {
frame = receiveFrame(60000);
Assert.assertNotNull(frame);
System.out.println("part of frame: " + frame.substring(0, 250));
Assert.assertTrue(frame.startsWith("MESSAGE"));
Assert.assertTrue(frame.indexOf("destination:") > 0);
int index = frame.indexOf(leadingPart);
assertEquals(msg.length(), (frame.length() - index));
}
// remove suscription
frame = "UNSUBSCRIBE\n" + "destination:" +
getQueuePrefix() +
getQueueName() +
"\n" +
"receipt:567\n" +
"\n\n" +
Stomp.NULL;
sendFrame(frame);
waitForReceipt();
frame = "DISCONNECT\n" + "\n\n" + Stomp.NULL;
sendFrame(frame);
} catch (Exception ex) {
ex.printStackTrace();
throw ex;
} finally {
cleanUp();
server.stop();
}
}
//core sender -> large (compressed regular) -> stomp v12 receiver
@Test
public void testReceiveLargeCompressedToRegularPersistentMessagesFromCoreV12() throws Exception {
try {
server = createPersistentServerWithStompMinLargeSize(2048);
server.start();
setUpAfterServer(true);
LargeMessageTestBase.TestLargeMessageInputStream input = new LargeMessageTestBase.TestLargeMessageInputStream(ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE, true);
LargeMessageTestBase.adjustLargeCompression(true, input, ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE);
char[] contents = input.toArray();
String msg = new String(contents);
int count = 10;
for (int i = 0; i < count; i++) {
this.sendMessage(msg);
}
StompClientConnection connV12 = StompClientConnectionFactory.createClientConnection("1.2", "localhost", port);
connV12.connect(defUser, defPass);
ClientStompFrame subFrame = connV12.createFrame("SUBSCRIBE");
subFrame.addHeader("id", "a-sub");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
connV12.sendFrame(subFrame);
for (int i = 0; i < count; i++) {
ClientStompFrame receiveFrame = connV12.receiveFrame(30000);
Assert.assertNotNull(receiveFrame);
System.out.println("part of frame: " + receiveFrame.getBody().substring(0, 20));
Assert.assertTrue(receiveFrame.getCommand().equals("MESSAGE"));
Assert.assertEquals(receiveFrame.getHeader("destination"), getQueuePrefix() + getQueueName());
assertEquals(contents.length, receiveFrame.getBody().length());
}
// remove susbcription
ClientStompFrame unsubFrame = connV12.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("id", "a-sub");
connV12.sendFrame(unsubFrame);
connV12.disconnect();
} catch (Exception ex) {
ex.printStackTrace();
throw ex;
} finally {
cleanUp();
server.stop();
}
}
//core sender -> large (compressed large) -> stomp v12 receiver
@Test
public void testReceiveLargeCompressedToLargePersistentMessagesFromCoreV12() throws Exception {
try {
server = createPersistentServerWithStompMinLargeSize(2048);
server.start();
setUpAfterServer(true);
LargeMessageTestBase.TestLargeMessageInputStream input = new LargeMessageTestBase.TestLargeMessageInputStream(ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE, true);
input.setSize(10 * ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE);
LargeMessageTestBase.adjustLargeCompression(false, input, 10 * ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE);
char[] contents = input.toArray();
String msg = new String(contents);
int count = 10;
for (int i = 0; i < count; i++) {
this.sendMessage(msg);
}
StompClientConnection connV12 = StompClientConnectionFactory.createClientConnection("1.2", "localhost", port);
connV12.connect(defUser, defPass);
ClientStompFrame subFrame = connV12.createFrame("SUBSCRIBE");
subFrame.addHeader("id", "a-sub");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
connV12.sendFrame(subFrame);
for (int i = 0; i < count; i++) {
ClientStompFrame receiveFrame = connV12.receiveFrame(30000);
Assert.assertNotNull(receiveFrame);
System.out.println("part of frame: " + receiveFrame.getBody().substring(0, 20));
Assert.assertTrue(receiveFrame.getCommand().equals("MESSAGE"));
Assert.assertEquals(receiveFrame.getHeader("destination"), getQueuePrefix() + getQueueName());
assertEquals(contents.length, receiveFrame.getBody().length());
}
// remove susbcription
ClientStompFrame unsubFrame = connV12.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("id", "a-sub");
connV12.sendFrame(unsubFrame);
connV12.disconnect();
} catch (Exception ex) {
ex.printStackTrace();
throw ex;
} finally {
cleanUp();
server.stop();
}
}
//core sender -> large (compressed large) -> stomp v10 receiver
@Test
public void testReceiveLargeCompressedToLargePersistentMessagesFromCore() throws Exception {
try {
server = createPersistentServerWithStompMinLargeSize(2048);
server.start();
setUpAfterServer(true);
LargeMessageTestBase.TestLargeMessageInputStream input = new LargeMessageTestBase.TestLargeMessageInputStream(ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE, true);
input.setSize(10 * ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE);
LargeMessageTestBase.adjustLargeCompression(false, input, 10 * ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE);
char[] contents = input.toArray();
String msg = new String(contents);
String leadingPart = msg.substring(0, 100);
int count = 10;
for (int i = 0; i < count; i++) {
this.sendMessage(msg);
}
String frame = "CONNECT\n" + "login: brianm\n" + "passcode: wombats\n\n" + Stomp.NULL;
sendFrame(frame);
frame = receiveFrame(10000);
Assert.assertTrue(frame.startsWith("CONNECTED"));
frame = "SUBSCRIBE\n" + "destination:" + getQueuePrefix() + getQueueName() + "\n" + "ack:auto\n\nfff" + Stomp.NULL;
sendFrame(frame);
for (int i = 0; i < count; i++) {
frame = receiveFrame(60000);
Assert.assertNotNull(frame);
System.out.println("part of frame: " + frame.substring(0, 250));
Assert.assertTrue(frame.startsWith("MESSAGE"));
Assert.assertTrue(frame.indexOf("destination:") > 0);
int index = frame.indexOf(leadingPart);
assertEquals(msg.length(), (frame.length() - index));
}
// remove suscription
frame = "UNSUBSCRIBE\n" + "destination:" +
getQueuePrefix() +
getQueueName() +
"\n" +
"receipt:567\n" +
"\n\n" +
Stomp.NULL;
sendFrame(frame);
waitForReceipt();
frame = "DISCONNECT\n" + "\n\n" + Stomp.NULL;
sendFrame(frame);
} catch (Exception ex) {
ex.printStackTrace();
throw ex;
} finally {
cleanUp();
server.stop();
}
}
protected JMSServerManager createPersistentServerWithStompMinLargeSize(int sz) throws Exception {
Map<String, Object> params = new HashMap<>();
params.put(TransportConstants.PROTOCOLS_PROP_NAME, StompProtocolManagerFactory.STOMP_PROTOCOL_NAME);
params.put(TransportConstants.PORT_PROP_NAME, TransportConstants.DEFAULT_STOMP_PORT);
params.put(TransportConstants.STOMP_CONSUMERS_CREDIT, "-1");
params.put(TransportConstants.STOMP_MIN_LARGE_MESSAGE_SIZE, sz);
TransportConfiguration stompTransport = new TransportConfiguration(NettyAcceptorFactory.class.getName(), params);
Configuration config = createBasicConfig().setPersistenceEnabled(true).addAcceptorConfiguration(stompTransport).addAcceptorConfiguration(new TransportConfiguration(InVMAcceptorFactory.class.getName()));
ActiveMQServer activeMQServer = addServer(ActiveMQServers.newActiveMQServer(config, defUser, defPass));
JMSConfiguration jmsConfig = new JMSConfigurationImpl();
jmsConfig.getQueueConfigurations().add(new JMSQueueConfigurationImpl().setName(getQueueName()).setBindings(getQueueName()));
jmsConfig.getTopicConfigurations().add(new TopicConfigurationImpl().setName(getTopicName()).setBindings(getTopicName()));
server = new JMSServerManagerImpl(activeMQServer, jmsConfig);
server.setRegistry(new JndiBindingRegistry((new InVMNamingContext())));
return server;
}
private void enableMessageIDTest(Boolean enable) throws Exception {
try {
server = createServerWithExtraStompOptions(null, enable);
server.start();
setUpAfterServer();
String connect_frame = "CONNECT\n" + "login: brianm\n" + "passcode: wombats\n" + "request-id: 1\n" + "\n" + Stomp.NULL;
sendFrame(connect_frame);
String f = receiveFrame(10000);
Assert.assertTrue(f.startsWith("CONNECTED"));
Assert.assertTrue(f.indexOf("response-id:1") >= 0);
String frame = "SEND\n" + "destination:" + getQueuePrefix() + getQueueName() + "\n\n" + "Hello World 1" + Stomp.NULL;
sendFrame(frame);
frame = "SEND\n" + "destination:" + getQueuePrefix() + getQueueName() + "\n\n" + "Hello World 2" + Stomp.NULL;
sendFrame(frame);
QueueBrowser browser = session.createBrowser(queue);
Enumeration enu = browser.getEnumeration();
while (enu.hasMoreElements()) {
Message msg = (Message) enu.nextElement();
String msgId = msg.getStringProperty("amqMessageId");
if (enable != null && enable.booleanValue()) {
assertNotNull(msgId);
assertTrue(msgId.indexOf("STOMP") == 0);
} else {
assertNull(msgId);
}
}
browser.close();
MessageConsumer consumer = session.createConsumer(queue);
TextMessage message = (TextMessage) consumer.receive(1000);
Assert.assertNotNull(message);
message = (TextMessage) consumer.receive(1000);
Assert.assertNotNull(message);
message = (TextMessage) consumer.receive(2000);
Assert.assertNull(message);
} finally {
cleanUp();
server.stop();
}
}
protected JMSServerManager createServerWithTTL(String ttl) throws Exception {
return createServerWithExtraStompOptions(ttl, null);
}
protected JMSServerManager createServerWithExtraStompOptions(String ttl, Boolean enableMessageID) throws Exception {
Map<String, Object> params = new HashMap<>();
params.put(TransportConstants.PROTOCOLS_PROP_NAME, StompProtocolManagerFactory.STOMP_PROTOCOL_NAME);
params.put(TransportConstants.PORT_PROP_NAME, TransportConstants.DEFAULT_STOMP_PORT);
if (ttl != null) {
params.put(TransportConstants.CONNECTION_TTL, ttl);
}
if (enableMessageID != null) {
params.put(TransportConstants.STOMP_ENABLE_MESSAGE_ID, enableMessageID);
}
params.put(TransportConstants.STOMP_CONSUMERS_CREDIT, "-1");
TransportConfiguration stompTransport = new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params);
Configuration config = createBasicConfig().setPersistenceEnabled(false).addAcceptorConfiguration(stompTransport).addAcceptorConfiguration(new TransportConfiguration(INVM_ACCEPTOR_FACTORY));
ActiveMQServer activeMQServer = addServer(ActiveMQServers.newActiveMQServer(config, defUser, defPass));
JMSConfiguration jmsConfig = new JMSConfigurationImpl();
jmsConfig.getQueueConfigurations().add(new JMSQueueConfigurationImpl().setName(getQueueName()).setDurable(false).setBindings(getQueueName()));
jmsConfig.getTopicConfigurations().add(new TopicConfigurationImpl().setName(getTopicName()).setBindings(getTopicName()));
server = new JMSServerManagerImpl(activeMQServer, jmsConfig);
server.setRegistry(new JndiBindingRegistry(new InVMNamingContext()));
return server;
}
public static class MyCoreInterceptor implements Interceptor {
static List<Packet> incomingInterceptedFrames = new ArrayList<>();
@Override
public boolean intercept(Packet packet, RemotingConnection connection) {
incomingInterceptedFrames.add(packet);
return true;
}
}
public static class MyIncomingStompFrameInterceptor implements StompFrameInterceptor {
static List<StompFrame> incomingInterceptedFrames = new ArrayList<>();
@Override
public boolean intercept(StompFrame stompFrame, RemotingConnection connection) {
incomingInterceptedFrames.add(stompFrame);
stompFrame.addHeader("incomingInterceptedProp", "incomingInterceptedVal");
return true;
}
}
public static class MyOutgoingStompFrameInterceptor implements StompFrameInterceptor {
static List<StompFrame> outgoingInterceptedFrames = new ArrayList<>();
@Override
public boolean intercept(StompFrame stompFrame, RemotingConnection connection) {
outgoingInterceptedFrames.add(stompFrame);
stompFrame.addHeader("outgoingInterceptedProp", "outgoingInterceptedVal");
return true;
}
}
@Test
public void stompFrameInterceptor() throws Exception {
MyIncomingStompFrameInterceptor.incomingInterceptedFrames.clear();
MyOutgoingStompFrameInterceptor.outgoingInterceptedFrames.clear();
try {
List<String> incomingInterceptorList = new ArrayList<>();
incomingInterceptorList.add("org.apache.activemq.artemis.tests.integration.stomp.ExtraStompTest$MyIncomingStompFrameInterceptor");
incomingInterceptorList.add("org.apache.activemq.artemis.tests.integration.stomp.ExtraStompTest$MyCoreInterceptor");
List<String> outgoingInterceptorList = new ArrayList<>();
outgoingInterceptorList.add("org.apache.activemq.artemis.tests.integration.stomp.ExtraStompTest$MyOutgoingStompFrameInterceptor");
server = createServerWithStompInterceptor(incomingInterceptorList, outgoingInterceptorList);
server.start();
setUpAfterServer(); // This will make some calls through core
// So we clear them here
MyCoreInterceptor.incomingInterceptedFrames.clear();
String frame = "CONNECT\n" + "login: brianm\n" + "passcode: wombats\n\n" + Stomp.NULL;
sendFrame(frame);
frame = receiveFrame(100000);
frame = "SUBSCRIBE\n" + "destination:" + getQueuePrefix() + getQueueName() + "\n" + "ack:auto\n\nfff" + Stomp.NULL;
sendFrame(frame);
assertEquals(0, MyCoreInterceptor.incomingInterceptedFrames.size());
sendMessage(getName());
// Something was supposed to be called on sendMessages
assertTrue("core interceptor is not working", MyCoreInterceptor.incomingInterceptedFrames.size() > 0);
receiveFrame(10000);
frame = "SEND\n" + "destination:" +
getQueuePrefix() +
getQueueName() +
"\n\n" +
"Hello World" +
Stomp.NULL;
sendFrame(frame);
receiveFrame(10000);
frame = "DISCONNECT\n" + "\n\n" + Stomp.NULL;
sendFrame(frame);
} finally {
cleanUp();
server.stop();
}
List<String> incomingCommands = new ArrayList<>(4);
incomingCommands.add("CONNECT");
incomingCommands.add("SUBSCRIBE");
incomingCommands.add("SEND");
incomingCommands.add("DISCONNECT");
List<String> outgoingCommands = new ArrayList<>(3);
outgoingCommands.add("CONNECTED");
outgoingCommands.add("MESSAGE");
outgoingCommands.add("MESSAGE");
long timeout = System.currentTimeMillis() + 1000;
// Things are async, giving some time to things arrive before we actually assert
while (MyIncomingStompFrameInterceptor.incomingInterceptedFrames.size() < 4 &&
MyOutgoingStompFrameInterceptor.outgoingInterceptedFrames.size() < 3 &&
timeout > System.currentTimeMillis()) {
Thread.sleep(10);
}
Assert.assertEquals(4, MyIncomingStompFrameInterceptor.incomingInterceptedFrames.size());
Assert.assertEquals(3, MyOutgoingStompFrameInterceptor.outgoingInterceptedFrames.size());
for (int i = 0; i < MyIncomingStompFrameInterceptor.incomingInterceptedFrames.size(); i++) {
Assert.assertEquals(incomingCommands.get(i), MyIncomingStompFrameInterceptor.incomingInterceptedFrames.get(i).getCommand());
Assert.assertEquals("incomingInterceptedVal", MyIncomingStompFrameInterceptor.incomingInterceptedFrames.get(i).getHeader("incomingInterceptedProp"));
}
for (int i = 0; i < MyOutgoingStompFrameInterceptor.outgoingInterceptedFrames.size(); i++) {
Assert.assertEquals(outgoingCommands.get(i), MyOutgoingStompFrameInterceptor.outgoingInterceptedFrames.get(i).getCommand());
}
Assert.assertEquals("incomingInterceptedVal", MyOutgoingStompFrameInterceptor.outgoingInterceptedFrames.get(2).getHeader("incomingInterceptedProp"));
Assert.assertEquals("outgoingInterceptedVal", MyOutgoingStompFrameInterceptor.outgoingInterceptedFrames.get(2).getHeader("outgoingInterceptedProp"));
}
protected JMSServerManager createServerWithStompInterceptor(List<String> stompIncomingInterceptor,
List<String> stompOutgoingInterceptor) throws Exception {
Map<String, Object> params = new HashMap<>();
params.put(TransportConstants.PROTOCOLS_PROP_NAME, StompProtocolManagerFactory.STOMP_PROTOCOL_NAME);
params.put(TransportConstants.PORT_PROP_NAME, TransportConstants.DEFAULT_STOMP_PORT);
params.put(TransportConstants.STOMP_CONSUMERS_CREDIT, "-1");
TransportConfiguration stompTransport = new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params);
Configuration config = createBasicConfig().setPersistenceEnabled(false).addAcceptorConfiguration(stompTransport).addAcceptorConfiguration(new TransportConfiguration(INVM_ACCEPTOR_FACTORY)).setIncomingInterceptorClassNames(stompIncomingInterceptor).setOutgoingInterceptorClassNames(stompOutgoingInterceptor);
ActiveMQServer hornetQServer = addServer(ActiveMQServers.newActiveMQServer(config, defUser, defPass));
JMSConfiguration jmsConfig = new JMSConfigurationImpl();
jmsConfig.getQueueConfigurations().add(new JMSQueueConfigurationImpl().setName(getQueueName()).setDurable(false).setBindings(getQueueName()));
jmsConfig.getTopicConfigurations().add(new TopicConfigurationImpl().setName(getTopicName()).setBindings(getTopicName()));
server = new JMSServerManagerImpl(hornetQServer, jmsConfig);
server.setRegistry(new JndiBindingRegistry(new InVMNamingContext()));
return server;
}
}

View File

@ -19,32 +19,20 @@ package org.apache.activemq.artemis.tests.integration.stomp;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import org.apache.activemq.artemis.core.protocol.stomp.Stomp;
import org.apache.activemq.artemis.jms.server.JMSServerManager;
import org.apache.activemq.artemis.tests.integration.stomp.util.ClientStompFrame;
import org.junit.Test;
public class StompConnectionCleanupTest extends StompTestBase {
public class StompConnectionCleanupTest extends StompTest {
private static final long CONNECTION_TTL = 2000;
// ARTEMIS-231
@Test
public void testConnectionCleanupWithTopicSubscription() throws Exception {
String frame = "CONNECT\n" + "login: brianm\n" + "passcode: wombats\n\n" + Stomp.NULL;
sendFrame(frame);
frame = receiveFrame(10000);
conn.connect(defUser, defPass);
//We send and consumer a message to ensure a STOMP connection and server session is created
System.out.println("Received frame: " + frame);
assertTrue(frame.startsWith("CONNECTED"));
frame = "SUBSCRIBE\n" + "destination:" + getTopicPrefix() + getTopicName() + "\n" + "ack:auto\n\n" + Stomp.NULL;
sendFrame(frame);
frame = "DISCONNECT\n\n" + Stomp.NULL;
sendFrame(frame);
subscribeTopic(conn, null, "auto", null);
// Now we wait until the connection is cleared on the server, which will happen some time after ttl, since no data
// is being sent
@ -72,25 +60,16 @@ public class StompConnectionCleanupTest extends StompTestBase {
@Test
public void testConnectionCleanup() throws Exception {
String frame = "CONNECT\n" + "login: brianm\n" + "passcode: wombats\n\n" + Stomp.NULL;
sendFrame(frame);
frame = receiveFrame(10000);
conn.connect(defUser, defPass);
//We send and consumer a message to ensure a STOMP connection and server session is created
subscribe(conn, null, "auto", null);
System.out.println("Received frame: " + frame);
send(conn, getQueuePrefix() + getQueueName(), null, "Hello World");
assertTrue(frame.startsWith("CONNECTED"));
ClientStompFrame frame = conn.receiveFrame(10000);
frame = "SUBSCRIBE\n" + "destination:" + getQueuePrefix() + getQueueName() + "\n" + "ack:auto\n\n" + Stomp.NULL;
sendFrame(frame);
frame = "SEND\n" + "destination:" + getQueuePrefix() + getQueueName() + "\n\n" + "Hello World" + Stomp.NULL;
sendFrame(frame);
frame = receiveFrame(10000);
assertTrue(frame.startsWith("MESSAGE"));
assertTrue(frame.indexOf("destination:") > 0);
assertTrue(frame.getCommand().equals("MESSAGE"));
assertTrue(frame.getHeader("destination").equals(getQueuePrefix() + getQueueName()));
// Now we wait until the connection is cleared on the server, which will happen some time after ttl, since no data
// is being sent
@ -118,13 +97,7 @@ public class StompConnectionCleanupTest extends StompTestBase {
@Test
public void testConnectionNotCleanedUp() throws Exception {
String frame = "CONNECT\n" + "login: brianm\n" + "passcode: wombats\n\n" + Stomp.NULL;
sendFrame(frame);
frame = receiveFrame(10000);
//We send and consumer a message to ensure a STOMP connection and server session is created
assertTrue(frame.startsWith("CONNECTED"));
conn.connect(defUser, defPass);
MessageConsumer consumer = session.createConsumer(queue);
@ -136,8 +109,7 @@ public class StompConnectionCleanupTest extends StompTestBase {
while (true) {
//Send and receive a msg
frame = "SEND\n" + "destination:" + getQueuePrefix() + getQueueName() + "\n\n" + "Hello World" + Stomp.NULL;
sendFrame(frame);
send(conn, getQueuePrefix() + getQueueName(), null, "Hello World");
Message msg = consumer.receive(1000);
assertNotNull(msg);

View File

@ -1,78 +0,0 @@
/*
* 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.artemis.tests.integration.stomp;
import java.nio.charset.StandardCharsets;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.DefaultHttpContent;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequestEncoder;
import io.netty.handler.codec.http.HttpResponseDecoder;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class StompOverHttpTest extends StompTest {
@Override
protected void addChannelHandlers(int index, SocketChannel ch) {
ch.pipeline().addLast(new HttpRequestEncoder());
ch.pipeline().addLast(new HttpResponseDecoder());
ch.pipeline().addLast(new HttpHandler());
ch.pipeline().addLast("decoder", new StringDecoder(StandardCharsets.UTF_8));
ch.pipeline().addLast("encoder", new StringEncoder(StandardCharsets.UTF_8));
ch.pipeline().addLast(new StompClientHandler(index));
}
@Override
public String receiveFrame(long timeOut) throws Exception {
//we are request/response so may need to send an empty request so we get responses piggy backed
sendFrame(new byte[]{});
return super.receiveFrame(timeOut);
}
class HttpHandler extends ChannelDuplexHandler {
@Override
public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
if (msg instanceof DefaultHttpContent) {
DefaultHttpContent response = (DefaultHttpContent) msg;
ctx.fireChannelRead(response.content());
}
}
@Override
public void write(final ChannelHandlerContext ctx, final Object msg, ChannelPromise promise) throws Exception {
if (msg instanceof ByteBuf) {
ByteBuf buf = (ByteBuf) msg;
FullHttpRequest httpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "", buf);
httpRequest.headers().add(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(buf.readableBytes()));
ctx.write(httpRequest, promise);
} else {
ctx.write(msg, promise);
}
}
}
}

View File

@ -1,151 +0,0 @@
/*
* 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.artemis.tests.integration.stomp;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
import io.netty.handler.codec.string.StringDecoder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class StompOverWebsocketTest extends StompTest {
private ChannelPromise handshakeFuture;
private final boolean useBinaryFrames;
@Parameterized.Parameters(name = "useBinaryFrames={0}")
public static Collection<Object[]> data() {
List<Object[]> list = Arrays.asList(new Object[][]{{Boolean.TRUE}, {Boolean.FALSE}});
return list;
}
public StompOverWebsocketTest(Boolean useBinaryFrames) {
super();
this.useBinaryFrames = useBinaryFrames;
}
@Override
protected void addChannelHandlers(int index, SocketChannel ch) throws URISyntaxException {
ch.pipeline().addLast("http-codec", new HttpClientCodec());
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(8192));
ch.pipeline().addLast(new WebsocketHandler(WebSocketClientHandshakerFactory.newHandshaker(new URI("ws://localhost:8080/websocket"), WebSocketVersion.V13, null, false, null)));
ch.pipeline().addLast("decoder", new StringDecoder(StandardCharsets.UTF_8));
ch.pipeline().addLast(new StompClientHandler(index));
}
@Override
protected void handshake() throws InterruptedException {
handshakeFuture.sync();
}
class WebsocketHandler extends ChannelDuplexHandler {
private WebSocketClientHandshaker handshaker;
WebsocketHandler(WebSocketClientHandshaker webSocketClientHandshaker) {
this.handshaker = webSocketClientHandshaker;
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
handshakeFuture = ctx.newPromise();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
handshaker.handshake(ctx.channel());
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("WebSocket Client disconnected!");
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Channel ch = ctx.channel();
if (!handshaker.isHandshakeComplete()) {
handshaker.finishHandshake(ch, (FullHttpResponse) msg);
System.out.println("WebSocket Client connected!");
handshakeFuture.setSuccess();
return;
}
if (msg instanceof FullHttpResponse) {
FullHttpResponse response = (FullHttpResponse) msg;
throw new Exception("Unexpected FullHttpResponse (getStatus=" + response.getStatus() + ", content=" + response.content().toString(StandardCharsets.UTF_8) + ')');
}
WebSocketFrame frame = (WebSocketFrame) msg;
if (frame instanceof BinaryWebSocketFrame) {
BinaryWebSocketFrame dataFrame = (BinaryWebSocketFrame) frame;
super.channelRead(ctx, dataFrame.content());
} else if (frame instanceof PongWebSocketFrame) {
System.out.println("WebSocket Client received pong");
} else if (frame instanceof CloseWebSocketFrame) {
System.out.println("WebSocket Client received closing");
ch.close();
}
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
try {
if (msg instanceof String) {
ctx.write(createFrame((String) msg), promise);
} else {
super.write(ctx, msg, promise);
}
} catch (Exception e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}
protected WebSocketFrame createFrame(String msg) {
if (useBinaryFrames) {
return new BinaryWebSocketFrame(Unpooled.copiedBuffer(msg, StandardCharsets.UTF_8));
} else {
return new TextWebSocketFrame(msg);
}
}
}

View File

@ -26,34 +26,17 @@ import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import java.io.IOException;
import java.net.Socket;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.UUID;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.core.config.Configuration;
import org.apache.activemq.artemis.core.protocol.mqtt.MQTTProtocolManagerFactory;
import org.apache.activemq.artemis.core.protocol.stomp.Stomp;
import org.apache.activemq.artemis.core.protocol.stomp.StompProtocolManagerFactory;
import org.apache.activemq.artemis.core.registry.JndiBindingRegistry;
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory;
@ -63,6 +46,7 @@ import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
import org.apache.activemq.artemis.core.security.Role;
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.ActiveMQServers;
import org.apache.activemq.artemis.core.server.impl.AddressInfo;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.apache.activemq.artemis.jms.client.ActiveMQJMSConnectionFactory;
import org.apache.activemq.artemis.jms.server.JMSServerManager;
@ -73,13 +57,16 @@ import org.apache.activemq.artemis.jms.server.config.impl.TopicConfigurationImpl
import org.apache.activemq.artemis.jms.server.impl.JMSServerManagerImpl;
import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
import org.apache.activemq.artemis.tests.integration.IntegrationTestLogger;
import org.apache.activemq.artemis.tests.integration.stomp.util.ClientStompFrame;
import org.apache.activemq.artemis.tests.integration.stomp.util.StompClientConnection;
import org.apache.activemq.artemis.tests.unit.util.InVMNamingContext;
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
import org.junit.After;
import org.junit.Before;
public abstract class StompTestBase extends ActiveMQTestBase {
protected String hostname = "127.0.0.1";
protected final int port = 61613;
private ConnectionFactory connectionFactory;
@ -98,98 +85,56 @@ public abstract class StompTestBase extends ActiveMQTestBase {
protected String defPass = "wombats";
protected boolean autoCreateServer = true;
private List<Bootstrap> bootstraps = new ArrayList<>();
// private Channel channel;
private List<BlockingQueue<String>> priorityQueues = new ArrayList<>();
private List<EventLoopGroup> groups = new ArrayList<>();
private List<Channel> channels = new ArrayList<>();
// Implementation methods
// -------------------------------------------------------------------------
public boolean isCompressLargeMessages() {
return false;
}
public boolean isSecurityEnabled() {
return false;
}
public boolean isPersistenceEnabled() {
return false;
}
public boolean isEnableStompMessageId() {
return false;
}
public Integer getStompMinLargeMessageSize() {
return null;
}
public List<String> getIncomingInterceptors() {
return null;
}
public List<String> getOutgoingInterceptors() {
return null;
}
@Override
@Before
public void setUp() throws Exception {
super.setUp();
if (autoCreateServer) {
server = createServer();
addServer(server.getActiveMQServer());
server.start();
connectionFactory = createConnectionFactory();
createBootstrap();
if (isSecurityEnabled()) {
connection = connectionFactory.createConnection("brianm", "wombats");
} else {
connection = connectionFactory.createConnection();
}
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
queue = session.createQueue(getQueueName());
topic = session.createTopic(getTopicName());
connection.start();
}
}
private void createBootstrap() {
createBootstrap(0, port);
}
protected void createBootstrap(int port) {
createBootstrap(0, port);
}
protected void createBootstrap(final int index, int port) {
priorityQueues.add(index, new ArrayBlockingQueue<String>(1000));
groups.add(index, new NioEventLoopGroup());
bootstraps.add(index, new Bootstrap());
bootstraps.get(index).group(groups.get(index)).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true).handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
addChannelHandlers(index, ch);
}
});
// Start the client.
try {
channels.add(index, bootstraps.get(index).connect("localhost", port).sync().channel());
handshake();
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
protected void handshake() throws InterruptedException {
}
protected void addChannelHandlers(int index, SocketChannel ch) throws URISyntaxException {
ch.pipeline().addLast("decoder", new StringDecoder(StandardCharsets.UTF_8));
ch.pipeline().addLast("encoder", new StringEncoder(StandardCharsets.UTF_8));
ch.pipeline().addLast(new StompClientHandler(index));
}
protected void setUpAfterServer() throws Exception {
setUpAfterServer(false);
}
protected void setUpAfterServer(boolean jmsCompressLarge) throws Exception {
server = createServer();
server.start();
connectionFactory = createConnectionFactory();
ActiveMQConnectionFactory activeMQConnectionFactory = (ActiveMQConnectionFactory) connectionFactory;
activeMQConnectionFactory.setCompressLargeMessage(jmsCompressLarge);
createBootstrap();
((ActiveMQConnectionFactory)connectionFactory).setCompressLargeMessage(isCompressLargeMessages());
connection = connectionFactory.createConnection();
connection.start();
if (isSecurityEnabled()) {
connection = connectionFactory.createConnection("brianm", "wombats");
} else {
connection = connectionFactory.createConnection();
}
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
queue = session.createQueue(getQueueName());
topic = session.createTopic(getTopicName());
connection.start();
}
/**
@ -198,14 +143,30 @@ public abstract class StompTestBase extends ActiveMQTestBase {
*/
protected JMSServerManager createServer() throws Exception {
Map<String, Object> params = new HashMap<>();
params.put(TransportConstants.PROTOCOLS_PROP_NAME, StompProtocolManagerFactory.STOMP_PROTOCOL_NAME);
params.put(TransportConstants.PROTOCOLS_PROP_NAME, StompProtocolManagerFactory.STOMP_PROTOCOL_NAME + "," + MQTTProtocolManagerFactory.MQTT_PROTOCOL_NAME);
params.put(TransportConstants.PORT_PROP_NAME, TransportConstants.DEFAULT_STOMP_PORT);
params.put(TransportConstants.STOMP_CONSUMERS_CREDIT, "-1");
if (isEnableStompMessageId()) {
params.put(TransportConstants.STOMP_ENABLE_MESSAGE_ID, true);
}
if (getStompMinLargeMessageSize() != null) {
params.put(TransportConstants.STOMP_MIN_LARGE_MESSAGE_SIZE, 2048);
}
TransportConfiguration stompTransport = new TransportConfiguration(NettyAcceptorFactory.class.getName(), params);
TransportConfiguration allTransport = new TransportConfiguration(NettyAcceptorFactory.class.getName());
Configuration config = createBasicConfig().setSecurityEnabled(isSecurityEnabled()).setPersistenceEnabled(true).addAcceptorConfiguration(stompTransport).addAcceptorConfiguration(new TransportConfiguration(InVMAcceptorFactory.class.getName()));
config.addAcceptorConfiguration(allTransport);
Configuration config = createBasicConfig().setSecurityEnabled(isSecurityEnabled())
.setPersistenceEnabled(isPersistenceEnabled())
.addAcceptorConfiguration(stompTransport)
.addAcceptorConfiguration(new TransportConfiguration(InVMAcceptorFactory.class.getName()))
.setConnectionTtlCheckInterval(500);
if (getIncomingInterceptors() != null) {
config.setIncomingInterceptorClassNames(getIncomingInterceptors());
}
if (getOutgoingInterceptors() != null) {
config.setOutgoingInterceptorClassNames(getOutgoingInterceptors());
}
ActiveMQServer activeMQServer = addServer(ActiveMQServers.newActiveMQServer(config, defUser, defPass));
@ -222,62 +183,19 @@ public abstract class StompTestBase extends ActiveMQTestBase {
}
JMSConfiguration jmsConfig = new JMSConfigurationImpl();
jmsConfig.getQueueConfigurations().add(new JMSQueueConfigurationImpl().setName(getQueueName()).setDurable(false).setBindings(getQueueName()));
jmsConfig.getQueueConfigurations().add(new JMSQueueConfigurationImpl().setName(getQueueName()).setBindings(getQueueName()));
jmsConfig.getTopicConfigurations().add(new TopicConfigurationImpl().setName(getTopicName()).setBindings(getTopicName()));
server = new JMSServerManagerImpl(activeMQServer, jmsConfig);
server.setRegistry(new JndiBindingRegistry(new InVMNamingContext()));
return server;
}
@Override
@After
public void tearDown() throws Exception {
if (autoCreateServer) {
connection.close();
for (EventLoopGroup group : groups) {
if (group != null) {
for (Channel channel : channels) {
channel.close();
}
group.shutdownGracefully(0, 5000, TimeUnit.MILLISECONDS);
}
}
}
super.tearDown();
}
protected void cleanUp() throws Exception {
connection.close();
if (groups.get(0) != null) {
groups.get(0).shutdown();
}
}
protected void reconnect() throws Exception {
reconnect(0);
}
protected void reconnect(long sleep) throws Exception {
groups.get(0).shutdown();
if (sleep > 0) {
Thread.sleep(sleep);
}
createBootstrap();
}
protected ConnectionFactory createConnectionFactory() {
return new ActiveMQJMSConnectionFactory(false, new TransportConfiguration(InVMConnectorFactory.class.getName()));
}
protected Socket createSocket() throws IOException {
return new Socket("localhost", port);
}
protected String getQueueName() {
return "test";
return "testQueue";
}
protected String getQueuePrefix() {
@ -292,65 +210,28 @@ public abstract class StompTestBase extends ActiveMQTestBase {
return "";
}
protected void assertChannelClosed() throws InterruptedException {
assertChannelClosed(0);
public void sendJmsMessage(String msg) throws Exception {
sendJmsMessage(msg, queue);
}
protected void assertChannelClosed(int index) throws InterruptedException {
boolean closed = channels.get(index).closeFuture().await(5000);
assertTrue("channel not closed", closed);
}
public void sendFrame(String data) throws Exception {
IntegrationTestLogger.LOGGER.info("Sending: " + data);
sendFrame(0, data);
}
public void sendFrame(int index, String data) throws Exception {
channels.get(index).writeAndFlush(data);
}
public void sendFrame(byte[] data) throws Exception {
sendFrame(0, data);
}
public void sendFrame(int index, byte[] data) throws Exception {
ByteBuf buffer = Unpooled.buffer(data.length);
buffer.writeBytes(data);
channels.get(index).writeAndFlush(buffer);
}
public String receiveFrame(long timeOut) throws Exception {
return receiveFrame(0, timeOut);
}
public String receiveFrame(int index, long timeOut) throws Exception {
String msg = priorityQueues.get(index).poll(timeOut, TimeUnit.MILLISECONDS);
return msg;
}
public void sendMessage(String msg) throws Exception {
sendMessage(msg, queue);
}
public void sendMessage(String msg, Destination destination) throws Exception {
public void sendJmsMessage(String msg, Destination destination) throws Exception {
MessageProducer producer = session.createProducer(destination);
TextMessage message = session.createTextMessage(msg);
producer.send(message);
}
public void sendMessage(byte[] data, Destination destination) throws Exception {
sendMessage(data, "foo", "xyz", destination);
public void sendJmsMessage(byte[] data, Destination destination) throws Exception {
sendJmsMessage(data, "foo", "xyz", destination);
}
public void sendMessage(String msg, String propertyName, String propertyValue) throws Exception {
sendMessage(msg.getBytes(StandardCharsets.UTF_8), propertyName, propertyValue, queue);
public void sendJmsMessage(String msg, String propertyName, String propertyValue) throws Exception {
sendJmsMessage(msg.getBytes(StandardCharsets.UTF_8), propertyName, propertyValue, queue);
}
public void sendMessage(byte[] data,
String propertyName,
String propertyValue,
Destination destination) throws Exception {
public void sendJmsMessage(byte[] data,
String propertyName,
String propertyValue,
Destination destination) throws Exception {
MessageProducer producer = session.createProducer(destination);
BytesMessage message = session.createBytesMessage();
message.setStringProperty(propertyName, propertyValue);
@ -358,59 +239,294 @@ public abstract class StompTestBase extends ActiveMQTestBase {
producer.send(message);
}
protected void waitForReceipt() throws Exception {
String frame = receiveFrame(50000);
assertNotNull(frame);
assertTrue(frame.indexOf("RECEIPT") > -1);
public void abortTransaction(StompClientConnection conn, String txID) throws IOException, InterruptedException {
ClientStompFrame abortFrame = conn.createFrame(Stomp.Commands.ABORT)
.addHeader(Stomp.Headers.TRANSACTION, txID);
conn.sendFrame(abortFrame);
}
protected void waitForFrameToTakeEffect() throws InterruptedException {
// bit of a dirty hack :)
// another option would be to force some kind of receipt to be returned
// from the frame
Thread.sleep(500);
public void beginTransaction(StompClientConnection conn, String txID) throws IOException, InterruptedException {
ClientStompFrame beginFrame = conn.createFrame(Stomp.Commands.BEGIN)
.addHeader(Stomp.Headers.TRANSACTION, txID);
conn.sendFrame(beginFrame);
}
public boolean isSecurityEnabled() {
return false;
public void commitTransaction(StompClientConnection conn, String txID) throws IOException, InterruptedException {
commitTransaction(conn, txID, false);
}
class StompClientHandler extends SimpleChannelInboundHandler<String> {
int index = 0;
StompClientHandler(int index) {
this.index = index;
public void commitTransaction(StompClientConnection conn,
String txID,
boolean receipt) throws IOException, InterruptedException {
ClientStompFrame beginFrame = conn.createFrame(Stomp.Commands.COMMIT)
.addHeader(Stomp.Headers.TRANSACTION, txID);
String uuid = UUID.randomUUID().toString();
if (receipt) {
beginFrame.addHeader(Stomp.Headers.RECEIPT_REQUESTED, uuid);
}
StringBuffer currentMessage = new StringBuffer("");
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
currentMessage.append(msg);
String fullMessage = currentMessage.toString();
if (fullMessage.contains("\0\n")) {
int messageEnd = fullMessage.indexOf("\0\n");
String actualMessage = fullMessage.substring(0, messageEnd);
fullMessage = fullMessage.substring(messageEnd + 2);
currentMessage = new StringBuffer("");
BlockingQueue queue = priorityQueues.get(index);
if (queue == null) {
queue = new ArrayBlockingQueue(1000);
priorityQueues.add(index, queue);
}
queue.add(actualMessage);
if (fullMessage.length() > 0) {
channelRead(ctx, fullMessage);
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
ClientStompFrame resp = conn.sendFrame(beginFrame);
if (receipt) {
assertEquals(uuid, resp.getHeader(Stomp.Headers.Response.RECEIPT_ID));
}
}
public void ack(StompClientConnection conn,
String subscriptionId,
ClientStompFrame messageIdFrame) throws IOException, InterruptedException {
String messageID = messageIdFrame.getHeader(Stomp.Headers.Message.MESSAGE_ID);
ClientStompFrame frame = conn.createFrame(Stomp.Commands.ACK)
.addHeader(Stomp.Headers.Message.MESSAGE_ID, messageID);
if (subscriptionId != null) {
frame.addHeader(Stomp.Headers.Ack.SUBSCRIPTION, subscriptionId);
}
ClientStompFrame response = conn.sendFrame(frame);
if (response != null) {
throw new IOException("failed to ack " + response);
}
}
public void ack(StompClientConnection conn,
String subscriptionId,
String mid,
String txID) throws IOException, InterruptedException {
ClientStompFrame frame = conn.createFrame(Stomp.Commands.ACK)
.addHeader(Stomp.Headers.Ack.SUBSCRIPTION, subscriptionId)
.addHeader(Stomp.Headers.Message.MESSAGE_ID, mid);
if (txID != null) {
frame.addHeader(Stomp.Headers.TRANSACTION, txID);
}
conn.sendFrame(frame);
}
public void nack(StompClientConnection conn, String subscriptionId, String messageId) throws IOException, InterruptedException {
ClientStompFrame frame = conn.createFrame(Stomp.Commands.NACK)
.addHeader(Stomp.Headers.Ack.SUBSCRIPTION, subscriptionId)
.addHeader(Stomp.Headers.Message.MESSAGE_ID, messageId);
conn.sendFrame(frame);
}
public ClientStompFrame subscribe(StompClientConnection conn,
String subscriptionId) throws IOException, InterruptedException {
return subscribe(conn, subscriptionId, Stomp.Headers.Subscribe.AckModeValues.AUTO, null, null);
}
public ClientStompFrame subscribe(StompClientConnection conn,
String subscriptionId,
String ack) throws IOException, InterruptedException {
return subscribe(conn, subscriptionId, ack, null, null);
}
public ClientStompFrame subscribe(StompClientConnection conn,
String subscriptionId,
String ack,
String durableId) throws IOException, InterruptedException {
return subscribe(conn, subscriptionId, ack, durableId, null);
}
public ClientStompFrame subscribe(StompClientConnection conn,
String subscriptionId,
String ack,
String durableId,
boolean receipt) throws IOException, InterruptedException {
return subscribe(conn, subscriptionId, ack, durableId, null, receipt);
}
public ClientStompFrame subscribe(StompClientConnection conn,
String subscriptionId,
String ack,
String durableId,
String selector) throws IOException, InterruptedException {
return subscribe(conn, subscriptionId, ack, durableId, selector, false);
}
public ClientStompFrame subscribe(StompClientConnection conn,
String subscriptionId,
String ack,
String durableId,
String selector,
boolean receipt) throws IOException, InterruptedException {
return subscribe(conn, subscriptionId, ack, durableId, selector, getQueuePrefix() + getQueueName(), receipt);
}
public ClientStompFrame subscribe(StompClientConnection conn,
String subscriptionId,
String ack,
String durableId,
String selector,
String destination,
boolean receipt) throws IOException, InterruptedException {
ClientStompFrame frame = conn.createFrame(Stomp.Commands.SUBSCRIBE)
.addHeader(Stomp.Headers.Subscribe.SUBSCRIPTION_TYPE, AddressInfo.RoutingType.ANYCAST.toString())
.addHeader(Stomp.Headers.Subscribe.DESTINATION, destination);
if (subscriptionId != null) {
frame.addHeader(Stomp.Headers.Subscribe.ID, subscriptionId);
}
if (ack != null) {
frame.addHeader(Stomp.Headers.Subscribe.ACK_MODE, ack);
}
if (durableId != null) {
frame.addHeader(Stomp.Headers.Subscribe.DURABLE_SUBSCRIPTION_NAME, durableId);
}
if (selector != null) {
frame.addHeader(Stomp.Headers.Subscribe.SELECTOR, selector);
}
String uuid = UUID.randomUUID().toString();
if (receipt) {
frame.addHeader(Stomp.Headers.RECEIPT_REQUESTED, uuid);
}
frame = conn.sendFrame(frame);
if (receipt) {
assertEquals(uuid, frame.getHeader(Stomp.Headers.Response.RECEIPT_ID));
}
return frame;
}
public ClientStompFrame subscribeTopic(StompClientConnection conn,
String subscriptionId,
String ack,
String durableId) throws IOException, InterruptedException {
return subscribeTopic(conn, subscriptionId, ack, durableId, false);
}
public ClientStompFrame subscribeTopic(StompClientConnection conn,
String subscriptionId,
String ack,
String durableId,
boolean receipt) throws IOException, InterruptedException {
return subscribeTopic(conn, subscriptionId, ack, durableId, receipt, false);
}
public ClientStompFrame subscribeTopic(StompClientConnection conn,
String subscriptionId,
String ack,
String durableId,
boolean receipt,
boolean noLocal) throws IOException, InterruptedException {
ClientStompFrame frame = conn.createFrame(Stomp.Commands.SUBSCRIBE)
.addHeader(Stomp.Headers.Subscribe.SUBSCRIPTION_TYPE, AddressInfo.RoutingType.MULTICAST.toString())
.addHeader(Stomp.Headers.Subscribe.DESTINATION, getTopicPrefix() + getTopicName());
if (subscriptionId != null) {
frame.addHeader(Stomp.Headers.Subscribe.ID, subscriptionId);
}
if (ack != null) {
frame.addHeader(Stomp.Headers.Subscribe.ACK_MODE, ack);
}
if (durableId != null) {
frame.addHeader(Stomp.Headers.Subscribe.DURABLE_SUBSCRIPTION_NAME, durableId);
}
String uuid = UUID.randomUUID().toString();
if (receipt) {
frame.addHeader(Stomp.Headers.RECEIPT_REQUESTED, uuid);
}
if (noLocal) {
frame.addHeader(Stomp.Headers.Subscribe.NO_LOCAL, "true");
}
frame = conn.sendFrame(frame);
if (receipt) {
assertNotNull("Requested receipt, but response is null", frame);
assertTrue(frame.getHeader(Stomp.Headers.Response.RECEIPT_ID).equals(uuid));
}
return frame;
}
public ClientStompFrame unsubscribe(StompClientConnection conn, String subscriptionId) throws IOException, InterruptedException {
return unsubscribe(conn, subscriptionId, null, false, false);
}
public ClientStompFrame unsubscribe(StompClientConnection conn,
String subscriptionId,
boolean receipt) throws IOException, InterruptedException {
return unsubscribe(conn, subscriptionId, null, receipt, false);
}
public ClientStompFrame unsubscribe(StompClientConnection conn,
String subscriptionId,
String destination,
boolean receipt,
boolean durable) throws IOException, InterruptedException {
ClientStompFrame frame = conn.createFrame(Stomp.Commands.UNSUBSCRIBE);
if (durable && subscriptionId != null) {
frame.addHeader(Stomp.Headers.Unsubscribe.DURABLE_SUBSCRIPTION_NAME, subscriptionId);
} else if (!durable && subscriptionId != null) {
frame.addHeader(Stomp.Headers.Unsubscribe.ID, subscriptionId);
}
if (destination != null) {
frame.addHeader(Stomp.Headers.Unsubscribe.DESTINATION, destination);
}
String uuid = UUID.randomUUID().toString();
if (receipt) {
frame.addHeader(Stomp.Headers.RECEIPT_REQUESTED, uuid);
}
frame = conn.sendFrame(frame);
if (receipt) {
assertEquals(Stomp.Responses.RECEIPT, frame.getCommand());
assertEquals(uuid, frame.getHeader(Stomp.Headers.Response.RECEIPT_ID));
}
return frame;
}
public ClientStompFrame send(StompClientConnection conn, String destination, String contentType, String body) throws IOException, InterruptedException {
return send(conn, destination, contentType, body, false);
}
public ClientStompFrame send(StompClientConnection conn, String destination, String contentType, String body, boolean receipt) throws IOException, InterruptedException {
return send(conn, destination, contentType, body, receipt, null);
}
public ClientStompFrame send(StompClientConnection conn, String destination, String contentType, String body, boolean receipt, AddressInfo.RoutingType destinationType) throws IOException, InterruptedException {
return send(conn, destination, contentType, body, receipt, destinationType, null);
}
public ClientStompFrame send(StompClientConnection conn, String destination, String contentType, String body, boolean receipt, AddressInfo.RoutingType destinationType, String txId) throws IOException, InterruptedException {
ClientStompFrame frame = conn.createFrame(Stomp.Commands.SEND)
.addHeader(Stomp.Headers.Send.DESTINATION, destination)
.setBody(body);
if (contentType != null) {
frame.addHeader(Stomp.Headers.CONTENT_TYPE, contentType);
}
if (destinationType != null) {
frame.addHeader(Stomp.Headers.Send.DESTINATION_TYPE, destinationType.toString());
}
if (txId != null) {
frame.addHeader(Stomp.Headers.TRANSACTION, txId);
}
String uuid = UUID.randomUUID().toString();
if (receipt) {
frame.addHeader(Stomp.Headers.RECEIPT_REQUESTED, uuid);
}
frame = conn.sendFrame(frame);
if (receipt) {
assertEquals(Stomp.Responses.RECEIPT, frame.getCommand());
assertEquals(uuid, frame.getHeader(Stomp.Headers.Response.RECEIPT_ID));
}
IntegrationTestLogger.LOGGER.info("Received: " + frame);
return frame;
}
}

View File

@ -0,0 +1,159 @@
/**
* 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.artemis.tests.integration.stomp;
import java.util.ArrayList;
import java.util.List;
import org.apache.activemq.artemis.api.core.Interceptor;
import org.apache.activemq.artemis.core.protocol.core.Packet;
import org.apache.activemq.artemis.core.protocol.stomp.StompFrame;
import org.apache.activemq.artemis.core.protocol.stomp.StompFrameInterceptor;
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
import org.apache.activemq.artemis.tests.integration.IntegrationTestLogger;
import org.apache.activemq.artemis.tests.integration.stomp.util.ClientStompFrame;
import org.apache.activemq.artemis.tests.integration.stomp.util.StompClientConnection;
import org.apache.activemq.artemis.tests.integration.stomp.util.StompClientConnectionFactory;
import org.junit.Assert;
import org.junit.Test;
public class StompTestWithInterceptors extends StompTestBase {
@Override
public List<String> getIncomingInterceptors() {
List<String> stompIncomingInterceptor = new ArrayList<>();
stompIncomingInterceptor.add("org.apache.activemq.artemis.tests.integration.stomp.StompTestWithInterceptors$MyIncomingStompFrameInterceptor");
stompIncomingInterceptor.add("org.apache.activemq.artemis.tests.integration.stomp.StompTestWithInterceptors$MyCoreInterceptor");
return stompIncomingInterceptor;
}
@Override
public List<String> getOutgoingInterceptors() {
List<String> stompOutgoingInterceptor = new ArrayList<>();
stompOutgoingInterceptor.add("org.apache.activemq.artemis.tests.integration.stomp.StompTestWithInterceptors$MyOutgoingStompFrameInterceptor");
return stompOutgoingInterceptor;
}
@Test
public void stompFrameInterceptor() throws Exception {
MyIncomingStompFrameInterceptor.incomingInterceptedFrames.clear();
MyOutgoingStompFrameInterceptor.outgoingInterceptedFrames.clear();
Thread.sleep(200);
// So we clear them here
MyCoreInterceptor.incomingInterceptedFrames.clear();
StompClientConnection conn = StompClientConnectionFactory.createClientConnection("1.0", hostname, port);
conn.connect(defUser, defPass);
ClientStompFrame subFrame = conn.createFrame("SUBSCRIBE");
subFrame.addHeader("subscription-type", "ANYCAST");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
conn.sendFrame(subFrame);
assertEquals(0, MyCoreInterceptor.incomingInterceptedFrames.size());
sendJmsMessage(getName());
// Something was supposed to be called on sendMessages
assertTrue("core interceptor is not working", MyCoreInterceptor.incomingInterceptedFrames.size() > 0);
conn.receiveFrame(10000);
ClientStompFrame frame = conn.createFrame("SEND");
frame.addHeader("destination", getQueuePrefix() + getQueueName());
frame.setBody("Hello World");
conn.sendFrame(frame);
conn.disconnect();
List<String> incomingCommands = new ArrayList<>(4);
incomingCommands.add("CONNECT");
incomingCommands.add("SUBSCRIBE");
incomingCommands.add("SEND");
incomingCommands.add("DISCONNECT");
List<String> outgoingCommands = new ArrayList<>(3);
outgoingCommands.add("CONNECTED");
outgoingCommands.add("MESSAGE");
outgoingCommands.add("MESSAGE");
long timeout = System.currentTimeMillis() + 1000;
// Things are async, giving some time to things arrive before we actually assert
while (MyIncomingStompFrameInterceptor.incomingInterceptedFrames.size() < 4 &&
MyOutgoingStompFrameInterceptor.outgoingInterceptedFrames.size() < 3 &&
timeout > System.currentTimeMillis()) {
Thread.sleep(10);
}
Assert.assertEquals(4, MyIncomingStompFrameInterceptor.incomingInterceptedFrames.size());
Assert.assertEquals(3, MyOutgoingStompFrameInterceptor.outgoingInterceptedFrames.size());
for (int i = 0; i < MyIncomingStompFrameInterceptor.incomingInterceptedFrames.size(); i++) {
Assert.assertEquals(incomingCommands.get(i), MyIncomingStompFrameInterceptor.incomingInterceptedFrames.get(i).getCommand());
Assert.assertEquals("incomingInterceptedVal", MyIncomingStompFrameInterceptor.incomingInterceptedFrames.get(i).getHeader("incomingInterceptedProp"));
}
for (int i = 0; i < MyOutgoingStompFrameInterceptor.outgoingInterceptedFrames.size(); i++) {
Assert.assertEquals(outgoingCommands.get(i), MyOutgoingStompFrameInterceptor.outgoingInterceptedFrames.get(i).getCommand());
}
Assert.assertEquals("incomingInterceptedVal", MyOutgoingStompFrameInterceptor.outgoingInterceptedFrames.get(2).getHeader("incomingInterceptedProp"));
Assert.assertEquals("outgoingInterceptedVal", MyOutgoingStompFrameInterceptor.outgoingInterceptedFrames.get(2).getHeader("outgoingInterceptedProp"));
}
public static class MyCoreInterceptor implements Interceptor {
static List<Packet> incomingInterceptedFrames = new ArrayList<>();
@Override
public boolean intercept(Packet packet, RemotingConnection connection) {
IntegrationTestLogger.LOGGER.info("Core intercepted: " + packet);
incomingInterceptedFrames.add(packet);
return true;
}
}
public static class MyIncomingStompFrameInterceptor implements StompFrameInterceptor {
static List<StompFrame> incomingInterceptedFrames = new ArrayList<>();
@Override
public boolean intercept(StompFrame stompFrame, RemotingConnection connection) {
incomingInterceptedFrames.add(stompFrame);
stompFrame.addHeader("incomingInterceptedProp", "incomingInterceptedVal");
return true;
}
}
public static class MyOutgoingStompFrameInterceptor implements StompFrameInterceptor {
static List<StompFrame> outgoingInterceptedFrames = new ArrayList<>();
@Override
public boolean intercept(StompFrame stompFrame, RemotingConnection connection) {
outgoingInterceptedFrames.add(stompFrame);
stompFrame.addHeader("outgoingInterceptedProp", "outgoingInterceptedVal");
return true;
}
}
}

View File

@ -0,0 +1,416 @@
/*
* 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.artemis.tests.integration.stomp;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
import org.apache.activemq.artemis.tests.integration.IntegrationTestLogger;
import org.apache.activemq.artemis.tests.integration.largemessage.LargeMessageTestBase;
import org.apache.activemq.artemis.tests.integration.stomp.util.ClientStompFrame;
import org.apache.activemq.artemis.tests.integration.stomp.util.StompClientConnection;
import org.apache.activemq.artemis.tests.integration.stomp.util.StompClientConnectionFactory;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class StompTestWithLargeMessages extends StompTestBase {
@Override
@Before
public void setUp() throws Exception {
super.setUp();
}
@Override
public boolean isCompressLargeMessages() {
return true;
}
@Override
public boolean isPersistenceEnabled() {
return true;
}
@Override
public Integer getStompMinLargeMessageSize() {
return 2048;
}
//stomp sender -> large -> stomp receiver
@Test
public void testSendReceiveLargePersistentMessages() throws Exception {
StompClientConnection conn = StompClientConnectionFactory.createClientConnection("1.0", hostname, port);
conn.connect(defUser, defPass);
int count = 10;
int msgSize = 1024 * 1024;
char[] contents = new char[msgSize];
for (int i = 0; i < msgSize; i++) {
contents[i] = 'A';
}
String body = new String(contents);
for (int i = 0; i < count; i++) {
ClientStompFrame frame = conn.createFrame("SEND");
frame.addHeader("destination", getQueuePrefix() + getQueueName());
frame.addHeader("persistent", "true");
frame.setBody(body);
conn.sendFrame(frame);
}
ClientStompFrame subFrame = conn.createFrame("SUBSCRIBE");
subFrame.addHeader("subscription-type", "ANYCAST");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
conn.sendFrame(subFrame);
for (int i = 0; i < count; i++) {
ClientStompFrame frame = conn.receiveFrame(60000);
Assert.assertNotNull(frame);
System.out.println("part of frame: " + frame.getBody().substring(0, 200));
Assert.assertTrue(frame.getCommand().equals("MESSAGE"));
Assert.assertTrue(frame.getHeader("destination").equals(getQueuePrefix() + getQueueName()));
int index = frame.getBody().indexOf("AAAA");
assertEquals(msgSize, (frame.getBody().length() - index));
}
ClientStompFrame unsubFrame = conn.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("destination", getQueuePrefix() + getQueueName());
unsubFrame.addHeader("receipt", "567");
ClientStompFrame response = conn.sendFrame(unsubFrame);
assertNotNull(response);
assertNotNull(response.getCommand().equals("RECEIPT"));
conn.disconnect();
}
//core sender -> large -> stomp receiver
@Test
public void testReceiveLargePersistentMessagesFromCore() throws Exception {
StompClientConnection conn = StompClientConnectionFactory.createClientConnection("1.0", hostname, port);
conn.connect(defUser, defPass);
int msgSize = 3 * ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE;
char[] contents = new char[msgSize];
for (int i = 0; i < msgSize; i++) {
contents[i] = 'B';
}
String msg = new String(contents);
int count = 10;
for (int i = 0; i < count; i++) {
this.sendJmsMessage(msg);
}
ClientStompFrame subFrame = conn.createFrame("SUBSCRIBE");
subFrame.addHeader("subscription-type", "ANYCAST");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
conn.sendFrame(subFrame);
for (int i = 0; i < count; i++) {
ClientStompFrame frame = conn.receiveFrame(60000);
Assert.assertNotNull(frame);
System.out.println("part of frame: " + frame.getBody().substring(0, 200));
Assert.assertTrue(frame.getCommand().equals("MESSAGE"));
Assert.assertTrue(frame.getHeader("destination").equals(getQueuePrefix() + getQueueName()));
int index = frame.getBody().indexOf("BBB");
assertEquals(msgSize, (frame.getBody().length() - index));
}
ClientStompFrame unsubFrame = conn.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("destination", getQueuePrefix() + getQueueName());
unsubFrame.addHeader("receipt", "567");
ClientStompFrame response = conn.sendFrame(unsubFrame);
assertNotNull(response);
assertNotNull(response.getCommand().equals("RECEIPT"));
conn.disconnect();
}
//stomp v12 sender -> large -> stomp v12 receiver
@Test
public void testSendReceiveLargePersistentMessagesV12() throws Exception {
StompClientConnection connV12 = StompClientConnectionFactory.createClientConnection("1.2", "localhost", port);
connV12.connect(defUser, defPass);
int count = 10;
int szBody = 1024 * 1024;
char[] contents = new char[szBody];
for (int i = 0; i < szBody; i++) {
contents[i] = 'A';
}
String body = new String(contents);
ClientStompFrame frame = connV12.createFrame("SEND");
frame.addHeader("destination-type", "ANYCAST");
frame.addHeader("destination", getQueuePrefix() + getQueueName());
frame.addHeader("persistent", "true");
frame.setBody(body);
for (int i = 0; i < count; i++) {
connV12.sendFrame(frame);
}
ClientStompFrame subFrame = connV12.createFrame("SUBSCRIBE");
subFrame.addHeader("id", "a-sub");
subFrame.addHeader("subscription-type", "ANYCAST");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
connV12.sendFrame(subFrame);
for (int i = 0; i < count; i++) {
ClientStompFrame receiveFrame = connV12.receiveFrame(30000);
Assert.assertNotNull(receiveFrame);
System.out.println("part of frame: " + receiveFrame.getBody().substring(0, 20));
Assert.assertTrue(receiveFrame.getCommand().equals("MESSAGE"));
Assert.assertEquals(receiveFrame.getHeader("destination"), getQueuePrefix() + getQueueName());
assertEquals(szBody, receiveFrame.getBody().length());
}
// remove susbcription
ClientStompFrame unsubFrame = connV12.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("id", "a-sub");
connV12.sendFrame(unsubFrame);
connV12.disconnect();
}
//core sender -> large -> stomp v12 receiver
@Test
public void testReceiveLargePersistentMessagesFromCoreV12() throws Exception {
int msgSize = 3 * ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE;
char[] contents = new char[msgSize];
for (int i = 0; i < msgSize; i++) {
contents[i] = 'B';
}
String msg = new String(contents);
int count = 10;
for (int i = 0; i < count; i++) {
this.sendJmsMessage(msg);
}
StompClientConnection connV12 = StompClientConnectionFactory.createClientConnection("1.2", "localhost", port);
connV12.connect(defUser, defPass);
ClientStompFrame subFrame = connV12.createFrame("SUBSCRIBE");
subFrame.addHeader("id", "a-sub");
subFrame.addHeader("subscription-type", "ANYCAST");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
connV12.sendFrame(subFrame);
for (int i = 0; i < count; i++) {
ClientStompFrame receiveFrame = connV12.receiveFrame(30000);
Assert.assertNotNull(receiveFrame);
System.out.println("part of frame: " + receiveFrame.getBody().substring(0, 20));
Assert.assertTrue(receiveFrame.getCommand().equals("MESSAGE"));
Assert.assertEquals(receiveFrame.getHeader("destination"), getQueuePrefix() + getQueueName());
assertEquals(msgSize, receiveFrame.getBody().length());
}
// remove susbcription
ClientStompFrame unsubFrame = connV12.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("id", "a-sub");
connV12.sendFrame(unsubFrame);
connV12.disconnect();
}
//core sender -> large (compressed regular) -> stomp v10 receiver
@Test
public void testReceiveLargeCompressedToRegularPersistentMessagesFromCore() throws Exception {
StompClientConnection conn = StompClientConnectionFactory.createClientConnection("1.0", hostname, port);
conn.connect(defUser, defPass);
LargeMessageTestBase.TestLargeMessageInputStream input = new LargeMessageTestBase.TestLargeMessageInputStream(ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE, true);
LargeMessageTestBase.adjustLargeCompression(true, input, ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE);
char[] contents = input.toArray();
String msg = new String(contents);
String leadingPart = msg.substring(0, 100);
int count = 10;
for (int i = 0; i < count; i++) {
this.sendJmsMessage(msg);
}
ClientStompFrame subFrame = conn.createFrame("SUBSCRIBE");
subFrame.addHeader("subscription-type", "ANYCAST");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
conn.sendFrame(subFrame);
for (int i = 0; i < count; i++) {
ClientStompFrame receiveFrame = conn.receiveFrame(30000);
Assert.assertNotNull(receiveFrame);
System.out.println("part of frame: " + receiveFrame.getBody().substring(0, 250));
Assert.assertTrue(receiveFrame.getCommand().equals("MESSAGE"));
Assert.assertEquals(receiveFrame.getHeader("destination"), getQueuePrefix() + getQueueName());
int index = receiveFrame.getBody().indexOf(leadingPart);
assertEquals(msg.length(), (receiveFrame.getBody().length() - index));
}
// remove suscription
ClientStompFrame unsubFrame = conn.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("destination", getQueuePrefix() + getQueueName());
unsubFrame.addHeader("receipt", "567");
ClientStompFrame response = conn.sendFrame(unsubFrame);
assertNotNull(response);
assertNotNull(response.getCommand().equals("RECEIPT"));
conn.disconnect();
}
//core sender -> large (compressed regular) -> stomp v12 receiver
@Test
public void testReceiveLargeCompressedToRegularPersistentMessagesFromCoreV12() throws Exception {
LargeMessageTestBase.TestLargeMessageInputStream input = new LargeMessageTestBase.TestLargeMessageInputStream(ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE, true);
LargeMessageTestBase.adjustLargeCompression(true, input, ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE);
char[] contents = input.toArray();
String msg = new String(contents);
int count = 10;
for (int i = 0; i < count; i++) {
this.sendJmsMessage(msg);
}
StompClientConnection connV12 = StompClientConnectionFactory.createClientConnection("1.2", "localhost", port);
connV12.connect(defUser, defPass);
ClientStompFrame subFrame = connV12.createFrame("SUBSCRIBE");
subFrame.addHeader("id", "a-sub");
subFrame.addHeader("subscription-type", "ANYCAST");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
connV12.sendFrame(subFrame);
for (int i = 0; i < count; i++) {
ClientStompFrame receiveFrame = connV12.receiveFrame(30000);
Assert.assertNotNull(receiveFrame);
System.out.println("part of frame: " + receiveFrame.getBody().substring(0, 20));
Assert.assertTrue(receiveFrame.getCommand().equals("MESSAGE"));
Assert.assertEquals(receiveFrame.getHeader("destination"), getQueuePrefix() + getQueueName());
assertEquals(contents.length, receiveFrame.getBody().length());
}
// remove susbcription
ClientStompFrame unsubFrame = connV12.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("id", "a-sub");
connV12.sendFrame(unsubFrame);
connV12.disconnect();
}
//core sender -> large (compressed large) -> stomp v12 receiver
@Test
public void testReceiveLargeCompressedToLargePersistentMessagesFromCoreV12() throws Exception {
LargeMessageTestBase.TestLargeMessageInputStream input = new LargeMessageTestBase.TestLargeMessageInputStream(ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE, true);
input.setSize(10 * ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE);
LargeMessageTestBase.adjustLargeCompression(false, input, 10 * ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE);
char[] contents = input.toArray();
String msg = new String(contents);
int count = 10;
for (int i = 0; i < count; i++) {
this.sendJmsMessage(msg);
}
IntegrationTestLogger.LOGGER.info("Message count for " + getQueueName() + ": " + server.getActiveMQServer().locateQueue(SimpleString.toSimpleString(getQueueName())).getMessageCount());
StompClientConnection connV12 = StompClientConnectionFactory.createClientConnection("1.2", hostname, port);
connV12.connect(defUser, defPass);
ClientStompFrame subFrame = connV12.createFrame("SUBSCRIBE");
subFrame.addHeader("id", "a-sub");
subFrame.addHeader("subscription-type", "ANYCAST");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
connV12.sendFrame(subFrame);
for (int i = 0; i < count; i++) {
ClientStompFrame receiveFrame = connV12.receiveFrame(30000);
Assert.assertNotNull(receiveFrame);
System.out.println("part of frame: " + receiveFrame.getBody().substring(0, 20));
Assert.assertTrue(receiveFrame.getCommand().equals("MESSAGE"));
Assert.assertEquals(receiveFrame.getHeader("destination"), getQueuePrefix() + getQueueName());
assertEquals(contents.length, receiveFrame.getBody().length());
}
// remove susbcription
ClientStompFrame unsubFrame = connV12.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("id", "a-sub");
connV12.sendFrame(unsubFrame);
connV12.disconnect();
}
//core sender -> large (compressed large) -> stomp v10 receiver
@Test
public void testReceiveLargeCompressedToLargePersistentMessagesFromCore() throws Exception {
LargeMessageTestBase.TestLargeMessageInputStream input = new LargeMessageTestBase.TestLargeMessageInputStream(ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE, true);
input.setSize(10 * ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE);
LargeMessageTestBase.adjustLargeCompression(false, input, 10 * ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE);
char[] contents = input.toArray();
String msg = new String(contents);
String leadingPart = msg.substring(0, 100);
int count = 10;
for (int i = 0; i < count; i++) {
this.sendJmsMessage(msg);
}
StompClientConnection conn = StompClientConnectionFactory.createClientConnection("1.0", hostname, port);
conn.connect(defUser, defPass);
ClientStompFrame subFrame = conn.createFrame("SUBSCRIBE");
subFrame.addHeader("subscription-type", "ANYCAST");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
conn.sendFrame(subFrame);
for (int i = 0; i < count; i++) {
ClientStompFrame frame = conn.receiveFrame(60000);
Assert.assertNotNull(frame);
System.out.println("part of frame: " + frame.getBody().substring(0, 250));
Assert.assertTrue(frame.getCommand().equals("MESSAGE"));
Assert.assertTrue(frame.getHeader("destination").equals(getQueuePrefix() + getQueueName()));
int index = frame.getBody().toString().indexOf(leadingPart);
assertEquals(msg.length(), (frame.getBody().toString().length() - index));
}
ClientStompFrame unsubFrame = conn.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("destination", getQueuePrefix() + getQueueName());
unsubFrame.addHeader("receipt", "567");
conn.sendFrame(unsubFrame);
conn.disconnect();
}
}

View File

@ -0,0 +1,78 @@
/**
* 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.artemis.tests.integration.stomp;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.QueueBrowser;
import javax.jms.TextMessage;
import java.util.Enumeration;
import org.apache.activemq.artemis.tests.integration.stomp.util.ClientStompFrame;
import org.apache.activemq.artemis.tests.integration.stomp.util.StompClientConnection;
import org.apache.activemq.artemis.tests.integration.stomp.util.StompClientConnectionFactory;
import org.junit.Assert;
import org.junit.Test;
public class StompTestWithMessageID extends StompTestBase {
@Override
public boolean isEnableStompMessageId() {
return true;
}
@Test
public void testEnableMessageID() throws Exception {
StompClientConnection conn = StompClientConnectionFactory.createClientConnection("1.0", hostname, port);
conn.connect(defUser, defPass);
ClientStompFrame frame = conn.createFrame("SEND");
frame.addHeader("destination", getQueuePrefix() + getQueueName());
frame.setBody("Hello World 1");
conn.sendFrame(frame);
frame = conn.createFrame("SEND");
frame.addHeader("destination", getQueuePrefix() + getQueueName());
frame.setBody("Hello World 2");
conn.sendFrame(frame);
QueueBrowser browser = session.createBrowser(queue);
Enumeration enu = browser.getEnumeration();
while (enu.hasMoreElements()) {
Message msg = (Message) enu.nextElement();
String msgId = msg.getStringProperty("amqMessageId");
assertNotNull(msgId);
assertTrue(msgId.indexOf("STOMP") == 0);
}
browser.close();
MessageConsumer consumer = session.createConsumer(queue);
TextMessage message = (TextMessage) consumer.receive(1000);
Assert.assertNotNull(message);
message = (TextMessage) consumer.receive(1000);
Assert.assertNotNull(message);
message = (TextMessage) consumer.receive(2000);
Assert.assertNull(message);
}
}

View File

@ -19,27 +19,34 @@ package org.apache.activemq.artemis.tests.integration.stomp;
import javax.jms.MessageConsumer;
import javax.jms.TextMessage;
import org.apache.activemq.artemis.core.protocol.stomp.Stomp;
import org.apache.activemq.artemis.tests.integration.stomp.util.ClientStompFrame;
import org.apache.activemq.artemis.tests.integration.stomp.util.StompClientConnection;
import org.apache.activemq.artemis.tests.integration.stomp.util.StompClientConnectionFactory;
import org.junit.Assert;
import org.junit.Test;
public class StompTestWithSecurity extends StompTestBase {
@Override
public boolean isSecurityEnabled() {
return true;
}
@Test
public void testJMSXUserID() throws Exception {
server.getActiveMQServer().getConfiguration().setPopulateValidatedUser(true);
MessageConsumer consumer = session.createConsumer(queue);
String frame = "CONNECT\n" + "login: brianm\n" + "passcode: wombats\n\n" + Stomp.NULL;
sendFrame(frame);
StompClientConnection conn = StompClientConnectionFactory.createClientConnection("1.0", hostname, port);
conn.connect(defUser, defPass);
frame = receiveFrame(10000);
Assert.assertTrue(frame.startsWith("CONNECTED"));
ClientStompFrame frame = conn.createFrame("SEND");
frame.addHeader("destination", getQueuePrefix() + getQueueName());
frame.setBody("Hello World");
conn.sendFrame(frame);
frame = "SEND\n" + "destination:" + getQueuePrefix() + getQueueName() + "\n\n" + "Hello World" + Stomp.NULL;
sendFrame(frame);
conn.disconnect();
TextMessage message = (TextMessage) consumer.receive(1000);
Assert.assertNotNull(message);
@ -54,9 +61,4 @@ public class StompTestWithSecurity extends StompTestBase {
long tmsg = message.getJMSTimestamp();
Assert.assertTrue(Math.abs(tnow - tmsg) < 1000);
}
@Override
public boolean isSecurityEnabled() {
return true;
}
}

View File

@ -24,9 +24,9 @@ import java.util.Iterator;
import java.util.List;
import java.util.Set;
public abstract class AbstractClientStompFrame implements ClientStompFrame {
import org.apache.activemq.artemis.core.protocol.stomp.Stomp;
protected static final String HEADER_RECEIPT = "receipt";
public abstract class AbstractClientStompFrame implements ClientStompFrame {
protected static final Set<String> validCommands = new HashSet<>();
protected String command;
@ -36,19 +36,19 @@ public abstract class AbstractClientStompFrame implements ClientStompFrame {
protected String EOL = "\n";
static {
validCommands.add("CONNECT");
validCommands.add("CONNECTED");
validCommands.add("SEND");
validCommands.add("RECEIPT");
validCommands.add("SUBSCRIBE");
validCommands.add("UNSUBSCRIBE");
validCommands.add("MESSAGE");
validCommands.add("BEGIN");
validCommands.add("COMMIT");
validCommands.add("ABORT");
validCommands.add("ACK");
validCommands.add("DISCONNECT");
validCommands.add("ERROR");
validCommands.add(Stomp.Commands.CONNECT);
validCommands.add(Stomp.Responses.CONNECTED);
validCommands.add(Stomp.Commands.SEND);
validCommands.add(Stomp.Responses.RECEIPT);
validCommands.add(Stomp.Commands.SUBSCRIBE);
validCommands.add(Stomp.Commands.UNSUBSCRIBE);
validCommands.add(Stomp.Responses.MESSAGE);
validCommands.add(Stomp.Commands.BEGIN);
validCommands.add(Stomp.Commands.COMMIT);
validCommands.add(Stomp.Commands.ABORT);
validCommands.add(Stomp.Commands.ACK);
validCommands.add(Stomp.Commands.DISCONNECT);
validCommands.add(Stomp.Responses.ERROR);
}
public AbstractClientStompFrame(String command) {
@ -80,37 +80,15 @@ public abstract class AbstractClientStompFrame implements ClientStompFrame {
@Override
public ByteBuffer toByteBuffer() {
if (isPing()) {
ByteBuffer buffer = ByteBuffer.allocateDirect(1);
buffer.put((byte) 0x0A);
buffer.rewind();
return buffer;
}
StringBuffer sb = new StringBuffer();
sb.append(command + EOL);
int n = headers.size();
for (int i = 0; i < n; i++) {
sb.append(headers.get(i).key + ":" + headers.get(i).val + EOL);
}
sb.append(EOL);
if (body != null) {
sb.append(body);
}
sb.append((char) 0);
String data = sb.toString();
byte[] byteValue = data.getBytes(StandardCharsets.UTF_8);
ByteBuffer buffer = ByteBuffer.allocateDirect(byteValue.length);
buffer.put(byteValue);
buffer.rewind();
return buffer;
return toByteBufferInternal(null);
}
@Override
public ByteBuffer toByteBufferWithExtra(String str) {
return toByteBufferInternal(str);
}
public ByteBuffer toByteBufferInternal(String str) {
StringBuffer sb = new StringBuffer();
sb.append(command + EOL);
int n = headers.size();
@ -122,7 +100,9 @@ public abstract class AbstractClientStompFrame implements ClientStompFrame {
sb.append(body);
}
sb.append((char) 0);
sb.append(str);
if (str != null) {
sb.append(str);
}
String data = sb.toString();
@ -137,26 +117,29 @@ public abstract class AbstractClientStompFrame implements ClientStompFrame {
@Override
public boolean needsReply() {
if ("CONNECT".equals(command) || headerKeys.contains(HEADER_RECEIPT)) {
if (Stomp.Commands.CONNECT.equals(command) || headerKeys.contains(Stomp.Headers.RECEIPT_REQUESTED)) {
return true;
}
return false;
}
@Override
public void setCommand(String command) {
public ClientStompFrame setCommand(String command) {
this.command = command;
return this;
}
@Override
public void addHeader(String key, String val) {
public ClientStompFrame addHeader(String key, String val) {
headers.add(new Header(key, val));
headerKeys.add(key);
return this;
}
@Override
public void setBody(String body) {
public ClientStompFrame setBody(String body) {
this.body = body;
return this;
}
@Override

View File

@ -27,29 +27,12 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.apache.activemq.artemis.core.protocol.stomp.Stomp;
import org.apache.activemq.artemis.tests.integration.IntegrationTestLogger;
public abstract class AbstractStompClientConnection implements StompClientConnection {
public static final String STOMP_COMMAND = "STOMP";
public static final String ACCEPT_HEADER = "accept-version";
public static final String HOST_HEADER = "host";
public static final String VERSION_HEADER = "version";
public static final String RECEIPT_HEADER = "receipt";
protected static final String CONNECT_COMMAND = "CONNECT";
protected static final String CONNECTED_COMMAND = "CONNECTED";
protected static final String DISCONNECT_COMMAND = "DISCONNECT";
protected static final String LOGIN_HEADER = "login";
protected static final String PASSCODE_HEADER = "passcode";
//ext
protected static final String CLIENT_ID_HEADER = "client-id";
protected Pinger pinger;
protected String version;
protected String host;
protected int port;
@ -58,13 +41,10 @@ public abstract class AbstractStompClientConnection implements StompClientConnec
protected StompFrameFactory factory;
protected final SocketChannel socketChannel;
protected ByteBuffer readBuffer;
protected List<Byte> receiveList;
protected BlockingQueue<ClientStompFrame> frameQueue = new LinkedBlockingQueue<>();
protected boolean connected = false;
private int serverPingCounter;
protected int serverPingCounter;
public AbstractStompClientConnection(String version, String host, int port) throws IOException {
this.version = version;
@ -90,11 +70,15 @@ public abstract class AbstractStompClientConnection implements StompClientConnec
new ReaderThread().start();
}
@Override
public ClientStompFrame sendFrame(ClientStompFrame frame) throws IOException, InterruptedException {
private ClientStompFrame sendFrameInternal(ClientStompFrame frame, boolean wicked) throws IOException, InterruptedException {
ClientStompFrame response = null;
IntegrationTestLogger.LOGGER.info("Sending frame:\n" + frame);
ByteBuffer buffer = frame.toByteBuffer();
IntegrationTestLogger.LOGGER.info("Sending " + (wicked ? "*wicked* " : "") + "frame:\n" + frame);
ByteBuffer buffer;
if (wicked) {
buffer = frame.toByteBufferWithExtra("\n");
} else {
buffer = frame.toByteBuffer();
}
while (buffer.remaining() > 0) {
socketChannel.write(buffer);
}
@ -105,7 +89,7 @@ public abstract class AbstractStompClientConnection implements StompClientConnec
//filter out server ping
while (response != null) {
if (response.getCommand().equals("STOMP")) {
if (response.getCommand().equals(Stomp.Commands.STOMP)) {
response = receiveFrame();
} else {
break;
@ -113,32 +97,19 @@ public abstract class AbstractStompClientConnection implements StompClientConnec
}
}
IntegrationTestLogger.LOGGER.info("Received:\n" + response);
return response;
}
@Override
public ClientStompFrame sendFrame(ClientStompFrame frame) throws IOException, InterruptedException {
return sendFrameInternal(frame, false);
}
@Override
public ClientStompFrame sendWickedFrame(ClientStompFrame frame) throws IOException, InterruptedException {
ClientStompFrame response = null;
ByteBuffer buffer = frame.toByteBufferWithExtra("\n");
while (buffer.remaining() > 0) {
socketChannel.write(buffer);
}
//now response
if (frame.needsReply()) {
response = receiveFrame();
//filter out server ping
while (response != null) {
if (response.getCommand().equals("STOMP")) {
response = receiveFrame();
} else {
break;
}
}
}
return response;
return sendFrameInternal(frame, true);
}
@Override
@ -186,17 +157,12 @@ public abstract class AbstractStompClientConnection implements StompClientConnec
readBuffer.rewind();
}
@Override
public int getServerPingNumber() {
return serverPingCounter;
}
protected void incrementServerPing() {
serverPingCounter++;
}
private boolean validateFrame(ClientStompFrame f) {
String h = f.getHeader("content-length");
String h = f.getHeader(Stomp.Headers.CONTENT_LENGTH);
if (h != null) {
int len = Integer.valueOf(h);
if (f.getBody().getBytes(StandardCharsets.UTF_8).length < len) {
@ -271,34 +237,15 @@ public abstract class AbstractStompClientConnection implements StompClientConnec
return this.frameQueue.size();
}
@Override
public void startPinger(long interval) {
pinger = new Pinger(interval);
pinger.startPing();
}
@Override
public void stopPinger() {
if (pinger != null) {
pinger.stopPing();
try {
pinger.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
pinger = null;
}
}
private class Pinger extends Thread {
protected class Pinger extends Thread {
long pingInterval;
ClientStompFrame pingFrame;
volatile boolean stop = false;
private Pinger(long interval) {
Pinger(long interval) {
this.pingInterval = interval;
pingFrame = createFrame("STOMP");
pingFrame = createFrame(Stomp.Commands.STOMP);
pingFrame.setBody("\n");
pingFrame.setForceOneway();
pingFrame.setPing(true);
@ -329,5 +276,4 @@ public abstract class AbstractStompClientConnection implements StompClientConnec
}
}
}
}

View File

@ -27,11 +27,11 @@ public interface ClientStompFrame {
boolean needsReply();
void setCommand(String command);
ClientStompFrame setCommand(String command);
void addHeader(String string, String string2);
ClientStompFrame addHeader(String string, String string2);
void setBody(String string);
ClientStompFrame setBody(String string);
String getCommand();
@ -43,8 +43,8 @@ public interface ClientStompFrame {
boolean isPing();
void setForceOneway();
ClientStompFrame setForceOneway();
void setPing(boolean b);
ClientStompFrame setPing(boolean b);
}

View File

@ -29,19 +29,19 @@ public class ClientStompFrameV10 extends AbstractClientStompFrame {
super(command, validate);
}
@Override
public ClientStompFrame setForceOneway() {
throw new IllegalStateException("Doesn't apply with V1.0!");
}
@Override
public ClientStompFrame setPing(boolean b) {
throw new IllegalStateException("Doesn't apply with V1.0!");
}
@Override
public boolean isPing() {
return false;
}
@Override
public void setForceOneway() {
throw new IllegalStateException("Doesn't apply with V1.0!");
}
@Override
public void setPing(boolean b) {
throw new IllegalStateException("Doesn't apply with V1.0!");
}
}

View File

@ -16,14 +16,13 @@
*/
package org.apache.activemq.artemis.tests.integration.stomp.util;
/**
* pls use factory to create frames.
*/
public class ClientStompFrameV11 extends AbstractClientStompFrame {
import org.apache.activemq.artemis.core.protocol.stomp.Stomp;
public class ClientStompFrameV11 extends ClientStompFrameV10 {
static {
validCommands.add("NACK");
validCommands.add("STOMP");
validCommands.add(Stomp.Commands.NACK);
validCommands.add(Stomp.Commands.STOMP);
}
boolean forceOneway = false;
@ -38,8 +37,9 @@ public class ClientStompFrameV11 extends AbstractClientStompFrame {
}
@Override
public void setForceOneway() {
public ClientStompFrame setForceOneway() {
forceOneway = true;
return this;
}
@Override
@ -47,15 +47,17 @@ public class ClientStompFrameV11 extends AbstractClientStompFrame {
if (forceOneway)
return false;
if ("CONNECT".equals(command) || "STOMP".equals(command) || headerKeys.contains(HEADER_RECEIPT)) {
if (Stomp.Commands.STOMP.equals(command)) {
return true;
}
return false;
return super.needsReply();
}
@Override
public void setPing(boolean b) {
public ClientStompFrame setPing(boolean b) {
isPing = b;
return this;
}
@Override

View File

@ -16,17 +16,7 @@
*/
package org.apache.activemq.artemis.tests.integration.stomp.util;
/**
*/
public class ClientStompFrameV12 extends AbstractClientStompFrame {
static {
validCommands.add("NACK");
validCommands.add("STOMP");
}
boolean forceOneway = false;
boolean isPing = false;
public class ClientStompFrameV12 extends ClientStompFrameV11 {
public ClientStompFrameV12(String command) {
this(command, true, true);
@ -44,32 +34,6 @@ public class ClientStompFrameV12 extends AbstractClientStompFrame {
}
}
@Override
public void setForceOneway() {
forceOneway = true;
}
@Override
public boolean needsReply() {
if (forceOneway)
return false;
if ("CONNECT".equals(command) || "STOMP".equals(command) || headerKeys.contains(HEADER_RECEIPT)) {
return true;
}
return false;
}
@Override
public void setPing(boolean b) {
isPing = b;
}
@Override
public boolean isPing() {
return isPing;
}
@Override
public String toString() {
return "[1.2]" + super.toString();

View File

@ -18,9 +18,6 @@ package org.apache.activemq.artemis.tests.integration.stomp.util;
import java.io.IOException;
/**
* pls use factory to create frames.
*/
public interface StompClientConnection {
ClientStompFrame sendFrame(ClientStompFrame frame) throws IOException, InterruptedException;
@ -35,7 +32,7 @@ public interface StompClientConnection {
ClientStompFrame connect(String defUser, String defPass) throws Exception;
void connect(String defUser, String defPass, String clientId) throws Exception;
ClientStompFrame connect(String defUser, String defPass, String clientId) throws Exception;
boolean isConnected();

View File

@ -18,52 +18,47 @@ package org.apache.activemq.artemis.tests.integration.stomp.util;
import java.io.IOException;
/**
* pls use factory to create frames.
*/
import org.apache.activemq.artemis.core.protocol.stomp.Stomp;
import org.apache.activemq.artemis.tests.integration.IntegrationTestLogger;
public class StompClientConnectionV10 extends AbstractStompClientConnection {
public StompClientConnectionV10(String host, int port) throws IOException {
super("1.0", host, port);
}
public StompClientConnectionV10(String version, String host, int port) throws IOException {
super(version, host, port);
}
@Override
public ClientStompFrame connect(String username, String passcode) throws IOException, InterruptedException {
ClientStompFrame frame = factory.newFrame(CONNECT_COMMAND);
frame.addHeader(LOGIN_HEADER, username);
frame.addHeader(PASSCODE_HEADER, passcode);
return connect(username, passcode, null);
}
@Override
public ClientStompFrame connect(String username, String passcode, String clientID) throws IOException, InterruptedException {
ClientStompFrame frame = factory.newFrame(Stomp.Commands.CONNECT);
frame.addHeader(Stomp.Headers.Connect.LOGIN, username);
frame.addHeader(Stomp.Headers.Connect.PASSCODE, passcode);
if (clientID != null) {
frame.addHeader(Stomp.Headers.Connect.CLIENT_ID, clientID);
}
ClientStompFrame response = this.sendFrame(frame);
if (response.getCommand().equals(CONNECTED_COMMAND)) {
if (response.getCommand().equals(Stomp.Responses.CONNECTED)) {
connected = true;
} else {
System.out.println("Connection failed with: " + response);
IntegrationTestLogger.LOGGER.warn("Connection failed with: " + response);
connected = false;
}
return response;
}
@Override
public void connect(String username, String passcode, String clientID) throws IOException, InterruptedException {
ClientStompFrame frame = factory.newFrame(CONNECT_COMMAND);
frame.addHeader(LOGIN_HEADER, username);
frame.addHeader(PASSCODE_HEADER, passcode);
frame.addHeader(CLIENT_ID_HEADER, clientID);
ClientStompFrame response = this.sendFrame(frame);
if (response.getCommand().equals(CONNECTED_COMMAND)) {
connected = true;
} else {
System.out.println("Connection failed with: " + response);
connected = false;
}
}
@Override
public void disconnect() throws IOException, InterruptedException {
ClientStompFrame frame = factory.newFrame(DISCONNECT_COMMAND);
ClientStompFrame frame = factory.newFrame(Stomp.Commands.DISCONNECT);
this.sendFrame(frame);
close();

View File

@ -17,28 +17,40 @@
package org.apache.activemq.artemis.tests.integration.stomp.util;
import java.io.IOException;
import java.util.UUID;
public class StompClientConnectionV11 extends AbstractStompClientConnection {
import org.apache.activemq.artemis.core.protocol.stomp.Stomp;
public class StompClientConnectionV11 extends StompClientConnectionV10 {
public StompClientConnectionV11(String host, int port) throws IOException {
super("1.1", host, port);
}
public StompClientConnectionV11(String version, String host, int port) throws IOException {
super(version, host, port);
}
@Override
public ClientStompFrame connect(String username, String passcode) throws IOException, InterruptedException {
ClientStompFrame frame = factory.newFrame(CONNECT_COMMAND);
frame.addHeader(ACCEPT_HEADER, "1.1");
frame.addHeader(HOST_HEADER, "localhost");
public ClientStompFrame connect(String username, String passcode, String clientID) throws IOException, InterruptedException {
ClientStompFrame frame = factory.newFrame(Stomp.Commands.CONNECT);
frame.addHeader(Stomp.Headers.Connect.ACCEPT_VERSION, getVersion());
frame.addHeader(Stomp.Headers.Connect.HOST, "localhost");
if (clientID != null) {
frame.addHeader(Stomp.Headers.Connect.CLIENT_ID, clientID);
}
if (username != null) {
frame.addHeader(LOGIN_HEADER, username);
frame.addHeader(PASSCODE_HEADER, passcode);
frame.addHeader(Stomp.Headers.Connect.LOGIN, username);
frame.addHeader(Stomp.Headers.Connect.PASSCODE, passcode);
}
ClientStompFrame response = this.sendFrame(frame);
if (response.getCommand().equals(CONNECTED_COMMAND)) {
String version = response.getHeader(VERSION_HEADER);
assert (version.equals("1.1"));
if (Stomp.Responses.CONNECTED.equals(response.getCommand())) {
String version = response.getHeader(Stomp.Headers.Connected.VERSION);
if (!version.equals(getVersion()))
throw new IllegalStateException("incorrect version!");
this.username = username;
this.passcode = passcode;
@ -49,46 +61,21 @@ public class StompClientConnectionV11 extends AbstractStompClientConnection {
return response;
}
@Override
public void connect(String username, String passcode, String clientID) throws IOException, InterruptedException {
ClientStompFrame frame = factory.newFrame(CONNECT_COMMAND);
frame.addHeader(ACCEPT_HEADER, "1.1");
frame.addHeader(HOST_HEADER, "localhost");
frame.addHeader(CLIENT_ID_HEADER, clientID);
if (username != null) {
frame.addHeader(LOGIN_HEADER, username);
frame.addHeader(PASSCODE_HEADER, passcode);
}
ClientStompFrame response = this.sendFrame(frame);
if (response.getCommand().equals(CONNECTED_COMMAND)) {
String version = response.getHeader(VERSION_HEADER);
assert (version.equals("1.1"));
this.username = username;
this.passcode = passcode;
this.connected = true;
} else {
connected = false;
}
}
public void connect1(String username, String passcode) throws IOException, InterruptedException {
ClientStompFrame frame = factory.newFrame(STOMP_COMMAND);
frame.addHeader(ACCEPT_HEADER, "1.0,1.1");
frame.addHeader(HOST_HEADER, "127.0.0.1");
ClientStompFrame frame = factory.newFrame(Stomp.Commands.STOMP);
frame.addHeader(Stomp.Headers.Connect.ACCEPT_VERSION, "1.0,1.1");
frame.addHeader(Stomp.Headers.Connect.HOST, "127.0.0.1");
if (username != null) {
frame.addHeader(LOGIN_HEADER, username);
frame.addHeader(PASSCODE_HEADER, passcode);
frame.addHeader(Stomp.Headers.Connect.LOGIN, username);
frame.addHeader(Stomp.Headers.Connect.PASSCODE, passcode);
}
ClientStompFrame response = this.sendFrame(frame);
if (response.getCommand().equals(CONNECTED_COMMAND)) {
String version = response.getHeader(VERSION_HEADER);
assert (version.equals("1.1"));
if (Stomp.Responses.CONNECTED.equals(response.getCommand())) {
String version = response.getHeader(Stomp.Headers.Connected.VERSION);
if (!version.equals(getVersion()))
throw new IllegalStateException("incorrect version!");
this.username = username;
this.passcode = passcode;
@ -103,12 +90,15 @@ public class StompClientConnectionV11 extends AbstractStompClientConnection {
public void disconnect() throws IOException, InterruptedException {
stopPinger();
ClientStompFrame frame = factory.newFrame(DISCONNECT_COMMAND);
frame.addHeader("receipt", "1");
ClientStompFrame frame = factory.newFrame(Stomp.Commands.DISCONNECT);
String uuid = UUID.randomUUID().toString();
frame.addHeader(Stomp.Headers.RECEIPT_REQUESTED, uuid);
ClientStompFrame result = this.sendFrame(frame);
if (result == null || (!"RECEIPT".equals(result.getCommand())) || (!"1".equals(result.getHeader("receipt-id")))) {
if (result == null || (!Stomp.Responses.RECEIPT.equals(result.getCommand())) || (!uuid.equals(result.getHeader(Stomp.Headers.Response.RECEIPT_ID)))) {
throw new IOException("Disconnect failed! " + result);
}
@ -122,4 +112,28 @@ public class StompClientConnectionV11 extends AbstractStompClientConnection {
return factory.newFrame(command);
}
@Override
public void startPinger(long interval) {
pinger = new Pinger(interval);
pinger.startPing();
}
@Override
public void stopPinger() {
if (pinger != null) {
pinger.stopPing();
try {
pinger.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
pinger = null;
}
}
@Override
public int getServerPingNumber() {
return serverPingCounter;
}
}

View File

@ -18,90 +18,13 @@ package org.apache.activemq.artemis.tests.integration.stomp.util;
import java.io.IOException;
public class StompClientConnectionV12 extends AbstractStompClientConnection {
public class StompClientConnectionV12 extends StompClientConnectionV11 {
public StompClientConnectionV12(String host, int port) throws IOException {
super("1.2", host, port);
}
@Override
public ClientStompFrame createFrame(String command) {
return factory.newFrame(command);
}
@Override
public ClientStompFrame connect(String username, String passcode) throws IOException, InterruptedException {
ClientStompFrame frame = factory.newFrame(CONNECT_COMMAND);
frame.addHeader(ACCEPT_HEADER, "1.2");
frame.addHeader(HOST_HEADER, "localhost");
if (username != null) {
frame.addHeader(LOGIN_HEADER, username);
frame.addHeader(PASSCODE_HEADER, passcode);
}
ClientStompFrame response = this.sendFrame(frame);
if (response.getCommand().equals(CONNECTED_COMMAND)) {
String version = response.getHeader(VERSION_HEADER);
if (!version.equals("1.2"))
throw new IllegalStateException("incorrect version!");
this.username = username;
this.passcode = passcode;
this.connected = true;
} else {
connected = false;
}
return response;
}
@Override
public void disconnect() throws IOException, InterruptedException {
stopPinger();
ClientStompFrame frame = factory.newFrame(DISCONNECT_COMMAND);
frame.addHeader("receipt", "1");
ClientStompFrame result = this.sendFrame(frame);
if (result == null || (!"RECEIPT".equals(result.getCommand())) || (!"1".equals(result.getHeader("receipt-id")))) {
throw new IOException("Disconnect failed! " + result);
}
close();
connected = false;
}
@Override
public void connect(String username, String passcode, String clientID) throws Exception {
ClientStompFrame frame = factory.newFrame(CONNECT_COMMAND);
frame.addHeader(ACCEPT_HEADER, "1.2");
frame.addHeader(HOST_HEADER, "localhost");
frame.addHeader(CLIENT_ID_HEADER, clientID);
if (username != null) {
frame.addHeader(LOGIN_HEADER, username);
frame.addHeader(PASSCODE_HEADER, passcode);
}
ClientStompFrame response = this.sendFrame(frame);
if (response.getCommand().equals(CONNECTED_COMMAND)) {
String version = response.getHeader(VERSION_HEADER);
if (!version.equals("1.2"))
throw new IllegalStateException("incorrect version!");
this.username = username;
this.passcode = passcode;
this.connected = true;
} else {
connected = false;
}
}
public ClientStompFrame createAnyFrame(String command) {
return factory.newAnyFrame(command);
}
}

View File

@ -24,4 +24,6 @@ public interface StompFrameFactory {
ClientStompFrame newAnyFrame(String command);
String[] handleHeaders(String header);
}

View File

@ -38,18 +38,18 @@ import java.util.StringTokenizer;
public class StompFrameFactoryV10 implements StompFrameFactory {
@Override
public ClientStompFrame createFrame(String data) {
public ClientStompFrame createFrame(final String data) {
//split the string at "\n\n"
String[] dataFields = data.split("\n\n");
StringTokenizer tokenizer = new StringTokenizer(dataFields[0], "\n");
String command = tokenizer.nextToken();
ClientStompFrame frame = new ClientStompFrameV10(command);
ClientStompFrame frame = newFrame(command);
while (tokenizer.hasMoreTokens()) {
String header = tokenizer.nextToken();
String[] fields = header.split(":");
String[] fields = handleHeaders(header);
frame.addHeader(fields[0], fields[1]);
}
@ -60,6 +60,11 @@ public class StompFrameFactoryV10 implements StompFrameFactory {
return frame;
}
@Override
public String[] handleHeaders(String header) {
return header.split(":");
}
@Override
public ClientStompFrame newFrame(String command) {
return new ClientStompFrameV10(command);

View File

@ -16,8 +16,6 @@
*/
package org.apache.activemq.artemis.tests.integration.stomp.util;
import java.util.StringTokenizer;
/**
* 1.1 frames
* <br>
@ -36,32 +34,10 @@ import java.util.StringTokenizer;
* 13. RECEIPT
* 14. ERROR
*/
public class StompFrameFactoryV11 implements StompFrameFactory {
public class StompFrameFactoryV11 extends StompFrameFactoryV10 {
@Override
public ClientStompFrame createFrame(final String data) {
//split the string at "\n\n"
String[] dataFields = data.split("\n\n");
StringTokenizer tokenizer = new StringTokenizer(dataFields[0], "\n");
String command = tokenizer.nextToken();
ClientStompFrame frame = new ClientStompFrameV11(command);
while (tokenizer.hasMoreTokens()) {
String header = tokenizer.nextToken();
String[] fields = splitAndDecodeHeader(header);
frame.addHeader(fields[0], fields[1]);
}
//body (without null byte)
if (dataFields.length == 2) {
frame.setBody(dataFields[1]);
}
return frame;
}
private String[] splitAndDecodeHeader(String header) {
public String[] handleHeaders(String header) {
// split the header into the key and value at the ":" since there shouldn't be any unescaped colons in the header
// except for the one separating the key and value
String[] result = header.split(":");

View File

@ -16,44 +16,10 @@
*/
package org.apache.activemq.artemis.tests.integration.stomp.util;
import java.util.StringTokenizer;
public class StompFrameFactoryV12 implements StompFrameFactory {
public class StompFrameFactoryV12 extends StompFrameFactoryV11 {
@Override
public ClientStompFrame createFrame(String data) {
//split the string at "\n\n"
String[] dataFields = data.split("\n\n");
StringTokenizer tokenizer = new StringTokenizer(dataFields[0], "\n");
String command = tokenizer.nextToken();
ClientStompFrame frame = new ClientStompFrameV12(command);
while (tokenizer.hasMoreTokens()) {
String header = tokenizer.nextToken();
String[] fields = splitAndDecodeHeader(header);
frame.addHeader(fields[0], fields[1]);
}
//body (without null byte)
if (dataFields.length == 2) {
frame.setBody(dataFields[1]);
}
return frame;
}
public void printByteHeader(String headers) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < headers.length(); i++) {
char c = headers.charAt(i);
buffer.append((byte) c + " ");
}
System.out.println("header in byte : " + buffer.toString());
}
private String[] splitAndDecodeHeader(String header) {
public String[] handleHeaders(String header) {
// split the header into the key and value at the ":" since there shouldn't be any unescaped colons in the header
// except for the one separating the key and value
String[] result = header.split(":");

View File

@ -18,6 +18,8 @@ package org.apache.activemq.artemis.tests.integration.stomp.v11;
import java.nio.charset.StandardCharsets;
import org.apache.activemq.artemis.core.protocol.stomp.Stomp;
import org.apache.activemq.artemis.tests.integration.stomp.StompTestBase;
import org.apache.activemq.artemis.tests.integration.stomp.util.ClientStompFrame;
import org.apache.activemq.artemis.tests.integration.stomp.util.StompClientConnection;
import org.apache.activemq.artemis.tests.integration.stomp.util.StompClientConnectionFactory;
@ -28,15 +30,19 @@ import org.junit.Test;
/*
* Some Stomp tests against server with persistence enabled are put here.
*/
public class ExtraStompTest extends StompV11TestBase {
public class ExtraStompTest extends StompTestBase {
private StompClientConnection connV10;
private StompClientConnection connV11;
@Override
public boolean isPersistenceEnabled() {
return true;
}
@Override
@Before
public void setUp() throws Exception {
persistenceEnabled = true;
super.setUp();
connV10 = StompClientConnectionFactory.createClientConnection("1.0", hostname, port);
connV10.connect(defUser, defPass);
@ -57,331 +63,142 @@ public class ExtraStompTest extends StompV11TestBase {
@Test
public void testSendAndReceive10() throws Exception {
String msg1 = "Hello World 1!";
String msg2 = "Hello World 2!";
ClientStompFrame frame = connV10.createFrame("SEND");
frame.addHeader("destination", getQueuePrefix() + getQueueName());
frame.addHeader("content-length", String.valueOf(msg1.getBytes(StandardCharsets.UTF_8).length));
frame.addHeader("persistent", "true");
frame.setBody(msg1);
connV10.sendFrame(frame);
ClientStompFrame frame2 = connV10.createFrame("SEND");
frame2.addHeader("destination", getQueuePrefix() + getQueueName());
frame2.addHeader("content-length", String.valueOf(msg2.getBytes(StandardCharsets.UTF_8).length));
frame2.addHeader("persistent", "true");
frame2.setBody(msg2);
connV10.sendFrame(frame2);
ClientStompFrame subFrame = connV10.createFrame("SUBSCRIBE");
subFrame.addHeader("id", "a-sub");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
connV10.sendFrame(subFrame);
frame = connV10.receiveFrame();
System.out.println("received " + frame);
assertEquals("MESSAGE", frame.getCommand());
assertEquals("a-sub", frame.getHeader("subscription"));
assertNotNull(frame.getHeader("message-id"));
assertEquals(getQueuePrefix() + getQueueName(), frame.getHeader("destination"));
assertEquals(msg1, frame.getBody());
frame = connV10.receiveFrame();
System.out.println("received " + frame);
assertEquals("MESSAGE", frame.getCommand());
assertEquals("a-sub", frame.getHeader("subscription"));
assertNotNull(frame.getHeader("message-id"));
assertEquals(getQueuePrefix() + getQueueName(), frame.getHeader("destination"));
assertEquals(msg2, frame.getBody());
//unsub
ClientStompFrame unsubFrame = connV10.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("id", "a-sub");
connV10.sendFrame(unsubFrame);
testSendAndReceive(connV10);
}
@Test
public void testSendAndReceive11() throws Exception {
testSendAndReceive(connV11);
}
public void testSendAndReceive(StompClientConnection conn) throws Exception {
String msg1 = "Hello World 1!";
String msg2 = "Hello World 2!";
ClientStompFrame frame = connV11.createFrame("SEND");
frame.addHeader("destination", getQueuePrefix() + getQueueName());
frame.addHeader("content-length", String.valueOf(msg1.getBytes(StandardCharsets.UTF_8).length));
frame.addHeader("persistent", "true");
ClientStompFrame frame = conn.createFrame(Stomp.Commands.SEND);
frame.addHeader(Stomp.Headers.Subscribe.DESTINATION, getQueuePrefix() + getQueueName());
frame.addHeader(Stomp.Headers.CONTENT_LENGTH, String.valueOf(msg1.getBytes(StandardCharsets.UTF_8).length));
frame.addHeader(Stomp.Headers.Send.PERSISTENT, Boolean.TRUE.toString());
frame.setBody(msg1);
connV11.sendFrame(frame);
conn.sendFrame(frame);
ClientStompFrame frame2 = connV11.createFrame("SEND");
frame2.addHeader("destination", getQueuePrefix() + getQueueName());
frame2.addHeader("content-length", String.valueOf(msg2.getBytes(StandardCharsets.UTF_8).length));
frame2.addHeader("persistent", "true");
ClientStompFrame frame2 = conn.createFrame(Stomp.Commands.SEND);
frame2.addHeader(Stomp.Headers.Subscribe.DESTINATION, getQueuePrefix() + getQueueName());
frame2.addHeader(Stomp.Headers.CONTENT_LENGTH, String.valueOf(msg2.getBytes(StandardCharsets.UTF_8).length));
frame2.addHeader(Stomp.Headers.Send.PERSISTENT, Boolean.TRUE.toString());
frame2.setBody(msg2);
connV11.sendFrame(frame2);
conn.sendFrame(frame2);
ClientStompFrame subFrame = connV11.createFrame("SUBSCRIBE");
subFrame.addHeader("id", "a-sub");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
subscribe(conn, "a-sub");
connV11.sendFrame(subFrame);
frame = connV11.receiveFrame();
System.out.println("received " + frame);
assertEquals("MESSAGE", frame.getCommand());
assertEquals("a-sub", frame.getHeader("subscription"));
assertNotNull(frame.getHeader("message-id"));
assertEquals(getQueuePrefix() + getQueueName(), frame.getHeader("destination"));
frame = conn.receiveFrame();
assertEquals(Stomp.Responses.MESSAGE, frame.getCommand());
assertEquals("a-sub", frame.getHeader(Stomp.Headers.Message.SUBSCRIPTION));
assertNotNull(frame.getHeader(Stomp.Headers.Message.MESSAGE_ID));
assertEquals(getQueuePrefix() + getQueueName(), frame.getHeader(Stomp.Headers.Subscribe.DESTINATION));
assertEquals(msg1, frame.getBody());
frame = connV11.receiveFrame();
System.out.println("received " + frame);
assertEquals("MESSAGE", frame.getCommand());
assertEquals("a-sub", frame.getHeader("subscription"));
assertNotNull(frame.getHeader("message-id"));
assertEquals(getQueuePrefix() + getQueueName(), frame.getHeader("destination"));
frame = conn.receiveFrame();
assertEquals(Stomp.Responses.MESSAGE, frame.getCommand());
assertEquals("a-sub", frame.getHeader(Stomp.Headers.Message.SUBSCRIPTION));
assertNotNull(frame.getHeader(Stomp.Headers.Message.MESSAGE_ID));
assertEquals(getQueuePrefix() + getQueueName(), frame.getHeader(Stomp.Headers.Subscribe.DESTINATION));
assertEquals(msg2, frame.getBody());
//unsub
ClientStompFrame unsubFrame = connV11.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("id", "a-sub");
connV11.sendFrame(unsubFrame);
unsubscribe(conn, "a-sub");
}
@Test
public void testNoGarbageAfterPersistentMessageV10() throws Exception {
ClientStompFrame subFrame = connV10.createFrame("SUBSCRIBE");
subFrame.addHeader("id", "a-sub");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
connV10.sendFrame(subFrame);
ClientStompFrame frame = connV10.createFrame("SEND");
frame.addHeader("destination", getQueuePrefix() + getQueueName());
frame.addHeader("content-length", "11");
frame.addHeader("persistent", "true");
frame.setBody("Hello World");
connV10.sendFrame(frame);
frame = connV10.createFrame("SEND");
frame.addHeader("destination", getQueuePrefix() + getQueueName());
frame.addHeader("content-length", "11");
frame.addHeader("persistent", "true");
frame.setBody("Hello World");
connV10.sendFrame(frame);
frame = connV10.receiveFrame(10000);
System.out.println("received: " + frame);
assertEquals("Hello World", frame.getBody());
//if activemq sends trailing garbage bytes, the second message
//will not be normal
frame = connV10.receiveFrame(10000);
System.out.println("received: " + frame);
assertEquals("Hello World", frame.getBody());
//unsub
ClientStompFrame unsubFrame = connV10.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("id", "a-sub");
connV10.sendFrame(unsubFrame);
}
@Test
public void testNoGarbageOnPersistentRedeliveryV10() throws Exception {
ClientStompFrame frame = connV10.createFrame("SEND");
frame.addHeader("destination", getQueuePrefix() + getQueueName());
frame.addHeader("content-length", "11");
frame.addHeader("persistent", "true");
frame.setBody("Hello World");
connV10.sendFrame(frame);
frame = connV10.createFrame("SEND");
frame.addHeader("destination", getQueuePrefix() + getQueueName());
frame.addHeader("content-length", "11");
frame.addHeader("persistent", "true");
frame.setBody("Hello World");
connV10.sendFrame(frame);
ClientStompFrame subFrame = connV10.createFrame("SUBSCRIBE");
subFrame.addHeader("id", "a-sub");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "client");
connV10.sendFrame(subFrame);
// receive but don't ack
frame = connV10.receiveFrame(10000);
frame = connV10.receiveFrame(10000);
System.out.println("received: " + frame);
//unsub
ClientStompFrame unsubFrame = connV10.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("id", "a-sub");
connV10.sendFrame(unsubFrame);
subFrame = connV10.createFrame("SUBSCRIBE");
subFrame.addHeader("id", "a-sub");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
connV10.sendFrame(subFrame);
frame = connV10.receiveFrame(10000);
frame = connV10.receiveFrame(10000);
//second receive will get problem if trailing bytes
assertEquals("Hello World", frame.getBody());
System.out.println("received again: " + frame);
//unsub
unsubFrame = connV10.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("id", "a-sub");
connV10.sendFrame(unsubFrame);
testNoGarbageAfterPersistentMessage(connV10);
}
@Test
public void testNoGarbageAfterPersistentMessageV11() throws Exception {
ClientStompFrame subFrame = connV11.createFrame("SUBSCRIBE");
subFrame.addHeader("id", "a-sub");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
testNoGarbageAfterPersistentMessage(connV11);
}
connV11.sendFrame(subFrame);
ClientStompFrame frame = connV11.createFrame("SEND");
frame.addHeader("destination", getQueuePrefix() + getQueueName());
frame.addHeader("content-length", "11");
frame.addHeader("persistent", "true");
public void testNoGarbageAfterPersistentMessage(StompClientConnection conn) throws Exception {
subscribe(conn, "a-sub");
ClientStompFrame frame = conn.createFrame(Stomp.Commands.SEND);
frame.addHeader(Stomp.Headers.Subscribe.DESTINATION, getQueuePrefix() + getQueueName());
frame.addHeader(Stomp.Headers.CONTENT_LENGTH, "11");
frame.addHeader(Stomp.Headers.Send.PERSISTENT, Boolean.TRUE.toString());
frame.setBody("Hello World");
connV11.sendFrame(frame);
conn.sendFrame(frame);
frame = connV11.createFrame("SEND");
frame.addHeader("destination", getQueuePrefix() + getQueueName());
frame.addHeader("content-length", "11");
frame.addHeader("persistent", "true");
frame = conn.createFrame(Stomp.Commands.SEND);
frame.addHeader(Stomp.Headers.Subscribe.DESTINATION, getQueuePrefix() + getQueueName());
frame.addHeader(Stomp.Headers.CONTENT_LENGTH, "11");
frame.addHeader(Stomp.Headers.Send.PERSISTENT, Boolean.TRUE.toString());
frame.setBody("Hello World");
connV11.sendFrame(frame);
frame = connV11.receiveFrame(10000);
conn.sendFrame(frame);
System.out.println("received: " + frame);
frame = conn.receiveFrame(10000);
assertEquals("Hello World", frame.getBody());
//if activemq sends trailing garbage bytes, the second message
//will not be normal
frame = connV11.receiveFrame(10000);
System.out.println("received: " + frame);
frame = conn.receiveFrame(10000);
assertEquals("Hello World", frame.getBody());
//unsub
ClientStompFrame unsubFrame = connV11.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("id", "a-sub");
connV11.sendFrame(unsubFrame);
unsubscribe(conn, "a-sub");
}
@Test
public void testNoGarbageOnPersistentRedeliveryV10() throws Exception {
testNoGarbageOnPersistentRedelivery(connV10);
}
@Test
public void testNoGarbageOnPersistentRedeliveryV11() throws Exception {
ClientStompFrame frame = connV11.createFrame("SEND");
frame.addHeader("destination", getQueuePrefix() + getQueueName());
frame.addHeader("content-length", "11");
frame.addHeader("persistent", "true");
testNoGarbageOnPersistentRedelivery(connV11);
}
public void testNoGarbageOnPersistentRedelivery(StompClientConnection conn) throws Exception {
ClientStompFrame frame = conn.createFrame(Stomp.Commands.SEND);
frame.addHeader(Stomp.Headers.Subscribe.DESTINATION, getQueuePrefix() + getQueueName());
frame.addHeader(Stomp.Headers.CONTENT_LENGTH, "11");
frame.addHeader(Stomp.Headers.Send.PERSISTENT, Boolean.TRUE.toString());
frame.setBody("Hello World");
connV11.sendFrame(frame);
conn.sendFrame(frame);
frame = connV11.createFrame("SEND");
frame.addHeader("destination", getQueuePrefix() + getQueueName());
frame.addHeader("content-length", "11");
frame.addHeader("persistent", "true");
frame = conn.createFrame(Stomp.Commands.SEND);
frame.addHeader(Stomp.Headers.Subscribe.DESTINATION, getQueuePrefix() + getQueueName());
frame.addHeader(Stomp.Headers.CONTENT_LENGTH, "11");
frame.addHeader(Stomp.Headers.Send.PERSISTENT, Boolean.TRUE.toString());
frame.setBody("Hello World");
connV11.sendFrame(frame);
conn.sendFrame(frame);
ClientStompFrame subFrame = connV11.createFrame("SUBSCRIBE");
subFrame.addHeader("id", "a-sub");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "client");
connV11.sendFrame(subFrame);
subscribe(conn, "a-sub", Stomp.Headers.Subscribe.AckModeValues.CLIENT);
// receive but don't ack
frame = connV11.receiveFrame(10000);
frame = connV11.receiveFrame(10000);
frame = conn.receiveFrame(10000);
frame = conn.receiveFrame(10000);
System.out.println("received: " + frame);
unsubscribe(conn, "a-sub");
//unsub
ClientStompFrame unsubFrame = connV11.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("id", "a-sub");
connV11.sendFrame(unsubFrame);
subscribe(conn, "a-sub");
subFrame = connV11.createFrame("SUBSCRIBE");
subFrame.addHeader("id", "a-sub");
subFrame.addHeader("destination", getQueuePrefix() + getQueueName());
subFrame.addHeader("ack", "auto");
connV11.sendFrame(subFrame);
frame = connV11.receiveFrame(10000);
frame = connV11.receiveFrame(10000);
frame = conn.receiveFrame(10000);
frame = conn.receiveFrame(10000);
//second receive will get problem if trailing bytes
assertEquals("Hello World", frame.getBody());
System.out.println("received again: " + frame);
//unsub
unsubFrame = connV11.createFrame("UNSUBSCRIBE");
unsubFrame.addHeader("id", "a-sub");
connV11.sendFrame(unsubFrame);
unsubscribe(conn, "a-sub");
}
}

View File

@ -1,167 +0,0 @@
/*
* 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.artemis.tests.integration.stomp.v11;
import javax.jms.BytesMessage;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.core.config.Configuration;
import org.apache.activemq.artemis.core.protocol.stomp.StompProtocolManagerFactory;
import org.apache.activemq.artemis.core.registry.JndiBindingRegistry;
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory;
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptorFactory;
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.ActiveMQServers;
import org.apache.activemq.artemis.jms.client.ActiveMQJMSConnectionFactory;
import org.apache.activemq.artemis.jms.server.JMSServerManager;
import org.apache.activemq.artemis.jms.server.config.JMSConfiguration;
import org.apache.activemq.artemis.jms.server.config.impl.JMSConfigurationImpl;
import org.apache.activemq.artemis.jms.server.config.impl.JMSQueueConfigurationImpl;
import org.apache.activemq.artemis.jms.server.config.impl.TopicConfigurationImpl;
import org.apache.activemq.artemis.jms.server.impl.JMSServerManagerImpl;
import org.apache.activemq.artemis.tests.unit.util.InVMNamingContext;
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
import org.junit.Before;
public abstract class StompV11TestBase extends ActiveMQTestBase {
protected String hostname = "127.0.0.1";
protected int port = 61613;
private ConnectionFactory connectionFactory;
private Connection connection;
protected Session session;
protected Queue queue;
protected Topic topic;
protected JMSServerManager server;
protected String defUser = "brianm";
protected String defPass = "wombats";
protected boolean persistenceEnabled = false;
// Implementation methods
// -------------------------------------------------------------------------
@Override
@Before
public void setUp() throws Exception {
super.setUp();
server = createServer();
server.start();
connectionFactory = createConnectionFactory();
connection = connectionFactory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
queue = session.createQueue(getQueueName());
topic = session.createTopic(getTopicName());
connection.start();
}
/**
* @return
* @throws Exception
*/
protected JMSServerManager createServer() throws Exception {
Map<String, Object> params = new HashMap<>();
params.put(TransportConstants.PROTOCOLS_PROP_NAME, StompProtocolManagerFactory.STOMP_PROTOCOL_NAME);
params.put(TransportConstants.PORT_PROP_NAME, TransportConstants.DEFAULT_STOMP_PORT);
params.put(TransportConstants.STOMP_CONSUMERS_CREDIT, "-1");
TransportConfiguration stompTransport = new TransportConfiguration(NettyAcceptorFactory.class.getName(), params);
Configuration config = createBasicConfig().setPersistenceEnabled(persistenceEnabled).addAcceptorConfiguration(stompTransport).addAcceptorConfiguration(new TransportConfiguration(InVMAcceptorFactory.class.getName())).setConnectionTtlCheckInterval(500);
ActiveMQServer activeMQServer = addServer(ActiveMQServers.newActiveMQServer(config, defUser, defPass));
JMSConfiguration jmsConfig = new JMSConfigurationImpl();
jmsConfig.getQueueConfigurations().add(new JMSQueueConfigurationImpl().setName(getQueueName()).setBindings(getQueueName()));
jmsConfig.getTopicConfigurations().add(new TopicConfigurationImpl().setName(getTopicName()).setBindings(getTopicName()));
server = new JMSServerManagerImpl(activeMQServer, jmsConfig);
server.setRegistry(new JndiBindingRegistry(new InVMNamingContext()));
return server;
}
protected ConnectionFactory createConnectionFactory() {
return new ActiveMQJMSConnectionFactory(false, new TransportConfiguration(InVMConnectorFactory.class.getName()));
}
protected String getQueueName() {
return "test";
}
protected String getQueuePrefix() {
return "";
}
protected String getTopicName() {
return "testtopic";
}
protected String getTopicPrefix() {
return "";
}
public void sendMessage(String msg) throws Exception {
sendMessage(msg, queue);
}
public void sendMessage(String msg, Destination destination) throws Exception {
MessageProducer producer = session.createProducer(destination);
TextMessage message = session.createTextMessage(msg);
producer.send(message);
}
public void sendMessage(byte[] data, Destination destination) throws Exception {
sendMessage(data, "foo", "xyz", destination);
}
public void sendMessage(String msg, String propertyName, String propertyValue) throws Exception {
sendMessage(msg.getBytes(StandardCharsets.UTF_8), propertyName, propertyValue, queue);
}
public void sendMessage(byte[] data,
String propertyName,
String propertyValue,
Destination destination) throws Exception {
MessageProducer producer = session.createProducer(destination);
BytesMessage message = session.createBytesMessage();
message.setStringProperty(propertyName, propertyValue);
message.writeBytes(data);
producer.send(message);
}
}

View File

@ -169,11 +169,24 @@ public class JMSClusteredTestBase extends ActiveMQTestBase {
final String destinationLabel = "toServer" + destination;
final String sourceLabel = "server" + source;
Configuration configuration = createDefaultInVMConfig(source).setSecurityEnabled(false).setJMXManagementEnabled(true).setPersistenceEnabled(false).addConnectorConfiguration(destinationLabel, new TransportConfiguration(InVMConnectorFactory.class.getName(), generateInVMParams(destination))).addConnectorConfiguration(sourceLabel, new TransportConfiguration(InVMConnectorFactory.class.getName(), generateInVMParams(source))).addClusterConfiguration(new ClusterConnectionConfiguration().setName(destinationLabel).setAddress("jms").setConnectorName(sourceLabel).setRetryInterval(250).setMaxHops(MAX_HOPS).setConfirmationWindowSize(1024).setMessageLoadBalancingType(MessageLoadBalancingType.ON_DEMAND).setStaticConnectors(new ArrayList<String>() {
{
add(destinationLabel);
}
}));
Configuration configuration = createDefaultInVMConfig(source).setSecurityEnabled(false)
.setJMXManagementEnabled(true)
.setPersistenceEnabled(false)
.addConnectorConfiguration(destinationLabel, new TransportConfiguration(InVMConnectorFactory.class.getName(), generateInVMParams(destination)))
.addConnectorConfiguration(sourceLabel, new TransportConfiguration(InVMConnectorFactory.class.getName(), generateInVMParams(source)))
.addClusterConfiguration(new ClusterConnectionConfiguration().setName(destinationLabel)
// TODO should this be changed?
.setAddress("jms")
.setConnectorName(sourceLabel)
.setRetryInterval(250)
.setMaxHops(MAX_HOPS)
.setConfirmationWindowSize(1024)
.setMessageLoadBalancingType(MessageLoadBalancingType.ON_DEMAND)
.setStaticConnectors(new ArrayList<String>() {
{
add(destinationLabel);
}
}));
configuration.getAddressesSettings().put("#", new AddressSettings().setRedistributionDelay(0));

View File

@ -340,6 +340,7 @@ public class MessageProducerTest extends JMSTestCase {
@Test
public void testCreateProducerOnInexistentDestination() throws Exception {
getJmsServer().getAddressSettingsRepository().addMatch("#", new AddressSettings().setAutoCreateJmsQueues(false));
getJmsServer().getAddressSettingsRepository().addMatch("#", new AddressSettings().setAutoCreateJmsTopics(false));
Connection pconn = createConnection();
try {
Session ps = pconn.createSession(false, Session.AUTO_ACKNOWLEDGE);

View File

@ -170,6 +170,7 @@ public class SessionTest extends ActiveMQServerTestCase {
@Test
public void testCreateNonExistentTopic() throws Exception {
getJmsServer().getAddressSettingsRepository().addMatch("#", new AddressSettings().setAutoCreateJmsQueues(false));
getJmsServer().getAddressSettingsRepository().addMatch("#", new AddressSettings().setAutoCreateJmsTopics(false));
Connection conn = getConnectionFactory().createConnection();
Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
try {
@ -198,6 +199,7 @@ public class SessionTest extends ActiveMQServerTestCase {
@Test
public void testCreateTopicWhileQueueWithSameNameExists() throws Exception {
getJmsServer().getAddressSettingsRepository().addMatch("#", new AddressSettings().setAutoCreateJmsQueues(false));
getJmsServer().getAddressSettingsRepository().addMatch("#", new AddressSettings().setAutoCreateJmsTopics(false));
Connection conn = getConnectionFactory().createConnection();
Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
try {

View File

@ -1125,7 +1125,7 @@ public class MessageHeaderTest extends MessageHeaderTestBase {
}
@Override
public void createAddress(SimpleString address, boolean multicast) throws ActiveMQException {
public void createAddress(SimpleString address, boolean multicast, final boolean autoCreated) throws ActiveMQException {
}

View File

@ -30,7 +30,6 @@ import org.apache.activemq.artemis.core.postoffice.RoutingStatus;
import org.apache.activemq.artemis.core.postoffice.impl.DuplicateIDCacheImpl;
import org.apache.activemq.artemis.core.server.MessageReference;
import org.apache.activemq.artemis.core.server.Queue;
import org.apache.activemq.artemis.core.server.QueueCreator;
import org.apache.activemq.artemis.core.server.RoutingContext;
import org.apache.activemq.artemis.core.server.ServerMessage;
import org.apache.activemq.artemis.core.server.impl.AddressInfo;
@ -162,7 +161,6 @@ public class FakePostOffice implements PostOffice {
@Override
public RoutingStatus route(ServerMessage message,
QueueCreator creator,
RoutingContext context,
boolean direct) throws Exception {
return RoutingStatus.OK;
@ -171,7 +169,6 @@ public class FakePostOffice implements PostOffice {
@Override
public RoutingStatus route(ServerMessage message,
QueueCreator creator,
Transaction tx,
boolean direct) throws Exception {
return RoutingStatus.OK;
@ -179,7 +176,6 @@ public class FakePostOffice implements PostOffice {
@Override
public RoutingStatus route(ServerMessage message,
QueueCreator creator,
RoutingContext context,
boolean direct,
boolean rejectDuplicates) throws Exception {
@ -189,7 +185,6 @@ public class FakePostOffice implements PostOffice {
@Override
public RoutingStatus route(ServerMessage message,
QueueCreator creator,
Transaction tx,
boolean direct,
boolean rejectDuplicates) throws Exception {
@ -201,7 +196,7 @@ public class FakePostOffice implements PostOffice {
}
@Override
public RoutingStatus route(ServerMessage message, QueueCreator queueCreator, boolean direct) throws Exception {
public RoutingStatus route(ServerMessage message, boolean direct) throws Exception {
return RoutingStatus.OK;
}
}