Commit 336714a4 authored by Markus Koschany's avatar Markus Koschany

Imported Upstream version 5.13.3+dfsg

parent 0ed42d96
......@@ -14,7 +14,7 @@
<parent>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-parent</artifactId>
<version>5.13.2</version>
<version>5.13.3</version>
</parent>
<artifactId>activemq-all</artifactId>
......@@ -127,6 +127,7 @@
<include>org.springframework:spring-context</include>
<include>org.springframework:spring-expression</include>
<include>org.springframework:spring-jms</include>
<include>org.springframework:spring-messaging</include>
<include>org.springframework:spring-tx</include>
<include>org.apache.xbean:xbean-spring</include>
<include>org.apache.camel:camel-jms</include>
......
......@@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-parent</artifactId>
<version>5.13.2</version>
<version>5.13.3</version>
</parent>
<artifactId>activemq-amqp</artifactId>
......
/**
/*
* 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.
......@@ -118,14 +118,17 @@ public abstract class InboundTransformer {
} else {
jms.setJMSDeliveryMode(defaultDeliveryMode);
}
if (header.getPriority() != null) {
jms.setJMSPriority(header.getPriority().intValue());
} else {
jms.setJMSPriority(defaultPriority);
}
if (header.getFirstAcquirer() != null) {
jms.setBooleanProperty(prefixVendor + "FirstAcquirer", header.getFirstAcquirer());
}
if (header.getDeliveryCount() != null) {
vendor.setJMSXDeliveryCount(jms, header.getDeliveryCount().longValue());
}
......@@ -188,7 +191,7 @@ public abstract class InboundTransformer {
final Properties properties = amqp.getProperties();
if (properties != null) {
if (properties.getMessageId() != null) {
jms.setJMSMessageID(properties.getMessageId().toString());
jms.setJMSMessageID(AMQPMessageIdHelper.INSTANCE.toBaseMessageIdString(properties.getMessageId()));
}
Binary userId = properties.getUserId();
if (userId != null) {
......@@ -236,6 +239,7 @@ public abstract class InboundTransformer {
if (header.getTtl() != null) {
ttl = header.getTtl().longValue();
}
if (ttl == 0) {
jms.setJMSExpiration(0);
} else {
......
......@@ -41,6 +41,7 @@ import javax.jms.Topic;
import org.apache.activemq.command.ActiveMQMessage;
import org.apache.activemq.command.MessageId;
import org.apache.activemq.transport.amqp.AmqpProtocolException;
import org.apache.qpid.proton.amqp.Binary;
import org.apache.qpid.proton.amqp.Symbol;
import org.apache.qpid.proton.amqp.UnsignedByte;
......@@ -180,7 +181,11 @@ public class JMSMappingOutboundTransformer extends OutboundTransformer {
MessageId msgId = amqMsg.getMessageId();
if (msgId.getTextView() != null) {
props.setMessageId(msgId.getTextView());
try {
props.setMessageId(AMQPMessageIdHelper.INSTANCE.toIdObject(msgId.getTextView()));
} catch (AmqpProtocolException e) {
props.setMessageId(msgId.getTextView().toString());
}
} else {
props.setMessageId(msgId.toString());
}
......
......@@ -198,6 +198,32 @@ public class AmqpMessage {
return message.getProperties().getMessageId().toString();
}
/**
* Return the set MessageId value in the original form, if there are no properties
* in the given message return null.
*
* @return the set message ID in its original form or null if not set.
*/
public Object getRawMessageId() {
if (message.getProperties() == null) {
return null;
}
return message.getProperties().getMessageId();
}
/**
* Sets the MessageId property on an outbound message using the provided value
*
* @param messageId
* the message ID value to set.
*/
public void setRawMessageId(Object messageId) {
checkReadOnly();
lazyCreateProperties();
getWrappedMessage().setMessageId(messageId);
}
/**
* Sets the GroupId property on an outbound message using the provided String
*
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.transport.amqp.interop;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.apache.activemq.broker.jmx.QueueViewMBean;
import org.apache.activemq.transport.amqp.client.AmqpClient;
import org.apache.activemq.transport.amqp.client.AmqpClientTestSupport;
import org.apache.activemq.transport.amqp.client.AmqpConnection;
import org.apache.activemq.transport.amqp.client.AmqpMessage;
import org.apache.activemq.transport.amqp.client.AmqpReceiver;
import org.apache.activemq.transport.amqp.client.AmqpSender;
import org.apache.activemq.transport.amqp.client.AmqpSession;
import org.apache.qpid.proton.amqp.Binary;
import org.apache.qpid.proton.amqp.UnsignedLong;
import org.junit.Test;
/**
* Tests that the AMQP MessageID value and type are preserved.
*/
public class AmqpMessageIdPreservationTest extends AmqpClientTestSupport {
@Override
protected boolean isPersistent() {
return true;
}
@Test(timeout = 60000)
public void testStringMessageIdIsPreserved() throws Exception {
doTestMessageIdPreservation("msg-id-string:1");
}
@Test(timeout = 60000)
public void testStringMessageIdIsPreservedAfterRestart() throws Exception {
doTestMessageIdPreservationOnBrokerRestart("msg-id-string:1");
}
@Test(timeout = 60000)
public void testUUIDMessageIdIsPreserved() throws Exception {
doTestMessageIdPreservation(UUID.randomUUID());
}
@Test(timeout = 60000)
public void testUUIDMessageIdIsPreservedAfterRestart() throws Exception {
doTestMessageIdPreservationOnBrokerRestart(UUID.randomUUID());
}
@Test(timeout = 60000)
public void testUnsignedLongMessageIdIsPreserved() throws Exception {
doTestMessageIdPreservation(new UnsignedLong(255l));
}
@Test(timeout = 60000)
public void testUnsignedLongMessageIdIsPreservedAfterRestart() throws Exception {
doTestMessageIdPreservationOnBrokerRestart(new UnsignedLong(255l));
}
@Test(timeout = 60000)
public void testBinaryLongMessageIdIsPreserved() throws Exception {
byte[] payload = new byte[32];
for (int i = 0; i < 32; ++i) {
payload[i] = (byte) ('a' + i);
}
doTestMessageIdPreservation(new Binary(payload));
}
@Test(timeout = 60000)
public void testBinaryLongMessageIdIsPreservedAfterRestart() throws Exception {
byte[] payload = new byte[32];
for (int i = 0; i < 32; ++i) {
payload[i] = (byte) ('a' + i);
}
doTestMessageIdPreservationOnBrokerRestart(new Binary(payload));
}
@Test(timeout = 60000)
public void testStringMessageIdPrefixIsPreserved() throws Exception {
doTestMessageIdPreservation("ID:msg-id-string:1");
}
public void doTestMessageIdPreservation(Object messageId) throws Exception {
AmqpClient client = createAmqpClient();
AmqpConnection connection = client.connect();
AmqpSession session = connection.createSession();
AmqpSender sender = session.createSender("queue://" + getTestName());
AmqpMessage message = new AmqpMessage();
message.setRawMessageId(messageId);
message.setText("Test-Message");
sender.send(message);
sender.close();
QueueViewMBean queue = getProxyToQueue(getTestName());
assertEquals(1, queue.getQueueSize());
AmqpReceiver receiver = session.createReceiver("queue://" + getTestName());
receiver.flow(1);
AmqpMessage received = receiver.receive(5, TimeUnit.SECONDS);
assertNotNull("Should have got a message", received);
assertEquals(received.getRawMessageId().getClass(), messageId.getClass());
assertEquals(messageId, received.getRawMessageId());
receiver.close();
connection.close();
}
public void doTestMessageIdPreservationOnBrokerRestart(Object messageId) throws Exception {
AmqpClient client = createAmqpClient();
AmqpConnection connection = client.connect();
AmqpSession session = connection.createSession();
AmqpSender sender = session.createSender("queue://" + getTestName());
AmqpMessage message = new AmqpMessage();
message.setRawMessageId(messageId);
message.setText("Test-Message");
message.setDurable(true);
sender.send(message);
sender.close();
connection.close();
restartBroker();
QueueViewMBean queue = getProxyToQueue(getTestName());
assertEquals(1, queue.getQueueSize());
connection = client.connect();
session = connection.createSession();
AmqpReceiver receiver = session.createReceiver("queue://" + getTestName());
receiver.flow(1);
AmqpMessage received = receiver.receive(5, TimeUnit.SECONDS);
assertNotNull("Should have got a message", received);
assertEquals(received.getRawMessageId().getClass(), messageId.getClass());
assertEquals(messageId, received.getRawMessageId());
receiver.close();
connection.close();
}
}
......@@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-parent</artifactId>
<version>5.13.2</version>
<version>5.13.3</version>
</parent>
<artifactId>activemq-blueprint</artifactId>
......
......@@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-parent</artifactId>
<version>5.13.2</version>
<version>5.13.3</version>
</parent>
<artifactId>activemq-broker</artifactId>
......
......@@ -289,15 +289,14 @@ public class AdvisoryBroker extends BrokerFilter {
//in case of multiple matches
VirtualConsumerPair key = new VirtualConsumerPair(virtualDestination, destination);
ConsumerInfo i = brokerConsumerDests.get(key);
if (consumerInfo.equals(i)) {
if (brokerConsumerDests.remove(key) != null) {
if (consumerInfo.equals(i) && brokerConsumerDests.remove(key) != null) {
LOG.debug("Virtual consumer pair removed: {} for consumer: {} ", key, i);
fireVirtualDestinationRemoveAdvisory(context, consumerInfo);
break;
}
}
}
}
}
// ensure we don't modify (and loose/overwrite) an in-flight add advisory, so duplicate
info = info.copy();
......@@ -549,6 +548,7 @@ public class AdvisoryBroker extends BrokerFilter {
super.virtualDestinationAdded(context, virtualDestination);
if (virtualDestinations.add(virtualDestination)) {
LOG.debug("Virtual destination added: {}", virtualDestination);
try {
// Don't advise advisory topics.
if (!AdvisorySupport.isAdvisoryTopic(virtualDestination.getVirtualDestination())) {
......@@ -592,22 +592,27 @@ public class AdvisoryBroker extends BrokerFilter {
//if no consumer info, we need to create one - this is the case when an advisory is fired
//because of the existence of a destination matching a virtual destination
if (info == null) {
//store the virtual destination and the activeMQDestination as a pair so that we can keep track
//of all matching forwarded destinations that caused demand
VirtualConsumerPair pair = new VirtualConsumerPair(virtualDestination, activeMQDest);
if (brokerConsumerDests.get(pair) == null) {
ConnectionId connectionId = new ConnectionId(connectionIdGenerator.generateId());
SessionId sessionId = new SessionId(connectionId, sessionIdGenerator.getNextSequenceId());
ConsumerId consumerId = new ConsumerId(sessionId, consumerIdGenerator.getNextSequenceId());
info = new ConsumerInfo(consumerId);
//store the virtual destination and the activeMQDestination as a pair so that we can keep track
//of all matching forwarded destinations that caused demand
if(brokerConsumerDests.putIfAbsent(new VirtualConsumerPair(virtualDestination, activeMQDest), info) == null) {
if(brokerConsumerDests.putIfAbsent(pair, info) == null) {
LOG.debug("Virtual consumer pair added: {} for consumer: {} ", pair, info);
info.setDestination(virtualDestination.getVirtualDestination());
ActiveMQTopic topic = AdvisorySupport.getVirtualDestinationConsumerAdvisoryTopic(info.getDestination());
if (virtualDestinationConsumers.putIfAbsent(info, virtualDestination) == null) {
LOG.debug("Virtual consumer added: {}, for virtual destination: {}", info, virtualDestination);
fireConsumerAdvisory(context, info.getDestination(), topic, info);
}
}
}
//this is the case of a real consumer coming online
} else {
info = info.copy();
......@@ -615,6 +620,7 @@ public class AdvisoryBroker extends BrokerFilter {
ActiveMQTopic topic = AdvisorySupport.getVirtualDestinationConsumerAdvisoryTopic(info.getDestination());
if (virtualDestinationConsumers.putIfAbsent(info, virtualDestination) == null) {
LOG.debug("Virtual consumer added: {}, for virtual destination: {}", info, virtualDestination);
fireConsumerAdvisory(context, info.getDestination(), topic, info);
}
}
......@@ -626,6 +632,7 @@ public class AdvisoryBroker extends BrokerFilter {
super.virtualDestinationRemoved(context, virtualDestination);
if (virtualDestinations.remove(virtualDestination)) {
LOG.debug("Virtual destination removed: {}", virtualDestination);
try {
consumersLock.readLock().lock();
try {
......@@ -636,17 +643,18 @@ public class AdvisoryBroker extends BrokerFilter {
//find all consumers for this virtual destination
if (virtualDestinationConsumers.get(info).equals(virtualDestination)) {
fireVirtualDestinationRemoveAdvisory(context, info);
}
//check consumers created for the existence of a destination to see if they
//match the consumerinfo and clean up
for (VirtualConsumerPair activeMQDest : brokerConsumerDests.keySet()) {
ConsumerInfo i = brokerConsumerDests.get(activeMQDest);
if (info.equals(i)) {
brokerConsumerDests.remove(activeMQDest);
if (info.equals(i) && brokerConsumerDests.remove(activeMQDest) != null) {
LOG.debug("Virtual consumer pair removed: {} for consumer: {} ", activeMQDest, i);
}
}
}
}
}
}
} finally {
......@@ -663,6 +671,7 @@ public class AdvisoryBroker extends BrokerFilter {
VirtualDestination virtualDestination = virtualDestinationConsumers.remove(info);
if (virtualDestination != null) {
LOG.debug("Virtual consumer removed: {}, for virtual destination: {}", info, virtualDestination);
ActiveMQTopic topic = AdvisorySupport.getVirtualDestinationConsumerAdvisoryTopic(virtualDestination.getVirtualDestination());
ActiveMQDestination dest = info.getDestination();
......@@ -897,6 +906,7 @@ public class AdvisoryBroker extends BrokerFilter {
this.virtualDestination = virtualDestination;
this.activeMQDestination = activeMQDestination;
}
@Override
public int hashCode() {
final int prime = 31;
......@@ -912,6 +922,7 @@ public class AdvisoryBroker extends BrokerFilter {
.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
......@@ -935,6 +946,13 @@ public class AdvisoryBroker extends BrokerFilter {
return false;
return true;
}
@Override
public String toString() {
return "VirtualConsumerPair [virtualDestination=" + virtualDestination + ", activeMQDestination="
+ activeMQDestination + "]";
}
private AdvisoryBroker getOuterType() {
return AdvisoryBroker.this;
}
......
......@@ -35,8 +35,8 @@ import org.apache.activemq.usage.SystemUsage;
public class HealthView implements HealthViewMBean {
ManagedRegionBroker broker;
String currentState = "Good";
private ManagedRegionBroker broker;
private volatile String currentState = "Good";
public HealthView(ManagedRegionBroker broker) {
this.broker = broker;
......@@ -87,6 +87,7 @@ public class HealthView implements HealthViewMBean {
while (dir != null && !dir.isDirectory()) {
dir = dir.getParentFile();
}
long storeSize = adapter.size();
long storeLimit = usage.getStoreUsage().getLimit();
long dirFreeSpace = dir.getUsableSpace();
......@@ -166,18 +167,30 @@ public class HealthView implements HealthViewMBean {
}
}
StringBuilder currentState = new StringBuilder();
if (answer != null && !answer.isEmpty()) {
this.currentState = "Getting Worried {";
currentState.append("Getting Worried {");
for (HealthStatus hs : answer) {
currentState += hs + " , ";
currentState.append(hs).append(" , ");
}
currentState += " }";
currentState.append(" }");
} else {
this.currentState = "Good";
currentState.append("Good");
}
this.currentState = currentState.toString();
return answer;
}
@Override
public String healthStatus() throws Exception {
// Must invoke healthList in order to update state.
healthList();
return getCurrentStatus();
}
/**
* @return String representation of the current Broker state
*/
......
......@@ -33,13 +33,26 @@ public interface HealthViewMBean {
* like <a href="http://jolokia.org/">jolokia</a> to access JMX.
*
* If in doubt, please use the {@link #getCurrentStatus()} method instead!
*
* @return a list of HealthStatus objects that describe the health of the Broker.
*/
@MBeanInfo("List of warnings and errors about the current health of the Broker - empty list is Good!")
List<HealthStatus> healthList() throws Exception;
/**
* @return a String representation of current Broker health state.
*/
@MBeanInfo("String representation of current Broker state")
String healthStatus() throws Exception;
/**
* Warning, this method only return a value if the health or healthList method has previously
* been called. The value is not updated on its own and requires periodic calls to the health
* or healthList methods to refresh its value.
*
* @return String representation of the current Broker state
*/
@MBeanInfo("String representation of current Broker state")
String getCurrentStatus();
}
......@@ -26,102 +26,137 @@ public class NetworkConnectorView implements NetworkConnectorViewMBean {
this.connector = connector;
}
@Override
public void start() throws Exception {
connector.start();
}
@Override
public void stop() throws Exception {
connector.stop();
}
@Override
public String getName() {
return connector.getName();
}
@Override
public int getMessageTTL() {
return connector.getMessageTTL();
}
@Override
public int getConsumerTTL() {
return connector.getConsumerTTL();
}
@Override
public int getPrefetchSize() {
return connector.getPrefetchSize();
}
@Override
public int getAdvisoryPrefetchSize() {
return connector.getAdvisoryPrefetchSize();
}
@Override
public String getUserName() {
return connector.getUserName();
}
@Override
public boolean isBridgeTempDestinations() {
return connector.isBridgeTempDestinations();
}
@Override
public boolean isConduitSubscriptions() {
return connector.isConduitSubscriptions();
}
@Override
public boolean isDecreaseNetworkConsumerPriority() {
return connector.isDecreaseNetworkConsumerPriority();
}
@Override
public boolean isDispatchAsync() {
return connector.isDispatchAsync();
}
@Override
public boolean isDynamicOnly() {
return connector.isDynamicOnly();
}
@Override
public boolean isDuplex() {
return connector.isDuplex();
}
@Override
public boolean isSuppressDuplicateQueueSubscriptions() {
return connector.isSuppressDuplicateQueueSubscriptions();
}
@Override
public boolean isSuppressDuplicateTopicSubscriptions() {
return connector.isSuppressDuplicateTopicSubscriptions();
}
@Override
public void setBridgeTempDestinations(boolean bridgeTempDestinations) {
connector.setBridgeTempDestinations(bridgeTempDestinations);
}
@Override
public void setConduitSubscriptions(boolean conduitSubscriptions) {
connector.setConduitSubscriptions(conduitSubscriptions);
}
@Override
public void setDispatchAsync(boolean dispatchAsync) {
connector.setDispatchAsync(dispatchAsync);
}
@Override
public void setDynamicOnly(boolean dynamicOnly) {
connector.setDynamicOnly(dynamicOnly);
}
@Override