diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/client/impl/ClientProducerImpl.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/client/impl/ClientProducerImpl.java index c9c6d75926..f3fd2e1f69 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/client/impl/ClientProducerImpl.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/client/impl/ClientProducerImpl.java @@ -44,6 +44,8 @@ public class ClientProducerImpl implements ClientProducerInternal { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + private final int id; + private final SimpleString address; private final ClientSessionInternal session; @@ -75,7 +77,10 @@ public class ClientProducerImpl implements ClientProducerInternal { final boolean autoGroup, final SimpleString groupID, final int minLargeMessageSize, - final SessionContext sessionContext) { + final SessionContext sessionContext, + final int producerID) { + this.id = producerID; + this.sessionContext = sessionContext; this.session = session; @@ -197,6 +202,11 @@ public class ClientProducerImpl implements ClientProducerInternal { return producerCredits; } + @Override + public int getID() { + return id; + } + private void doCleanup() { if (address != null) { session.returnCredits(address); @@ -204,6 +214,8 @@ public class ClientProducerImpl implements ClientProducerInternal { session.removeProducer(this); + sessionContext.removeProducer(id); + closed = true; } @@ -290,7 +302,7 @@ public class ClientProducerImpl implements ClientProducerInternal { theCredits.acquireCredits(creditSize); - sessionContext.sendFullMessage(msgI, sendBlocking, handler, address); + sessionContext.sendFullMessage(msgI, sendBlocking, handler, address, id); } private void checkClosed() throws ActiveMQException { @@ -381,7 +393,7 @@ public class ClientProducerImpl implements ClientProducerInternal { lastChunk = pos >= bodySize; SendAcknowledgementHandler messageHandler = lastChunk ? handler : null; - int creditsUsed = sessionContext.sendServerLargeMessageChunk(msgI, -1, sendBlocking, lastChunk, bodyBuffer.array(), messageHandler); + int creditsUsed = sessionContext.sendServerLargeMessageChunk(msgI, -1, sendBlocking, lastChunk, bodyBuffer.array(), id, messageHandler); credits.acquireCredits(creditsUsed); } @@ -492,7 +504,7 @@ public class ClientProducerImpl implements ClientProducerInternal { headerSent = true; sendInitialLargeMessageHeader(msgI, credits); } - int creditsSent = sessionContext.sendLargeMessageChunk(msgI, messageSize.get(), sendBlocking, true, buff, reconnectID, handler); + int creditsSent = sessionContext.sendLargeMessageChunk(msgI, messageSize.get(), sendBlocking, true, buff, reconnectID, id, handler); credits.acquireCredits(creditsSent); } } else { @@ -501,7 +513,7 @@ public class ClientProducerImpl implements ClientProducerInternal { sendInitialLargeMessageHeader(msgI, credits); } - int creditsSent = sessionContext.sendLargeMessageChunk(msgI, messageSize.get(), sendBlocking, false, buff, reconnectID, handler); + int creditsSent = sessionContext.sendLargeMessageChunk(msgI, messageSize.get(), sendBlocking, false, buff, reconnectID, id, handler); credits.acquireCredits(creditsSent); } } diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/client/impl/ClientProducerInternal.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/client/impl/ClientProducerInternal.java index 6190885e3d..963f86fdbe 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/client/impl/ClientProducerInternal.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/client/impl/ClientProducerInternal.java @@ -26,4 +26,6 @@ public interface ClientProducerInternal extends ClientProducer { void cleanUp(); ClientProducerCredits getProducerCredits(); + + int getID(); } diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/client/impl/ClientSessionImpl.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/client/impl/ClientSessionImpl.java index dfb99e65ee..e388673645 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/client/impl/ClientSessionImpl.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/client/impl/ClientSessionImpl.java @@ -161,6 +161,8 @@ public final class ClientSessionImpl implements ClientSessionInternal, FailureLi private final CoreMessageObjectPools coreMessageObjectPools = new CoreMessageObjectPools(); + private AtomicInteger producerIDs = new AtomicInteger(); + ClientSessionImpl(final ClientSessionFactoryInternal sessionFactory, final String name, final String username, @@ -2031,10 +2033,20 @@ public final class ClientSessionImpl implements ClientSessionInternal, FailureLi final int maxRate) throws ActiveMQException { checkClosed(); - ClientProducerInternal producer = new ClientProducerImpl(this, address, maxRate == -1 ? null : new TokenBucketLimiterImpl(maxRate, false), autoCommitSends && blockOnNonDurableSend, autoCommitSends && blockOnDurableSend, autoGroup, groupID == null ? null : new SimpleString(groupID), minLargeMessageSize, sessionContext); + ClientProducerInternal producer = new ClientProducerImpl(this, + address, + maxRate == -1 ? null : new TokenBucketLimiterImpl(maxRate, false), + autoCommitSends && blockOnNonDurableSend, + autoCommitSends && blockOnDurableSend, + autoGroup, groupID == null ? null : new SimpleString(groupID), + minLargeMessageSize, + sessionContext, + producerIDs.incrementAndGet()); addProducer(producer); + sessionContext.createProducer(producer); + return producer; } diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/CoreRemotingConnection.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/CoreRemotingConnection.java index 43035b0520..3f8699b5b8 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/CoreRemotingConnection.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/CoreRemotingConnection.java @@ -76,6 +76,11 @@ public interface CoreRemotingConnection extends RemotingConnection { return version < PacketImpl.ARTEMIS_2_18_0_VERSION; } + default boolean isBeforeProducerMetricsChanged() { + int version = getChannelVersion(); + return version < PacketImpl.ARTEMIS_2_28_0_VERSION; + } + /** * Sets the client protocol used on the communication. This will determine if the client has * support for certain packet types diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/ActiveMQSessionContext.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/ActiveMQSessionContext.java index 7f248b7403..b864dc1013 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/ActiveMQSessionContext.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/ActiveMQSessionContext.java @@ -58,6 +58,7 @@ import org.apache.activemq.artemis.core.client.impl.ClientConsumerInternal; import org.apache.activemq.artemis.core.client.impl.ClientLargeMessageInternal; import org.apache.activemq.artemis.core.client.impl.ClientMessageInternal; import org.apache.activemq.artemis.core.client.impl.ClientProducerCredits; +import org.apache.activemq.artemis.core.client.impl.ClientProducerInternal; import org.apache.activemq.artemis.core.client.impl.ClientSessionImpl; import org.apache.activemq.artemis.core.message.impl.CoreMessage; import org.apache.activemq.artemis.core.protocol.core.Channel; @@ -68,6 +69,7 @@ import org.apache.activemq.artemis.core.protocol.core.Packet; import org.apache.activemq.artemis.core.protocol.core.ResponseHandler; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.ActiveMQExceptionMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.CreateAddressMessage; +import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.CreateProducerMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.CreateQueueMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.CreateQueueMessage_V2; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.CreateSessionMessage; @@ -76,6 +78,7 @@ import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.Disconnect import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.DisconnectConsumerWithKillMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.ReattachSessionMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.ReattachSessionResponseMessage; +import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.RemoveProducerMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.RollbackMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionAcknowledgeMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionAddMetaDataMessageV2; @@ -105,10 +108,12 @@ import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionRec import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionRequestProducerCreditsMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionSendContinuationMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionSendContinuationMessage_V2; +import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionSendContinuationMessage_V3; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionSendLargeMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionSendMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionSendMessage_1X; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionSendMessage_V2; +import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionSendMessage_V3; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionUniqueAddMetaDataMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionXAAfterFailedMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionXACommitMessage; @@ -371,6 +376,20 @@ public class ActiveMQSessionContext extends SessionContext { return remotingConnection.isWritable(callback); } + @Override + public void createProducer(ClientProducerInternal producer) { + if (!sessionChannel.getConnection().isBeforeProducerMetricsChanged()) { + sessionChannel.send(new CreateProducerMessage(producer.getID(), producer.getAddress())); + } + } + + @Override + public void removeProducer(int id) { + if (!sessionChannel.getConnection().isBeforeProducerMetricsChanged()) { + sessionChannel.send(new RemoveProducerMessage(id)); + } + } + @Override public ClientConsumerInternal createConsumer(SimpleString queueName, SimpleString filterString, @@ -546,15 +565,19 @@ public class ActiveMQSessionContext extends SessionContext { public void sendFullMessage(ICoreMessage msgI, boolean sendBlocking, SendAcknowledgementHandler handler, - SimpleString defaultAddress) throws ActiveMQException { + SimpleString defaultAddress, + int senderID) throws ActiveMQException { final SessionSendMessage packet; if (sessionChannel.getConnection().isVersionBeforeAddressChange()) { packet = new SessionSendMessage_1X(msgI, sendBlocking, handler); } else if (sessionChannel.getConnection().isVersionBeforeAsyncResponseChange()) { packet = new SessionSendMessage(msgI, sendBlocking, handler); - } else { + } else if (sessionChannel.getConnection().isBeforeProducerMetricsChanged()) { boolean responseRequired = confirmationWindow != -1 || sendBlocking; packet = new SessionSendMessage_V2(msgI, responseRequired, handler); + } else { + boolean responseRequired = confirmationWindow != -1 || sendBlocking; + packet = new SessionSendMessage_V3(msgI, responseRequired, handler, senderID); } if (sendBlocking) { sessionChannel.sendBlocking(packet, PacketImpl.NULL_RESPONSE); @@ -579,8 +602,9 @@ public class ActiveMQSessionContext extends SessionContext { boolean lastChunk, byte[] chunk, int reconnectID, + int senderID, SendAcknowledgementHandler messageHandler) throws ActiveMQException { - return sendSessionSendContinuationMessage(this.sessionChannel, msgI, messageBodySize, sendBlocking, lastChunk, chunk, messageHandler); + return sendSessionSendContinuationMessage(this.sessionChannel, msgI, messageBodySize, sendBlocking, lastChunk, chunk, senderID, messageHandler); } @Override @@ -589,8 +613,9 @@ public class ActiveMQSessionContext extends SessionContext { boolean sendBlocking, boolean lastChunk, byte[] chunk, + int senderID, SendAcknowledgementHandler messageHandler) throws ActiveMQException { - return sendSessionSendContinuationMessage(this.sessionChannel, msgI, messageBodySize, sendBlocking, lastChunk, chunk, messageHandler); + return sendSessionSendContinuationMessage(this.sessionChannel, msgI, messageBodySize, sendBlocking, lastChunk, chunk, senderID, messageHandler); } @Override @@ -1043,13 +1068,16 @@ public class ActiveMQSessionContext extends SessionContext { boolean sendBlocking, boolean lastChunk, byte[] chunk, + int senderID, SendAcknowledgementHandler messageHandler) throws ActiveMQException { final boolean requiresResponse = lastChunk && sendBlocking; final SessionSendContinuationMessage chunkPacket; if (sessionChannel.getConnection().isVersionBeforeAsyncResponseChange()) { chunkPacket = new SessionSendContinuationMessage(msgI, chunk, !lastChunk, requiresResponse, messageBodySize, messageHandler); - } else { + } else if (sessionChannel.getConnection().isBeforeProducerMetricsChanged()) { chunkPacket = new SessionSendContinuationMessage_V2(msgI, chunk, !lastChunk, requiresResponse || confirmationWindow != -1, messageBodySize, messageHandler); + } else { + chunkPacket = new SessionSendContinuationMessage_V3(msgI, chunk, !lastChunk, requiresResponse || confirmationWindow != -1, messageBodySize, senderID, messageHandler); } //perform a weak form of flow control to avoid OOM on tight loops final CoreRemotingConnection connection = channel.getConnection(); diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/PacketDecoder.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/PacketDecoder.java index 2967c970e9..6b71951cd3 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/PacketDecoder.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/PacketDecoder.java @@ -79,6 +79,7 @@ import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionRec import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionRequestProducerCreditsMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionSendContinuationMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionSendContinuationMessage_V2; +import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionSendContinuationMessage_V3; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionUniqueAddMetaDataMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionXAAfterFailedMessage; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionXACommitMessage; @@ -423,8 +424,10 @@ public abstract class PacketDecoder implements Serializable { case SESS_SEND_CONTINUATION: { if (connection.isVersionBeforeAsyncResponseChange()) { packet = new SessionSendContinuationMessage(); - } else { + } else if (connection.isBeforeProducerMetricsChanged()) { packet = new SessionSendContinuationMessage_V2(); + } else { + packet = new SessionSendContinuationMessage_V3(); } break; } diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/PacketImpl.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/PacketImpl.java index b83e3ee849..00020faecc 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/PacketImpl.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/PacketImpl.java @@ -47,6 +47,9 @@ public class PacketImpl implements Packet { // 2.24.0 public static final int ARTEMIS_2_24_0_VERSION = 133; + // 2.28.0 + public static final int ARTEMIS_2_28_0_VERSION = 134; + public static final SimpleString OLD_QUEUE_PREFIX = new SimpleString("jms.queue."); public static final SimpleString OLD_TEMP_QUEUE_PREFIX = new SimpleString("jms.tempqueue."); public static final SimpleString OLD_TOPIC_PREFIX = new SimpleString("jms.topic."); @@ -293,7 +296,9 @@ public class PacketImpl implements Packet { public static final byte DISCONNECT_V3 = -19; + public static final byte CREATE_PRODUCER = -20; + public static final byte REMOVE_PRODUCER = -21; public PacketImpl(final byte type) { this.type = type; diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/CreateProducerMessage.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/CreateProducerMessage.java new file mode 100644 index 0000000000..ead9a9594b --- /dev/null +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/CreateProducerMessage.java @@ -0,0 +1,83 @@ +/* + * 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.protocol.core.impl.wireformat; + +import org.apache.activemq.artemis.api.core.ActiveMQBuffer; +import org.apache.activemq.artemis.api.core.SimpleString; +import org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl; + +import java.util.Objects; + +public class CreateProducerMessage extends PacketImpl { + protected int id; + + protected SimpleString address; + + public CreateProducerMessage() { + super(PacketImpl.CREATE_PRODUCER); + } + + public CreateProducerMessage(int id, SimpleString address) { + super(PacketImpl.CREATE_PRODUCER); + this.id = id; + this.address = address; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public SimpleString getAddress() { + return address; + } + + public void setAddress(SimpleString address) { + this.address = address; + } + + + + @Override + public void encodeRest(final ActiveMQBuffer buffer) { + buffer.writeInt(id); + buffer.writeNullableSimpleString(address); + } + + @Override + public void decodeRest(final ActiveMQBuffer buffer) { + id = buffer.readInt(); + address = buffer.readNullableSimpleString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + CreateProducerMessage that = (CreateProducerMessage) o; + return Objects.equals(id, that.id) && Objects.equals(address, that.address); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), id, address); + } +} diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/RemoveProducerMessage.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/RemoveProducerMessage.java new file mode 100644 index 0000000000..a6f8d7755c --- /dev/null +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/RemoveProducerMessage.java @@ -0,0 +1,68 @@ +/* + * 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.protocol.core.impl.wireformat; + +import org.apache.activemq.artemis.api.core.ActiveMQBuffer; +import org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl; + +import java.util.Objects; + +public class RemoveProducerMessage extends PacketImpl { + + protected int id; + + public RemoveProducerMessage(int id) { + super(PacketImpl.REMOVE_PRODUCER); + this.id = id; + } + + public RemoveProducerMessage() { + super(PacketImpl.REMOVE_PRODUCER); + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + @Override + public void encodeRest(final ActiveMQBuffer buffer) { + buffer.writeInt(id); + } + + @Override + public void decodeRest(final ActiveMQBuffer buffer) { + id = buffer.readInt(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + RemoveProducerMessage that = (RemoveProducerMessage) o; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), id); + } +} diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/SessionSendContinuationMessage.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/SessionSendContinuationMessage.java index 1aa521650e..1db5ff7f47 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/SessionSendContinuationMessage.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/SessionSendContinuationMessage.java @@ -180,4 +180,8 @@ public class SessionSendContinuationMessage extends SessionContinuationMessage { public SendAcknowledgementHandler getHandler() { return handler; } + + public int getSenderID() { + return -1; + } } diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/SessionSendContinuationMessage_V3.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/SessionSendContinuationMessage_V3.java new file mode 100644 index 0000000000..60db0c2d92 --- /dev/null +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/SessionSendContinuationMessage_V3.java @@ -0,0 +1,72 @@ +/* + * 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.protocol.core.impl.wireformat; + +import org.apache.activemq.artemis.api.core.ActiveMQBuffer; +import org.apache.activemq.artemis.api.core.Message; +import org.apache.activemq.artemis.api.core.client.SendAcknowledgementHandler; +import org.apache.activemq.artemis.utils.DataConstants; + +/** + * A SessionSendContinuationMessage
+ */ +public class SessionSendContinuationMessage_V3 extends SessionSendContinuationMessage_V2 { + + private int senderID; + + public SessionSendContinuationMessage_V3() { + super(); + } + + /** + * @param body + * @param continues + * @param requiresResponse + */ + public SessionSendContinuationMessage_V3(final Message message, + final byte[] body, + final boolean continues, + final boolean requiresResponse, + final long messageBodySize, + final int senderID, + final SendAcknowledgementHandler handler) { + super(message, body, continues, requiresResponse, messageBodySize, handler); + this.senderID = senderID; + } + + @Override + public int expectedEncodeSize() { + return super.expectedEncodeSize() + DataConstants.SIZE_INT; + } + + @Override + public void encodeRest(final ActiveMQBuffer buffer) { + super.encodeRest(buffer); + buffer.writeInt(senderID); + } + + @Override + public void decodeRest(final ActiveMQBuffer buffer) { + super.decodeRest(buffer); + senderID = buffer.readInt(); + } + + @Override + public int getSenderID() { + return senderID; + } +} diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/SessionSendMessage.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/SessionSendMessage.java index dafcb8fc6d..206af04c77 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/SessionSendMessage.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/SessionSendMessage.java @@ -136,4 +136,7 @@ public class SessionSendMessage extends MessagePacket { return true; } + public int getSenderID() { + return -1; + } } diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/SessionSendMessage_V3.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/SessionSendMessage_V3.java new file mode 100644 index 0000000000..690b931f62 --- /dev/null +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/wireformat/SessionSendMessage_V3.java @@ -0,0 +1,63 @@ +/* + * 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.protocol.core.impl.wireformat; + +import org.apache.activemq.artemis.api.core.ActiveMQBuffer; +import org.apache.activemq.artemis.api.core.ICoreMessage; +import org.apache.activemq.artemis.api.core.client.SendAcknowledgementHandler; +import org.apache.activemq.artemis.core.message.impl.CoreMessage; +import org.apache.activemq.artemis.utils.DataConstants; + +public class SessionSendMessage_V3 extends SessionSendMessage_V2 { + + private int senderID; + + /** This will be using the CoreMessage because it is meant for the core-protocol */ + public SessionSendMessage_V3(final ICoreMessage message, + final boolean requiresResponse, + final SendAcknowledgementHandler handler, + final int senderID) { + super(message, requiresResponse, handler); + this.senderID = senderID; + } + + public SessionSendMessage_V3(final CoreMessage message) { + super(message); + } + + @Override + public void encodeRest(ActiveMQBuffer buffer) { + super.encodeRest(buffer); + buffer.writeInt(senderID); + } + + @Override + public void decodeRest(final ActiveMQBuffer buffer) { + super.decodeRest(buffer); + senderID = buffer.readInt(); + } + + @Override + protected int fieldsEncodeSize() { + return super.fieldsEncodeSize() + DataConstants.SIZE_INT; + } + + @Override + public int getSenderID() { + return senderID; + } +} diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/spi/core/remoting/SessionContext.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/spi/core/remoting/SessionContext.java index cbe9dd8b54..7c33fff290 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/spi/core/remoting/SessionContext.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/spi/core/remoting/SessionContext.java @@ -37,6 +37,7 @@ import org.apache.activemq.artemis.core.client.impl.ClientConsumerInternal; import org.apache.activemq.artemis.core.client.impl.ClientLargeMessageInternal; import org.apache.activemq.artemis.core.client.impl.ClientMessageInternal; import org.apache.activemq.artemis.core.client.impl.ClientProducerCredits; +import org.apache.activemq.artemis.core.client.impl.ClientProducerInternal; import org.apache.activemq.artemis.core.client.impl.ClientSessionInternal; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionQueueQueryResponseMessage; import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection; @@ -142,7 +143,8 @@ public abstract class SessionContext { public abstract void sendFullMessage(ICoreMessage msgI, boolean sendBlocking, SendAcknowledgementHandler handler, - SimpleString defaultAddress) throws ActiveMQException; + SimpleString defaultAddress, + int senderID) throws ActiveMQException; /** * it should return the number of credits (or bytes) used to send this packet @@ -159,6 +161,7 @@ public abstract class SessionContext { boolean lastChunk, byte[] chunk, int reconnectID, + int senderID, SendAcknowledgementHandler messageHandler) throws ActiveMQException; public abstract int sendServerLargeMessageChunk(Message msgI, @@ -166,6 +169,7 @@ public abstract class SessionContext { boolean sendBlocking, boolean lastChunk, byte[] chunk, + int senderID, SendAcknowledgementHandler messageHandler) throws ActiveMQException; public abstract void setSendAcknowledgementHandler(SendAcknowledgementHandler handler); @@ -385,4 +389,8 @@ public abstract class SessionContext { public abstract void linkFlowControl(SimpleString address, ClientProducerCredits clientProducerCredits); public abstract boolean isWritable(ReadyListener callback); + + public abstract void createProducer(ClientProducerInternal producer); + + public abstract void removeProducer(int id); } diff --git a/artemis-core-client/src/main/resources/activemq-version.properties b/artemis-core-client/src/main/resources/activemq-version.properties index 8ca160b89e..7295b14231 100644 --- a/artemis-core-client/src/main/resources/activemq-version.properties +++ b/artemis-core-client/src/main/resources/activemq-version.properties @@ -20,4 +20,4 @@ activemq.version.minorVersion=${activemq.version.minorVersion} activemq.version.microVersion=${activemq.version.microVersion} activemq.version.incrementingVersion=${activemq.version.incrementingVersion} activemq.version.versionTag=${activemq.version.versionTag} -activemq.version.compatibleVersionList=121,122,123,124,125,126,127,128,129,130,131,132,133 +activemq.version.compatibleVersionList=121,122,123,124,125,126,127,128,129,130,131,132,133,134 diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/consumers.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/consumers.js index 8312e44b53..3da804108e 100644 --- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/consumers.js +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/consumers.js @@ -98,7 +98,15 @@ var Artemis; {name: "Address", visible: true}, {name: "Remote Address", visible: true}, {name: "Local Address", visible: true}, - {name: "Creation Time", visible: true} + {name: "Creation Time", visible: true}, + {name: "Messages in Transit", visible: false}, + {name: "Messages in Transit Size", visible: false}, + {name: "Messages Delivered", visible: false}, + {name: "Messages Delivered Size", visible: false}, + {name: "Messages Acknowledged", visible: false}, + {name: "Messages Acknowledged awaiting Commit", visible: false}, + {name: "Last Delivered Time", visible: false}, + {name: "Last Acknowledged Time", visible: false} ] }; @@ -130,7 +138,13 @@ var Artemis; {id: 'queue', name: 'Queue'}, {id: 'protocol', name: 'Protocol'}, {id: 'localAddress', name: 'Local Address'}, - {id: 'remoteAddress', name: 'Remote Address'} + {id: 'remoteAddress', name: 'Remote Address'}, + {id: 'messagesInTransit', name: 'Messages in Transit'}, + {id: 'messagesInTransitSize', name: 'Messages in Transit Size'}, + {id: 'messagesDelivered', name: 'Messages Delivered'}, + {id: 'messagesDeliveredSize', name: 'Messages Delivered Size'}, + {id: 'messagesAcknowledged', name: 'Messages Acknowledged'}, + {id: 'messagesAcknowledgedAwaitingCommit', name: 'Messages Acknowledged awaiting Commit'} ], operationOptions: [ {id: 'EQUALS', name: 'Equals'}, @@ -181,7 +195,15 @@ var Artemis; { header: 'Address', itemField: 'addressName' , htmlTemplate: 'consumers-anchor-column-template', colActionFn: (item) => selectAddress(item.idx) }, { header: 'Remote Address', itemField: 'remoteAddress' }, { header: 'Local Address', itemField: 'localAddress' }, - { header: 'Creation Time', itemField: 'creationTime' } + { header: 'Creation Time', itemField: 'creationTime' }, + { header: 'Messages in Transit', itemField: 'messagesInTransit' }, + { header: 'Messages in Transit Size', itemField: 'messagesInTransitSize' }, + { header: 'Messages Delivered', itemField: 'messagesDelivered' }, + { header: 'Messages Delivered Size', itemField: 'messagesDeliveredSize' }, + { header: 'Messages Acknowledged', itemField: 'messagesAcknowledged' }, + { header: 'Messages Acknowledged awaiting Commit', itemField: 'messagesAcknowledgedAwaitingCommit' }, + { header: 'Last Delivered Time', itemField: 'lastDeliveredTime', templateFn: function(value) { return formatTimestamp(value);} }, + { header: 'Last Acknowledged Time', itemField: 'lastAcknowledgedTime' , templateFn: function(value) { return formatTimestamp(value);} } ]; ctrl.refresh = function () { @@ -279,6 +301,25 @@ var Artemis; } }; + function formatTimestamp(timestamp) { + Artemis.log.info("in timestamp " + timestamp + " " + (typeof timestamp !== "number")); + if (isNaN(timestamp) || typeof timestamp !== "number") { + Artemis.log.info("returning timestamp " + timestamp + " " + (typeof timestamp !== "number")); + return timestamp; + } + if (timestamp === 0) { + return "N/A"; + } + var d = new Date(timestamp); + // "yyyy-MM-dd HH:mm:ss" + //add 1 to month as getmonth returns the position not the actual month + return d.getFullYear() + "-" + pad2(d.getMonth() + 1) + "-" + pad2(d.getDate()) + " " + pad2(d.getHours()) + ":" + pad2(d.getMinutes()) + ":" + pad2(d.getSeconds()); + } + function pad2(value) { + return (value < 10 ? '0' : '') + value; + } + + ctrl.pagination.setOperation(ctrl.loadOperation); function onError(response) { diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/producers.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/producers.js index 9602336886..a58ebcef84 100644 --- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/producers.js +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/producers.js @@ -72,6 +72,7 @@ var Artemis; ordering: false, columns: [ {name: "ID", visible: true}, + {name: "Name", visible: true}, {name: "Session", visible: true}, {name: "Client ID", visible: true}, {name: "Protocol", visible: true}, @@ -79,7 +80,10 @@ var Artemis; {name: "Validated User", visible: false}, {name: "Address", visible: true}, {name: "Remote Address", visible: true}, - {name: "Local Address", visible: true} + {name: "Local Address", visible: true}, + {name: "Messages Sent", visible: false}, + {name: "Messages Sent Size", visible: false}, + {name: "Last Produced Message ID", visible: false} ] }; @@ -103,6 +107,7 @@ var Artemis; ctrl.filter = { fieldOptions: [ {id: 'id', name: 'ID'}, + {id: 'name', name: 'Name'}, {id: 'session', name: 'Session'}, {id: 'clientID', name: 'Client ID'}, {id: 'user', name: 'User'}, @@ -140,6 +145,7 @@ var Artemis; }; ctrl.tableColumns = [ { header: 'ID', itemField: 'id' }, + { header: 'Name', itemField: 'name' }, { header: 'Session', itemField: 'session' , htmlTemplate: 'producers-anchor-column-template', colActionFn: (item) => selectSession(item.idx) }, { header: 'Client ID', itemField: 'clientID' }, { header: 'Protocol', itemField: 'protocol' }, @@ -147,7 +153,10 @@ var Artemis; { header: 'Validated User', name: 'validatedUser'}, { header: 'Address', itemField: 'addressName' , htmlTemplate: 'producers-anchor-column-template', colActionFn: (item) => selectAddress(item.idx) }, { header: 'Remote Address', itemField: 'remoteAddress' }, - { header: 'Local Address', itemField: 'localAddress' } + { header: 'Local Address', itemField: 'localAddress' }, + { header: 'Messages Sent', itemField: 'msgSent'}, + { header: 'Messages Sent Size', itemField: 'msgSizeSent'}, + { header: 'Last Produced Message ID', itemField: 'lastProducedMessageID'} ]; ctrl.refresh = function () { diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/AMQPSessionCallback.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/AMQPSessionCallback.java index 637cdf10f2..0603688a96 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/AMQPSessionCallback.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/AMQPSessionCallback.java @@ -41,7 +41,6 @@ import org.apache.activemq.artemis.core.server.MessageReference; import org.apache.activemq.artemis.core.server.QueueQueryResult; import org.apache.activemq.artemis.core.server.RoutingContext; import org.apache.activemq.artemis.core.server.ServerConsumer; -import org.apache.activemq.artemis.core.server.ServerProducer; import org.apache.activemq.artemis.core.server.ServerSession; import org.apache.activemq.artemis.core.server.impl.AddressInfo; import org.apache.activemq.artemis.core.settings.impl.AddressFullMessagePolicy; @@ -202,14 +201,14 @@ public class AMQPSessionCallback implements SessionCallback { false, // boolean autoCommitAcks, false, // boolean preAcknowledge, true, //boolean xa, - null, this, true, operationContext, manager.getPrefixes(), manager.getSecurityDomain()); + null, this, true, operationContext, manager.getPrefixes(), manager.getSecurityDomain(), false); } else { serverSession = manager.getServer().createSession(name, connection.getUser(), connection.getPassword(), ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE, protonSPI.getProtonConnectionDelegate(), // RemotingConnection remotingConnection, false, // boolean autoCommitSends false, // boolean autoCommitAcks, false, // boolean preAcknowledge, true, //boolean xa, - null, this, true, operationContext, manager.getPrefixes(), manager.getSecurityDomain(), connection.getValidatedUser()); + null, this, true, operationContext, manager.getPrefixes(), manager.getSecurityDomain(), connection.getValidatedUser(), false); } } @@ -532,7 +531,7 @@ public class AMQPSessionCallback implements SessionCallback { OperationContext oldContext = recoverContext(); try { if (invokeIncoming((AMQPMessage) message, (ActiveMQProtonRemotingConnection) transportConnection.getProtocolConnection()) == null) { - serverSession.send(transaction, message, directDeliver, false, routingContext); + serverSession.send(transaction, message, directDeliver, receiver.getName(), false, routingContext); afterIO(new IOCallback() { @Override @@ -744,8 +743,8 @@ public class AMQPSessionCallback implements SessionCallback { return protonSPI.invokeOutgoingInterceptors(message, connection); } - public void addProducer(ServerProducer serverProducer) { - serverSession.addProducer(serverProducer); + public void addProducer(String name, String address) { + serverSession.addProducer(name, ProtonProtocolManagerFactory.AMQP_PROTOCOL_NAME, address); } public void removeProducer(String name) { diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/AMQPSessionContext.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/AMQPSessionContext.java index 90c271cfde..b64f41f3f8 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/AMQPSessionContext.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/AMQPSessionContext.java @@ -24,8 +24,6 @@ import java.util.concurrent.ConcurrentHashMap; import org.apache.activemq.artemis.api.core.ActiveMQSecurityException; import org.apache.activemq.artemis.core.server.ActiveMQServer; -import org.apache.activemq.artemis.core.server.ServerProducer; -import org.apache.activemq.artemis.core.server.impl.ServerProducerImpl; import org.apache.activemq.artemis.protocol.amqp.connect.mirror.AMQPMirrorControllerSource; import org.apache.activemq.artemis.protocol.amqp.connect.mirror.AMQPMirrorControllerTarget; import org.apache.activemq.artemis.protocol.amqp.broker.AMQPSessionCallback; @@ -160,7 +158,6 @@ public class AMQPSessionContext extends ProtonInitializable { } public void removeReceiver(Receiver receiver) { - sessionSPI.removeProducer(receiver.getName()); receivers.remove(receiver); } @@ -229,8 +226,7 @@ public class AMQPSessionContext extends ProtonInitializable { AMQPMirrorControllerTarget protonReceiver = new AMQPMirrorControllerTarget(sessionSPI, connection, this, receiver, server); protonReceiver.initialize(); receivers.put(receiver, protonReceiver); - ServerProducer serverProducer = new ServerProducerImpl(receiver.getName(), "AMQP", receiver.getTarget().getAddress()); - sessionSPI.addProducer(serverProducer); + sessionSPI.addProducer(receiver.getName(), receiver.getTarget().getAddress()); receiver.setContext(protonReceiver); HashMap brokerIDProperties = new HashMap<>(); brokerIDProperties.put(AMQPMirrorControllerSource.BROKER_ID, server.getNodeID().toString()); @@ -255,8 +251,7 @@ public class AMQPSessionContext extends ProtonInitializable { ProtonServerReceiverContext protonReceiver = new ProtonServerReceiverContext(sessionSPI, connection, this, receiver); protonReceiver.initialize(); receivers.put(receiver, protonReceiver); - ServerProducer serverProducer = new ServerProducerImpl(receiver.getName(), "AMQP", receiver.getTarget().getAddress()); - sessionSPI.addProducer(serverProducer); + sessionSPI.addProducer(receiver.getName(), receiver.getTarget().getAddress()); receiver.setContext(protonReceiver); connection.runNow(() -> { receiver.open(); diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/ProtonServerReceiverContext.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/ProtonServerReceiverContext.java index 199e8c2d95..33e87bd5ed 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/ProtonServerReceiverContext.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/ProtonServerReceiverContext.java @@ -270,6 +270,7 @@ public class ProtonServerReceiverContext extends ProtonAbstractReceiver { @Override public void close(boolean remoteLinkClose) throws ActiveMQAMQPException { super.close(remoteLinkClose); + sessionSPI.removeProducer(receiver.getName()); org.apache.qpid.proton.amqp.messaging.Target target = (org.apache.qpid.proton.amqp.messaging.Target) receiver.getRemoteTarget(); if (target != null && target.getDynamic() && (target.getExpiryPolicy() == TerminusExpiryPolicy.LINK_DETACH || target.getExpiryPolicy() == TerminusExpiryPolicy.SESSION_END)) { try { diff --git a/artemis-protocols/artemis-mqtt-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/mqtt/MQTTConnectionManager.java b/artemis-protocols/artemis-mqtt-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/mqtt/MQTTConnectionManager.java index fc6b5fd91b..fe1b9c50c6 100644 --- a/artemis-protocols/artemis-mqtt-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/mqtt/MQTTConnectionManager.java +++ b/artemis-protocols/artemis-mqtt-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/mqtt/MQTTConnectionManager.java @@ -169,7 +169,9 @@ public class MQTTConnectionManager { MQTTUtil.SESSION_AUTO_CREATE_QUEUE, server.newOperationContext(), session.getProtocolManager().getPrefixes(), - session.getProtocolManager().getSecurityDomain(), validatedUser); + session.getProtocolManager().getSecurityDomain(), + validatedUser, + false); return (ServerSessionImpl) serverSession; } diff --git a/artemis-protocols/artemis-mqtt-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/mqtt/MQTTPublishManager.java b/artemis-protocols/artemis-mqtt-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/mqtt/MQTTPublishManager.java index c65cf2186b..0059140a31 100644 --- a/artemis-protocols/artemis-mqtt-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/mqtt/MQTTPublishManager.java +++ b/artemis-protocols/artemis-mqtt-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/mqtt/MQTTPublishManager.java @@ -42,8 +42,10 @@ import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.protocol.mqtt.exceptions.DisconnectException; import org.apache.activemq.artemis.core.server.Queue; import org.apache.activemq.artemis.core.server.ServerConsumer; +import org.apache.activemq.artemis.core.server.ServerProducer; import org.apache.activemq.artemis.core.server.impl.ServerSessionImpl; import org.apache.activemq.artemis.core.transaction.Transaction; +import org.apache.activemq.artemis.utils.UUIDGenerator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.invoke.MethodHandles; @@ -72,6 +74,10 @@ public class MQTTPublishManager { private SimpleString managementAddress; + private final String senderName = UUIDGenerator.getInstance().generateUUID().toString(); + + private boolean createProducer = true; + private ServerConsumer managementConsumer; private MQTTSession session; @@ -173,6 +179,10 @@ public class MQTTPublishManager { */ void sendToQueue(MqttPublishMessage message, boolean internal) throws Exception { synchronized (lock) { + if (createProducer) { + session.getServerSession().addProducer(senderName, MQTTProtocolManagerFactory.MQTT_PROTOCOL_NAME, ServerProducer.ANONYMOUS); + createProducer = false; + } String topic = message.variableHeader().topicName(); if (session.getVersion() == MQTTVersion.MQTT_5) { Integer alias = MQTTUtil.getProperty(Integer.class, message.variableHeader().properties(), TOPIC_ALIAS); @@ -206,7 +216,6 @@ public class MQTTPublishManager { if (qos > 0) { serverMessage.setDurable(MQTTUtil.DURABLE_MESSAGES); } - int messageId = message.variableHeader().packetId(); if (qos < 2 || !state.getPubRec().contains(messageId)) { if (qos == 2 && !internal) @@ -217,7 +226,7 @@ public class MQTTPublishManager { if (session.getServer().getAddressInfo(address) == null && session.getServer().getAddressSettingsRepository().getMatch(coreAddress).isAutoCreateAddresses()) { session.getServerSession().createAddress(address, RoutingType.MULTICAST, true); } - session.getServerSession().send(tx, serverMessage, true, false); + session.getServerSession().send(tx, serverMessage, true, senderName, false); if (message.fixedHeader().isRetain()) { ByteBuf payload = message.payload(); @@ -303,7 +312,7 @@ public class MQTTPublishManager { if (ref != null) { Message m = MQTTUtil.createPubRelMessage(session, getManagementAddress(), messageId); //send the management message via the internal server session to bypass security. - session.getInternalServerSession().send(m, true); + session.getInternalServerSession().send(m, true, senderName); session.getServerSession().individualAcknowledge(ref.getB(), ref.getA()); releaseFlowControl(ref.getB()); } else { diff --git a/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/OpenWireConnection.java b/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/OpenWireConnection.java index 943d9a3cf2..bb22cc48d0 100644 --- a/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/OpenWireConnection.java +++ b/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/OpenWireConnection.java @@ -837,7 +837,7 @@ public class OpenWireConnection extends AbstractRemotingConnection implements Se } private void createInternalSession(ConnectionInfo info) throws Exception { - internalSession = server.createSession(UUIDGenerator.getInstance().generateStringUUID(), context.getUserName(), info.getPassword(), -1, this, true, false, false, false, null, null, true, operationContext, protocolManager.getPrefixes(), protocolManager.getSecurityDomain(), validatedUser); + internalSession = server.createSession(UUIDGenerator.getInstance().generateStringUUID(), context.getUserName(), info.getPassword(), -1, this, true, false, false, false, null, null, true, operationContext, protocolManager.getPrefixes(), protocolManager.getSecurityDomain(), validatedUser, false); } //raise the refCount of context @@ -1261,6 +1261,10 @@ public class OpenWireConnection extends AbstractRemotingConnection implements Se } ss.addProducer(info); + getSession(info.getProducerId().getParentId()).getCoreSession().addProducer( + info.getProducerId().toString(), + OpenWireProtocolManagerFactory.OPENWIRE_PROTOCOL_NAME, + info.getDestination() != null ? info.getDestination().getPhysicalName() : null); } return null; @@ -1290,6 +1294,7 @@ public class OpenWireConnection extends AbstractRemotingConnection implements Se } synchronized (producerExchanges) { producerExchanges.remove(id); + getSession(id.getParentId()).getCoreSession().removeProducer(id.toString()); } return null; } diff --git a/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/amq/AMQConsumer.java b/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/amq/AMQConsumer.java index 057160ba33..d064d5036c 100644 --- a/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/amq/AMQConsumer.java +++ b/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/amq/AMQConsumer.java @@ -362,6 +362,7 @@ public class AMQConsumer { if (ack.isIndividualAck() || ack.isStandardAck()) { for (MessageReference ref : ackList) { ref.acknowledge(transaction, serverConsumer); + serverConsumer.metricsAcknowledge(ref, transaction); removeRolledback(ref); } } else if (ack.isPoisonAck()) { diff --git a/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/amq/AMQSession.java b/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/amq/AMQSession.java index 28caa08f92..aa7b899b9c 100644 --- a/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/amq/AMQSession.java +++ b/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/amq/AMQSession.java @@ -132,7 +132,7 @@ public class AMQSession implements SessionCallback { // now try { - coreSession = server.createSession(name, username, password, minLargeMessageSize, connection, true, false, false, false, null, this, true, connection.getOperationContext(), protocolManager.getPrefixes(), protocolManager.getSecurityDomain(), connection.getValidatedUser()); + coreSession = server.createSession(name, username, password, minLargeMessageSize, connection, true, false, false, false, null, this, true, connection.getOperationContext(), protocolManager.getPrefixes(), protocolManager.getSecurityDomain(), connection.getValidatedUser(), false); } catch (Exception e) { logger.error("error init session", e); } @@ -392,7 +392,6 @@ public class AMQSession implements SessionCallback { assert clientId.toString().equals(this.connection.getState().getInfo().getClientId()) : "Session cached clientId must be the same of the connection"; originalCoreMsg.putStringProperty(MessageUtil.CONNECTION_ID_PROPERTY_NAME, clientId); - /* ActiveMQ failover transport will attempt to reconnect after connection failure. Any sent messages that did * not receive acks will be resent. (ActiveMQ broker handles this by returning a last sequence id received to * the client). To handle this in Artemis we use a duplicate ID cache. To do this we check to see if the @@ -438,7 +437,7 @@ public class AMQSession implements SessionCallback { restoreAutoRead(); } - getCoreSession().send(coreMsg, false, dest.isTemporary()); + getCoreSession().send(coreMsg, false, producerInfo.getProducerId().toString(), dest.isTemporary()); if (count == null || count.decrementAndGet() == 0) { if (sendProducerAck) { @@ -462,7 +461,7 @@ public class AMQSession implements SessionCallback { Exception exceptionToSend = null; try { - getCoreSession().send(coreMsg, false, dest.isTemporary()); + getCoreSession().send(coreMsg, false, producerInfo.getProducerId().toString(), dest.isTemporary()); } catch (Exception e) { logger.debug("Sending exception to the client", e); exceptionToSend = e; diff --git a/artemis-protocols/artemis-openwire-protocol/src/test/java/org/apache/activemq/artemis/core/protocol/openwire/amq/OpenWireConnectionTest.java b/artemis-protocols/artemis-openwire-protocol/src/test/java/org/apache/activemq/artemis/core/protocol/openwire/amq/OpenWireConnectionTest.java index f9c969c192..9071c755a5 100644 --- a/artemis-protocols/artemis-openwire-protocol/src/test/java/org/apache/activemq/artemis/core/protocol/openwire/amq/OpenWireConnectionTest.java +++ b/artemis-protocols/artemis-openwire-protocol/src/test/java/org/apache/activemq/artemis/core/protocol/openwire/amq/OpenWireConnectionTest.java @@ -71,7 +71,7 @@ public class OpenWireConnectionTest { ServerSession serverSession = Mockito.mock(ServerSession.class); Mockito.when(serverSession.getName()).thenReturn("session"); Mockito.doReturn(serverSession).when(server).createSession(Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.anyInt(), Mockito.any(), Mockito.anyBoolean(), Mockito.anyBoolean(), Mockito.anyBoolean(), - Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any()); + Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.anyBoolean()); OpenWireProtocolManager openWireProtocolManager = new OpenWireProtocolManager(null, server,null, null); openWireProtocolManager.setSecurityDomain("securityDomain"); diff --git a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompProtocolManager.java b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompProtocolManager.java index ab7e004f80..291b595399 100644 --- a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompProtocolManager.java +++ b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompProtocolManager.java @@ -247,7 +247,7 @@ public class StompProtocolManager extends AbstractProtocolManager= connection.getMinLargeMessageSize()) { throw BUNDLE.headerTooBig(); @@ -402,7 +417,7 @@ public class StompSession implements SessionCallback { largeMessage.toMessage().putLongProperty(Message.HDR_LARGE_BODY_SIZE, bytes.length); - session.send(largeMessage.toMessage(), direct); + session.send(largeMessage.toMessage(), direct, senderName); } } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/AbstractControl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/AbstractControl.java index 98e966ef6a..205956394e 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/AbstractControl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/AbstractControl.java @@ -122,7 +122,7 @@ public abstract class AbstractControl extends StandardMBean { Integer.MAX_VALUE, fakeConnection, true, true, false, false, address.toString(), fakeConnection.callback, - false, new DummyOperationContext(), Collections.emptyMap(), null, validatedUser); + false, new DummyOperationContext(), Collections.emptyMap(), null, validatedUser, false); try { CoreMessage message = new CoreMessage(storageManager.generateID(), 50); if (headers != null) { @@ -159,7 +159,7 @@ public abstract class AbstractControl extends StandardMBean { } // There's no point on direct delivery using the management thread, use false here - serverSession.send(message, false); + serverSession.send(message, false, null); return "" + message.getMessageID(); } finally { try { diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java index 25deb59e09..bca62eedfa 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java @@ -79,6 +79,7 @@ import org.apache.activemq.artemis.core.config.TransformerConfiguration; import org.apache.activemq.artemis.core.filter.Filter; import org.apache.activemq.artemis.core.management.impl.view.AddressView; import org.apache.activemq.artemis.core.management.impl.view.ConnectionView; +import org.apache.activemq.artemis.core.management.impl.view.ConsumerField; import org.apache.activemq.artemis.core.management.impl.view.ConsumerView; import org.apache.activemq.artemis.core.management.impl.view.ProducerView; import org.apache.activemq.artemis.core.management.impl.view.QueueView; @@ -107,6 +108,7 @@ import org.apache.activemq.artemis.core.server.ConnectorServiceFactory; import org.apache.activemq.artemis.core.server.Consumer; import org.apache.activemq.artemis.core.server.Divert; import org.apache.activemq.artemis.core.server.JournalType; +import org.apache.activemq.artemis.core.server.MessageReference; import org.apache.activemq.artemis.core.server.Queue; import org.apache.activemq.artemis.core.server.ServerConsumer; import org.apache.activemq.artemis.core.server.ServerProducer; @@ -2609,7 +2611,7 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active try { Set producers = new HashSet<>(); for (ServerSession session : server.getSessions()) { - producers.addAll(session.getServerProducers().values()); + producers.addAll(session.getServerProducers()); } ProducerView view = new ProducerView(server); view.setCollection(producers); @@ -2767,7 +2769,24 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active } private JsonObject toJSONObject(ServerConsumer consumer) throws Exception { - JsonObjectBuilder obj = JsonLoader.createObjectBuilder().add("consumerID", consumer.getID()).add("connectionID", consumer.getConnectionID().toString()).add("sessionID", consumer.getSessionID()).add("queueName", consumer.getQueue().getName().toString()).add("browseOnly", consumer.isBrowseOnly()).add("creationTime", consumer.getCreationTime()).add("deliveringCount", consumer.getDeliveringMessages().size()); + List deliveringMessages = consumer.getDeliveringMessages(); + JsonObjectBuilder obj = JsonLoader.createObjectBuilder() + .add(ConsumerField.ID.getAlternativeName(), consumer.getID()) + .add(ConsumerField.CONNECTION.getAlternativeName(), consumer.getConnectionID().toString()) + .add(ConsumerField.SESSION.getAlternativeName(), consumer.getSessionID()) + .add(ConsumerField.QUEUE.getAlternativeName(), consumer.getQueue().getName().toString()) + .add(ConsumerField.BROWSE_ONLY.getName(), consumer.isBrowseOnly()) + .add(ConsumerField.CREATION_TIME.getName(), consumer.getCreationTime()) + // deliveringCount is renamed as MESSAGES_IN_TRANSIT but left in json for backward compatibility + .add(ConsumerField.MESSAGES_IN_TRANSIT.getAlternativeName(), consumer.getMessagesInTransit()) + .add(ConsumerField.MESSAGES_IN_TRANSIT.getName(), consumer.getMessagesInTransit()) + .add(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName(), consumer.getMessagesInTransitSize()) + .add(ConsumerField.MESSAGES_DELIVERED.getName(), consumer.getMessagesDelivered()) + .add(ConsumerField.MESSAGES_DELIVERED_SIZE.getName(), consumer.getMessagesDeliveredSize()) + .add(ConsumerField.MESSAGES_ACKNOWLEDGED.getName(), consumer.getMessagesAcknowledged()) + .add(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName(), consumer.getMessagesAcknowledgedAwaitingCommit()) + .add(ConsumerField.LAST_DELIVERED_TIME.getName(), consumer.getLastDeliveredTime()) + .add(ConsumerField.LAST_ACKNOWLEDGED_TIME.getName(), consumer.getLastAcknowledgedTime()); if (consumer.getFilter() != null) { obj.add("filter", consumer.getFilter().getFilterString().toString()); } @@ -4407,14 +4426,6 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active } } - public String[] listTargetAddresses(final String sessionID) { - ServerSession session = server.getSessionByID(sessionID); - if (session != null) { - return session.getTargetAddresses(); - } - return new String[0]; - } - @Override public void onNotification(org.apache.activemq.artemis.core.server.management.Notification notification) { if (!(notification.getType() instanceof CoreNotificationType)) diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/QueueControlImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/QueueControlImpl.java index 9bced82671..5b37b6570d 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/QueueControlImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/QueueControlImpl.java @@ -36,6 +36,7 @@ import org.apache.activemq.artemis.api.core.management.QueueControl; import org.apache.activemq.artemis.api.core.management.ResourceNames; import org.apache.activemq.artemis.core.filter.Filter; import org.apache.activemq.artemis.core.filter.impl.FilterImpl; +import org.apache.activemq.artemis.core.management.impl.view.ConsumerField; import org.apache.activemq.artemis.core.messagecounter.MessageCounter; import org.apache.activemq.artemis.core.messagecounter.impl.MessageCounterHelper; import org.apache.activemq.artemis.core.persistence.StorageManager; @@ -1826,9 +1827,20 @@ public class QueueControlImpl extends AbstractControl implements QueueControl { if (consumer instanceof ServerConsumer) { ServerConsumer serverConsumer = (ServerConsumer) consumer; - - JsonObjectBuilder obj = JsonLoader.createObjectBuilder().add("consumerID", serverConsumer.getID()).add("connectionID", serverConsumer.getConnectionID().toString()).add("sessionID", serverConsumer.getSessionID()).add("browseOnly", serverConsumer.isBrowseOnly()).add("creationTime", serverConsumer.getCreationTime()); - + JsonObjectBuilder obj = JsonLoader.createObjectBuilder() + .add(ConsumerField.ID.getAlternativeName(), serverConsumer.getID()) + .add(ConsumerField.CONNECTION.getAlternativeName(), serverConsumer.getConnectionID().toString()) + .add(ConsumerField.SESSION.getAlternativeName(), serverConsumer.getSessionID()) + .add(ConsumerField.BROWSE_ONLY.getName(), serverConsumer.isBrowseOnly()) + .add(ConsumerField.CREATION_TIME.getName(), serverConsumer.getCreationTime()) + .add(ConsumerField.MESSAGES_IN_TRANSIT.getName(), serverConsumer.getMessagesInTransit()) + .add(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName(), serverConsumer.getMessagesInTransitSize()) + .add(ConsumerField.MESSAGES_DELIVERED.getName(), serverConsumer.getMessagesDelivered()) + .add(ConsumerField.MESSAGES_DELIVERED_SIZE.getName(), serverConsumer.getMessagesDeliveredSize()) + .add(ConsumerField.MESSAGES_ACKNOWLEDGED.getName(), serverConsumer.getMessagesAcknowledged()) + .add(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName(), serverConsumer.getMessagesAcknowledgedAwaitingCommit()) + .add(ConsumerField.LAST_DELIVERED_TIME.getName(), serverConsumer.getLastDeliveredTime()) + .add(ConsumerField.LAST_ACKNOWLEDGED_TIME.getName(), serverConsumer.getLastAcknowledgedTime()); jsonArray.add(obj); } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/ConsumerField.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/ConsumerField.java index c0d2cf38f4..c4066a19a5 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/ConsumerField.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/ConsumerField.java @@ -20,9 +20,10 @@ import java.util.Map; import java.util.TreeMap; public enum ConsumerField { - ID("id"), - SESSION("session"), - QUEUE("queue"), + ID("id", "consumerID"), + SESSION("session", "sessionID"), + CONNECTION("connection", "connectionID"), + QUEUE("queue", "queueName"), FILTER("filter"), ADDRESS("address"), USER("user"), @@ -32,7 +33,16 @@ public enum ConsumerField { LOCAL_ADDRESS("localAddress"), REMOTE_ADDRESS("remoteAddress"), QUEUE_TYPE("queueType"), - CREATION_TIME("creationTime"); + BROWSE_ONLY("browseOnly"), + CREATION_TIME("creationTime"), + MESSAGES_IN_TRANSIT("messagesInTransit", "deliveringCount"), + MESSAGES_IN_TRANSIT_SIZE("messagesInTransitSize"), + MESSAGES_DELIVERED("messagesDelivered"), + MESSAGES_DELIVERED_SIZE("messagesDeliveredSize"), + MESSAGES_ACKNOWLEDGED("messagesAcknowledged"), + MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT("messagesAcknowledgedAwaitingCommit"), + LAST_DELIVERED_TIME("lastDeliveredTime"), + LAST_ACKNOWLEDGED_TIME("lastAcknowledgedTime"); private static final Map lookup = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); @@ -44,12 +54,28 @@ public enum ConsumerField { private final String name; + private final String alternativeName; + public String getName() { return name; } + /** + * There is some inconsistency with some json objects returned for consumers because they were hard coded. + * This is just to track the differences and provide backward compatibility. + * @return the old alternative name + */ + public String getAlternativeName() { + return alternativeName; + } + ConsumerField(String name) { + this(name, ""); + } + + ConsumerField(String name, String alternativeName) { this.name = name; + this.alternativeName = alternativeName; } public static ConsumerField valueOfName(String name) { diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/ConsumerView.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/ConsumerView.java index 77ffb304ae..97eaf93ee2 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/ConsumerView.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/ConsumerView.java @@ -16,6 +16,7 @@ */ package org.apache.activemq.artemis.core.management.impl.view; +import org.apache.activemq.artemis.core.management.impl.ActiveMQServerControlImpl; import org.apache.activemq.artemis.json.JsonObjectBuilder; import java.util.Date; @@ -46,7 +47,7 @@ public class ConsumerView extends ActiveMQAbstractView { @Override public JsonObjectBuilder toJson(ServerConsumer consumer) { ServerSession session = server.getSessionByID(consumer.getSessionID()); - + ActiveMQServerControlImpl serverControl = server.getActiveMQServerControl(); //if session is not available then consumer is not in valid state - ignore if (session == null) { return null; @@ -71,7 +72,15 @@ public class ConsumerView extends ActiveMQAbstractView { .add(ConsumerField.ADDRESS.getName(), toString(consumer.getQueueAddress())) .add(ConsumerField.LOCAL_ADDRESS.getName(), toString(consumer.getConnectionLocalAddress())) .add(ConsumerField.REMOTE_ADDRESS.getName(), toString(consumer.getConnectionRemoteAddress())) - .add(ConsumerField.CREATION_TIME.getName(), new Date(consumer.getCreationTime()).toString()); + .add(ConsumerField.CREATION_TIME.getName(), new Date(consumer.getCreationTime()).toString()) + .add(ConsumerField.MESSAGES_IN_TRANSIT.getName(), toString(consumer.getMessagesInTransit())) + .add(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName(), toString(consumer.getMessagesInTransitSize())) + .add(ConsumerField.MESSAGES_DELIVERED.getName(), toString(consumer.getMessagesDelivered())) + .add(ConsumerField.MESSAGES_DELIVERED_SIZE.getName(), toString(consumer.getMessagesDeliveredSize())) + .add(ConsumerField.MESSAGES_ACKNOWLEDGED.getName(), toString(consumer.getMessagesAcknowledged())) + .add(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName(), toString(consumer.getMessagesAcknowledgedAwaitingCommit())) + .add(ConsumerField.LAST_DELIVERED_TIME.getName(), consumer.getLastDeliveredTime()) + .add(ConsumerField.LAST_ACKNOWLEDGED_TIME.getName(), consumer.getLastAcknowledgedTime()); return obj; } @@ -111,6 +120,22 @@ public class ConsumerView extends ActiveMQAbstractView { return consumer.getConnectionRemoteAddress(); case CREATION_TIME: return new Date(consumer.getCreationTime()); + case MESSAGES_IN_TRANSIT: + return consumer.getMessagesInTransit(); + case MESSAGES_IN_TRANSIT_SIZE: + return consumer.getMessagesInTransitSize(); + case MESSAGES_DELIVERED: + return consumer.getMessagesDelivered(); + case MESSAGES_DELIVERED_SIZE: + return consumer.getMessagesDeliveredSize(); + case MESSAGES_ACKNOWLEDGED: + return consumer.getMessagesAcknowledged(); + case MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT: + return consumer.getMessagesAcknowledgedAwaitingCommit(); + case LAST_DELIVERED_TIME: + return consumer.getLastDeliveredTime(); + case LAST_ACKNOWLEDGED_TIME: + return consumer.getLastAcknowledgedTime(); default: throw new IllegalArgumentException("Unsupported field, " + fieldName); } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/ProducerField.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/ProducerField.java index 87f9cb2ecc..075f2ccf30 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/ProducerField.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/ProducerField.java @@ -21,15 +21,20 @@ import java.util.TreeMap; public enum ProducerField { ID("id"), - SESSION("session"), + NAME("name"), + SESSION("session", "sessionID"), CONNECTION_ID("connectionID"), - ADDRESS("address"), USER("user"), + ADDRESS("address", "destination"), + USER("user"), VALIDATED_USER("validatedUser"), PROTOCOL("protocol"), CLIENT_ID("clientID"), LOCAL_ADDRESS("localAddress"), REMOTE_ADDRESS("remoteAddress"), - CREATION_TIME("creationTime"); + CREATION_TIME("creationTime"), + MESSAGE_SENT("msgSent"), + MESSAGE_SENT_SIZE("msgSizeSent"), + LAST_PRODUCED_MESSAGE_ID("lastProducedMessageID"); private static final Map lookup = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); @@ -41,12 +46,27 @@ public enum ProducerField { private final String name; + private final String alternativeName; + public String getName() { return name; } + /** + * There is some inconsistency with some json objects returned for consumers because they were hard coded. + * This is just to track the differences and provide backward compatibility. + * @return the old alternative name + */ + public String getAlternativeName() { + return alternativeName; + } + ProducerField(String name) { + this(name, ""); + } + ProducerField(String name, String alternativeName) { this.name = name; + this.alternativeName = alternativeName; } public static ProducerField valueOfName(String name) { diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/ProducerView.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/ProducerView.java index cfddf7c65d..76556f0ab6 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/ProducerView.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/ProducerView.java @@ -59,6 +59,7 @@ public class ProducerView extends ActiveMQAbstractView { JsonObjectBuilder obj = JsonLoader.createObjectBuilder() .add(ProducerField.ID.getName(), toString(producer.getID())) + .add(ProducerField.NAME.getName(), toString(producer.getName())) .add(ProducerField.SESSION.getName(), toString(session.getName())) .add(ProducerField.CLIENT_ID.getName(), toString(sessionClientID)) .add(ProducerField.USER.getName(), toString(session.getUsername())) @@ -67,7 +68,10 @@ public class ProducerView extends ActiveMQAbstractView { .add(ProducerField.ADDRESS.getName(), toString(producer.getAddress() != null ? producer.getAddress() : session.getDefaultAddress())) .add(ProducerField.LOCAL_ADDRESS.getName(), toString(session.getRemotingConnection().getTransportConnection().getLocalAddress())) .add(ProducerField.REMOTE_ADDRESS.getName(), toString(session.getRemotingConnection().getTransportConnection().getRemoteAddress())) - .add(ProducerField.CREATION_TIME.getName(), toString(producer.getCreationTime())); + .add(ProducerField.CREATION_TIME.getName(), toString(producer.getCreationTime())) + .add(ProducerField.MESSAGE_SENT.getName(), producer.getMessagesSent()) + .add(ProducerField.MESSAGE_SENT_SIZE.getName(), producer.getMessagesSentSize()) + .add(ProducerField.LAST_PRODUCED_MESSAGE_ID.getName(), toString(producer.getLastProducedMessageID())); return obj; } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/predicate/ConsumerFilterPredicate.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/predicate/ConsumerFilterPredicate.java index b42e5a473a..ceb48eeb7a 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/predicate/ConsumerFilterPredicate.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/view/predicate/ConsumerFilterPredicate.java @@ -59,6 +59,18 @@ public class ConsumerFilterPredicate extends ActiveMQFilterPredicate poolNullResponseV2; + private final IntObjectHashMap producers = new IntObjectHashMap<>(); + public ServerSessionPacketHandler(final ActiveMQServer server, final ServerSession session, final Channel channel) { @@ -323,7 +334,8 @@ public class ServerSessionPacketHandler implements ChannelHandler { case SESS_SEND_CONTINUATION: { SessionSendContinuationMessage message = (SessionSendContinuationMessage) packet; requiresResponse = message.isRequiresResponse(); - sendContinuations(message.getPacketSize(), message.getMessageBodySize(), message.getBody(), message.isContinues()); + int senderID = message.getSenderID(); + sendContinuations(message.getPacketSize(), message.getMessageBodySize(), message.getBody(), message.isContinues(), senderID); if (requiresResponse) { response = createNullResponseMessage(packet); } @@ -635,6 +647,28 @@ public class ServerSessionPacketHandler implements ChannelHandler { } break; } + case CREATE_PRODUCER: { + CreateProducerMessage message = (CreateProducerMessage) packet; + if (!producers.containsKey(message.getId())) { + // this is used to create/destroy the producer so needs to be unique + String senderName = PRODUCER_ID_PREFIX + UUIDGenerator.getInstance().generateUUID(); + producers.put(message.getId(), senderName); + session.addProducer(senderName, ActiveMQClient.DEFAULT_CORE_PROTOCOL, message.getAddress() != null ? message.getAddress().toString() : null); + } else { + ActiveMQServerLogger.LOGGER.producerAlreadyExists(message.getId(),session.getName(), remotingConnection.getRemoteAddress()); + } + break; + } + case REMOVE_PRODUCER: { + RemoveProducerMessage message = (RemoveProducerMessage) packet; + String remove = producers.remove(message.getId()); + if (remove != null) { + session.removeProducer(remove); + } else { + ActiveMQServerLogger.LOGGER.producerDoesNotExist(message.getId(), session.getName(), remotingConnection.getRemoteAddress()); + } + break; + } } } catch (ActiveMQIOErrorException e) { response = onActiveMQIOErrorExceptionWhileHandlePacket(packet, e, requiresResponse, response, this.session); @@ -747,7 +781,7 @@ public class ServerSessionPacketHandler implements ChannelHandler { try { final SessionSendMessage message = (SessionSendMessage) packet; requiresResponse = message.isRequiresResponse(); - this.session.send(EmbedMessageUtil.extractEmbedded(message.getMessage(), storageManager), this.direct); + this.session.send(EmbedMessageUtil.extractEmbedded(message.getMessage(), storageManager), this.direct, producers.get(message.getSenderID())); if (requiresResponse) { response = createNullResponseMessage(packet); } @@ -1049,7 +1083,8 @@ public class ServerSessionPacketHandler implements ChannelHandler { private void sendContinuations(final int packetSize, final long messageBodySize, final byte[] body, - final boolean continues) throws Exception { + final boolean continues, + final int senderID) throws Exception { synchronized (largeMessageLock) { if (currentLargeMessage == null) { @@ -1071,7 +1106,7 @@ public class ServerSessionPacketHandler implements ChannelHandler { LargeServerMessage message = currentLargeMessage; currentLargeMessage.setStorageManager(storageManager); currentLargeMessage = null; - session.doSend(session.getCurrentTransaction(), EmbedMessageUtil.extractEmbedded((ICoreMessage)message.toMessage(), storageManager), null, false, false); + session.doSend(session.getCurrentTransaction(), EmbedMessageUtil.extractEmbedded((ICoreMessage)message.toMessage(), storageManager), null, false, producers.get(senderID), false); } } } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/ActiveMQPacketHandler.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/ActiveMQPacketHandler.java index 64dd56d196..28c53c4602 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/ActiveMQPacketHandler.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/protocol/core/impl/ActiveMQPacketHandler.java @@ -45,9 +45,7 @@ import org.apache.activemq.artemis.core.security.ActiveMQPrincipal; import org.apache.activemq.artemis.core.server.ActiveMQMessageBundle; import org.apache.activemq.artemis.core.server.ActiveMQServer; import org.apache.activemq.artemis.core.server.ActiveMQServerLogger; -import org.apache.activemq.artemis.core.server.ServerProducer; import org.apache.activemq.artemis.core.server.ServerSession; -import org.apache.activemq.artemis.core.server.impl.ServerProducerImpl; import org.apache.activemq.artemis.core.version.Version; import org.apache.activemq.artemis.logs.AuditLogger; import org.slf4j.Logger; @@ -183,9 +181,8 @@ public class ActiveMQPacketHandler implements ChannelHandler { Map routingTypeMap = protocolManager.getPrefixes(); CoreSessionCallback sessionCallback = new CoreSessionCallback(request.getName(), protocolManager, channel, connection); - ServerSession session = server.createSession(request.getName(), activeMQPrincipal == null ? request.getUsername() : activeMQPrincipal.getUserName(), activeMQPrincipal == null ? request.getPassword() : activeMQPrincipal.getPassword(), request.getMinLargeMessageSize(), connection, request.isAutoCommitSends(), request.isAutoCommitAcks(), request.isPreAcknowledge(), request.isXA(), request.getDefaultAddress(), sessionCallback, true, sessionOperationContext, routingTypeMap, protocolManager.getSecurityDomain(), validatedUser); - ServerProducer serverProducer = new ServerProducerImpl(session.getName(), "CORE", request.getDefaultAddress()); - session.addProducer(serverProducer); + boolean isLegacyProducer = request.getVersion() < PacketImpl.ARTEMIS_2_28_0_VERSION; + ServerSession session = server.createSession(request.getName(), activeMQPrincipal == null ? request.getUsername() : activeMQPrincipal.getUserName(), activeMQPrincipal == null ? request.getPassword() : activeMQPrincipal.getPassword(), request.getMinLargeMessageSize(), connection, request.isAutoCommitSends(), request.isAutoCommitAcks(), request.isPreAcknowledge(), request.isXA(), request.getDefaultAddress(), sessionCallback, true, sessionOperationContext, routingTypeMap, protocolManager.getSecurityDomain(), validatedUser, isLegacyProducer); ServerSessionPacketHandler handler = new ServerSessionPacketHandler(server, session, channel); channel.setHandler(handler); sessionCallback.setSessionHandler(handler); diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServer.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServer.java index 2f690afa8d..97031c2df6 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServer.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServer.java @@ -349,7 +349,9 @@ public interface ActiveMQServer extends ServiceComponent { boolean autoCreateQueues, OperationContext context, Map prefixes, - String securityDomain, String validatedUser) throws Exception; + String securityDomain, + String validatedUser, + boolean isLegacyProducer) throws Exception; /** This is to be used in places where security is bypassed, like internal sessions, broker connections, etc... */ ServerSession createInternalSession(String name, @@ -364,7 +366,8 @@ public interface ActiveMQServer extends ServiceComponent { boolean autoCreateQueues, OperationContext context, Map prefixes, - String securityDomain) throws Exception; + String securityDomain, + boolean isLegacyProducer) throws Exception; /** should the server rebuild page counters upon startup. * this will be useful on testing or an embedded broker scenario */ diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java index 2b9699df52..eaec474036 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java @@ -1220,7 +1220,11 @@ public interface ActiveMQServerLogger { @LogMessage(id = 222308, value = "Unable to listen for incoming fail-back request because {} is null. Ensure the broker has the proper cluster-connection configuration.", level = LogMessage.Level.WARN) void failBackCheckerFailure(String component); + @LogMessage(id = 222309, value = "Trying to remove a producer with ID {} that doesnt exist from session {} on Connection {}.", level = LogMessage.Level.WARN) + void producerDoesNotExist(int id, String session, String remoteAddress); + @LogMessage(id = 222310, value = "Trying to add a producer with ID {} that already exists to session {} on Connection {}.", level = LogMessage.Level.WARN) + void producerAlreadyExists(int id, String session, String remoteAddress); @LogMessage(id = 224000, value = "Failure in initialisation", level = LogMessage.Level.ERROR) void initializationError(Throwable e); diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ConsumerInfo.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ConsumerInfo.java index 23642565b4..3ac36b3ef7 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ConsumerInfo.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ConsumerInfo.java @@ -62,4 +62,51 @@ public interface ConsumerInfo { */ String getConnectionRemoteAddress(); + /** + * Returns how many messages are out for delivery but not yet acknowledged + * @return delivering count + */ + int getMessagesInTransit(); + + /** + * Returns the combined size of all the messages out for delivery but not yet acknowledged + * @return the total size of all the messages + */ + long getMessagesInTransitSize(); + + /** + * Returns The total number of messages sent to a consumer including redeliveries that have been acknowledged + * @return the total number of messages delivered. + */ + long getMessagesDelivered(); + + /** + * Returns the total size of all the messages delivered to the consumer. This includes redelivered messages + * @return The total size of all the messages + */ + long getMessagesDeliveredSize(); + + /** + * Returns the number of messages acknowledged by this consumer since it was created + * @return messages acknowledged + */ + long getMessagesAcknowledged(); + + /** + * Returns the number of acknowledged messages that are awaiting commit in a transaction + * @return th eno acknowledgements awaiting commit + */ + int getMessagesAcknowledgedAwaitingCommit(); + + /** + * Returns the time in milliseconds that the last message was delivered to a consumer + * @return the time of the last message delivered + */ + long getLastDeliveredTime(); + + /** + * Returns the time in milliseconds that the last message was acknowledged by a consumer + * @return the time of the last message was acknowledged + */ + long getLastAcknowledgedTime(); } \ No newline at end of file diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ServerConsumer.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ServerConsumer.java index e743c0401c..646df6a787 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ServerConsumer.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ServerConsumer.java @@ -110,4 +110,11 @@ public interface ServerConsumer extends Consumer, ConsumerInfo { long getCreationTime(); String getSessionID(); + + /** + * This is needed when some protocols (OW) handle the acks themselves and need to update the metrics + * @param ref the message reference + * @param transaction the tx + */ + void metricsAcknowledge(MessageReference ref, Transaction transaction); } \ No newline at end of file diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ServerProducer.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ServerProducer.java index 97f8fe52d4..64abf8eed7 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ServerProducer.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ServerProducer.java @@ -17,7 +17,12 @@ package org.apache.activemq.artemis.core.server; public interface ServerProducer { - String getAddress(); + String ANONYMOUS = "ANONYMOUS"; + + long getID(); + + String getName(); + String getAddress();; String getProtocol(); @@ -29,7 +34,14 @@ public interface ServerProducer { String getConnectionID(); - String getID(); long getCreationTime(); + + Object getLastProducedMessageID(); + + long getMessagesSent(); + + long getMessagesSentSize(); + + void updateMetrics(Object lastProducedMessageID, int encodeSize); } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ServerSession.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ServerSession.java index f238a4925d..2d880f1ec8 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ServerSession.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ServerSession.java @@ -18,6 +18,7 @@ package org.apache.activemq.artemis.core.server; import org.apache.activemq.artemis.json.JsonArrayBuilder; import javax.transaction.xa.Xid; +import java.util.Collection; import java.util.EnumSet; import java.util.List; import java.util.Map; @@ -332,11 +333,13 @@ public interface ServerSession extends SecurityAuth { RoutingStatus send(Transaction tx, Message message, boolean direct, + String senderName, boolean noAutoCreateQueue) throws Exception; RoutingStatus send(Transaction tx, Message message, boolean direct, + String senderName, boolean noAutoCreateQueue, RoutingContext routingContext) throws Exception; @@ -345,18 +348,20 @@ public interface ServerSession extends SecurityAuth { Message msg, SimpleString originalAddress, boolean direct, + String senderName, boolean noAutoCreateQueue) throws Exception; RoutingStatus doSend(Transaction tx, Message msg, SimpleString originalAddress, boolean direct, + String senderName, boolean noAutoCreateQueue, RoutingContext routingContext) throws Exception; - RoutingStatus send(Message message, boolean direct, boolean noAutoCreateQueue) throws Exception; + RoutingStatus send(Message message, boolean direct, String senderName, boolean noAutoCreateQueue) throws Exception; - RoutingStatus send(Message message, boolean direct) throws Exception; + RoutingStatus send(Message message, boolean direct, String senderName) throws Exception; void forceConsumerDelivery(long consumerID, long sequence) throws Exception; @@ -376,8 +381,6 @@ public interface ServerSession extends SecurityAuth { Map getMetaData(); - String[] getTargetAddresses(); - /** * Add all the producers detail to the JSONArray object. * This is a method to be used by the management layer. @@ -387,7 +390,6 @@ public interface ServerSession extends SecurityAuth { */ void describeProducersInfo(JsonArrayBuilder objs) throws Exception; - String getLastSentMessageID(String address); long getCreationTime(); @@ -522,11 +524,11 @@ public interface ServerSession extends SecurityAuth { Pair> getAddressAndRoutingTypes(SimpleString address, EnumSet defaultRoutingTypes); - void addProducer(ServerProducer serverProducer); + void addProducer(String name, String protocol, String address); void removeProducer(String ID); - Map getServerProducers(); + Collection getServerProducers(); String getDefaultAddress(); diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java index 9e122d670e..2a313ce4a2 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java @@ -1746,7 +1746,8 @@ public class ActiveMQServerImpl implements ActiveMQServer { final OperationContext context, final Map prefixes, final String securityDomain, - String validatedUser) throws Exception { + String validatedUser, + boolean isLegacyProducer) throws Exception { if (validatedUser == null) { validatedUser = validateUser(username, password, connection, securityDomain); } @@ -1758,7 +1759,7 @@ public class ActiveMQServerImpl implements ActiveMQServer { autoCommitAcks, preAcknowledge, xa, defaultAddress, callback, autoCreateQueues, prefixes); } - final ServerSessionImpl session = internalCreateSession(name, username, password, validatedUser, minLargeMessageSize, connection, autoCommitSends, autoCommitAcks, preAcknowledge, xa, defaultAddress, callback, context, autoCreateQueues, prefixes, securityDomain); + final ServerSessionImpl session = internalCreateSession(name, username, password, validatedUser, minLargeMessageSize, connection, autoCommitSends, autoCommitAcks, preAcknowledge, xa, defaultAddress, callback, context, autoCreateQueues, prefixes, securityDomain, isLegacyProducer); return session; } @@ -1786,8 +1787,9 @@ public class ActiveMQServerImpl implements ActiveMQServer { boolean autoCreateQueues, OperationContext context, Map prefixes, - String securityDomain) throws Exception { - ServerSessionImpl session = internalCreateSession(name, null, null, null, minLargeMessageSize, connection, autoCommitSends, autoCommitAcks, preAcknowledge, xa, defaultAddress, callback, context, autoCreateQueues, prefixes, securityDomain); + String securityDomain, + boolean isLegacyProducer) throws Exception { + ServerSessionImpl session = internalCreateSession(name, null, null, null, minLargeMessageSize, connection, autoCommitSends, autoCommitAcks, preAcknowledge, xa, defaultAddress, callback, context, autoCreateQueues, prefixes, securityDomain, isLegacyProducer); session.disableSecurity(); return session; } @@ -1864,14 +1866,15 @@ public class ActiveMQServerImpl implements ActiveMQServer { OperationContext context, boolean autoCreateQueues, Map prefixes, - String securityDomain) throws Exception { + String securityDomain, + boolean isLegacyProducer) throws Exception { if (hasBrokerSessionPlugins()) { callBrokerSessionPlugins(plugin -> plugin.beforeCreateSession(name, username, minLargeMessageSize, connection, autoCommitSends, autoCommitAcks, preAcknowledge, xa, defaultAddress, callback, autoCreateQueues, context, prefixes)); } - ServerSessionImpl session = 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, prefixes, securityDomain); + ServerSessionImpl session = 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, prefixes, securityDomain, isLegacyProducer); sessions.put(name, session); diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerConsumerImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerConsumerImpl.java index e8ed25652b..d75a939336 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerConsumerImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerConsumerImpl.java @@ -26,7 +26,9 @@ import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicLongFieldUpdater; import java.util.function.Function; import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; @@ -61,6 +63,8 @@ import org.apache.activemq.artemis.core.server.SlowConsumerDetectionListener; import org.apache.activemq.artemis.core.server.management.ManagementService; import org.apache.activemq.artemis.core.server.management.Notification; import org.apache.activemq.artemis.core.transaction.Transaction; +import org.apache.activemq.artemis.core.transaction.TransactionOperationAbstract; +import org.apache.activemq.artemis.core.transaction.TransactionPropertyIndexes; import org.apache.activemq.artemis.core.transaction.impl.TransactionImpl; import org.apache.activemq.artemis.logs.AuditLogger; import org.apache.activemq.artemis.spi.core.protocol.SessionCallback; @@ -153,14 +157,14 @@ public class ServerConsumerImpl implements ServerConsumer, ReadyListener { private AtomicLong messageConsumedSnapshot = new AtomicLong(0); - private long acks; - private boolean requiresLegacyPrefix = false; private boolean anycast = false; private boolean isClosed = false; + ServerConsumerMetrics metrics = new ServerConsumerMetrics(); + public ServerConsumerImpl(final long id, final ServerSession session, @@ -355,6 +359,11 @@ public class ServerConsumerImpl implements ServerConsumer, ReadyListener { return this.session.getName(); } + @Override + public void metricsAcknowledge(MessageReference ref, Transaction transaction) { + metrics.addAcknowledge(ref.getMessage().getEncodeSize(), transaction); + } + @Override public List getDeliveringMessages() { synchronized (lock) { @@ -441,6 +450,8 @@ public class ServerConsumerImpl implements ServerConsumer, ReadyListener { deliveringRefs.add(ref); } + metrics.addMessage(ref.getMessage().getEncodeSize()); + ref.handled(); ref.setConsumerId(this.id); @@ -466,7 +477,7 @@ public class ServerConsumerImpl implements ServerConsumer, ReadyListener { if (preAcknowledge) { // With pre-ack, we ack *before* sending to the client ref.getQueue().acknowledge(ref, this); - acks++; + metrics.addAcknowledge(ref.getMessage().getEncodeSize(), null); } } @@ -704,9 +715,9 @@ public class ServerConsumerImpl implements ServerConsumer, ReadyListener { final List refs = new ArrayList<>(deliveringRefs.size()); MessageReference ref; while ((ref = deliveringRefs.poll()) != null) { + metrics.addAcknowledge(ref.getMessage().getEncodeSize(), tx); if (performACK) { ref.acknowledge(tx, this); - performACK = false; } else { refs.add(ref); @@ -911,8 +922,7 @@ public class ServerConsumerImpl implements ServerConsumer, ReadyListener { ref.acknowledge(tx, this); ackedRefs.add(ref.getMessageID()); - - acks++; + metrics.addAcknowledge(ref.getMessage().getEncodeSize(), tx); } while (ref.getMessageID() != messageID); @@ -973,11 +983,9 @@ public class ServerConsumerImpl implements ServerConsumer, ReadyListener { tx.markAsRollbackOnly(ils); throw ils; } - + metrics.addAcknowledge(ref.getMessage().getEncodeSize(), tx); ref.acknowledge(tx, this); - acks++; - if (startedTransaction) { tx.commit(); } @@ -1016,7 +1024,7 @@ public class ServerConsumerImpl implements ServerConsumer, ReadyListener { if (!failed) { ref.decrementDeliveryCount(); } - + metrics.addAcknowledge(ref.getMessage().getEncodeSize(), null); ref.getQueue().cancel(ref, System.currentTimeMillis()); } @@ -1032,7 +1040,7 @@ public class ServerConsumerImpl implements ServerConsumer, ReadyListener { if (ref == null) { return; // nothing to be done } - + metrics.addAcknowledge(ref.getMessage().getEncodeSize(), null); ref.getQueue().sendToDeadLetterAddress(null, ref); } @@ -1040,6 +1048,7 @@ public class ServerConsumerImpl implements ServerConsumer, ReadyListener { public synchronized void backToDelivering(MessageReference reference) { synchronized (lock) { deliveringRefs.addFirst(reference); + metrics.addMessage(reference.getMessage().getEncodeSize()); } } @@ -1059,10 +1068,12 @@ public class ServerConsumerImpl implements ServerConsumer, ReadyListener { } if (deliveringRefs.peek().getMessage().getMessageID() == messageID) { - return deliveringRefs.poll(); + MessageReference ref = deliveringRefs.poll(); + return ref; } //slow path in a separate method - return removeDeliveringRefById(messageID); + MessageReference ref = removeDeliveringRefById(messageID); + return ref; } } @@ -1114,6 +1125,7 @@ public class ServerConsumerImpl implements ServerConsumer, ReadyListener { public float getRate() { float timeSlice = ((System.currentTimeMillis() - consumerRateCheckTime.getAndSet(System.currentTimeMillis())) / 1000.0f); + long acks = metrics.getMessagesAcknowledged(); if (timeSlice == 0) { messageConsumedSnapshot.getAndSet(acks); return 0.0f; @@ -1513,7 +1525,143 @@ public class ServerConsumerImpl implements ServerConsumer, ReadyListener { return this.session.getRemotingConnection().getTransportConnection().getRemoteAddress(); } + @Override + public long getMessagesInTransitSize() { + return metrics.getMessagesInTransitSize(); + } + + @Override + public int getMessagesInTransit() { + return deliveringRefs.size(); + } + + @Override + public long getLastDeliveredTime() { + return metrics.getLastDeliveredTime(); + } + + @Override + public long getLastAcknowledgedTime() { + return metrics.getLastAcknowledgedTime(); + } + + @Override + public long getMessagesAcknowledged() { + return metrics.getMessagesAcknowledged(); + } + + @Override + public long getMessagesDeliveredSize() { + return metrics.getMessagesDeliveredSize(); + } + + @Override + public long getMessagesDelivered() { + return metrics.getMessagesDelivered(); + } + + @Override + public int getMessagesAcknowledgedAwaitingCommit() { + return metrics.getMessagesAcknowledgedAwaitingCommit(); + } + public SessionCallback getCallback() { return callback; } + + static class ServerConsumerMetrics extends TransactionOperationAbstract { + + /** + * Since messages can be delivered (incremented) and acknowledged (decremented) at the same time we have to protect + * the encode size and make it atomic. The other fields are ok since they are only accessed from a single thread. + */ + private static final AtomicLongFieldUpdater messagesInTransitSizeUpdater = AtomicLongFieldUpdater.newUpdater(ServerConsumerMetrics.class, "messagesInTransitSize"); + + private volatile long messagesInTransitSize = 0; + + private static final AtomicIntegerFieldUpdater messagesAcknowledgedAwaitingCommitUpdater = AtomicIntegerFieldUpdater.newUpdater(ServerConsumerMetrics.class, "messagesAcknowledgedAwaitingCommit"); + + private volatile int messagesAcknowledgedAwaitingCommit = 0; + + private static final AtomicLongFieldUpdatermessagesDeliveredSizeUpdater = AtomicLongFieldUpdater.newUpdater(ServerConsumerMetrics.class, "messagesDeliveredSize"); + + private volatile long messagesDeliveredSize = 0; + + private volatile long lastDeliveredTime = 0; + + private volatile long lastAcknowledgedTime = 0; + + private static final AtomicLongFieldUpdatermessagesDeliveredUpdater = AtomicLongFieldUpdater.newUpdater(ServerConsumerMetrics.class, "messagesDelivered"); + + private volatile long messagesDelivered = 0; + + private static final AtomicLongFieldUpdater messagesAcknowledgedUpdater = AtomicLongFieldUpdater.newUpdater(ServerConsumerMetrics.class, "messagesAcknowledged"); + + private volatile long messagesAcknowledged = 0; + + + public long getMessagesInTransitSize() { + return messagesInTransitSizeUpdater.get(this); + } + + public long getMessagesDeliveredSize() { + return messagesDeliveredSizeUpdater.get(this); + } + + public long getLastDeliveredTime() { + return lastDeliveredTime; + } + + public long getLastAcknowledgedTime() { + return lastAcknowledgedTime; + } + + public long getMessagesDelivered() { + return messagesDeliveredUpdater.get(this); + } + + public long getMessagesAcknowledged() { + return messagesAcknowledgedUpdater.get(this); + } + + public int getMessagesAcknowledgedAwaitingCommit() { + return messagesAcknowledgedAwaitingCommitUpdater.get(this); + } + + public void addMessage(int encodeSize) { + messagesInTransitSizeUpdater.addAndGet(this, encodeSize); + messagesDeliveredSizeUpdater.addAndGet(this, encodeSize); + messagesDeliveredUpdater.addAndGet(this, 1); + lastDeliveredTime = System.currentTimeMillis(); + } + + public void addAcknowledge(int encodeSize, Transaction tx) { + messagesInTransitSizeUpdater.addAndGet(this, -encodeSize); + messagesAcknowledgedUpdater.addAndGet(this, 1); + lastAcknowledgedTime = System.currentTimeMillis(); + if (tx != null) { + addOperation(tx); + messagesAcknowledgedAwaitingCommitUpdater.addAndGet(this, 1); + } + } + + @Override + public void afterCommit(Transaction tx) { + messagesAcknowledgedAwaitingCommitUpdater.set(this, 0); + } + + + @Override + public void afterRollback(Transaction tx) { + messagesAcknowledgedAwaitingCommitUpdater.set(this, 0); + } + + public void addOperation(Transaction tx) { + Object property = tx.getProperty(TransactionPropertyIndexes.CONSUMER_METRICS_OPERATION); + if (property == null) { + tx.putProperty(TransactionPropertyIndexes.CONSUMER_METRICS_OPERATION, this); + tx.addOperation(this); + } + } + } } \ No newline at end of file diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerLegacyProducersImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerLegacyProducersImpl.java new file mode 100644 index 0000000000..e1ab46561a --- /dev/null +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerLegacyProducersImpl.java @@ -0,0 +1,83 @@ +/* + * 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.impl; + +import org.apache.activemq.artemis.api.core.Message; +import org.apache.activemq.artemis.core.server.ServerProducer; +import org.apache.activemq.artemis.core.server.ServerSession; +import org.apache.activemq.artemis.utils.collections.MaxSizeMap; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class ServerLegacyProducersImpl implements ServerProducers { + + private static final int MAX_PRODUCER_METRIC_SIZE = 100; + + protected final Map producers = Collections.synchronizedMap(new MaxSizeMap<>(MAX_PRODUCER_METRIC_SIZE)); + private final String sessionName; + + private final String connectionID; + + public ServerLegacyProducersImpl(ServerSession session) { + this.sessionName = session.getName(); + this.connectionID = session.getConnectionID() != null ? session.getConnectionID().toString() : null; + } + + @Override + public Map cloneProducers() { + return new HashMap<>(producers); + } + + @Override + public Collection getServerProducers() { + return new ArrayList<>(producers.values()); + } + + @Override + public ServerProducer getServerProducer(String senderName, Message msg, ServerSessionImpl serverSession) { + String address = msg.getAddress(); + String name = sessionName + ":" + address; + ServerProducer producer = producers.get(name); + if (producer == null) { + producer = new ServerProducerImpl(name, "CORE", address); + producer.setSessionID(sessionName); + producer.setConnectionID(connectionID); + producers.put(name, producer); + } + return producer; + } + + @Override + public void put(String id, ServerProducer producer) { + //never called as we track by address the old way + } + + @Override + public void remove(String id) { + //never called as we track by address the old way + } + + @Override + public void clear() { + producers.clear(); + } + +} diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerProducerImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerProducerImpl.java index bc0f910484..cb7eef011d 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerProducerImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerProducerImpl.java @@ -18,23 +18,50 @@ package org.apache.activemq.artemis.core.server.impl; import org.apache.activemq.artemis.core.server.ServerProducer; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicLongFieldUpdater; + public class ServerProducerImpl implements ServerProducer { - private final String ID; + + private static final AtomicLong PRODUCER_ID_GENERATOR = new AtomicLong(); + + private final long ID; + private final String name; private final String protocol; private final long creationTime; + private volatile long messagesSent = 0; + private volatile long messagesSentSize = 0; + private static final AtomicLongFieldUpdater messagesSentUpdater = AtomicLongFieldUpdater.newUpdater(ServerProducerImpl.class, "messagesSent"); + + private static final AtomicLongFieldUpdater messagesSentSizeUpdater = AtomicLongFieldUpdater.newUpdater(ServerProducerImpl.class, "messagesSentSize"); private final String address; + + private volatile Object lastProducedMessageID; + private String sessionID; + private String connectionID; - public ServerProducerImpl(String ID, String protocol, String address) { - this.ID = ID; + public ServerProducerImpl(String name, String protocol, String address) { + this.ID = PRODUCER_ID_GENERATOR.incrementAndGet(); + this.name = name; this.protocol = protocol; this.address = address; this.creationTime = System.currentTimeMillis(); } + @Override + public long getID() { + return ID; + } + + @Override + public String getName() { + return name; + } + @Override public String getAddress() { return address; @@ -52,7 +79,6 @@ public class ServerProducerImpl implements ServerProducer { @Override public void setConnectionID(String connectionID) { - this.connectionID = connectionID; } @@ -66,13 +92,30 @@ public class ServerProducerImpl implements ServerProducer { return connectionID; } - @Override - public String getID() { - return ID; - } - @Override public long getCreationTime() { return creationTime; } + + @Override + public void updateMetrics(Object lastProducedMessageID, int encodeSize) { + messagesSentUpdater.addAndGet(this, 1); + messagesSentSizeUpdater.getAndAdd(this, encodeSize); + this.lastProducedMessageID = lastProducedMessageID; + } + + @Override + public Object getLastProducedMessageID() { + return lastProducedMessageID; + } + + @Override + public long getMessagesSent() { + return messagesSent; + } + + @Override + public long getMessagesSentSize() { + return messagesSentSize; + } } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerProducers.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerProducers.java new file mode 100644 index 0000000000..99f79010fc --- /dev/null +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerProducers.java @@ -0,0 +1,37 @@ +/* + * 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.impl; + +import org.apache.activemq.artemis.api.core.Message; +import org.apache.activemq.artemis.core.server.ServerProducer; + +import java.util.Collection; +import java.util.Map; + +public interface ServerProducers { + Map cloneProducers(); + + Collection getServerProducers(); + + ServerProducer getServerProducer(String senderName, Message msg, ServerSessionImpl serverSession); + + void put(String id, ServerProducer producer); + + void remove(String id); + + void clear(); +} diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerProducersImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerProducersImpl.java new file mode 100644 index 0000000000..ca8561e326 --- /dev/null +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerProducersImpl.java @@ -0,0 +1,63 @@ +/* + * 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.impl; + +import org.apache.activemq.artemis.api.core.Message; +import org.apache.activemq.artemis.core.server.ServerProducer; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class ServerProducersImpl implements ServerProducers { + protected final Map producers = new ConcurrentHashMap<>(); + + @Override + public Map cloneProducers() { + return new HashMap<>(producers); + } + + @Override + public Collection getServerProducers() { + return new ArrayList<>(producers.values()); + } + + @Override + public ServerProducer getServerProducer(String senderName, Message msg, ServerSessionImpl serverSession) { + if (senderName != null) { + return producers.get(senderName); + } + return null; + } + + @Override + public void put(String id, ServerProducer producer) { + producers.put(id, producer); + } + + @Override + public void remove(String id) { + producers.remove(id); + } + + @Override + public void clear() { + producers.clear(); + } +} diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerSessionImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerSessionImpl.java index af27a0e8ad..ce02f88e2f 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerSessionImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerSessionImpl.java @@ -16,6 +16,7 @@ */ package org.apache.activemq.artemis.core.server.impl; +import org.apache.activemq.artemis.core.management.impl.view.ProducerField; import org.apache.activemq.artemis.api.core.ActiveMQAddressExistsException; import org.apache.activemq.artemis.api.core.ActiveMQQueueExistsException; import org.apache.activemq.artemis.core.postoffice.Bindings; @@ -25,17 +26,16 @@ import java.security.cert.X509Certificate; import javax.transaction.xa.XAException; import javax.transaction.xa.Xid; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicLong; import org.apache.activemq.artemis.Closeable; import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; @@ -102,7 +102,6 @@ import org.apache.activemq.artemis.utils.ByteUtil; import org.apache.activemq.artemis.utils.CompositeAddress; import org.apache.activemq.artemis.utils.JsonLoader; import org.apache.activemq.artemis.utils.PrefixUtil; -import org.apache.activemq.artemis.utils.collections.MaxSizeMap; import org.apache.activemq.artemis.utils.collections.TypedProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -115,7 +114,6 @@ public class ServerSessionImpl implements ServerSession, FailureListener { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - private boolean securityEnabled = true; private final String securityDomain; @@ -140,7 +138,7 @@ public class ServerSessionImpl implements ServerSession, FailureListener { protected final Map consumers = new ConcurrentHashMap<>(); - protected final Map producers = new ConcurrentHashMap<>(); + protected final ServerProducers serverProducers; protected Transaction tx; @@ -184,9 +182,6 @@ public class ServerSessionImpl implements ServerSession, FailureListener { private final OperationContext context; - // Session's usage should be by definition single threaded, hence it's not needed to use a concurrentHashMap here - protected final Map> targetAddressInfos = new MaxSizeMap<>(100); - private final long creationTime = System.currentTimeMillis(); // to prevent session from being closed twice. @@ -228,7 +223,8 @@ public class ServerSessionImpl implements ServerSession, FailureListener { final OperationContext context, final PagingManager pagingManager, final Map prefixes, - final String securityDomain) throws Exception { + final String securityDomain, + boolean isLegacyProducer) throws Exception { this.username = username; this.password = password; @@ -289,6 +285,11 @@ public class ServerSessionImpl implements ServerSession, FailureListener { sendSessionNotification(CoreNotificationType.SESSION_CREATED); this.securityDomain = securityDomain; + if (isLegacyProducer) { + serverProducers = new ServerLegacyProducersImpl(this); + } else { + serverProducers = new ServerProducersImpl(); + } } // ServerSession implementation --------------------------------------------------------------------------- @@ -450,7 +451,7 @@ public class ServerSessionImpl implements ServerSession, FailureListener { } consumers.clear(); - producers.clear(); + serverProducers.clear(); if (closeables != null) { for (Closeable closeable : closeables) { @@ -1186,10 +1187,6 @@ public class ServerSessionImpl implements ServerSession, FailureListener { remotingConnection.removeFailureListener(cleaner); } - - if (server.getAddressInfo(unPrefixedQueueName) == null) { - targetAddressInfos.remove(queueToDelete); - } } @Override @@ -1790,29 +1787,32 @@ public class ServerSessionImpl implements ServerSession, FailureListener { @Override - public RoutingStatus send(final Message message, final boolean direct) throws Exception { - return send(message, direct, false); + public RoutingStatus send(final Message message, final boolean direct, final String senderName) throws Exception { + return send(message, direct, senderName,false); } @Override public RoutingStatus send(final Message message, final boolean direct, + final String senderName, boolean noAutoCreateQueue) throws Exception { - return send(getCurrentTransaction(), message, direct, noAutoCreateQueue); + return send(getCurrentTransaction(), message, direct, senderName, noAutoCreateQueue); } @Override public synchronized RoutingStatus send(Transaction tx, Message msg, final boolean direct, + final String senderName, boolean noAutoCreateQueue) throws Exception { - return send(tx, msg, direct, noAutoCreateQueue, routingContext); + return send(tx, msg, direct, senderName, noAutoCreateQueue, routingContext); } @Override public synchronized RoutingStatus send(Transaction tx, Message messageParameter, final boolean direct, + final String senderName, boolean noAutoCreateQueue, RoutingContext routingContext) throws Exception { final Message message = LargeServerMessageImpl.checkLargeMessage(messageParameter, storageManager); @@ -1865,7 +1865,7 @@ public class ServerSessionImpl implements ServerSession, FailureListener { result = handleManagementMessage(tx, message, direct); } else { - result = doSend(tx, message, address, direct, noAutoCreateQueue, routingContext); + result = doSend(tx, message, address, direct, senderName, noAutoCreateQueue, routingContext); } if (AuditLogger.isMessageLoggingEnabled()) { @@ -1975,30 +1975,6 @@ public class ServerSessionImpl implements ServerSession, FailureListener { return metaData; } - @Override - public String[] getTargetAddresses() { - Map> copy = cloneTargetAddresses(); - Iterator iter = copy.keySet().iterator(); - int num = copy.keySet().size(); - String[] addresses = new String[num]; - int i = 0; - while (iter.hasNext()) { - addresses[i] = iter.next().toString(); - i++; - } - return addresses; - } - - @Override - public String getLastSentMessageID(String address) { - Pair value = targetAddressInfos.get(SimpleString.toSimpleString(address)); - if (value != null) { - return value.getA().toString(); - } else { - return null; - } - } - @Override public long getCreationTime() { return this.creationTime; @@ -2010,14 +1986,22 @@ public class ServerSessionImpl implements ServerSession, FailureListener { @Override public void describeProducersInfo(JsonArrayBuilder array) throws Exception { - Map> targetCopy = cloneTargetAddresses(); - - for (Map.Entry> entry : targetCopy.entrySet()) { + Map targetCopy = cloneProducers(); + for (Map.Entry entry : targetCopy.entrySet()) { String uuid = null; - if (entry.getValue().getA() != null) { - uuid = entry.getValue().getA().toString(); + if (entry.getValue().getLastProducedMessageID() != null) { + uuid = entry.getValue().getLastProducedMessageID().toString(); } - JsonObjectBuilder producerInfo = JsonLoader.createObjectBuilder().add("connectionID", this.getConnectionID().toString()).add("sessionID", this.getName()).add("destination", entry.getKey().toString()).add("lastUUIDSent", uuid, JsonValue.NULL).add("msgSent", entry.getValue().getB().longValue()); + JsonObjectBuilder producerInfo = JsonLoader.createObjectBuilder() + .add(ProducerField.ID.getName(), String.valueOf(entry.getValue().getID())) + .add(ProducerField.NAME.getName(), entry.getValue().getName()) + .add(ProducerField.CONNECTION_ID.getName(), this.getConnectionID().toString()) + .add(ProducerField.SESSION.getAlternativeName(), this.getName()) + .add(ProducerField.CREATION_TIME.getName(), String.valueOf(entry.getValue().getCreationTime())) + .add(ProducerField.ADDRESS.getAlternativeName(), entry.getValue().getAddress()) + .add(ProducerField.LAST_PRODUCED_MESSAGE_ID.getName(), uuid, JsonValue.NULL) + .add(ProducerField.MESSAGE_SENT.getName(), entry.getValue().getMessagesSent()) + .add(ProducerField.MESSAGE_SENT_SIZE.getName(), entry.getValue().getMessagesSentSize()); array.add(producerInfo); } } @@ -2098,8 +2082,8 @@ public class ServerSessionImpl implements ServerSession, FailureListener { connectionFailed(me, failedOver); } - public Map> cloneTargetAddresses() { - return new HashMap<>(targetAddressInfos); + public Map cloneProducers() { + return serverProducers.cloneProducers(); } private void setStarted(final boolean s) { @@ -2140,7 +2124,7 @@ public class ServerSessionImpl implements ServerSession, FailureListener { } reply.setAddress(replyTo); - doSend(tx, reply, null, direct, false, routingContext); + doSend(tx, reply, null, direct, null, false, routingContext); } return RoutingStatus.OK; } @@ -2202,8 +2186,9 @@ public class ServerSessionImpl implements ServerSession, FailureListener { final Message msg, final SimpleString originalAddress, final boolean direct, + final String senderName, final boolean noAutoCreateQueue) throws Exception { - return doSend(tx, msg, originalAddress, direct, noAutoCreateQueue, routingContext); + return doSend(tx, msg, originalAddress, direct, senderName, noAutoCreateQueue, routingContext); } @@ -2212,6 +2197,7 @@ public class ServerSessionImpl implements ServerSession, FailureListener { final Message msg, final SimpleString originalAddress, final boolean direct, + final String senderName, final boolean noAutoCreateQueue, final RoutingContext routingContext) throws Exception { @@ -2272,14 +2258,7 @@ public class ServerSessionImpl implements ServerSession, FailureListener { logger.debug("Routing result for {} = {}", msg, result); - Pair value = targetAddressInfos.get(msg.getAddressSimpleString()); - - if (value == null) { - targetAddressInfos.put(msg.getAddressSimpleString(), new Pair<>(msg.getUserID(), new AtomicLong(1))); - } else { - value.setA(msg.getUserID()); - value.getB().incrementAndGet(); - } + updateProducerMetrics(msg, senderName); } finally { if (!routingContext.isReusable()) { routingContext.clear(); @@ -2395,20 +2374,21 @@ public class ServerSessionImpl implements ServerSession, FailureListener { } @Override - public void addProducer(ServerProducer serverProducer) { - serverProducer.setSessionID(getName()); - serverProducer.setConnectionID(getConnectionID().toString()); - producers.put(serverProducer.getID(), serverProducer); + public void addProducer(String name, String protocol, String address) { + ServerProducer producer = new ServerProducerImpl(name, protocol, address != null ? address : ServerProducer.ANONYMOUS); + producer.setSessionID(getName()); + producer.setConnectionID(getConnectionID() != null ? getConnectionID().toString() : null); + serverProducers.put(name, producer); } @Override public void removeProducer(String ID) { - producers.remove(ID); + serverProducers.remove(ID); } @Override - public Map getServerProducers() { - return Collections.unmodifiableMap(new HashMap(producers)); + public Collection getServerProducers() { + return serverProducers.getServerProducers(); } @Override @@ -2436,4 +2416,13 @@ public class ServerSessionImpl implements ServerSession, FailureListener { public String toManagementString() { return "ServerSession [id=" + getConnectionID() + ":" + getName() + "]"; } + + private void updateProducerMetrics(Message msg, String senderName) { + ServerProducer serverProducer = serverProducers.getServerProducer(senderName, msg, this); + if (serverProducer != null) { + serverProducer.updateMetrics(msg.getUserID(), msg instanceof LargeServerMessageImpl ? ((LargeServerMessageImpl)msg).getBodyBufferSize() : msg.getEncodeSize()); + } + } + + } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/transaction/TransactionPropertyIndexes.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/transaction/TransactionPropertyIndexes.java index 4ba31eeb47..d6c332a6b5 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/transaction/TransactionPropertyIndexes.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/transaction/TransactionPropertyIndexes.java @@ -35,4 +35,6 @@ public class TransactionPropertyIndexes { public static final int PAGE_CURSOR_POSITIONS = 8; public static final int EXPIRY_LOGGER = 9; + + public static final int CONSUMER_METRICS_OPERATION = 10; } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/transaction/impl/TransactionImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/transaction/impl/TransactionImpl.java index 27acad2130..13ee0ba73e 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/transaction/impl/TransactionImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/transaction/impl/TransactionImpl.java @@ -48,7 +48,7 @@ public class TransactionImpl implements Transaction { private List storeOperations; - private static final int INITIAL_NUM_PROPERTIES = 10; + private static final int INITIAL_NUM_PROPERTIES = 11; private Object[] properties = null; diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/tests/util/ActiveMQTestBase.java b/artemis-server/src/test/java/org/apache/activemq/artemis/tests/util/ActiveMQTestBase.java index fb04c2b2a4..db80b028ab 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/tests/util/ActiveMQTestBase.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/tests/util/ActiveMQTestBase.java @@ -65,6 +65,7 @@ import org.apache.activemq.artemis.api.core.ActiveMQBuffer; import org.apache.activemq.artemis.api.core.ActiveMQException; import org.apache.activemq.artemis.api.core.ActiveMQExceptionType; import org.apache.activemq.artemis.api.core.ICoreMessage; +import org.apache.activemq.artemis.api.core.JsonUtil; import org.apache.activemq.artemis.api.core.Message; import org.apache.activemq.artemis.api.core.Pair; import org.apache.activemq.artemis.api.core.QueueConfiguration; @@ -136,6 +137,7 @@ import org.apache.activemq.artemis.core.settings.impl.AddressSettings; import org.apache.activemq.artemis.core.transaction.impl.XidImpl; import org.apache.activemq.artemis.jdbc.store.drivers.JDBCUtils; import org.apache.activemq.artemis.jdbc.store.sql.SQLProvider; +import org.apache.activemq.artemis.json.JsonObject; import org.apache.activemq.artemis.nativo.jlibaio.LibaioContext; import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager; import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager; @@ -2627,6 +2629,15 @@ public abstract class ActiveMQTestBase extends Assert { return !hadToInterrupt; } + public String createJsonFilter(String fieldName, String operationName, String value) { + HashMap filterMap = new HashMap<>(); + filterMap.put("field", fieldName); + filterMap.put("operation", operationName); + filterMap.put("value", value); + JsonObject jsonFilterObject = JsonUtil.toJsonObject(filterMap); + return jsonFilterObject.toString(); + } + protected static ReplicationEndpoint getReplicationEndpoint(ActiveMQServer server) { final Activation activation = server.getActivation(); if (activation instanceof SharedNothingBackupActivation) { diff --git a/pom.xml b/pom.xml index ae419584e9..340bf92dca 100644 --- a/pom.xml +++ b/pom.xml @@ -182,7 +182,7 @@ 1 0 0 - 133,132,131,130,129,128,127,126,125,124,123,122 + 134,133,132,131,130,129,128,127,126,125,124,123,122 ${project.version} ${project.version}(${activemq.version.incrementingVersion}) diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cli/DummyServerConsumer.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cli/DummyServerConsumer.java index 169303623a..8aebf19906 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cli/DummyServerConsumer.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cli/DummyServerConsumer.java @@ -180,6 +180,26 @@ public class DummyServerConsumer implements ServerConsumer { return null; } + @Override + public void metricsAcknowledge(MessageReference ref, Transaction transaction) { + + } + + @Override + public long getMessagesInTransitSize() { + return 0; + } + + @Override + public long getMessagesDeliveredSize() { + return 0; + } + + @Override + public long getMessagesDelivered() { + return 0; + } + @Override public void promptDelivery() { @@ -278,4 +298,29 @@ public class DummyServerConsumer implements ServerConsumer { // TODO Auto-generated method stub return null; } + + @Override + public int getMessagesInTransit() { + return 0; + } + + @Override + public long getLastDeliveredTime() { + return 0; + } + + @Override + public long getLastAcknowledgedTime() { + return 0; + } + + @Override + public long getMessagesAcknowledged() { + return 0; + } + + @Override + public int getMessagesAcknowledgedAwaitingCommit() { + return 0; + } } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/HangConsumerTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/HangConsumerTest.java index da54d4835c..8c3dfd5d93 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/HangConsumerTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/HangConsumerTest.java @@ -595,8 +595,9 @@ public class HangConsumerTest extends ActiveMQTestBase { OperationContext context, boolean autoCreateQueue, Map prefixes, - String securityDomain) 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, getPagingManager(), prefixes, securityDomain); + String securityDomain, + boolean isLegacyProducer) 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, getPagingManager(), prefixes, securityDomain, isLegacyProducer); } } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/LargeMessageTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/LargeMessageTest.java index 5914d62b3a..774fcde742 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/LargeMessageTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/LargeMessageTest.java @@ -29,6 +29,7 @@ import java.io.InputStream; import java.lang.management.ManagementFactory; import java.lang.management.OperatingSystemMXBean; import java.nio.ByteBuffer; +import java.util.Collection; import java.util.HashMap; import java.util.UUID; import java.util.concurrent.CountDownLatch; @@ -61,6 +62,7 @@ import org.apache.activemq.artemis.core.server.ActiveMQServer; 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.ServerProducer; import org.apache.activemq.artemis.core.settings.impl.AddressFullMessagePolicy; import org.apache.activemq.artemis.core.settings.impl.AddressSettings; import org.apache.activemq.artemis.tests.integration.largemessage.LargeMessageTestBase; @@ -2570,6 +2572,79 @@ public class LargeMessageTest extends LargeMessageTestBase { session.commit(); } + @Test + public void testSendServerMessageMetrics() throws Exception { + ActiveMQServer server = createServer(true, isNetty(), storeType); + + server.start(); + + ClientSessionFactory sf = addSessionFactory(createSessionFactory(locator)); + + ClientSession session = sf.createSession(false, false); + + LargeServerMessageImpl fileMessage = new LargeServerMessageImpl((JournalStorageManager) server.getStorageManager()); + + fileMessage.setMessageID(1005); + + for (int i = 0; i < largeMessageSize; i++) { + fileMessage.addBytes(new byte[]{ActiveMQTestBase.getSamplebyte(i)}); + } + + // The server would be doing this + fileMessage.putLongProperty(Message.HDR_LARGE_BODY_SIZE, largeMessageSize); + + fileMessage.releaseResources(false, false); + + session.createQueue(new QueueConfiguration(ADDRESS)); + + ClientProducer prod = session.createProducer(ADDRESS); + + prod.send(fileMessage); + + fileMessage.deleteFile(); + + session.commit(); + + Collection serverProducers = server.getSessions().iterator().next().getServerProducers(); + + Assert.assertEquals(1, serverProducers.size()); + + ServerProducer producer = serverProducers.iterator().next(); + + Assert.assertEquals(1, producer.getMessagesSent()); + + Assert.assertEquals(largeMessageSize, producer.getMessagesSentSize()); + + fileMessage = new LargeServerMessageImpl((JournalStorageManager) server.getStorageManager()); + + fileMessage.setMessageID(1006); + + for (int i = 0; i < largeMessageSize; i++) { + fileMessage.addBytes(new byte[]{ActiveMQTestBase.getSamplebyte(i)}); + } + + // The server would be doing this + fileMessage.putLongProperty(Message.HDR_LARGE_BODY_SIZE, largeMessageSize); + + fileMessage.releaseResources(false, false); + + prod.send(fileMessage); + + fileMessage.deleteFile(); + + session.commit(); + + serverProducers = server.getSessions().iterator().next().getServerProducers(); + + Assert.assertEquals(1, serverProducers.size()); + + producer = serverProducers.iterator().next(); + + Assert.assertEquals(2, producer.getMessagesSent()); + + Assert.assertEquals(largeMessageSize * 2, producer.getMessagesSentSize()); + } + @Override diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/client/TemporaryDestinationTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/client/TemporaryDestinationTest.java index 91296cc895..463ad29743 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/client/TemporaryDestinationTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/client/TemporaryDestinationTest.java @@ -279,7 +279,7 @@ public class TemporaryDestinationTest extends JMSTestBase { producer.send(s.createMessage()); temporaryQueue.delete(); for (ServerSession serverSession : server.getSessions()) { - assertFalse(((ServerSessionImpl)serverSession).cloneTargetAddresses().containsKey(SimpleString.toSimpleString(temporaryQueue.getQueueName()))); + assertFalse(((ServerSessionImpl)serverSession).cloneProducers().containsKey(temporaryQueue.getQueueName())); } Wait.assertTrue(() -> server.locateQueue(temporaryQueue.getQueueName()) == null, 1000, 100); Wait.assertTrue(() -> server.getAddressInfo(SimpleString.toSimpleString(temporaryQueue.getQueueName())) == null, 1000, 100); @@ -323,26 +323,6 @@ public class TemporaryDestinationTest extends JMSTestBase { Wait.assertTrue(() -> server.getAddressInfo(SimpleString.toSimpleString(temporaryQueue.getQueueName())) == null, 1000, 100); } - @Test - public void testForTempQueueTargetInfosSizeLimit() throws Exception { - try { - conn = createConnection(); - Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - for (int i = 0; i < 200; i++) { - TemporaryQueue temporaryQueue = s.createTemporaryQueue(); - MessageProducer producer = s.createProducer(temporaryQueue); - producer.send(s.createMessage()); - } - for (ServerSession serverSession : server.getSessions()) { - assertTrue(((ServerSessionImpl)serverSession).cloneTargetAddresses().size() <= 100); - } - } finally { - if (conn != null) { - conn.close(); - } - } - } - @Test public void testForSecurityCacheLeak() throws Exception { server.getSecurityStore().setSecurityEnabled(true); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlTest.java index 17913f128c..cefbd969d0 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlTest.java @@ -22,8 +22,11 @@ import javax.jms.MessageConsumer; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; +import java.lang.reflect.Field; import java.nio.ByteBuffer; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -34,6 +37,7 @@ import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.CountDownLatch; @@ -73,7 +77,10 @@ import org.apache.activemq.artemis.core.config.BridgeConfiguration; import org.apache.activemq.artemis.core.config.ClusterConnectionConfiguration; import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.config.impl.SecurityConfiguration; +import org.apache.activemq.artemis.core.management.impl.view.ConsumerField; +import org.apache.activemq.artemis.core.management.impl.view.ProducerField; import org.apache.activemq.artemis.core.messagecounter.impl.MessageCounterManagerImpl; +import org.apache.activemq.artemis.core.persistence.OperationContext; import org.apache.activemq.artemis.core.persistence.config.PersistedDivertConfiguration; import org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory; import org.apache.activemq.artemis.core.remoting.impl.invm.TransportConstants; @@ -84,9 +91,12 @@ import org.apache.activemq.artemis.core.server.ActiveMQServers; import org.apache.activemq.artemis.core.server.BrokerConnection; import org.apache.activemq.artemis.core.server.Queue; import org.apache.activemq.artemis.core.server.ServerConsumer; +import org.apache.activemq.artemis.core.server.ServerProducer; import org.apache.activemq.artemis.core.server.ServerSession; import org.apache.activemq.artemis.core.server.ServiceComponent; import org.apache.activemq.artemis.core.server.impl.AddressInfo; +import org.apache.activemq.artemis.core.server.impl.ServerLegacyProducersImpl; +import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerSessionPlugin; import org.apache.activemq.artemis.core.settings.impl.AddressSettings; import org.apache.activemq.artemis.core.settings.impl.DeletionPolicy; import org.apache.activemq.artemis.core.settings.impl.SlowConsumerPolicy; @@ -96,8 +106,11 @@ import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory; import org.apache.activemq.artemis.jms.client.ActiveMQSession; import org.apache.activemq.artemis.json.JsonArray; import org.apache.activemq.artemis.json.JsonObject; +import org.apache.activemq.artemis.json.JsonValue; import org.apache.activemq.artemis.marker.WebServerComponentMarker; import org.apache.activemq.artemis.nativo.jlibaio.LibaioContext; +import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection; +import org.apache.activemq.artemis.spi.core.protocol.SessionCallback; import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager; import org.apache.activemq.artemis.spi.core.security.jaas.InVMLoginModule; import org.apache.activemq.artemis.tests.unit.core.config.impl.fakes.FakeConnectorServiceFactory; @@ -107,6 +120,7 @@ import org.apache.activemq.artemis.utils.RandomUtil; import org.apache.activemq.artemis.utils.RetryMethod; import org.apache.activemq.artemis.utils.RetryRule; import org.apache.activemq.artemis.utils.UUIDGenerator; +import org.apache.qpid.jms.JmsConnectionFactory; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -128,6 +142,9 @@ public class ActiveMQServerControlTest extends ManagementTestBase { protected boolean legacyCreateQueue; + // For any extended tests that may add extra prodcuers as part of the test + protected int extraProducers = 0; + private ActiveMQServer server; private Configuration conf; @@ -2190,8 +2207,13 @@ public class ActiveMQServerControlTest extends ManagementTestBase { JsonArray jsonArray = JsonUtil.readJsonArray(serverControl.listProducersInfoAsJSON()); - assertEquals(1, jsonArray.size()); - assertEquals(8, ((JsonObject) jsonArray.get(0)).getInt("msgSent")); + assertEquals(1 + extraProducers, jsonArray.size()); + JsonObject first = (JsonObject) jsonArray.get(0); + if (!first.getString(ProducerField.ADDRESS.getAlternativeName()).equalsIgnoreCase(atestq.toString())) { + first = (JsonObject) jsonArray.get(1); + } + assertEquals(8, ((JsonObject) first).getInt("msgSent")); + assertTrue(((JsonObject) first).getInt("msgSizeSent") > 0); clientSession.close(); locator.close(); @@ -2681,29 +2703,31 @@ public class ActiveMQServerControlTest extends ManagementTestBase { second = array.getJsonObject(0); } - Assert.assertNotNull(first.getJsonNumber("consumerID").longValue()); - Assert.assertTrue(first.getString("connectionID").length() > 0); - Assert.assertEquals(factory.getConnection().getID().toString(), first.getString("connectionID")); - Assert.assertTrue(first.getString("sessionID").length() > 0); - Assert.assertEquals(((ClientSessionImpl) session).getName(), first.getString("sessionID")); - Assert.assertTrue(first.getString("queueName").length() > 0); - Assert.assertEquals(queueName.toString(), first.getString("queueName")); - Assert.assertEquals(false, first.getBoolean("browseOnly")); - Assert.assertTrue(first.getJsonNumber("creationTime").longValue() > 0); - Assert.assertEquals(0, first.getJsonNumber("deliveringCount").longValue()); + Assert.assertNotNull(first.getJsonNumber(ConsumerField.ID.getAlternativeName()).longValue()); + Assert.assertTrue(first.getString(ConsumerField.CONNECTION.getAlternativeName()).length() > 0); + Assert.assertEquals(factory.getConnection().getID().toString(), first.getString(ConsumerField.CONNECTION.getAlternativeName())); + Assert.assertTrue(first.getString(ConsumerField.SESSION.getAlternativeName()).length() > 0); + Assert.assertEquals(((ClientSessionImpl) session).getName(), first.getString(ConsumerField.SESSION.getAlternativeName())); + Assert.assertTrue(first.getString(ConsumerField.QUEUE.getAlternativeName()).length() > 0); + Assert.assertEquals(queueName.toString(), first.getString(ConsumerField.QUEUE.getAlternativeName())); + Assert.assertEquals(false, first.getBoolean(ConsumerField.BROWSE_ONLY.getName())); + Assert.assertTrue(first.getJsonNumber(ConsumerField.CREATION_TIME.getName()).longValue() > 0); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + // test the old version that has been replaced for backward compatibility + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getAlternativeName()).longValue()); - Assert.assertNotNull(second.getJsonNumber("consumerID").longValue()); - Assert.assertTrue(second.getString("connectionID").length() > 0); - Assert.assertEquals(factory.getConnection().getID().toString(), second.getString("connectionID")); - Assert.assertTrue(second.getString("sessionID").length() > 0); - Assert.assertEquals(((ClientSessionImpl) session).getName(), second.getString("sessionID")); - Assert.assertTrue(second.getString("queueName").length() > 0); - Assert.assertEquals(queueName.toString(), second.getString("queueName")); - Assert.assertEquals(true, second.getBoolean("browseOnly")); - Assert.assertTrue(second.getJsonNumber("creationTime").longValue() > 0); - Assert.assertEquals(0, second.getJsonNumber("deliveringCount").longValue()); - Assert.assertTrue(second.getString("filter").length() > 0); - Assert.assertEquals(filter, second.getString("filter")); + Assert.assertNotNull(second.getJsonNumber(ConsumerField.ID.getAlternativeName()).longValue()); + Assert.assertTrue(second.getString(ConsumerField.CONNECTION.getAlternativeName()).length() > 0); + Assert.assertEquals(factory.getConnection().getID().toString(), second.getString(ConsumerField.CONNECTION.getAlternativeName())); + Assert.assertTrue(second.getString(ConsumerField.SESSION.getAlternativeName()).length() > 0); + Assert.assertEquals(((ClientSessionImpl) session).getName(), second.getString(ConsumerField.SESSION.getAlternativeName())); + Assert.assertTrue(second.getString(ConsumerField.QUEUE.getAlternativeName()).length() > 0); + Assert.assertEquals(queueName.toString(), second.getString(ConsumerField.QUEUE.getAlternativeName())); + Assert.assertEquals(true, second.getBoolean(ConsumerField.BROWSE_ONLY.getName())); + Assert.assertTrue(second.getJsonNumber(ConsumerField.CREATION_TIME.getName()).longValue() > 0); + Assert.assertEquals(0, second.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertTrue(second.getString(ConsumerField.FILTER.getName()).length() > 0); + Assert.assertEquals(filter, second.getString(ConsumerField.FILTER.getName())); } @Test @@ -2725,13 +2749,9 @@ public class ActiveMQServerControlTest extends ManagementTestBase { server.createQueue(new QueueConfiguration(queueName).setRoutingType(RoutingType.ANYCAST).setDurable(false)); } - Queue serverQueue = server.locateQueue(queueName); - addClientConsumer(session.createConsumer(queueName)); - Wait.assertEquals(1, serverQueue::getConsumerCount); - Thread.sleep(100); // we check timestamps, they need to be different + Thread.sleep(200); addClientConsumer(session2.createConsumer(queueName)); - Wait.assertEquals(2, serverQueue::getConsumerCount); String jsonString = serverControl.listAllConsumersAsJSON(); logger.debug(jsonString); @@ -2739,49 +2759,635 @@ public class ActiveMQServerControlTest extends ManagementTestBase { JsonArray array = JsonUtil.readJsonArray(jsonString); Assert.assertEquals(usingCore() ? 3 : 2, array.size()); + String key = "creationTime"; JsonObject[] sorted = new JsonObject[array.size()]; for (int i = 0; i < array.size(); i++) { sorted[i] = array.getJsonObject(i); } - JsonObject first = null; - JsonObject second = null; - - for (JsonObject obj : sorted) { - - if (obj.getString("connectionID").equals(factory.getConnection().getID().toString())) { - first = obj; + if (sorted[0].getJsonNumber(key).longValue() > sorted[1].getJsonNumber(key).longValue()) { + JsonObject o = sorted[1]; + sorted[1] = sorted[0]; + sorted[0] = o; + } + if (usingCore()) { + if (sorted[1].getJsonNumber(key).longValue() > sorted[2].getJsonNumber(key).longValue()) { + JsonObject o = sorted[2]; + sorted[2] = sorted[1]; + sorted[1] = o; } - - if (obj.getString("connectionID").equals(factory2.getConnection().getID().toString())) { - second = obj; + if (sorted[0].getJsonNumber(key).longValue() > sorted[1].getJsonNumber(key).longValue()) { + JsonObject o = sorted[1]; + sorted[1] = sorted[0]; + sorted[0] = o; } } - Assert.assertNotNull(first); - Assert.assertNotNull(second); + JsonObject first = sorted[0]; + JsonObject second = sorted[1]; - Assert.assertTrue(first.getJsonNumber("creationTime").longValue() > 0); - Assert.assertNotNull(first.getJsonNumber("consumerID").longValue()); - Assert.assertTrue(first.getString("connectionID").length() > 0); - Assert.assertEquals(factory.getConnection().getID().toString(), first.getString("connectionID")); - Assert.assertTrue(first.getString("sessionID").length() > 0); - Assert.assertEquals(((ClientSessionImpl) session).getName(), first.getString("sessionID")); - Assert.assertTrue(first.getString("queueName").length() > 0); - Assert.assertEquals(queueName.toString(), first.getString("queueName")); - Assert.assertEquals(false, first.getBoolean("browseOnly")); - Assert.assertEquals(0, first.getJsonNumber("deliveringCount").longValue()); + Assert.assertTrue(first.getJsonNumber(ConsumerField.CREATION_TIME.getName()).longValue() > 0); + Assert.assertNotNull(first.getJsonNumber(ConsumerField.ID.getAlternativeName()).longValue()); + Assert.assertTrue(first.getString(ConsumerField.CONNECTION.getAlternativeName()).length() > 0); + Assert.assertEquals(factory.getConnection().getID().toString(), first.getString(ConsumerField.CONNECTION.getAlternativeName())); + Assert.assertTrue(first.getString(ConsumerField.SESSION.getAlternativeName()).length() > 0); + Assert.assertEquals(((ClientSessionImpl) session).getName(), first.getString(ConsumerField.SESSION.getAlternativeName())); + Assert.assertTrue(first.getString(ConsumerField.QUEUE.getAlternativeName()).length() > 0); + Assert.assertEquals(queueName.toString(), first.getString(ConsumerField.QUEUE.getAlternativeName())); + Assert.assertEquals(false, first.getBoolean(ConsumerField.BROWSE_ONLY.getName())); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.LAST_DELIVERED_TIME.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.LAST_ACKNOWLEDGED_TIME.getName()).longValue()); - Assert.assertTrue(second.getJsonNumber("creationTime").longValue() > 0); - Assert.assertNotNull(second.getJsonNumber("consumerID").longValue()); - Assert.assertTrue(second.getString("connectionID").length() > 0); - Assert.assertEquals(factory2.getConnection().getID().toString(), second.getString("connectionID")); - Assert.assertTrue(second.getString("sessionID").length() > 0); - Assert.assertEquals(((ClientSessionImpl) session2).getName(), second.getString("sessionID")); - Assert.assertTrue(second.getString("queueName").length() > 0); - Assert.assertEquals(queueName.toString(), second.getString("queueName")); - Assert.assertEquals(false, second.getBoolean("browseOnly")); - Assert.assertEquals(0, second.getJsonNumber("deliveringCount").longValue()); + Assert.assertTrue(second.getJsonNumber(ConsumerField.CREATION_TIME.getName()).longValue() > 0); + Assert.assertNotNull(second.getJsonNumber(ConsumerField.ID.getAlternativeName()).longValue()); + Assert.assertTrue(second.getString(ConsumerField.CONNECTION.getAlternativeName()).length() > 0); + Assert.assertEquals(factory2.getConnection().getID().toString(), second.getString(ConsumerField.CONNECTION.getAlternativeName())); + Assert.assertTrue(second.getString(ConsumerField.SESSION.getAlternativeName()).length() > 0); + Assert.assertEquals(((ClientSessionImpl) session2).getName(), second.getString(ConsumerField.SESSION.getAlternativeName())); + Assert.assertTrue(second.getString(ConsumerField.QUEUE.getAlternativeName()).length() > 0); + Assert.assertEquals(queueName.toString(), second.getString(ConsumerField.QUEUE.getAlternativeName())); + Assert.assertEquals(false, second.getBoolean(ConsumerField.BROWSE_ONLY.getName())); + Assert.assertEquals(0, second.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(0, second.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(0, second.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(0, second.getJsonNumber(ConsumerField.LAST_DELIVERED_TIME.getName()).longValue()); + Assert.assertEquals(0, second.getJsonNumber(ConsumerField.LAST_ACKNOWLEDGED_TIME.getName()).longValue()); + + } + + + @Test + public void testListAllConsumersAsJSONTXCommit() throws Exception { + SimpleString queueName = new SimpleString(UUID.randomUUID().toString()); + ActiveMQServerControl serverControl = createManagementControl(); + + ServerLocator locator = createInVMNonHALocator(); + ClientSessionFactory factory = createSessionFactory(locator); + ClientSession session = factory.createSession(true,false, 1); + addClientSession(session); + + serverControl.createAddress(queueName.toString(), RoutingType.ANYCAST.name()); + if (legacyCreateQueue) { + server.createQueue(queueName, RoutingType.ANYCAST, queueName, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + + ClientConsumer consumer = session.createConsumer(queueName, null, 100, -1, false); + addClientConsumer(consumer); + session.start(); + + ClientProducer producer = session.createProducer(queueName); + int size = 0; + ClientMessage receive = null; + for (int i = 0; i < 100; i++) { + ClientMessage message = session.createMessage(true); + + producer.send(message); + size += message.getEncodeSize(); + receive = consumer.receive(); + } + + String jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + JsonArray array = JsonUtil.readJsonArray(jsonString); + JsonObject first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); + receive.acknowledge(); + session.commit(); + + jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + array = JsonUtil.readJsonArray(jsonString); + first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); + + int allSize = size; + for (int i = 0; i < 100; i++) { + ClientMessage message = session.createMessage(true); + + producer.send(message); + allSize += message.getEncodeSize(); + receive = consumer.receive(); + } + + jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + array = JsonUtil.readJsonArray(jsonString); + first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(200, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(allSize, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); + } + + @Test + public void testListAllConsumersAsJSONTXCommitAck() throws Exception { + SimpleString queueName = new SimpleString(UUID.randomUUID().toString()); + ActiveMQServerControl serverControl = createManagementControl(); + + ServerLocator locator = createInVMNonHALocator(); + ClientSessionFactory factory = createSessionFactory(locator); + ClientSession session = factory.createSession(true,false, 1); + addClientSession(session); + + serverControl.createAddress(queueName.toString(), RoutingType.ANYCAST.name()); + if (legacyCreateQueue) { + server.createQueue(queueName, RoutingType.ANYCAST, queueName, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + + ClientConsumer consumer = session.createConsumer(queueName, null, 100, -1, false); + addClientConsumer(consumer); + session.start(); + + ClientProducer producer = session.createProducer(queueName); + int size = 0; + ClientMessage receive = null; + for (int i = 0; i < 100; i++) { + ClientMessage message = session.createMessage(true); + + producer.send(message); + size += message.getEncodeSize(); + receive = consumer.receive(); + receive.acknowledge(); + } + + Wait.assertEquals(0, () -> JsonUtil.readJsonArray(serverControl.listAllConsumersAsJSON()).get(0).asJsonObject().getInt(ConsumerField.MESSAGES_IN_TRANSIT.getName())); + + String jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + JsonArray array = JsonUtil.readJsonArray(jsonString); + JsonObject first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); + session.commit(); + + Wait.assertEquals(0, () -> JsonUtil.readJsonArray(serverControl.listAllConsumersAsJSON()).get(0).asJsonObject().getInt(ConsumerField.MESSAGES_IN_TRANSIT.getName())); + + jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + array = JsonUtil.readJsonArray(jsonString); + first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); + } + + @Test + public void testListAllConsumersAsJSONTXRollback() throws Exception { + SimpleString queueName = new SimpleString(UUID.randomUUID().toString()); + ActiveMQServerControl serverControl = createManagementControl(); + + ServerLocator locator = createInVMNonHALocator(); + ClientSessionFactory factory = createSessionFactory(locator); + ClientSession session = factory.createSession(true,false, 1); + addClientSession(session); + + serverControl.createAddress(queueName.toString(), RoutingType.ANYCAST.name()); + if (legacyCreateQueue) { + server.createQueue(queueName, RoutingType.ANYCAST, queueName, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + + ClientConsumer consumer = session.createConsumer(queueName, null, 100, -1, false); + addClientConsumer(consumer); + session.start(); + + ClientProducer producer = session.createProducer(queueName); + int size = 0; + ClientMessage receive = null; + for (int i = 0; i < 100; i++) { + ClientMessage message = session.createMessage(true); + + producer.send(message); + size += message.getEncodeSize(); + receive = consumer.receive(); + } + + String jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + JsonArray array = JsonUtil.readJsonArray(jsonString); + JsonObject first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); + receive.acknowledge(); //stop the session so we dont receive the same messages + session.stop(); + jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + array = JsonUtil.readJsonArray(jsonString); + first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); + + session.rollback(); + jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + array = JsonUtil.readJsonArray(jsonString); + first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); + + int allSize = size * 2; + session.start(); + for (int i = 0; i < 100; i++) { + receive = consumer.receive(); + } + + jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + array = JsonUtil.readJsonArray(jsonString); + first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(200, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(allSize, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); + + receive.acknowledge(); + //stop the session so we dont receive the same messages + session.stop(); + session.rollback(); + jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + array = JsonUtil.readJsonArray(jsonString); + first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(200, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(allSize, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(200, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); + } + + @Test + public void testListAllConsumersAsJSONCancel() throws Exception { + SimpleString queueName = new SimpleString(UUID.randomUUID().toString()); + ActiveMQServerControl serverControl = createManagementControl(); + + ServerLocator locator = createInVMNonHALocator(); + ClientSessionFactory factory = createSessionFactory(locator); + ClientSession session = factory.createSession(true,false, 1); + addClientSession(session); + + serverControl.createAddress(queueName.toString(), RoutingType.ANYCAST.name()); + if (legacyCreateQueue) { + server.createQueue(queueName, RoutingType.ANYCAST, queueName, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + + ClientConsumer consumer = session.createConsumer(queueName, null, 100, -1, false); + addClientConsumer(consumer); + session.start(); + + ClientProducer producer = session.createProducer(queueName); + int size = 0; + ClientMessage receive = null; + for (int i = 0; i < 100; i++) { + ClientMessage message = session.createMessage(true); + + producer.send(message); + size += message.getEncodeSize(); + receive = consumer.receive(); + } + + String jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + JsonArray array = JsonUtil.readJsonArray(jsonString); + JsonObject first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); + receive.acknowledge(); + //close the consumer to cancel messages and recreate + consumer.close(); + session.close(); + session = factory.createSession(true,false, 1); + addClientSession(session); + + consumer = session.createConsumer(queueName, null, 100, -1, false); + addClientConsumer(consumer); + jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + array = JsonUtil.readJsonArray(jsonString); + first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); + } + + @Test + public void testListAllConsumersAsJSONNoTX() throws Exception { + SimpleString queueName = new SimpleString(UUID.randomUUID().toString()); + ActiveMQServerControl serverControl = createManagementControl(); + + ServerLocator locator = createInVMNonHALocator(); + ClientSessionFactory factory = createSessionFactory(locator); + ClientSession session = factory.createSession(true, true, 1); + addClientSession(session); + + serverControl.createAddress(queueName.toString(), RoutingType.ANYCAST.name()); + if (legacyCreateQueue) { + server.createQueue(queueName, RoutingType.ANYCAST, queueName, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + + ClientConsumer consumer = session.createConsumer(queueName, null, 100, -1, false); + addClientConsumer(consumer); + session.start(); + + ClientProducer producer = session.createProducer(queueName); + int size = 0; + ClientMessage receive = null; + for (int i = 0; i < 100; i++) { + ClientMessage message = session.createMessage(true); + + producer.send(message); + size += message.getEncodeSize(); + receive = consumer.receive(); + receive.acknowledge(); + } + + Wait.assertEquals(0, () -> JsonUtil.readJsonArray(serverControl.listAllConsumersAsJSON()).get(0).asJsonObject().getInt(ConsumerField.MESSAGES_IN_TRANSIT.getName())); + + String jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + JsonArray array = JsonUtil.readJsonArray(jsonString); + JsonObject first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); + } + + @Test + public void testListAllConsumersAsJSONXACommit() throws Exception { + SimpleString queueName = new SimpleString(UUID.randomUUID().toString()); + ActiveMQServerControl serverControl = createManagementControl(); + + ServerLocator locator = createInVMNonHALocator(); + ClientSessionFactory factory = createSessionFactory(locator); + ClientSession sendSession = factory.createSession(); + addClientSession(sendSession); + ClientSession session = factory.createSession(true, false, false); + addClientSession(session); + + serverControl.createAddress(queueName.toString(), RoutingType.ANYCAST.name()); + if (legacyCreateQueue) { + server.createQueue(queueName, RoutingType.ANYCAST, queueName, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + + ClientConsumer consumer = session.createConsumer(queueName, null, 100, -1, false); + addClientConsumer(consumer); + session.start(); + Xid xid = new XidImpl("xa1".getBytes(), 1, UUIDGenerator.getInstance().generateStringUUID().getBytes()); + session.start(xid, XAResource.TMNOFLAGS); + + ClientProducer producer = sendSession.createProducer(queueName); + int size = 0; + ClientMessage receive = null; + for (int i = 0; i < 100; i++) { + ClientMessage message = sendSession.createMessage(true); + + producer.send(message); + size += message.getEncodeSize(); + receive = consumer.receive(); + receive.acknowledge(); + } + + String jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + JsonArray array = JsonUtil.readJsonArray(jsonString); + JsonObject first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); + + session.end(xid, XAResource.TMSUCCESS); + session.prepare(xid); + jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + array = JsonUtil.readJsonArray(jsonString); + first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); + session.commit(xid, false); + jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + array = JsonUtil.readJsonArray(jsonString); + first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); + } + + @Test + public void testListAllConsumersAsJSONXARollback() throws Exception { + SimpleString queueName = new SimpleString(UUID.randomUUID().toString()); + ActiveMQServerControl serverControl = createManagementControl(); + + ServerLocator locator = createInVMNonHALocator(); + ClientSessionFactory factory = createSessionFactory(locator); + ClientSession sendSession = factory.createSession(); + addClientSession(sendSession); + ClientSession session = factory.createSession(true, false, false); + addClientSession(session); + + serverControl.createAddress(queueName.toString(), RoutingType.ANYCAST.name()); + if (legacyCreateQueue) { + server.createQueue(queueName, RoutingType.ANYCAST, queueName, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + + ClientConsumer consumer = session.createConsumer(queueName, null, 100, -1, false); + addClientConsumer(consumer); + session.start(); + Xid xid = new XidImpl("xa1".getBytes(), 1, UUIDGenerator.getInstance().generateStringUUID().getBytes()); + session.start(xid, XAResource.TMNOFLAGS); + + ClientProducer producer = sendSession.createProducer(queueName); + int size = 0; + ClientMessage receive = null; + for (int i = 0; i < 100; i++) { + ClientMessage message = sendSession.createMessage(true); + + producer.send(message); + size += message.getEncodeSize(); + receive = consumer.receive(); + receive.acknowledge(); + } + + String jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + JsonArray array = JsonUtil.readJsonArray(jsonString); + JsonObject first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); + + session.end(xid, XAResource.TMSUCCESS); + session.prepare(xid); + jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + array = JsonUtil.readJsonArray(jsonString); + first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); + session.stop(); + session.rollback(xid); + jsonString = serverControl.listAllConsumersAsJSON(); + logger.debug(jsonString); + Assert.assertNotNull(jsonString); + array = JsonUtil.readJsonArray(jsonString); + first = (JsonObject) array.get(0); + if (!first.getString(ConsumerField.QUEUE.getAlternativeName()).equalsIgnoreCase(queueName.toString())) { + first = (JsonObject) array.get(1); + } + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED.getName()).longValue()); + Assert.assertEquals(size, first.getJsonNumber(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()).longValue()); + Assert.assertEquals(100, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED.getName()).longValue()); + Assert.assertEquals(0, first.getJsonNumber(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName()).longValue()); } @Test @@ -3590,11 +4196,11 @@ public class ActiveMQServerControlTest extends ManagementTestBase { JsonArray array = (JsonArray) consumersAsJsonObject.get("data"); Assert.assertEquals("number of consumers returned from query", 2, array.size()); - Assert.assertEquals("check consumer's queue", queueName1.toString(), array.getJsonObject(0).getString("queue")); - Assert.assertEquals("check consumer's queue", queueName1.toString(), array.getJsonObject(0).getString("queue")); + Assert.assertEquals("check consumer's queue", queueName1.toString(), array.getJsonObject(0).getString(ConsumerField.QUEUE.getName())); + Assert.assertEquals("check consumer's queue", queueName1.toString(), array.getJsonObject(0).getString(ConsumerField.QUEUE.getName())); // test with a CONTAINS operation - filterString = createJsonFilter("queue", "CONTAINS", "my_queue"); + filterString = createJsonFilter(ConsumerField.QUEUE.getName(), "CONTAINS", "my_queue"); consumersAsJsonString = serverControl.listConsumers(filterString, 1, 50); consumersAsJsonObject = JsonUtil.readJsonObject(consumersAsJsonString); array = (JsonArray) consumersAsJsonObject.get("data"); @@ -3602,14 +4208,14 @@ public class ActiveMQServerControlTest extends ManagementTestBase { Assert.assertEquals("number of consumers returned from query", 3, array.size()); // filter by address - filterString = createJsonFilter("address", "EQUALS", addressName1.toString()); + filterString = createJsonFilter(ConsumerField.ADDRESS.getName(), "EQUALS", addressName1.toString()); consumersAsJsonString = serverControl.listConsumers(filterString, 1, 50); consumersAsJsonObject = JsonUtil.readJsonObject(consumersAsJsonString); array = (JsonArray) consumersAsJsonObject.get("data"); Assert.assertEquals("number of consumers returned from query", 2, array.size()); - Assert.assertEquals("check consumers address", addressName1.toString(), array.getJsonObject(0).getString("address")); - Assert.assertEquals("check consumers address", addressName1.toString(), array.getJsonObject(1).getString("address")); + Assert.assertEquals("check consumers address", addressName1.toString(), array.getJsonObject(0).getString(ConsumerField.ADDRESS.getName())); + Assert.assertEquals("check consumers address", addressName1.toString(), array.getJsonObject(1).getString(ConsumerField.ADDRESS.getName())); //test with empty filter - all consumers should be returned filterString = createJsonFilter("", "", ""); @@ -3627,24 +4233,31 @@ public class ActiveMQServerControlTest extends ManagementTestBase { Assert.assertEquals("number of consumers returned from query", 1, array.size()); //test contents of returned consumer - filterString = createJsonFilter("queue", "EQUALS", queueName3.toString()); + filterString = createJsonFilter(ConsumerField.QUEUE.getName(), "EQUALS", queueName3.toString()); consumersAsJsonString = serverControl.listConsumers(filterString, 1, 50); consumersAsJsonObject = JsonUtil.readJsonObject(consumersAsJsonString); array = (JsonArray) consumersAsJsonObject.get("data"); Assert.assertEquals("number of consumers returned from query", 1, array.size()); JsonObject jsonConsumer = array.getJsonObject(0); - Assert.assertEquals("queue name in consumer", queueName3.toString(), jsonConsumer.getString("queue")); - Assert.assertEquals("address name in consumer", addressName2.toString(), jsonConsumer.getString("address")); - Assert.assertEquals("consumer protocol ", "CORE", jsonConsumer.getString("protocol")); - Assert.assertEquals("queue type", "anycast", jsonConsumer.getString("queueType")); - Assert.assertNotEquals("id", "", jsonConsumer.getString("id")); - Assert.assertNotEquals("session", "", jsonConsumer.getString("session")); - Assert.assertEquals("clientID", "", jsonConsumer.getString("clientID")); - Assert.assertEquals("user", "", jsonConsumer.getString("user")); - Assert.assertNotEquals("localAddress", "", jsonConsumer.getString("localAddress")); - Assert.assertNotEquals("remoteAddress", "", jsonConsumer.getString("remoteAddress")); - Assert.assertNotEquals("creationTime", "", jsonConsumer.getString("creationTime")); + Assert.assertEquals("queue name in consumer", queueName3.toString(), jsonConsumer.getString(ConsumerField.QUEUE.getName())); + Assert.assertEquals("address name in consumer", addressName2.toString(), jsonConsumer.getString(ConsumerField.ADDRESS.getName())); + Assert.assertEquals("consumer protocol ", "CORE", jsonConsumer.getString(ConsumerField.PROTOCOL.getName())); + Assert.assertEquals("queue type", "anycast", jsonConsumer.getString(ConsumerField.QUEUE_TYPE.getName())); + Assert.assertNotEquals("id", "", jsonConsumer.getString(ConsumerField.ID.getName())); + Assert.assertNotEquals("session", "", jsonConsumer.getString(ConsumerField.SESSION.getName())); + Assert.assertEquals("clientID", "", jsonConsumer.getString(ConsumerField.CLIENT_ID.getName())); + Assert.assertEquals("user", "", jsonConsumer.getString(ConsumerField.USER.getName())); + Assert.assertNotEquals("localAddress", "", jsonConsumer.getString(ConsumerField.LOCAL_ADDRESS.getName())); + Assert.assertNotEquals("remoteAddress", "", jsonConsumer.getString(ConsumerField.REMOTE_ADDRESS.getName())); + Assert.assertNotEquals("creationTime", "", jsonConsumer.getString(ConsumerField.CREATION_TIME.getName())); + Assert.assertNotEquals("messagesInTransit", "", jsonConsumer.getString(ConsumerField.MESSAGES_IN_TRANSIT.getName())); + Assert.assertNotEquals("messagesInTransitSize", "", jsonConsumer.getString(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName())); + Assert.assertNotEquals("messagesDelivered", "", jsonConsumer.getString(ConsumerField.MESSAGES_DELIVERED.getName())); + Assert.assertNotEquals("messagesDeliveredSize", "", jsonConsumer.getString(ConsumerField.MESSAGES_DELIVERED_SIZE.getName())); + Assert.assertNotEquals("messagesAcknowledged", "", jsonConsumer.getString(ConsumerField.MESSAGES_ACKNOWLEDGED.getName())); + Assert.assertEquals("lastDeliveredTime", 0, jsonConsumer.getInt(ConsumerField.LAST_DELIVERED_TIME.getName())); + Assert.assertEquals("lastAcknowledgedTime", 0, jsonConsumer.getInt(ConsumerField.LAST_ACKNOWLEDGED_TIME.getName())); } } @@ -3677,26 +4290,26 @@ public class ActiveMQServerControlTest extends ManagementTestBase { ClientConsumer consumer_s3 = session3.createConsumer(queueName1); //test default Order - String filterString = createJsonFilter("queue", "EQUALS", queueName1.toString()); + String filterString = createJsonFilter(ConsumerField.QUEUE.getName(), "EQUALS", queueName1.toString()); String consumersAsJsonString = serverControl.listConsumers(filterString, 1, 50); JsonObject consumersAsJsonObject = JsonUtil.readJsonObject(consumersAsJsonString); JsonArray array = (JsonArray) consumersAsJsonObject.get("data"); Assert.assertEquals("number of consumers returned from query", 3, array.size()); - Assert.assertEquals("Consumer1 default order", session1.getName(), array.getJsonObject(0).getString("session")); - Assert.assertEquals("Consumer2 default order", session2.getName(), array.getJsonObject(1).getString("session")); - Assert.assertEquals("Consumer3 default order", session3.getName(), array.getJsonObject(2).getString("session")); + Assert.assertEquals("Consumer1 default order", session1.getName(), array.getJsonObject(0).getString(ConsumerField.SESSION.getName())); + Assert.assertEquals("Consumer2 default order", session2.getName(), array.getJsonObject(1).getString(ConsumerField.SESSION.getName())); + Assert.assertEquals("Consumer3 default order", session3.getName(), array.getJsonObject(2).getString(ConsumerField.SESSION.getName())); //test ordered by creationTime - filterString = createJsonFilter("queue", "EQUALS", queueName1.toString(), "creationTime", "desc"); + filterString = createJsonFilter(ConsumerField.QUEUE.getName(), "EQUALS", queueName1.toString(), "creationTime", "desc"); consumersAsJsonString = serverControl.listConsumers(filterString, 1, 50); consumersAsJsonObject = JsonUtil.readJsonObject(consumersAsJsonString); array = (JsonArray) consumersAsJsonObject.get("data"); Assert.assertEquals("number of consumers returned from query", 3, array.size()); - Assert.assertEquals("Consumer3 creation time", session3.getName(), array.getJsonObject(0).getString("session")); - Assert.assertEquals("Consumer2 creation time", session2.getName(), array.getJsonObject(1).getString("session")); - Assert.assertEquals("Consumer1 creation time", session1.getName(), array.getJsonObject(2).getString("session")); + Assert.assertEquals("Consumer3 creation time", session3.getName(), array.getJsonObject(0).getString(ConsumerField.SESSION.getName())); + Assert.assertEquals("Consumer2 creation time", session2.getName(), array.getJsonObject(1).getString(ConsumerField.SESSION.getName())); + Assert.assertEquals("Consumer1 creation time", session1.getName(), array.getJsonObject(2).getString(ConsumerField.SESSION.getName())); } } @@ -3978,7 +4591,9 @@ public class ActiveMQServerControlTest extends ManagementTestBase { ClientSession session2 = csf.createSession(); ClientProducer producer1 = session1.createProducer(addressName1); - ClientProducer producer2 = session1.createProducer(addressName1); + producer1.send(session1.createMessage(true)); + ClientProducer producer2 = session2.createProducer(addressName1); + producer2.send(session2.createMessage(true)); //bring back all producers String filterString = createJsonFilter("", "", ""); @@ -3986,7 +4601,7 @@ public class ActiveMQServerControlTest extends ManagementTestBase { JsonObject producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); JsonArray array = (JsonArray) producersAsJsonObject.get("data"); - Assert.assertTrue("number of producers returned from query", 2 <= array.size()); + Assert.assertEquals("number of producers returned from query", 2 + extraProducers, array.size()); boolean foundElement = false; for (int i = 0; i < array.size(); i++) { @@ -3999,15 +4614,15 @@ public class ActiveMQServerControlTest extends ManagementTestBase { foundElement = true; //check all fields - Assert.assertNotEquals("id", "", jsonSession.getString("id")); - Assert.assertNotEquals("session", "", jsonSession.getString("session")); - Assert.assertEquals("clientID", "", jsonSession.getString("clientID")); - Assert.assertEquals("user", "", jsonSession.getString("user")); - Assert.assertNotEquals("protocol", "", jsonSession.getString("protocol")); - Assert.assertEquals("address", "", jsonSession.getString("address")); - Assert.assertNotEquals("localAddress", "", jsonSession.getString("localAddress")); - Assert.assertNotEquals("remoteAddress", "", jsonSession.getString("remoteAddress")); - Assert.assertNotEquals("creationTime", "", jsonSession.getString("creationTime")); + Assert.assertNotEquals(ProducerField.ID.getName(), "", jsonSession.getString(ProducerField.ID.getName())); + Assert.assertNotEquals(ProducerField.SESSION.getName(), "", jsonSession.getString(ProducerField.SESSION.getName())); + Assert.assertEquals(ProducerField.CLIENT_ID.getName(), "", jsonSession.getString(ProducerField.CLIENT_ID.getName())); + Assert.assertEquals(ProducerField.USER.getName(), "", jsonSession.getString(ProducerField.USER.getName())); + Assert.assertNotEquals(ProducerField.PROTOCOL.getName(), "", jsonSession.getString(ProducerField.PROTOCOL.getName())); + Assert.assertEquals(ProducerField.ADDRESS.getName(), addressName1.toString(), jsonSession.getString(ProducerField.ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.LOCAL_ADDRESS.getName(), "", jsonSession.getString(ProducerField.LOCAL_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.REMOTE_ADDRESS.getName(), "", jsonSession.getString(ProducerField.REMOTE_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.CREATION_TIME.getName(), "", jsonSession.getString(ProducerField.CREATION_TIME.getName())); } @@ -4015,6 +4630,974 @@ public class ActiveMQServerControlTest extends ManagementTestBase { } } + @Test + public void testListProducersLargeMessages() throws Exception { + SimpleString queueName1 = new SimpleString("my_queue_one"); + SimpleString addressName1 = new SimpleString("my_address_one"); + + ActiveMQServerControl serverControl = createManagementControl(); + + server.addAddressInfo(new AddressInfo(addressName1, RoutingType.ANYCAST)); + if (legacyCreateQueue) { + server.createQueue(addressName1, RoutingType.ANYCAST, queueName1, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName1).setAddress(addressName1).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + + // create some consumers + try (ServerLocator locator = createInVMNonHALocator(); ClientSessionFactory csf = createSessionFactory(locator);) { + + ClientSession session1 = csf.createSession(); + ClientSession session2 = csf.createSession(); + + ClientProducer producer1 = session1.createProducer(addressName1); + producer1.send(session1.createMessage(true)); + ClientProducer producer2 = session2.createProducer(addressName1); + producer2.send(session2.createMessage(true)); + + //bring back all producers + String filterString = createJsonFilter("", "", ""); + String producersAsJsonString = serverControl.listProducers(filterString, 1, 50); + JsonObject producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + JsonArray array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 2 + extraProducers, array.size()); + + boolean foundElement = false; + for (int i = 0; i < array.size(); i++) { + + JsonObject jsonSession = array.getJsonObject(i); + if (jsonSession.getString("address").equals("activemq.management")) { + continue; + } + + foundElement = true; + + //check all fields + Assert.assertNotEquals(ProducerField.ID.getName(), "", jsonSession.getString(ProducerField.ID.getName())); + Assert.assertNotEquals(ProducerField.SESSION.getName(), "", jsonSession.getString(ProducerField.SESSION.getName())); + Assert.assertEquals(ProducerField.CLIENT_ID.getName(), "", jsonSession.getString(ProducerField.CLIENT_ID.getName())); + Assert.assertEquals(ProducerField.USER.getName(), "", jsonSession.getString(ProducerField.USER.getName())); + Assert.assertNotEquals(ProducerField.PROTOCOL.getName(), "", jsonSession.getString(ProducerField.PROTOCOL.getName())); + Assert.assertEquals(ProducerField.ADDRESS.getName(), addressName1.toString(), jsonSession.getString(ProducerField.ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.LOCAL_ADDRESS.getName(), "", jsonSession.getString(ProducerField.LOCAL_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.REMOTE_ADDRESS.getName(), "", jsonSession.getString(ProducerField.REMOTE_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.CREATION_TIME.getName(), "", jsonSession.getString(ProducerField.CREATION_TIME.getName())); + } + + + Assert.assertTrue("Valid session not found", foundElement); + } + } + + @Test + public void testListProducersAsJSONAgainstServer() throws Exception { + SimpleString queueName1 = new SimpleString("my_queue_one"); + SimpleString addressName1 = new SimpleString("my_address_one"); + + ActiveMQServerControl serverControl = createManagementControl(); + + server.addAddressInfo(new AddressInfo(addressName1, RoutingType.ANYCAST)); + if (legacyCreateQueue) { + server.createQueue(addressName1, RoutingType.ANYCAST, queueName1, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName1).setAddress(addressName1).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + + // create some consumers + try (ServerLocator locator = createInVMNonHALocator(); ClientSessionFactory csf = createSessionFactory(locator);) { + + ClientSession session1 = csf.createSession(); + + ClientProducer producer1 = session1.createProducer(addressName1); + producer1.send(session1.createMessage(true)); + + //bring back all producers + String producersAsJsonString = serverControl.listProducersInfoAsJSON(); + JsonArray array = JsonUtil.readJsonArray(producersAsJsonString); + + Assert.assertEquals("number of producers returned from query", 1 + extraProducers, array.size()); + + JsonObject jsonSession = array.getJsonObject(0); + if (!jsonSession.getString(ProducerField.ADDRESS.getAlternativeName()).equalsIgnoreCase(addressName1.toString())) { + jsonSession = array.getJsonObject(1); + } + + //get the only server producer + ServerProducer producer = server.getSessionByID(jsonSession.getString(ProducerField.SESSION.getAlternativeName())).getServerProducers().iterator().next(); + //check all fields + Assert.assertEquals(ProducerField.ID.getName(), String.valueOf(producer.getID()), jsonSession.getString(ProducerField.ID.getName())); + Assert.assertEquals(ProducerField.NAME.getName(), producer.getName(), jsonSession.getString(ProducerField.NAME.getName())); + Assert.assertEquals(ProducerField.SESSION.getName(), producer.getSessionID(), jsonSession.getString(ProducerField.SESSION.getAlternativeName())); + Assert.assertEquals(ProducerField.ADDRESS.getName(), producer.getAddress(), jsonSession.getString(ProducerField.ADDRESS.getAlternativeName())); + Assert.assertEquals(ProducerField.MESSAGE_SENT.getName(), producer.getMessagesSent(), jsonSession.getJsonNumber(ProducerField.MESSAGE_SENT.getName()).longValue()); + Assert.assertEquals(ProducerField.MESSAGE_SENT_SIZE.getName(), producer.getMessagesSentSize(), jsonSession.getJsonNumber(ProducerField.MESSAGE_SENT_SIZE.getName()).longValue()); + Assert.assertEquals(ProducerField.CREATION_TIME.getName(), String.valueOf(producer.getCreationTime()), jsonSession.getString(ProducerField.CREATION_TIME.getName())); + } + } + + @Test + public void testListProducersAgainstServer() throws Exception { + SimpleString queueName1 = new SimpleString("my_queue_one"); + SimpleString addressName1 = new SimpleString("my_address_one"); + + ActiveMQServerControl serverControl = createManagementControl(); + + server.addAddressInfo(new AddressInfo(addressName1, RoutingType.ANYCAST)); + if (legacyCreateQueue) { + server.createQueue(addressName1, RoutingType.ANYCAST, queueName1, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName1).setAddress(addressName1).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + + // create some consumers + try (ServerLocator locator = createInVMNonHALocator(); ClientSessionFactory csf = createSessionFactory(locator);) { + + ClientSession session1 = csf.createSession(); + + ClientProducer producer1 = session1.createProducer(addressName1); + producer1.send(session1.createMessage(true)); + + //bring back all producers + String filterString = createJsonFilter("", "", ""); + String producersAsJsonString = serverControl.listProducers(filterString, 1, 50); + JsonObject producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + JsonArray array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 1 + extraProducers, array.size()); + + JsonObject jsonSession = array.getJsonObject(0); + + //get the only server producer + ServerProducer producer = server.getSessionByID(jsonSession.getString(ProducerField.SESSION.getName())).getServerProducers().iterator().next(); + //check all fields + Assert.assertEquals(ProducerField.ID.getName(), String.valueOf(producer.getID()), jsonSession.getString(ProducerField.ID.getName())); + Assert.assertEquals(ProducerField.SESSION.getName(), producer.getSessionID(), jsonSession.getString(ProducerField.SESSION.getName())); + Assert.assertEquals(ProducerField.PROTOCOL.getName(), producer.getProtocol(), jsonSession.getString(ProducerField.PROTOCOL.getName())); + Assert.assertEquals(ProducerField.ADDRESS.getName(), producer.getAddress(), jsonSession.getString(ProducerField.ADDRESS.getName())); + Assert.assertEquals(ProducerField.MESSAGE_SENT.getName(), producer.getMessagesSent(), jsonSession.getJsonNumber(ProducerField.MESSAGE_SENT.getName()).longValue()); + Assert.assertEquals(ProducerField.MESSAGE_SENT_SIZE.getName(), producer.getMessagesSentSize(), jsonSession.getJsonNumber(ProducerField.MESSAGE_SENT_SIZE.getName()).longValue()); + Assert.assertEquals(ProducerField.CREATION_TIME.getName(), String.valueOf(producer.getCreationTime()), jsonSession.getString(ProducerField.CREATION_TIME.getName())); + } + } + @Test + public void testListProducersJMSCore() throws Exception { + testListProducersJMS(ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY)), "CORE"); + } + + @Test + public void testListProducersJMSAMQP() throws Exception { + testListProducersJMS(new JmsConnectionFactory("amqp://localhost:61616"), "AMQP"); + } + + @Test + public void testListProducersJMSOW() throws Exception { + testListProducersJMS(new org.apache.activemq.ActiveMQConnectionFactory("tcp://localhost:61616"), "CORE"); + } + + public void testListProducersJMS(ConnectionFactory connectionFactory, String protocol) throws Exception { + String queueName = "my_queue_one"; + SimpleString ssQueueName = SimpleString.toSimpleString(queueName); + ActiveMQServerControl serverControl = createManagementControl(); + + server.addAddressInfo(new AddressInfo(ssQueueName, RoutingType.ANYCAST)); + if (legacyCreateQueue) { + server.createQueue(ssQueueName, RoutingType.ANYCAST, ssQueueName, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName).setAddress(queueName).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + // create some producers + try (Connection conn = connectionFactory.createConnection();) { + + Session session1 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + Session session2 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer producer1 = session1.createProducer(session1.createQueue(queueName)); + producer1.send(session1.createMessage()); + MessageProducer producer2 = session2.createProducer(session2.createQueue(queueName)); + producer2.send(session2.createMessage()); + + //bring back all producers + String filterString = createJsonFilter("", "", ""); + String producersAsJsonString = serverControl.listProducers(filterString, 1, 50); + JsonObject producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + JsonArray array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 2 + extraProducers, array.size()); + + boolean foundElement = false; + for (int i = 0; i < array.size(); i++) { + + JsonObject jsonSession = array.getJsonObject(i); + if (jsonSession.getString("address").equals("activemq.management")) { + continue; + } + + foundElement = true; + + //check all fields + Assert.assertNotEquals(ProducerField.ID.getName(), "", jsonSession.getString(ProducerField.ID.getName())); + Assert.assertNotEquals(ProducerField.SESSION.getName(), "", jsonSession.getString(ProducerField.SESSION.getName())); + Assert.assertEquals(ProducerField.USER.getName(), "", jsonSession.getString(ProducerField.USER.getName())); + Assert.assertNotEquals(ProducerField.PROTOCOL.getName(), "", jsonSession.getString(ProducerField.PROTOCOL.getName())); + Assert.assertEquals(ProducerField.ADDRESS.getName(), queueName, jsonSession.getString(ProducerField.ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.LOCAL_ADDRESS.getName(), "", jsonSession.getString(ProducerField.LOCAL_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.REMOTE_ADDRESS.getName(), "", jsonSession.getString(ProducerField.REMOTE_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.CREATION_TIME.getName(), "", jsonSession.getString(ProducerField.CREATION_TIME.getName())); + } + + Assert.assertTrue("Valid session not found", foundElement); + } + } + + @Test + public void testListProducersJMSLegacy() throws Exception { + String queueName = "my_queue_one"; + SimpleString ssQueueName = SimpleString.toSimpleString(queueName); + ActiveMQServerControl serverControl = createManagementControl(); + + server.addAddressInfo(new AddressInfo(ssQueueName, RoutingType.ANYCAST)); + if (legacyCreateQueue) { + server.createQueue(ssQueueName, RoutingType.ANYCAST, ssQueueName, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName).setAddress(queueName).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + + //pretend we are an olde client by removing the producer id and changing the session to use lagacy producers + server.getBrokerSessionPlugins().add(new ActiveMQServerSessionPlugin() { + @Override + public void beforeCreateSession(String name, String username, int minLargeMessageSize, RemotingConnection connection, boolean autoCommitSends, boolean autoCommitAcks, boolean preAcknowledge, boolean xa, String defaultAddress, SessionCallback callback, boolean autoCreateQueues, OperationContext context, Map prefixes) throws ActiveMQException { + ActiveMQServerSessionPlugin.super.beforeCreateSession(name, username, minLargeMessageSize, connection, autoCommitSends, autoCommitAcks, preAcknowledge, xa, defaultAddress, callback, autoCreateQueues, context, prefixes); + } + + @Override + public void afterCreateSession(ServerSession session) throws ActiveMQException { + try { + Field serverProducers = session.getClass().getDeclaredField("serverProducers"); + serverProducers.setAccessible(true); + serverProducers.set(session, new ServerLegacyProducersImpl(session)); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + }); + + ActiveMQConnectionFactory connectionFactory = ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY)); + // create some producers + try (Connection conn = connectionFactory.createConnection();) { + + Session session1 = conn.createSession(); + Session session2 = conn.createSession(); + + MessageProducer producer1 = session1.createProducer(session1.createQueue(queueName)); + producer1.send(session1.createMessage()); + MessageProducer producer2 = session2.createProducer(session2.createQueue(queueName)); + producer2.send(session2.createMessage()); + + //bring back all producers + String filterString = createJsonFilter("", "", ""); + String producersAsJsonString = serverControl.listProducers(filterString, 1, 50); + JsonObject producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + JsonArray array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 2, array.size()); + + boolean foundElement = false; + for (int i = 0; i < array.size(); i++) { + + JsonObject jsonSession = array.getJsonObject(i); + if (jsonSession.getString("address").equals("activemq.management")) { + continue; + } + + foundElement = true; + + //check all fields + Assert.assertNotEquals(ProducerField.ID.getName(), "", jsonSession.getString(ProducerField.ID.getName())); + Assert.assertNotEquals(ProducerField.SESSION.getName(), "", jsonSession.getString(ProducerField.SESSION.getName())); + Assert.assertEquals(ProducerField.USER.getName(), "", jsonSession.getString(ProducerField.USER.getName())); + Assert.assertNotEquals(ProducerField.PROTOCOL.getName(), "", jsonSession.getString(ProducerField.PROTOCOL.getName())); + Assert.assertEquals(ProducerField.ADDRESS.getName(), queueName, jsonSession.getString(ProducerField.ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.LOCAL_ADDRESS.getName(), "", jsonSession.getString(ProducerField.LOCAL_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.REMOTE_ADDRESS.getName(), "", jsonSession.getString(ProducerField.REMOTE_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.CREATION_TIME.getName(), "", jsonSession.getString(ProducerField.CREATION_TIME.getName())); + } + + Assert.assertTrue("Valid session not found", foundElement); + + session1.close(); + + filterString = createJsonFilter("", "", ""); + producersAsJsonString = serverControl.listProducers(filterString, 1, 50); + producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 1, array.size()); + + session2.close(); + + filterString = createJsonFilter("", "", ""); + producersAsJsonString = serverControl.listProducers(filterString, 1, 50); + producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 0, array.size()); + } + } + + @Test + public void testListFqqnProducersJMSLegacy() throws Exception { + SimpleString queueName1 = new SimpleString("my_queue_one"); + SimpleString addressName1 = new SimpleString("my_address_one"); + SimpleString FQQNName = new SimpleString(addressName1 + "::" + queueName1); + ActiveMQServerControl serverControl = createManagementControl(); + + server.addAddressInfo(new AddressInfo(FQQNName, RoutingType.ANYCAST)); + if (legacyCreateQueue) { + server.createQueue(FQQNName, RoutingType.ANYCAST, FQQNName, null, false, false); + } else { + server.createQueue(new QueueConfiguration(FQQNName).setAddress(FQQNName).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + + //pretend we are an olde client by removing the producer id and changing the session to use lagacy producers + server.getBrokerSessionPlugins().add(new ActiveMQServerSessionPlugin() { + @Override + public void beforeCreateSession(String name, String username, int minLargeMessageSize, RemotingConnection connection, boolean autoCommitSends, boolean autoCommitAcks, boolean preAcknowledge, boolean xa, String defaultAddress, SessionCallback callback, boolean autoCreateQueues, OperationContext context, Map prefixes) throws ActiveMQException { + ActiveMQServerSessionPlugin.super.beforeCreateSession(name, username, minLargeMessageSize, connection, autoCommitSends, autoCommitAcks, preAcknowledge, xa, defaultAddress, callback, autoCreateQueues, context, prefixes); + } + + @Override + public void afterCreateSession(ServerSession session) throws ActiveMQException { + try { + Field serverProducers = session.getClass().getDeclaredField("serverProducers"); + serverProducers.setAccessible(true); + serverProducers.set(session, new ServerLegacyProducersImpl(session)); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + }); + ActiveMQConnectionFactory connectionFactory = ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY)); + // create some producers + try (Connection conn = connectionFactory.createConnection();) { + + Session session1 = conn.createSession(); + + MessageProducer producer1 = session1.createProducer(session1.createQueue(FQQNName.toString())); + producer1.send(session1.createMessage()); + + //bring back all producers + String filterString = createJsonFilter("", "", ""); + String producersAsJsonString = serverControl.listProducers(filterString, 1, 200); + JsonObject producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + JsonArray array = (JsonArray) producersAsJsonObject.get("data"); + + //this is testing that the producers tracked hasnt exceededd the max of 100 + Assert.assertEquals("number of producers returned from query", 1, array.size()); + + boolean foundElement = false; + for (int i = 0; i < array.size(); i++) { + + JsonObject jsonSession = array.getJsonObject(i); + if (jsonSession.getString("address").equals("activemq.management")) { + continue; + } + + foundElement = true; + + //check all fields + Assert.assertNotEquals(ProducerField.ID.getName(), "", jsonSession.getString(ProducerField.ID.getName())); + Assert.assertNotEquals(ProducerField.SESSION.getName(), "", jsonSession.getString(ProducerField.SESSION.getName())); + Assert.assertEquals(ProducerField.USER.getName(), "", jsonSession.getString(ProducerField.USER.getName())); + Assert.assertNotEquals(ProducerField.PROTOCOL.getName(), "", jsonSession.getString(ProducerField.PROTOCOL.getName())); + Assert.assertEquals(ProducerField.ADDRESS.getName(), FQQNName.toString(), jsonSession.getString(ProducerField.ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.LOCAL_ADDRESS.getName(), "", jsonSession.getString(ProducerField.LOCAL_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.REMOTE_ADDRESS.getName(), "", jsonSession.getString(ProducerField.REMOTE_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.CREATION_TIME.getName(), "", jsonSession.getString(ProducerField.CREATION_TIME.getName())); + } + + Assert.assertTrue("Valid session not found", foundElement); + } + } + + @Test + public void testListAnonProducersJMSLegacy() throws Exception { + String queueName = "my_queue_one"; + SimpleString ssQueueName = SimpleString.toSimpleString(queueName); + ActiveMQServerControl serverControl = createManagementControl(); + + server.addAddressInfo(new AddressInfo(ssQueueName, RoutingType.ANYCAST)); + if (legacyCreateQueue) { + server.createQueue(ssQueueName, RoutingType.ANYCAST, ssQueueName, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName).setAddress(queueName).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + + //pretend we are an olde client by removing the producer id and changing the session to use lagacy producers + server.getBrokerSessionPlugins().add(new ActiveMQServerSessionPlugin() { + @Override + public void beforeCreateSession(String name, String username, int minLargeMessageSize, RemotingConnection connection, boolean autoCommitSends, boolean autoCommitAcks, boolean preAcknowledge, boolean xa, String defaultAddress, SessionCallback callback, boolean autoCreateQueues, OperationContext context, Map prefixes) throws ActiveMQException { + ActiveMQServerSessionPlugin.super.beforeCreateSession(name, username, minLargeMessageSize, connection, autoCommitSends, autoCommitAcks, preAcknowledge, xa, defaultAddress, callback, autoCreateQueues, context, prefixes); + } + + @Override + public void afterCreateSession(ServerSession session) throws ActiveMQException { + try { + Field serverProducers = session.getClass().getDeclaredField("serverProducers"); + serverProducers.setAccessible(true); + serverProducers.set(session, new ServerLegacyProducersImpl(session)); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + }); + + ActiveMQConnectionFactory connectionFactory = ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY)); + // create some producers + try (Connection conn = connectionFactory.createConnection();) { + + Session session1 = conn.createSession(); + + MessageProducer producer1 = session1.createProducer(null); + for ( int i = 0; i < 110; i++) { + javax.jms.Queue queue = session1.createQueue(queueName + i); + producer1.send(queue, session1.createMessage()); + } + + //bring back all producers + String filterString = createJsonFilter("", "", ""); + String producersAsJsonString = serverControl.listProducers(filterString, 1, 200); + JsonObject producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + JsonArray array = (JsonArray) producersAsJsonObject.get("data"); + + //this is testing that the producers tracked hasnt exceededd the max of 100 + Assert.assertEquals("number of producers returned from query", 100, array.size()); + + boolean foundElement = false; + for (int i = 0; i < array.size(); i++) { + + JsonObject jsonSession = array.getJsonObject(i); + if (jsonSession.getString("address").equals("activemq.management")) { + continue; + } + + foundElement = true; + + //check all fields + Assert.assertNotEquals(ProducerField.ID.getName(), "", jsonSession.getString(ProducerField.ID.getName())); + Assert.assertNotEquals(ProducerField.SESSION.getName(), "", jsonSession.getString(ProducerField.SESSION.getName())); + Assert.assertEquals(ProducerField.USER.getName(), "", jsonSession.getString(ProducerField.USER.getName())); + Assert.assertNotEquals(ProducerField.PROTOCOL.getName(), "", jsonSession.getString(ProducerField.PROTOCOL.getName())); + Assert.assertNotEquals(ProducerField.LOCAL_ADDRESS.getName(), "", jsonSession.getString(ProducerField.LOCAL_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.REMOTE_ADDRESS.getName(), "", jsonSession.getString(ProducerField.REMOTE_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.CREATION_TIME.getName(), "", jsonSession.getString(ProducerField.CREATION_TIME.getName())); + } + + Assert.assertTrue("Valid session not found", foundElement); + + session1.close(); + + filterString = createJsonFilter("", "", ""); + producersAsJsonString = serverControl.listProducers(filterString, 1, 110); + producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 0, array.size()); + } + } + + @Test + public void testListProducersJMSCoreMultipleProducers() throws Exception { + testListProducersJMSMultipleProducers(ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY)), "CORE"); + } + + @Test + public void testListProducersJMSAMQPMultipleProducers() throws Exception { + testListProducersJMSMultipleProducers(new JmsConnectionFactory("amqp://localhost:61616"), "AMQP"); + } + + @Test + public void testListProducersJMSOpenWireMultipleProducers() throws Exception { + testListProducersJMSMultipleProducers(new org.apache.activemq.ActiveMQConnectionFactory("tcp://localhost:61616"), "OPENWIRE"); + } + public void testListProducersJMSMultipleProducers(ConnectionFactory connectionFactory, String protocol) throws Exception { + String queueName = "my_queue_one"; + SimpleString ssQueueName = SimpleString.toSimpleString(queueName); + ActiveMQServerControl serverControl = createManagementControl(); + + server.addAddressInfo(new AddressInfo(ssQueueName, RoutingType.ANYCAST)); + if (legacyCreateQueue) { + server.createQueue(ssQueueName, RoutingType.ANYCAST, ssQueueName, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName).setAddress(queueName).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + // create some producers + try (Connection conn = connectionFactory.createConnection();) { + + Session session1 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer producer1 = session1.createProducer(session1.createQueue(queueName)); + producer1.send(session1.createMessage()); + + //bring back all producers + String filterString = createJsonFilter("", "", ""); + String producersAsJsonString = serverControl.listProducers(filterString, 1, 50); + JsonObject producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + JsonArray array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 1 + extraProducers, array.size()); + + boolean foundElement = false; + for (int i = 0; i < array.size(); i++) { + + JsonObject jsonSession = array.getJsonObject(i); + if (jsonSession.getString("address").equals("activemq.management")) { + continue; + } + + foundElement = true; + + //check all fields + Assert.assertNotEquals(ProducerField.ID.getName(), "", jsonSession.getString(ProducerField.ID.getName())); + Assert.assertNotEquals(ProducerField.SESSION.getName(), "", jsonSession.getString(ProducerField.SESSION.getName())); + Assert.assertEquals(ProducerField.USER.getName(), "", jsonSession.getString(ProducerField.USER.getName())); + Assert.assertNotEquals(ProducerField.PROTOCOL.getName(), "", jsonSession.getString(ProducerField.PROTOCOL.getName())); + Assert.assertEquals(ProducerField.ADDRESS.getName(), queueName, jsonSession.getString(ProducerField.ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.LOCAL_ADDRESS.getName(), "", jsonSession.getString(ProducerField.LOCAL_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.REMOTE_ADDRESS.getName(), "", jsonSession.getString(ProducerField.REMOTE_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.CREATION_TIME.getName(), "", jsonSession.getString(ProducerField.CREATION_TIME.getName())); + } + + MessageProducer producer2 = session1.createProducer(session1.createQueue(queueName)); + producer2.send(session1.createMessage()); + + producersAsJsonString = serverControl.listProducers(filterString, 1, 50); + producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 2 + extraProducers, array.size()); + + producer1.close(); + + Wait.assertEquals(1 + extraProducers, () -> ((JsonArray) JsonUtil.readJsonObject(serverControl.listProducers(filterString, 1, 50)).get("data")).size()); + + producersAsJsonString = serverControl.listProducers(filterString, 1, 50); + producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 1 + extraProducers, array.size()); + + Assert.assertTrue("Valid session not found", foundElement); + } + } + + @Test + public void testListProducersJMSAnonCore() throws Exception { + testListProducersJMSAnon(ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY)), "CORE"); + } + + @Test + public void testListProducersJMSAnonAMQP() throws Exception { + testListProducersJMSAnon(new JmsConnectionFactory("amqp://localhost:61616"), "AMQP"); + } + + @Test + public void testListProducersJMSAnonOW() throws Exception { + testListProducersJMSAnon(new org.apache.activemq.ActiveMQConnectionFactory("tcp://localhost:61616"), "OPENWIRE"); + } + + public void testListProducersJMSAnon(ConnectionFactory connectionFactory, String protocol) throws Exception { + String queueName1 = "my_queue_one"; + String queueName2 = "my_queue_two"; + String queueName3 = "my_queue_three"; + SimpleString ssQueueName1 = SimpleString.toSimpleString(queueName1); + SimpleString ssQueueName2 = SimpleString.toSimpleString(queueName2); + SimpleString ssQueueName3 = SimpleString.toSimpleString(queueName3); + ActiveMQServerControl serverControl = createManagementControl(); + + server.addAddressInfo(new AddressInfo(ssQueueName1, RoutingType.ANYCAST)); + server.addAddressInfo(new AddressInfo(ssQueueName2, RoutingType.ANYCAST)); + server.addAddressInfo(new AddressInfo(ssQueueName3, RoutingType.ANYCAST)); + if (legacyCreateQueue) { + server.createQueue(ssQueueName1, RoutingType.ANYCAST, ssQueueName1, null, false, false); + server.createQueue(ssQueueName2, RoutingType.ANYCAST, ssQueueName2, null, false, false); + server.createQueue(ssQueueName3, RoutingType.ANYCAST, ssQueueName3, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName1).setAddress(queueName1).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + server.createQueue(new QueueConfiguration(queueName2).setAddress(queueName2).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + server.createQueue(new QueueConfiguration(queueName3).setAddress(queueName3).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + // create some producers + try (Connection conn = connectionFactory.createConnection();) { + + Session session1 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + Session session2 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + javax.jms.Queue queue1 = session1.createQueue(queueName1); + javax.jms.Queue queue2 = session1.createQueue(queueName2); + javax.jms.Queue queue3 = session1.createQueue(queueName3); + MessageProducer producer1 = session1.createProducer(null); + producer1.send(queue1, session1.createMessage()); + producer1.send(queue2, session1.createMessage()); + producer1.send(queue3, session1.createMessage()); + MessageProducer producer2 = session2.createProducer(null); + producer2.send(queue1, session2.createMessage()); + producer2.send(queue2, session2.createMessage()); + producer2.send(queue3, session2.createMessage()); + + //bring back all producers + String filterString = createJsonFilter("", "", ""); + String producersAsJsonString = serverControl.listProducers(filterString, 1, 50); + JsonObject producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + JsonArray array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 2 + extraProducers, array.size()); + + boolean foundElement = false; + for (int i = 0; i < array.size(); i++) { + + JsonObject jsonSession = array.getJsonObject(i); + if (jsonSession.getString("address").equals("activemq.management")) { + continue; + } + + foundElement = true; + + //check all fields + Assert.assertNotEquals(ProducerField.ID.getName(), "", jsonSession.getString(ProducerField.ID.getName())); + Assert.assertNotEquals(ProducerField.SESSION.getName(), "", jsonSession.getString(ProducerField.SESSION.getName())); + Assert.assertEquals(ProducerField.USER.getName(), "", jsonSession.getString(ProducerField.USER.getName())); + Assert.assertNotEquals(ProducerField.PROTOCOL.getName(), "", jsonSession.getString(ProducerField.PROTOCOL.getName())); + Assert.assertNotEquals(ProducerField.LOCAL_ADDRESS.getName(), "", jsonSession.getString(ProducerField.LOCAL_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.REMOTE_ADDRESS.getName(), "", jsonSession.getString(ProducerField.REMOTE_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.CREATION_TIME.getName(), "", jsonSession.getString(ProducerField.CREATION_TIME.getName())); + } + + Assert.assertTrue("Valid session not found", foundElement); + } + } + + @Test + public void testListProducersJMSTopicCore() throws Exception { + testListProducersJMSTopic(ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY)), "CORE"); + } + + @Test + public void testListProducersJMSTopicAMQP() throws Exception { + testListProducersJMSTopic(new JmsConnectionFactory("amqp://localhost:61616"), "AMQP"); + } + + @Test + public void testListProducersJMSTopicOW() throws Exception { + testListProducersJMSTopic(new org.apache.activemq.ActiveMQConnectionFactory("tcp://localhost:61616"), "OPENWIRE"); + } + public void testListProducersJMSTopic(ConnectionFactory connectionFactory, String protocol) throws Exception { + SimpleString topicName = SimpleString.toSimpleString("my-topic"); + ActiveMQServerControl serverControl = createManagementControl(); + + server.addAddressInfo(new AddressInfo(topicName, RoutingType.MULTICAST)); + if (legacyCreateQueue) { + return; + } + + server.addAddressInfo(new AddressInfo("")); + + try (Connection conn = connectionFactory.createConnection();) { + conn.setClientID("clientID"); + Session session1 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + Session session2 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Topic topic = session1.createTopic(topicName.toString()); + TopicSubscriber mysub1 = session1.createDurableSubscriber(topic, "mysub1"); + TopicSubscriber mysub2 = session2.createDurableSubscriber(topic, "mysub2"); + MessageProducer producer1 = session1.createProducer(topic); + producer1.send(session1.createMessage()); + MessageProducer producer2 = session2.createProducer(session2.createTopic(topicName.toString())); + producer2.send(session2.createMessage()); + + //bring back all producers + String filterString = createJsonFilter("", "", ""); + String producersAsJsonString = serverControl.listProducers(filterString, 1, 50); + JsonObject producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + JsonArray array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 2 + extraProducers, array.size()); + + boolean foundElement = false; + for (int i = 0; i < array.size(); i++) { + + JsonObject jsonSession = array.getJsonObject(i); + if (jsonSession.getString("address").equals("activemq.management")) { + continue; + } + + foundElement = true; + + //check all fields + Assert.assertNotEquals(ProducerField.ID.getName(), "", jsonSession.getString(ProducerField.ID.getName())); + Assert.assertNotEquals(ProducerField.SESSION.getName(), "", jsonSession.getString(ProducerField.SESSION.getName())); + Assert.assertEquals(ProducerField.USER.getName(), "", jsonSession.getString(ProducerField.USER.getName())); + Assert.assertNotEquals(ProducerField.PROTOCOL.getName(), "", jsonSession.getString(ProducerField.PROTOCOL.getName())); + Assert.assertEquals(ProducerField.ADDRESS.getName(), topicName.toString(), jsonSession.getString(ProducerField.ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.LOCAL_ADDRESS.getName(), "", jsonSession.getString(ProducerField.LOCAL_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.REMOTE_ADDRESS.getName(), "", jsonSession.getString(ProducerField.REMOTE_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.CREATION_TIME.getName(), "", jsonSession.getString(ProducerField.CREATION_TIME.getName())); + } + + //remove the subs and make sure producers still exist + mysub1.close(); + mysub2.close(); + session1.unsubscribe("mysub1"); + session2.unsubscribe("mysub2"); + producersAsJsonString = serverControl.listProducers(filterString, 1, 50); + producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + array = (JsonArray) producersAsJsonObject.get("data"); + assertEquals(2 + extraProducers, array.size()); + Assert.assertTrue("Valid session not found", foundElement); + } + } + + @Test + public void testListProducersFQQN() throws Exception { + SimpleString queueName1 = new SimpleString("my_queue_one"); + SimpleString addressName1 = new SimpleString("my_address_one"); + SimpleString FQQNName = new SimpleString(addressName1 + "::" + queueName1); + ActiveMQServerControl serverControl = createManagementControl(); + + server.addAddressInfo(new AddressInfo(addressName1, RoutingType.ANYCAST)); + if (legacyCreateQueue) { + server.createQueue(addressName1, RoutingType.ANYCAST, queueName1, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName1).setAddress(addressName1).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + + // create some consumers + try (ServerLocator locator = createInVMNonHALocator(); ClientSessionFactory csf = createSessionFactory(locator);) { + + ClientSession session1 = csf.createSession(); + ClientSession session2 = csf.createSession(); + + ClientProducer producer1 = session1.createProducer(FQQNName); + producer1.send(session1.createMessage(true)); + ClientProducer producer2 = session2.createProducer(FQQNName); + producer2.send(session2.createMessage(true)); + + //bring back all producers + String filterString = createJsonFilter("", "", ""); + String producersAsJsonString = serverControl.listProducers(filterString, 1, 50); + JsonObject producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + JsonArray array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 2 + extraProducers, array.size()); + + boolean foundElement = false; + for (int i = 0; i < array.size(); i++) { + + JsonObject jsonSession = array.getJsonObject(i); + if (jsonSession.getString("address").equals("activemq.management")) { + continue; + } + + foundElement = true; + + //check all fields + Assert.assertNotEquals(ProducerField.ID.getName(), "", jsonSession.getString(ProducerField.ID.getName())); + Assert.assertNotEquals(ProducerField.SESSION.getName(), "", jsonSession.getString(ProducerField.SESSION.getName())); + Assert.assertEquals(ProducerField.USER.getName(), "", jsonSession.getString(ProducerField.USER.getName())); + Assert.assertNotEquals(ProducerField.PROTOCOL.getName(), "", jsonSession.getString(ProducerField.PROTOCOL.getName())); + Assert.assertEquals(ProducerField.ADDRESS.getName(), FQQNName.toString(), jsonSession.getString(ProducerField.ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.LOCAL_ADDRESS.getName(), "", jsonSession.getString(ProducerField.LOCAL_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.REMOTE_ADDRESS.getName(), "", jsonSession.getString(ProducerField.REMOTE_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.CREATION_TIME.getName(), "", jsonSession.getString(ProducerField.CREATION_TIME.getName())); + } + + session1.deleteQueue(queueName1); + + producersAsJsonString = serverControl.listProducers(filterString, 1, 50); + producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + array = (JsonArray) producersAsJsonObject.get("data"); + + //make sure both producers still exist as we dont tie them to an address which would only be recreated on another send + assertEquals(2 + extraProducers, array.size()); + + Assert.assertTrue("Valid session not found", foundElement); + } + } + + @Test + public void testListProducersMessageCountsJMSCore() throws Exception { + testListProducersMessageCountsJMS(ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY)), "CORE"); + } + + @Test + public void testListProducersMessageCountsAMQPJMS() throws Exception { + testListProducersMessageCountsJMS(new JmsConnectionFactory("amqp://localhost:61616"), "AMQP"); + } + + @Test + public void testListProducersMessageCountsOWJMS() throws Exception { + testListProducersMessageCountsJMS(new org.apache.activemq.ActiveMQConnectionFactory("tcp://localhost:61616"), "OPENWIRE"); + } + + public void testListProducersMessageCountsJMS(ConnectionFactory connectionFactory, String protocol) throws Exception { + String myQueue = "my_queue"; + SimpleString queueName1 = new SimpleString(myQueue); + SimpleString addressName1 = new SimpleString(myQueue); + + + ActiveMQServerControl serverControl = createManagementControl(); + + server.addAddressInfo(new AddressInfo(addressName1, RoutingType.ANYCAST)); + if (legacyCreateQueue) { + server.createQueue(addressName1, RoutingType.ANYCAST, queueName1, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName1).setAddress(addressName1).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + + int numMessages = 10; + + try (Connection connection = connectionFactory.createConnection();) { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(session.createQueue(myQueue)); + for (int i = 0; i < numMessages; i++) { + javax.jms.Message message = session.createMessage(); + producer.send(message); + } + //bring back all producers + String filterString = createJsonFilter("", "", ""); + String producersAsJsonString = serverControl.listProducers(filterString, 1, 50); + JsonObject producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + JsonArray array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 1 + extraProducers, array.size()); + + JsonObject jsonSession = array.getJsonObject(0); + + //check all fields + Assert.assertNotEquals(ProducerField.ID.getName(), "", jsonSession.getString(ProducerField.ID.getName())); + Assert.assertNotEquals(ProducerField.SESSION.getName(), "", jsonSession.getString(ProducerField.SESSION.getName())); + Assert.assertEquals(ProducerField.USER.getName(), "", jsonSession.getString(ProducerField.USER.getName())); + Assert.assertEquals(ProducerField.PROTOCOL.getAlternativeName(), protocol, jsonSession.getString(ProducerField.PROTOCOL.getName())); + Assert.assertEquals(ProducerField.ADDRESS.getName(), addressName1.toString(), jsonSession.getString(ProducerField.ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.LOCAL_ADDRESS.getName(), "", jsonSession.getString(ProducerField.LOCAL_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.REMOTE_ADDRESS.getName(), "", jsonSession.getString(ProducerField.REMOTE_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.CREATION_TIME.getName(), "", jsonSession.getString(ProducerField.CREATION_TIME.getName())); + Assert.assertEquals(ProducerField.MESSAGE_SENT.getName(), numMessages, jsonSession.getInt(ProducerField.MESSAGE_SENT.getName())); + Assert.assertNotEquals(ProducerField.LAST_PRODUCED_MESSAGE_ID.getName(), "", jsonSession.getString(ProducerField.LAST_PRODUCED_MESSAGE_ID.getName())); + } + } + + + @Test + public void testListProducersMessageCounts() throws Exception { + SimpleString queueName1 = new SimpleString("my_queue_one"); + SimpleString addressName1 = new SimpleString("my_address_one"); + + ActiveMQServerControl serverControl = createManagementControl(); + + server.addAddressInfo(new AddressInfo(addressName1, RoutingType.ANYCAST)); + if (legacyCreateQueue) { + server.createQueue(addressName1, RoutingType.ANYCAST, queueName1, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName1).setAddress(addressName1).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + + int numMessages = 10; + + + // create some consumers + try (ServerLocator locator = createInVMNonHALocator(); ClientSessionFactory csf = createSessionFactory(locator);) { + + ClientSession session1 = csf.createSession(); + + ClientProducer producer1 = session1.createProducer(addressName1); + int messagesSize = 0; + for (int i = 0; i < numMessages; i++) { + ClientMessage message = session1.createMessage(true); + producer1.send(message); + messagesSize += message.getEncodeSize(); + } + //bring back all producers + String filterString = createJsonFilter("", "", ""); + String producersAsJsonString = serverControl.listProducers(filterString, 1, 50); + JsonObject producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + JsonArray array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 1 + extraProducers, array.size()); + + JsonObject jsonSession = array.getJsonObject(0); + + //check all fields + Assert.assertNotEquals(ProducerField.ID.getName(), "", jsonSession.getString(ProducerField.ID.getName())); + Assert.assertNotEquals(ProducerField.SESSION.getName(), "", jsonSession.getString(ProducerField.SESSION.getName())); + Assert.assertEquals(ProducerField.CLIENT_ID.getName(), "", jsonSession.getString(ProducerField.CLIENT_ID.getName())); + Assert.assertEquals(ProducerField.USER.getName(), "", jsonSession.getString(ProducerField.USER.getName())); + Assert.assertNotEquals(ProducerField.PROTOCOL.getAlternativeName(), "", jsonSession.getString(ProducerField.PROTOCOL.getName())); + Assert.assertEquals(ProducerField.ADDRESS.getName(), addressName1.toString(), jsonSession.getString(ProducerField.ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.LOCAL_ADDRESS.getName(), "", jsonSession.getString(ProducerField.LOCAL_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.REMOTE_ADDRESS.getName(), "", jsonSession.getString(ProducerField.REMOTE_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.CREATION_TIME.getName(), "", jsonSession.getString(ProducerField.CREATION_TIME.getName())); + Assert.assertEquals(ProducerField.MESSAGE_SENT.getName(), numMessages, jsonSession.getInt(ProducerField.MESSAGE_SENT.getName())); + Assert.assertEquals(ProducerField.MESSAGE_SENT_SIZE.getName(), messagesSize, jsonSession.getInt(ProducerField.MESSAGE_SENT_SIZE.getName())); + Assert.assertEquals(ProducerField.LAST_PRODUCED_MESSAGE_ID.getName(), "", jsonSession.getString(ProducerField.LAST_PRODUCED_MESSAGE_ID.getName())); + } + } + + @Test + public void testListProducersMessageCounts2() throws Exception { + SimpleString queueName1 = new SimpleString("my_queue_one"); + SimpleString addressName1 = new SimpleString("my_address_one"); + + ActiveMQServerControl serverControl = createManagementControl(); + + server.addAddressInfo(new AddressInfo(addressName1, RoutingType.ANYCAST)); + if (legacyCreateQueue) { + server.createQueue(addressName1, RoutingType.ANYCAST, queueName1, null, false, false); + } else { + server.createQueue(new QueueConfiguration(queueName1).setAddress(addressName1).setRoutingType(RoutingType.ANYCAST).setDurable(false)); + } + + int numMessages = 10; + + + // create some consumers + try (ServerLocator locator = createInVMNonHALocator(); ClientSessionFactory csf = createSessionFactory(locator);) { + + ClientSession session1 = csf.createSession(); + + ClientProducer producer1 = session1.createProducer(addressName1); + int messagesSize = 0; + for (int i = 0; i < numMessages; i++) { + ClientMessage message = session1.createMessage(true); + producer1.send(message); + messagesSize += message.getEncodeSize(); + } + //bring back all producers + String producersAsJsonString = serverControl.listProducersInfoAsJSON(); + JsonArray jsonArray = JsonUtil.readJsonArray(producersAsJsonString); + + JsonObject jsonSession = jsonArray.getJsonObject(0); + + if (!jsonSession.getString(ProducerField.ADDRESS.getAlternativeName()).equalsIgnoreCase(addressName1.toString())) { + jsonSession = jsonArray.getJsonObject(1); + } + + //check all fields + Assert.assertNotEquals(ProducerField.ID.getName(), "", jsonSession.getString(ProducerField.ID.getName())); + Assert.assertNotEquals(ProducerField.NAME.getName(), "", jsonSession.getString(ProducerField.NAME.getName())); + Assert.assertNotEquals(ProducerField.SESSION.getAlternativeName(), "", jsonSession.getString(ProducerField.SESSION.getAlternativeName())); + Assert.assertNotEquals(ProducerField.CREATION_TIME.getName(), "", jsonSession.getString(ProducerField.CREATION_TIME.getName())); + Assert.assertEquals(ProducerField.MESSAGE_SENT.getName(), numMessages, jsonSession.getInt(ProducerField.MESSAGE_SENT.getName())); + Assert.assertEquals(ProducerField.MESSAGE_SENT_SIZE.getName(), messagesSize, jsonSession.getInt(ProducerField.MESSAGE_SENT_SIZE.getName())); + Assert.assertEquals(ProducerField.LAST_PRODUCED_MESSAGE_ID.getName(), JsonValue.NULL, jsonSession.get(ProducerField.LAST_PRODUCED_MESSAGE_ID.getName())); + } + } + @Test public void testMemoryUsagePercentage() throws Exception { //messages size 100K @@ -4565,16 +6148,6 @@ public class ActiveMQServerControlTest extends ManagementTestBase { return ManagementControlHelper.createActiveMQServerControl(mbeanServer); } - - private String createJsonFilter(String fieldName, String operationName, String value) { - HashMap filterMap = new HashMap<>(); - filterMap.put("field", fieldName); - filterMap.put("operation", operationName); - filterMap.put("value", value); - JsonObject jsonFilterObject = JsonUtil.toJsonObject(filterMap); - return jsonFilterObject.toString(); - } - private String createJsonFilter(String fieldName, String operationName, String value,String sortColumn, String sortOrder) { HashMap filterMap = new HashMap<>(); filterMap.put("field", fieldName); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java index f141a8ba66..d42e45a3eb 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java @@ -31,6 +31,7 @@ public class ActiveMQServerControlUsingCoreTest extends ActiveMQServerControlTes public ActiveMQServerControlUsingCoreTest(boolean legacyCreateQueue) { super(legacyCreateQueue); + extraProducers = 1; } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/QueueControlTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/QueueControlTest.java index b59147fb1b..693118a601 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/QueueControlTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/QueueControlTest.java @@ -19,14 +19,24 @@ package org.apache.activemq.artemis.tests.integration.management; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.DeliveryMode; +import javax.jms.MessageConsumer; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; +import org.apache.activemq.artemis.api.core.TransportConfiguration; +import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient; +import org.apache.activemq.artemis.api.jms.JMSFactoryType; +import org.apache.activemq.artemis.core.management.impl.view.ConsumerField; import org.apache.activemq.artemis.core.paging.impl.PagingManagerTestAccessor; import org.apache.activemq.artemis.core.server.impl.QueueImplTestAccessor; +import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory; import org.apache.activemq.artemis.json.JsonArray; import org.apache.activemq.artemis.json.JsonObject; + +import javax.jms.XAConnection; +import javax.jms.XAConnectionFactory; +import javax.jms.XASession; import javax.management.Notification; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; @@ -466,6 +476,10 @@ public class QueueControlTest extends ManagementTestBase { assertEquals(1, obj.size()); + assertEquals(0, obj.get(0).asJsonObject().getInt(ConsumerField.LAST_DELIVERED_TIME.getName())); + + assertEquals(0, obj.get(0).asJsonObject().getInt(ConsumerField.LAST_ACKNOWLEDGED_TIME.getName())); + consumer.close(); Assert.assertEquals(0, queueControl.getConsumerCount()); @@ -476,6 +490,442 @@ public class QueueControlTest extends ManagementTestBase { session.deleteQueue(queue); } + @Test + public void testGetConsumerWithMessagesJSON() throws Exception { + long currentTime = System.currentTimeMillis(); + SimpleString address = RandomUtil.randomSimpleString(); + SimpleString queue = RandomUtil.randomSimpleString(); + + session.createQueue(new QueueConfiguration(queue).setAddress(address).setDurable(durable)); + + QueueControl queueControl = createManagementControl(address, queue); + + ClientProducer producer = session.createProducer(address); + + for (int i = 0; i < 10; i++) { + producer.send(session.createMessage(true)); + } + + Wait.assertEquals(0, () -> queueControl.getConsumerCount()); + + ClientConsumer consumer = session.createConsumer(queue); + Wait.assertEquals(1, () -> queueControl.getConsumerCount()); + + session.start(); + + ClientMessage clientMessage = null; + + int size = 0; + for (int i = 0; i < 5; i++) { + clientMessage = consumer.receiveImmediate(); + size += clientMessage.getEncodeSize(); + } + + JsonArray obj = JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()); + + assertEquals(1, obj.size()); + + Wait.assertEquals(5, () -> JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()).get(0).asJsonObject().getInt(ConsumerField.MESSAGES_IN_TRANSIT.getName())); + + obj = JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()); + + JsonObject jsonObject = obj.get(0).asJsonObject(); + + assertEquals(5, jsonObject.getInt(ConsumerField.MESSAGES_IN_TRANSIT.getName())); + + assertEquals(size, jsonObject.getInt(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName())); + + assertEquals(5, jsonObject.getInt(ConsumerField.MESSAGES_DELIVERED.getName())); + + assertEquals(size, jsonObject.getInt(ConsumerField.MESSAGES_DELIVERED_SIZE.getName())); + + assertEquals(0, jsonObject.getInt(ConsumerField.MESSAGES_ACKNOWLEDGED.getName())); + + long lastDelivered = jsonObject.getJsonNumber(ConsumerField.LAST_DELIVERED_TIME.getName()).longValue(); + + assertTrue(lastDelivered > currentTime); + + assertEquals( 0, jsonObject.getInt(ConsumerField.LAST_ACKNOWLEDGED_TIME.getName())); + + clientMessage.acknowledge(); + + session.commit(); + + Wait.assertEquals(5, () -> JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()).get(0).asJsonObject().getInt(ConsumerField.MESSAGES_ACKNOWLEDGED.getName())); + + obj = JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()); + + jsonObject = obj.get(0).asJsonObject(); + + assertEquals(0, jsonObject.getInt(ConsumerField.MESSAGES_IN_TRANSIT.getName())); + + long lastAcked = jsonObject.getJsonNumber(ConsumerField.LAST_ACKNOWLEDGED_TIME.getName()).longValue(); + + assertTrue("lastAcked = " + lastAcked + " lastDelivered = " + lastDelivered, lastAcked >= lastDelivered); + + currentTime = System.currentTimeMillis(); + + //now make sure they fall between the test time window + assertTrue("currentTime = " + currentTime + " lastAcked = " + lastAcked,currentTime >= lastAcked); + + consumer.close(); + + Assert.assertEquals(0, queueControl.getConsumerCount()); + + obj = JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()); + + assertEquals(0, obj.size()); + + session.deleteQueue(queue); + } + + @Test + public void testGetConsumerMessageCountsAutoAckCore() throws Exception { + ActiveMQConnectionFactory factory = ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY)); + factory.setConsumerWindowSize(1); + testGetConsumerMessageCountsAutoAck(factory, false); + } + + @Test + public void testGetConsumerMessageCountsAutoAckAMQP() throws Exception { + testGetConsumerMessageCountsAutoAck(new JmsConnectionFactory("amqp://localhost:61616"), false); + } + + @Test + public void testGetConsumerMessageCountsAutoAckOpenWire() throws Exception { + testGetConsumerMessageCountsAutoAck(new org.apache.activemq.ActiveMQConnectionFactory("tcp://localhost:61616"), false); + } + + @Test + public void testGetConsumerMessageCountsAutoAckCoreIndividualAck() throws Exception { + ActiveMQConnectionFactory factory = ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY)); + testGetConsumerMessageCountsAutoAck(factory, true); + } + + public void testGetConsumerMessageCountsAutoAck(ConnectionFactory factory, boolean usePriority) throws Exception { + SimpleString queueName = RandomUtil.randomSimpleString(); + this.session.createQueue(new QueueConfiguration(queueName).setAddress(queueName).setDurable(durable).setRoutingType(RoutingType.ANYCAST)); + + QueueControl queueControl = createManagementControl(queueName, queueName, RoutingType.ANYCAST); + Connection connection = factory.createConnection(); + try { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + javax.jms.Queue queue = session.createQueue(queueName.toString()); + + MessageProducer producer = session.createProducer(queue); + + for (int i = 0; i < 100; i++) { + javax.jms.Message message = session.createMessage(); + if (usePriority) { + producer.send(message, DeliveryMode.PERSISTENT, 1, javax.jms.Message.DEFAULT_TIME_TO_LIVE); + } else { + producer.send(message); + } + } + + MessageConsumer consumer = session.createConsumer(queue); + + connection.start(); + + javax.jms.Message message = null; + + for (int i = 0; i < 100; i++) { + message = consumer.receive(5000); + Assert.assertNotNull("message " + i + " not received",message); + } + + JsonArray obj = JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()); + + assertEquals(1, obj.size()); + + Wait.assertEquals(0, () -> JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()).get(0).asJsonObject().getInt(ConsumerField.MESSAGES_IN_TRANSIT.getName())); + Wait.assertEquals(0, () -> JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()).get(0).asJsonObject().getInt(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName())); + + + obj = JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()); + + JsonObject jsonObject = obj.get(0).asJsonObject(); + + assertEquals(0, jsonObject.getInt(ConsumerField.MESSAGES_IN_TRANSIT.getName())); + + assertEquals(0, jsonObject.getInt(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName())); + + assertEquals(100, jsonObject.getInt(ConsumerField.MESSAGES_DELIVERED.getName())); + + assertTrue(jsonObject.getInt(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()) > 0); + + assertEquals(100, jsonObject.getInt(ConsumerField.MESSAGES_ACKNOWLEDGED.getName())); + + assertEquals(0, jsonObject.getInt(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName())); + + consumer.close(); + } finally { + connection.close(); + } + } + + @Test + public void testGetConsumerMessageCountsClientAckCore() throws Exception { + ActiveMQConnectionFactory factory = ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY)); + factory.setConsumerWindowSize(1); + testGetConsumerMessageCountsClientAck(factory, false); + } + + @Test + public void testGetConsumerMessageCountsClientAckAMQP() throws Exception { + testGetConsumerMessageCountsClientAck(new JmsConnectionFactory("amqp://localhost:61616"), false); + } + + @Test + public void testGetConsumerMessageCountsClientAckOpenWire() throws Exception { + testGetConsumerMessageCountsClientAck(new org.apache.activemq.ActiveMQConnectionFactory("tcp://localhost:61616"), false); + } + + public void testGetConsumerMessageCountsClientAck(ConnectionFactory factory, boolean usePriority) throws Exception { + SimpleString queueName = RandomUtil.randomSimpleString(); + this.session.createQueue(new QueueConfiguration(queueName).setAddress(queueName).setDurable(durable).setRoutingType(RoutingType.ANYCAST)); + + QueueControl queueControl = createManagementControl(queueName, queueName, RoutingType.ANYCAST); + Connection connection = factory.createConnection(); + try { + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + javax.jms.Queue queue = session.createQueue(queueName.toString()); + + MessageProducer producer = session.createProducer(queue); + + for (int i = 0; i < 100; i++) { + javax.jms.Message message = session.createMessage(); + if (usePriority) { + producer.send(message, DeliveryMode.PERSISTENT, 1, javax.jms.Message.DEFAULT_TIME_TO_LIVE); + } else { + producer.send(message); + } + } + + MessageConsumer consumer = session.createConsumer(queue); + + connection.start(); + + javax.jms.Message message = null; + + for (int i = 0; i < 100; i++) { + message = consumer.receive(5000); + Assert.assertNotNull("message " + i + " not received",message); + message.acknowledge(); + } + + JsonArray obj = JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()); + + assertEquals(1, obj.size()); + + Wait.assertEquals(0, () -> JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()).get(0).asJsonObject().getInt(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName())); + Wait.assertEquals(0, () -> JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()).get(0).asJsonObject().getInt(ConsumerField.MESSAGES_IN_TRANSIT.getName())); + Wait.assertEquals(0, () -> JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()).get(0).asJsonObject().getInt(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName())); + + obj = JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()); + + JsonObject jsonObject = obj.get(0).asJsonObject(); + + assertEquals(0, jsonObject.getInt(ConsumerField.MESSAGES_IN_TRANSIT.getName())); + + assertEquals(0, jsonObject.getInt(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName())); + + assertEquals(100, jsonObject.getInt(ConsumerField.MESSAGES_DELIVERED.getName())); + + assertTrue(jsonObject.getInt(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()) > 0); + + assertEquals(100, jsonObject.getInt(ConsumerField.MESSAGES_ACKNOWLEDGED.getName())); + + assertEquals(0, jsonObject.getInt(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName())); + + consumer.close(); + } finally { + connection.close(); + } + } + + @Test + public void testGetConsumerMessageCountsTransactedCore() throws Exception { + ActiveMQConnectionFactory factory = ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY)); + factory.setConsumerWindowSize(1); + testGetConsumerMessageCountsTransacted(factory, false); + } + + @Test + public void testGetConsumerMessageCountsTransactedAMQP() throws Exception { + testGetConsumerMessageCountsTransacted(new JmsConnectionFactory("amqp://localhost:61616"), false); + } + + @Test + public void testGetConsumerMessageCountsTransactedOpenWire() throws Exception { + testGetConsumerMessageCountsTransacted(new org.apache.activemq.ActiveMQConnectionFactory("tcp://localhost:61616"), false); + } + + public void testGetConsumerMessageCountsTransacted(ConnectionFactory factory, boolean usePriority) throws Exception { + SimpleString queueName = RandomUtil.randomSimpleString(); + this.session.createQueue(new QueueConfiguration(queueName).setAddress(queueName).setDurable(durable).setRoutingType(RoutingType.ANYCAST)); + + QueueControl queueControl = createManagementControl(queueName, queueName, RoutingType.ANYCAST); + Connection connection = factory.createConnection(); + try { + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + + javax.jms.Queue queue = session.createQueue(queueName.toString()); + + MessageProducer producer = session.createProducer(queue); + + for (int i = 0; i < 100; i++) { + javax.jms.Message message = session.createMessage(); + if (usePriority) { + producer.send(message, DeliveryMode.PERSISTENT, 1, javax.jms.Message.DEFAULT_TIME_TO_LIVE); + } else { + producer.send(message); + } + } + session.commit(); + MessageConsumer consumer = session.createConsumer(queue); + + connection.start(); + + javax.jms.Message message = null; + + for (int i = 0; i < 100; i++) { + message = consumer.receive(5000); + Assert.assertNotNull("message " + i + " not received",message); + } + + session.commit(); + + JsonArray obj = JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()); + + assertEquals(1, obj.size()); + + Wait.assertEquals(0, () -> JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()).get(0).asJsonObject().getInt(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName())); + + obj = JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()); + + JsonObject jsonObject = obj.get(0).asJsonObject(); + + assertEquals(0, jsonObject.getInt(ConsumerField.MESSAGES_IN_TRANSIT.getName())); + + assertEquals(0, jsonObject.getInt(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName())); + + assertEquals(100, jsonObject.getInt(ConsumerField.MESSAGES_DELIVERED.getName())); + + assertTrue(jsonObject.getInt(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()) > 0); + + assertEquals(100, jsonObject.getInt(ConsumerField.MESSAGES_ACKNOWLEDGED.getName())); + + assertEquals(0, jsonObject.getInt(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName())); + + consumer.close(); + } finally { + connection.close(); + } + } + + @Test + public void testGetConsumerMessageCountsTransactedXACore() throws Exception { + ActiveMQConnectionFactory factory = ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY)); + factory.setConsumerWindowSize(1); + testGetConsumerMessageCountsTransactedXA(factory, false); + } + + @Test + public void testGetConsumerMessageCountsTransactedXAOpenWire() throws Exception { + testGetConsumerMessageCountsTransactedXA(new org.apache.activemq.ActiveMQXAConnectionFactory("tcp://localhost:61616"), false); + } + public void testGetConsumerMessageCountsTransactedXA(XAConnectionFactory factory, boolean usePriority) throws Exception { + SimpleString queueName = RandomUtil.randomSimpleString(); + this.session.createQueue(new QueueConfiguration(queueName).setAddress(queueName).setDurable(durable).setRoutingType(RoutingType.ANYCAST)); + + QueueControl queueControl = createManagementControl(queueName, queueName, RoutingType.ANYCAST); + XAConnection connection = factory.createXAConnection(); + try { + XASession session = connection.createXASession(); + + XidImpl xid = newXID(); + javax.jms.Queue queue = session.createQueue(queueName.toString()); + + MessageProducer producer = session.createProducer(queue); + session.getXAResource().start(xid, XAResource.TMNOFLAGS); + for (int i = 0; i < 100; i++) { + javax.jms.Message message = session.createMessage(); + if (usePriority) { + producer.send(message, DeliveryMode.PERSISTENT, 1, javax.jms.Message.DEFAULT_TIME_TO_LIVE); + } else { + producer.send(message); + } + } + session.getXAResource().end(xid, XAResource.TMSUCCESS); + session.getXAResource().commit(xid, true); + + MessageConsumer consumer = session.createConsumer(queue); + + connection.start(); + xid = newXID(); + javax.jms.Message message = null; + session.getXAResource().start(xid, XAResource.TMNOFLAGS); + for (int i = 0; i < 100; i++) { + message = consumer.receive(5000); + Assert.assertNotNull("message " + i + " not received",message); + } + session.getXAResource().end(xid, XAResource.TMSUCCESS); + + JsonArray obj = JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()); + + assertEquals(1, obj.size()); + + Wait.assertEquals(100, () -> JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()).get(0).asJsonObject().getInt(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName())); + + obj = JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()); + + JsonObject jsonObject = obj.get(0).asJsonObject(); + + assertEquals(0, jsonObject.getInt(ConsumerField.MESSAGES_IN_TRANSIT.getName())); + + assertEquals(0, jsonObject.getInt(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName())); + + assertEquals(100, jsonObject.getInt(ConsumerField.MESSAGES_DELIVERED.getName())); + + assertTrue(jsonObject.getInt(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()) > 0); + + assertEquals(100, jsonObject.getInt(ConsumerField.MESSAGES_ACKNOWLEDGED.getName())); + + assertEquals(100, jsonObject.getInt(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName())); + + session.getXAResource().commit(xid, true); + + obj = JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()); + + assertEquals(1, obj.size()); + + Wait.assertEquals(0, () -> JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()).get(0).asJsonObject().getInt(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName())); + + obj = JsonUtil.readJsonArray(queueControl.listConsumersAsJSON()); + + jsonObject = obj.get(0).asJsonObject(); + + assertEquals(0, jsonObject.getInt(ConsumerField.MESSAGES_IN_TRANSIT.getName())); + + assertEquals(0, jsonObject.getInt(ConsumerField.MESSAGES_IN_TRANSIT_SIZE.getName())); + + assertEquals(100, jsonObject.getInt(ConsumerField.MESSAGES_DELIVERED.getName())); + + assertTrue(jsonObject.getInt(ConsumerField.MESSAGES_DELIVERED_SIZE.getName()) > 0); + + assertEquals(100, jsonObject.getInt(ConsumerField.MESSAGES_ACKNOWLEDGED.getName())); + + assertEquals(0, jsonObject.getInt(ConsumerField.MESSAGES_ACKNOWLEDGED_AWAITING_COMMIT.getName())); + + consumer.close(); + } finally { + connection.close(); + } + } + @Test public void testGetMessageCount() throws Exception { SimpleString address = RandomUtil.randomSimpleString(); @@ -589,7 +1039,7 @@ public class QueueControlTest extends ManagementTestBase { if (key.equals("StringProperties")) { // these are very verbose composite data structures - assertTrue(value.toString().length() + " truncated? " + key, value.toString().length() <= 2048); + assertTrue(value.toString().length() + " truncated? " + key, value.toString().length() <= 3000); } else { assertTrue(value.toString().length() + " truncated? " + key, value.toString().length() <= 512); } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt/MQTTTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt/MQTTTest.java index bab1e2d834..aee3ba78be 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt/MQTTTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt/MQTTTest.java @@ -37,12 +37,14 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; +import org.apache.activemq.artemis.api.core.JsonUtil; import org.apache.activemq.artemis.api.core.QueueConfiguration; import org.apache.activemq.artemis.api.core.RoutingType; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.api.core.client.ActiveMQClient; import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.config.CoreAddressConfiguration; +import org.apache.activemq.artemis.core.management.impl.view.ProducerField; import org.apache.activemq.artemis.core.postoffice.Binding; import org.apache.activemq.artemis.core.postoffice.QueueBinding; import org.apache.activemq.artemis.core.protocol.mqtt.MQTTUtil; @@ -50,6 +52,8 @@ import org.apache.activemq.artemis.core.server.ActiveMQServer; import org.apache.activemq.artemis.core.server.Queue; import org.apache.activemq.artemis.core.server.impl.AddressInfo; import org.apache.activemq.artemis.core.settings.impl.AddressSettings; +import org.apache.activemq.artemis.json.JsonArray; +import org.apache.activemq.artemis.json.JsonObject; import org.apache.activemq.artemis.logs.AssertionLoggerHandler; import org.apache.activemq.artemis.tests.util.Wait; import org.apache.activemq.transport.amqp.client.AmqpClient; @@ -168,6 +172,63 @@ public class MQTTTest extends MQTTTestSupport { publishProvider.disconnect(); } + @Test + public void testProducerMetrics() throws Exception { + + final MQTTClientProvider publishProvider = getMQTTClientProvider(); + initializeConnection(publishProvider); + + for (int i = 0; i < NUM_MESSAGES; i++) { + String payload = "Message " + i; + publishProvider.publish("foo/bah", payload.getBytes(), AT_LEAST_ONCE); + } + + String filterString = createJsonFilter("", "", ""); + String producersAsJsonString = server.getActiveMQServerControl().listProducers(filterString, 1, 50); + JsonObject producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + JsonArray array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 1, array.size()); + + JsonObject producer = array.getJsonObject(0); + + Assert.assertNotEquals(ProducerField.ID.getName(), "", producer.getString(ProducerField.ID.getName())); + Assert.assertNotEquals(ProducerField.SESSION.getName(), "", producer.getString(ProducerField.SESSION.getName())); + Assert.assertNotEquals(ProducerField.CLIENT_ID.getName(), "", producer.getString(ProducerField.CLIENT_ID.getName())); + Assert.assertEquals(ProducerField.USER.getName(), "", producer.getString(ProducerField.USER.getName())); + Assert.assertEquals(ProducerField.PROTOCOL.getAlternativeName(), "MQTT", producer.getString(ProducerField.PROTOCOL.getName())); + Assert.assertEquals(ProducerField.ADDRESS.getName(), "ANONYMOUS", producer.getString(ProducerField.ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.LOCAL_ADDRESS.getName(), "", producer.getString(ProducerField.LOCAL_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.REMOTE_ADDRESS.getName(), "", producer.getString(ProducerField.REMOTE_ADDRESS.getName())); + Assert.assertNotEquals(ProducerField.CREATION_TIME.getName(), "", producer.getString(ProducerField.CREATION_TIME.getName())); + Assert.assertEquals(ProducerField.MESSAGE_SENT.getName(), NUM_MESSAGES, producer.getInt(ProducerField.MESSAGE_SENT.getName())); + Assert.assertEquals(ProducerField.LAST_PRODUCED_MESSAGE_ID.getName(), "", producer.getString(ProducerField.LAST_PRODUCED_MESSAGE_ID.getName())); + + final MQTTClientProvider publishProvider2 = getMQTTClientProvider(); + initializeConnection(publishProvider2); + for (int i = 0; i < NUM_MESSAGES; i++) { + String payload = "Message " + i; + publishProvider2.publish("foo/bah", payload.getBytes(), AT_LEAST_ONCE); + } + filterString = createJsonFilter("", "", ""); + producersAsJsonString = server.getActiveMQServerControl().listProducers(filterString, 1, 50); + producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 2, array.size()); + publishProvider.disconnect(); + + + publishProvider2.disconnect(); + + filterString = createJsonFilter("", "", ""); + producersAsJsonString = server.getActiveMQServerControl().listProducers(filterString, 1, 50); + producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 0, array.size()); + } + @Test(timeout = 60 * 1000) public void testDirectDeliverFalse() throws Exception { final MQTTClientProvider subscriptionProvider = getMQTTClientProvider(); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/StompTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/StompTest.java index 00fb0f66bd..e326be7fc1 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/StompTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/StompTest.java @@ -34,6 +34,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; +import org.apache.activemq.artemis.api.core.JsonUtil; import org.apache.activemq.artemis.api.core.QueueConfiguration; import org.apache.activemq.artemis.api.core.RoutingType; import org.apache.activemq.artemis.api.core.SimpleString; @@ -47,6 +48,7 @@ import org.apache.activemq.artemis.api.core.management.ActiveMQServerControl; import org.apache.activemq.artemis.api.core.management.ManagementHelper; import org.apache.activemq.artemis.api.core.management.ResourceNames; import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient; +import org.apache.activemq.artemis.core.management.impl.view.ProducerField; import org.apache.activemq.artemis.core.postoffice.Binding; import org.apache.activemq.artemis.core.postoffice.QueueBinding; import org.apache.activemq.artemis.core.postoffice.impl.LocalQueueBinding; @@ -59,6 +61,8 @@ import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl; import org.apache.activemq.artemis.core.server.impl.AddressInfo; import org.apache.activemq.artemis.core.settings.impl.AddressSettings; import org.apache.activemq.artemis.jms.client.ActiveMQMessage; +import org.apache.activemq.artemis.json.JsonArray; +import org.apache.activemq.artemis.json.JsonObject; import org.apache.activemq.artemis.logs.AssertionLoggerHandler; import org.apache.activemq.artemis.reader.MessageUtil; import org.apache.activemq.artemis.spi.core.remoting.Acceptor; @@ -163,6 +167,44 @@ public class StompTest extends StompTestBase { assertTrue(latch.await(60, TimeUnit.SECONDS)); } + @Test + public void testProducerMetrics() throws Exception { + conn.connect(defUser, defPass); + + send(conn, getQueuePrefix() + getQueueName(), null, "Hello World!", true); + + String filterString = createJsonFilter("", "", ""); + String producersAsJsonString = server.getActiveMQServerControl().listProducers(filterString, 1, 50); + JsonObject producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + JsonArray array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 1, array.size()); + + JsonObject producer = array.getJsonObject(0); + Assert.assertEquals(ProducerField.MESSAGE_SENT.getName(), 1, producer.getInt(ProducerField.MESSAGE_SENT.getName())); + + send(conn, getQueuePrefix() + getQueueName(), null, "Hello World!", true); + + producersAsJsonString = server.getActiveMQServerControl().listProducers(filterString, 1, 50); + producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 1, array.size()); + + producer = array.getJsonObject(0); + Assert.assertEquals(ProducerField.MESSAGE_SENT.getName(), 2, producer.getInt(ProducerField.MESSAGE_SENT.getName())); + + conn.closeTransport(); + + Wait.assertEquals(0, () -> ((JsonArray) JsonUtil.readJsonObject(server.getActiveMQServerControl().listProducers(filterString, 1, 50)).get("data")).size()); + + producersAsJsonString = server.getActiveMQServerControl().listProducers(filterString, 1, 50); + producersAsJsonObject = JsonUtil.readJsonObject(producersAsJsonString); + array = (JsonArray) producersAsJsonObject.get("data"); + + Assert.assertEquals("number of producers returned from query", 0, array.size()); + } + @Test public void testSendOverDiskFull() throws Exception { AssertionLoggerHandler.startCapture();